def build_positional_args(self, candidate, callsite):
"""Attempt to convert the positional and keyword args supplied at
the given callsite to the positional args expected by the candidate
funcdef.
Return a list of ast.Node instances, or raise ValueError if it
can't be done.
"""
if len(callsite.args) > len(candidate.args.args):
raise ValueError('too many positional arguments')
slots = {}
for idx, arg in enumerate(callsite.args):
slots[idx] = arg
for actual_kwarg in get_keywords(callsite):
idx = locate_kwarg(candidate, actual_kwarg.arg)
if idx in slots:
raise ValueError('positional slot %i already filled' % idx)
slots[idx] = actual_kwarg.value
actual_pos_args = []
for idx in range(len(candidate.args.args)):
if idx not in slots:
raise ValueError('argument %i not filled' % idx)
actual_pos_args.append(slots[idx])
return actual_pos_args
python类Node()的实例源码
def make_op_name_dict(self):
'''
Make a dict whose keys are operators ('+', '+=', etc),
and whose values are lists of values of ast.Node.__class__.__name__.
'''
d = {
'.': ['Attr',],
'(*)': ['Call', 'Tuple',],
'[*]': ['List', 'Subscript',],
'{*}': ['???',],
### 'and': 'BoolOp',
### 'or': 'BoolOp',
}
for op in (
'+', '-', '*', '/', '%', '**', '<<',
'>>', '|', '^', '&', '//',
):
d[op] = ['BinOp',]
for op in (
'==', '!=', '<', '<=', '>', '>=',
'is', 'is not', 'in', 'not in',
):
d[op] = ['Compare',]
return d
def transform_ast(self, node):
"""Apply the AST transformations from self.ast_transformers
Parameters
----------
node : ast.Node
The root node to be transformed. Typically called with the ast.Module
produced by parsing user input.
Returns
-------
An ast.Node corresponding to the node it was called with. Note that it
may also modify the passed object, so don't rely on references to the
original AST.
"""
for transformer in self.ast_transformers:
try:
node = transformer.visit(node)
except InputRejected:
# User-supplied AST transformers can reject an input by raising
# an InputRejected. Short-circuit in this case so that we
# don't unregister the transform.
raise
except Exception:
warn("AST transformer %r threw an error. It will be unregistered." % transformer)
self.ast_transformers.remove(transformer)
if self.ast_transformers:
ast.fix_missing_locations(node)
return node
def _get_node_line_end(self, node):
"""Get the last line of the given node.
This function can recurse if the given node is a complex node (like a FunctionDef node).
Args:
node (ast.Node): a node of the AST
Returns:
int: the last line of the statements in the given node
"""
if isinstance(node, ast.Assign):
return node.value.lineno
elif isinstance(node, ast.FunctionDef):
return self._get_node_line_end(node.body[-1])
def make_patterns_dict(self):
'''Assign all patterns to the appropriate ast.Node.'''
trace = False or self.trace_patterns
for pattern in self.general_patterns:
ops = self.find_pattern_ops(pattern)
if ops:
for op in ops:
# Add the pattern to op's list.
op_names = self.op_name_dict.get(op)
for op_name in op_names:
aList = self.patterns_dict.get(op_name, [])
aList.append(pattern)
self.patterns_dict[op_name] = aList
else:
# Enter the name in self.names_dict.
name = pattern.find_s
# Special case for 'number'
if name == 'number':
aList = self.patterns_dict.get('Num', [])
aList.append(pattern)
self.patterns_dict['Num'] = aList
elif name in self.names_dict:
g.trace('duplicate pattern', pattern)
else:
self.names_dict [name] = pattern.repl_s
if 0:
g.trace('names_dict...')
for z in sorted(self.names_dict):
print(' %s: %s' % (z, self.names_dict.get(z)))
if 0:
g.trace('patterns_dict...')
for z in sorted(self.patterns_dict):
aList = self.patterns_dict.get(z)
print(z)
for pattern in sorted(aList):
print(' '+repr(pattern))
# Note: retain self.general_patterns for use in argument lists.
def transform_ast(self, node):
"""Apply the AST transformations from self.ast_transformers
Parameters
----------
node : ast.Node
The root node to be transformed. Typically called with the ast.Module
produced by parsing user input.
Returns
-------
An ast.Node corresponding to the node it was called with. Note that it
may also modify the passed object, so don't rely on references to the
original AST.
"""
for transformer in self.ast_transformers:
try:
node = transformer.visit(node)
except InputRejected:
# User-supplied AST transformers can reject an input by raising
# an InputRejected. Short-circuit in this case so that we
# don't unregister the transform.
raise
except Exception:
warn("AST transformer %r threw an error. It will be unregistered." % transformer)
self.ast_transformers.remove(transformer)
if self.ast_transformers:
ast.fix_missing_locations(node)
return node
def transform_ast(self, node):
"""Apply the AST transformations from self.ast_transformers
Parameters
----------
node : ast.Node
The root node to be transformed. Typically called with the ast.Module
produced by parsing user input.
Returns
-------
An ast.Node corresponding to the node it was called with. Note that it
may also modify the passed object, so don't rely on references to the
original AST.
"""
for transformer in self.ast_transformers:
try:
node = transformer.visit(node)
except InputRejected:
# User-supplied AST transformers can reject an input by raising
# an InputRejected. Short-circuit in this case so that we
# don't unregister the transform.
raise
except Exception:
warn("AST transformer %r threw an error. It will be unregistered." % transformer)
self.ast_transformers.remove(transformer)
if self.ast_transformers:
ast.fix_missing_locations(node)
return node
def generic_visit(self, node):
"""
This function is called when all other nodes are encountered when traversing the tree.
When inheriting form this standard parser, this function will make the parser ignore
all nodes that are not relevant.
Args:
node (ast.Node): The node which is visited.
"""
pass # This ignore is necessary to keep the parser at base level, also look comment above in
# the visit_Module function body.
def transform_ast(self, node):
"""Apply the AST transformations from self.ast_transformers
Parameters
----------
node : ast.Node
The root node to be transformed. Typically called with the ast.Module
produced by parsing user input.
Returns
-------
An ast.Node corresponding to the node it was called with. Note that it
may also modify the passed object, so don't rely on references to the
original AST.
"""
for transformer in self.ast_transformers:
try:
node = transformer.visit(node)
except InputRejected:
# User-supplied AST transformers can reject an input by raising
# an InputRejected. Short-circuit in this case so that we
# don't unregister the transform.
raise
except Exception:
warn("AST transformer %r threw an error. It will be unregistered." % transformer)
self.ast_transformers.remove(transformer)
if self.ast_transformers:
ast.fix_missing_locations(node)
return node
def transform_ast(self, node):
"""Apply the AST transformations from self.ast_transformers
Parameters
----------
node : ast.Node
The root node to be transformed. Typically called with the ast.Module
produced by parsing user input.
Returns
-------
An ast.Node corresponding to the node it was called with. Note that it
may also modify the passed object, so don't rely on references to the
original AST.
"""
for transformer in self.ast_transformers:
try:
node = transformer.visit(node)
except InputRejected:
# User-supplied AST transformers can reject an input by raising
# an InputRejected. Short-circuit in this case so that we
# don't unregister the transform.
raise
except Exception:
warn("AST transformer %r threw an error. It will be unregistered." % transformer)
self.ast_transformers.remove(transformer)
if self.ast_transformers:
ast.fix_missing_locations(node)
return node