def __init__(self, stmt, context):
self.stmt = stmt
self.context = context
self.stmt_table = {
ast.Expr: self.expr,
ast.Pass: self.parse_pass,
ast.AnnAssign: self.ann_assign,
ast.Assign: self.assign,
ast.If: self.parse_if,
ast.Call: self.call,
ast.Assert: self.parse_assert,
ast.For: self.parse_for,
ast.AugAssign: self.aug_assign,
ast.Break: self.parse_break,
ast.Return: self.parse_return,
}
stmt_type = self.stmt.__class__
if stmt_type in self.stmt_table:
self.lll_node = self.stmt_table[stmt_type]()
elif isinstance(stmt, ast.Name) and stmt.id == "throw":
self.lll_node = LLLnode.from_list(['assert', 0], typ=None, pos=getpos(stmt))
else:
raise StructureException("Unsupported statement type", stmt)
python类Name()的实例源码
def assign(self):
from .parser import (
make_setter,
)
# Assignment (eg. x[4] = y)
if len(self.stmt.targets) != 1:
raise StructureException("Assignment statement must have one target", self.stmt)
sub = Expr(self.stmt.value, self.context).lll_node
if isinstance(self.stmt.targets[0], ast.Name) and self.stmt.targets[0].id not in self.context.vars:
pos = self.context.new_variable(self.stmt.targets[0].id, set_default_units(sub.typ))
variable_loc = LLLnode.from_list(pos, typ=sub.typ, location='memory', pos=getpos(self.stmt), annotation=self.stmt.targets[0].id)
o = make_setter(variable_loc, sub, 'memory', pos=getpos(self.stmt))
else:
# Checks to see if assignment is valid
target = self.get_target(self.stmt.targets[0])
o = make_setter(target, sub, target.location, pos=getpos(self.stmt))
o.pos = getpos(self.stmt)
return o
def _is_list_iter(self):
"""
Test if the current statement is a type of list, used in for loops.
"""
# Check for literal or memory list.
iter_var_type = self.context.vars.get(self.stmt.iter.id).typ if isinstance(self.stmt.iter, ast.Name) else None
if isinstance(self.stmt.iter, ast.List) or isinstance(iter_var_type, ListType):
return True
# Check for storage list.
if isinstance(self.stmt.iter, ast.Attribute):
iter_var_type = self.context.globals.get(self.stmt.iter.attr)
if iter_var_type and isinstance(iter_var_type.typ, ListType):
return True
return False
def get_target(self, target):
if isinstance(target, ast.Subscript) and self.context.in_for_loop: # Check if we are doing assignment of an iteration loop.
raise_exception = False
if isinstance(target.value, ast.Attribute):
list_name = "%s.%s" % (target.value.value.id, target.value.attr)
if list_name in self.context.in_for_loop:
raise_exception = True
if isinstance(target.value, ast.Name) and \
target.value.id in self.context.in_for_loop:
list_name = target.value.id
raise_exception = True
if raise_exception:
raise StructureException("Altering list '%s' which is being iterated!" % list_name, self.stmt)
if isinstance(target, ast.Name) and target.id in self.context.forvars:
raise StructureException("Altering iterator '%s' which is in use!" % target.id, self.stmt)
target = Expr.parse_variable_location(target, self.context)
if target.location == 'storage' and self.context.is_constant:
raise ConstancyViolationException("Cannot modify storage inside a constant function: %s" % target.annotation)
if not target.mutable:
raise ConstancyViolationException("Cannot modify function argument: %s" % target.annotation)
return target
def pack_logging_topics(event_id, args, expected_topics, context):
topics = [event_id]
for pos, expected_topic in enumerate(expected_topics):
typ = expected_topic.typ
arg = args[pos]
value = parse_expr(arg, context)
if isinstance(typ, ByteArrayType) and (isinstance(arg, ast.Str) or (isinstance(arg, ast.Name) and arg.id not in reserved_words)):
if value.typ.maxlen > typ.maxlen:
raise TypeMismatchException("Topic input bytes are to big: %r %r" % (value.typ, typ))
if isinstance(arg, ast.Str):
bytez, bytez_length = string_to_bytes(arg.s)
if len(bytez) > 32:
raise InvalidLiteralException("Can only log a maximum of 32 bytes at a time.")
topics.append(bytes_to_int(bytez + b'\x00' * (32 - bytez_length)))
else:
size = context.vars[arg.id].size
topics.append(byte_array_to_num(value, arg, 'num256', size))
else:
value = unwrap_location(value)
value = base_type_conversion(value, value.typ, typ)
topics.append(value)
return topics
def resolve_type_annotation(annotation):
"""Type annotation resolution."""
if isinstance(annotation, ast.Name):
if annotation.id == 'bool':
return BooleanLyraType()
elif annotation.id == 'int':
return IntegerLyraType()
elif annotation.id == 'float':
return FloatLyraType()
elif annotation.id == 'str':
return StringLyraType()
if isinstance(annotation, ast.Subscript):
if annotation.value.id == 'List':
value = resolve_type_annotation(annotation.slice.value)
return ListLyraType(value)
raise NotImplementedError(f"Type annotation {annotation} is not yet supported!")
def get_local_vars(source, namespace):
# local_vars = sys._getframe(depth).f_locals
local_vars_names = set(namespace.keys())
root = ast.parse(source)
required_vars_names = set()
for node in ast.walk(root):
if isinstance(node, ast.Name):
required_vars_names.add(node.id)
builtin_vars_names = set(vars(builtins).keys())
required_local_vars = required_vars_names & local_vars_names
# we might want to add a compiler-ish thing in the future
params = {}
for v in required_local_vars:
params[v] = namespace[v]
return params
def search(func, depth=1):
local_vars = sys._getframe(depth).f_locals
source = get_source_code(func)
tree = ast.parse(source)
child_funcs = []
for node in ast.walk(tree):
if isinstance(node, ast.Call):
if isinstance(node.func, ast.Name):
child_funcs.append(node.func.id)
elif (isinstance(node, ast.Name) and node.id in local_vars and callable(local_vars[node.id]) and node.id not in sys.builtin_module_names):
child_funcs.append(node.id)
child_load_str = ''
for child in child_funcs:
if child in local_vars:
try:
load_string = search(local_vars[child], depth=(depth + 1))
child_load_str += load_string + '\n'
except Exception as e:
pass
load_str = child_load_str + source
return load_str
def pop_format_context(self, expl_expr):
"""Format the %-formatted string with current format context.
The expl_expr should be an ast.Str instance constructed from
the %-placeholders created by .explanation_param(). This will
add the required code to format said string to .on_failure and
return the ast.Name instance of the formatted string.
"""
current = self.stack.pop()
if self.stack:
self.explanation_specifiers = self.stack[-1]
keys = [ast.Str(key) for key in current.keys()]
format_dict = ast.Dict(keys, list(current.values()))
form = ast.BinOp(expl_expr, ast.Mod(), format_dict)
name = "@py_format" + str(next(self.variable_counter))
self.on_failure.append(ast.Assign([ast.Name(name, ast.Store())], form))
return ast.Name(name, ast.Load())
def _is_for_yield(self, node: ast.For) -> bool:
if node.orelse:
return False
if not isinstance(node.target, ast.Name):
return False
body = node.body
if len(body) != 1:
return False
expr = body[0]
if not isinstance(expr, ast.Expr):
return False
yield_ = expr.value
if not isinstance(yield_, ast.Yield):
return False
name = yield_.value
if not isinstance(name, ast.Name):
return False
if name.id != node.target.id:
return False
return True
def visit_Module(self, node):
for expr in node.body:
if not isinstance(expr, ast.Assign):
continue
if not isinstance(expr.value, (ast.Num, ast.Str)):
continue
if len(expr.targets) != 1:
continue
name = expr.targets[0]
if not isinstance(name, ast.Name):
continue
name = name.id
if not self.is_const_name(name):
continue
if name in self._constants:
self._constants[name] = None
else:
self._constants[name] = expr.value
return self.generic_visit(node)
def safe_eval_gpr(expr, conf_genes):
"""Internal function to evaluate a gene-protein rule in an
injection-safe manner (hopefully).
"""
if isinstance(expr, Expression):
return safe_eval_gpr(expr.body, conf_genes)
elif isinstance(expr, Name):
fgid = format_gid(expr.id)
if fgid not in conf_genes:
return 0
return conf_genes[fgid]
elif isinstance(expr, BoolOp):
op = expr.op
if isinstance(op, Or):
return max(safe_eval_gpr(i, conf_genes) for i in expr.values)
elif isinstance(op, And):
return min(safe_eval_gpr(i, conf_genes) for i in expr.values)
else:
raise TypeError("unsupported operation " + op.__class__.__name__)
elif expr is None:
return 0
else:
raise TypeError("unsupported operation " + repr(expr))
def createNameMap(a, d=None):
if d == None:
d = { }
if not isinstance(a, ast.AST):
return d
if type(a) == ast.Module: # Need to go through the functions backwards to make this right
for i in range(len(a.body) - 1, -1, -1):
createNameMap(a.body[i], d)
return d
if type(a) in [ast.FunctionDef, ast.ClassDef]:
if hasattr(a, "originalId") and a.name not in d:
d[a.name] = a.originalId
elif type(a) == ast.arg:
if hasattr(a, "originalId") and a.arg not in d:
d[a.arg] = a.originalId
return d
elif type(a) == ast.Name:
if hasattr(a, "originalId") and a.id not in d:
d[a.id] = a.originalId
return d
for child in ast.iter_child_nodes(a):
createNameMap(child, d)
return d
def basicTypeSpecialFunction(cv):
"""If you're in a number or string (which has no metadata), move up to the AST to make the special functions work."""
if isinstance(cv, SwapVector) or isinstance(cv, MoveVector):
return cv
if (cv.path[0] in [('n', 'Number'), ('s', 'String'), ('id', 'Name'), ('arg', 'Argument'),
('value', 'Name Constant'), ('s', 'Bytes'), ('name', 'Alias')]):
cvCopy = cv.deepcopy()
cv.oldSubtree = deepcopy(cvCopy.traverseTree(cv.start))
if cv.path[0] == ('n', 'Number'):
cv.newSubtree = ast.Num(cv.newSubtree)
elif cv.path[0] == ('s', 'String'):
cv.newSubtree = ast.Str(cv.newSubtree)
elif cv.path[0] == ('id', 'Name'):
cv.newSubtree = ast.Name(cv.newSubtree, cv.oldSubtree.ctx)
elif cv.path[0] == ('arg', 'Argument'):
cv.newSubtree = ast.arg(cv.newSubtree, cv.oldSubtree.annotation)
elif cv.path[0] == ('value', 'Name Constant'):
cv.newSubtree = ast.NameConstant(cv.newSubtree)
elif cv.path[0] == ('s', 'Bytes'):
cv.newSubtree = ast.Bytes(cv.newSubtree)
elif cv.path[0] == ('name', 'Alias'):
cv.newSubtree = ast.alias(cv.newSubtree, cv.oldSubtree.asname)
cv.path = cv.path[1:]
return cv
def replaceHazards(a):
if not isinstance(a, ast.AST):
return
for field in ast.walk(a):
if type(a) == ast.Import:
for i in range(len(a.names)):
if a.names[i].name not in supportedLibraries:
if not (a.names[i].name[0] == "r" and a.names[i].name[1] in "0123456789") and not ("NotAllowed" in a.names[i].name):
a.names[i].name = a.names[i].name + "NotAllowed"
elif type(a) == ast.ImportFrom:
if a.module not in supportedLibraries:
if not (a.module[0] == "r" and a.module[1] in "0123456789") and not ("NotAllowed" in a.module):
a.module = a.module + "NotAllowed"
elif type(a) == ast.Call:
if type(a.func) == ast.Name and a.func.id in ["compile", "eval", "execfile", "file", "open", "__import__", "apply"]:
a.func.id = a.func.id + "NotAllowed"
def findHelperFunction(a, helperId, helperCount):
"""Finds the first helper function used in the ast"""
if not isinstance(a, ast.AST):
return None
# Check all the children, so that we don't end up with a recursive problem
for child in ast.iter_child_nodes(a):
f = findHelperFunction(child, helperId, helperCount)
if f != None:
return f
# Then check if this is the right call
if type(a) == ast.Call:
if type(a.func) == ast.Name and a.func.id == helperId:
if helperCount[0] > 0:
helperCount[0] -= 1
else:
return a
return None
def cleanupRanges(a):
"""Remove any range shenanigans, because Python lets you include unneccessary values"""
if not isinstance(a, ast.AST):
return a
if type(a) == ast.Call:
if type(a.func) == ast.Name:
if a.func.id in ["range"]:
if len(a.args) == 3:
# The step defaults to 1!
if type(a.args[2]) == ast.Num and a.args[2].n == 1:
a.args = a.args[:-1]
if len(a.args) == 2:
# The start defaults to 0!
if type(a.args[0]) == ast.Num and a.args[0].n == 0:
a.args = a.args[1:]
return applyToChildren(a, cleanupRanges)
def cleanupSlices(a):
"""Remove any slice shenanigans, because Python lets you include unneccessary values"""
if not isinstance(a, ast.AST):
return a
if type(a) == ast.Subscript:
if type(a.slice) == ast.Slice:
# Lower defaults to 0
if a.slice.lower != None and type(a.slice.lower) == ast.Num and a.slice.lower.n == 0:
a.slice.lower = None
# Upper defaults to len(value)
if a.slice.upper != None and type(a.slice.upper) == ast.Call and \
type(a.slice.upper.func) == ast.Name and a.slice.upper.func.id == "len":
if compareASTs(a.value, a.slice.upper.args[0], checkEquality=True) == 0:
a.slice.upper = None
# Step defaults to 1
if a.slice.step != None and type(a.slice.step) == ast.Num and a.slice.step.n == 1:
a.slice.step = None
return applyToChildren(a, cleanupSlices)
def getAllGlobalNames(a):
# Finds all names that can be accessed at the global level in the AST
if type(a) != ast.Module:
return []
names = []
for obj in a.body:
if type(obj) in [ast.FunctionDef, ast.ClassDef]:
names.append(obj.name)
elif type(obj) in [ast.Assign, ast.AugAssign]:
targets = obj.targets if type(obj) == ast.Assign else [obj.target]
for target in obj.targets:
if type(target) == ast.Name:
names.append(target.id)
elif type(target) in [ast.Tuple, ast.List]:
for elt in target.elts:
if type(elt) == ast.Name:
names.append(elt.id)
elif type(obj) in [ast.Import, ast.ImportFrom]:
for module in obj.names:
names.append(module.asname if module.asname != None else module.name)
return names
def num_negate(op):
top = type(op)
neg = not op.num_negated if hasattr(op, "num_negated") else True
if top == ast.Add:
newOp = ast.Sub()
elif top == ast.Sub:
newOp = ast.Add()
elif top in [ast.Mult, ast.Div, ast.Mod, ast.Pow, ast.LShift,
ast.RShift, ast.BitOr, ast.BitXor, ast.BitAnd, ast.FloorDiv]:
return None # can't negate this
elif top in [ast.Num, ast.Name]:
# this is a normal value, so put a - in front of it
newOp = ast.UnaryOp(ast.USub(addedNeg=True), op)
else:
log("astTools\tnum_negate\tUnusual type: " + str(top), "bug")
transferMetaData(op, newOp)
newOp.num_negated = neg
return newOp
def _translate_handler(self, handler):
if not isinstance(handler.type, ast.Name) or handler.type.id not in self._exceptions:
raise PseudoPythonTypeCheckError('%s' % str(ast.dump(handler.type)))
h = self.type_env[handler.name]
if h and h != 'Exception':
raise PseudoPythonTypeCheckError("can't change the type of exception %s to %s" % (handler.name, serialize_type(h)))
self.type_env[handler.name] = 'Exception'
return {
'type': 'exception_handler',
'pseudo_type': 'Void',
'exception': handler.type.id,
'is_builtin': handler.type.id == 'Exception',
'instance': handler.name,
'block': self._translate_node(handler.body)
#block [self._translate_node(z) for z in handler.body]
}
def _translate_zip(self, targets, sequences):
sequence_nodes = []
sketchup = {'type': '', 'iterators': {'type': 'for_iterator_zip', 'iterators': []}}
env = {}
for s, z in zip(sequences, targets):
sequence_nodes.append(self._translate_node(s))
self._confirm_iterable(sequence_nodes[-1]['pseudo_type'])
if not isinstance(z, ast.Name):
raise PseudoPythonTypeCheckError('index is not a name %s' % type(z).__name__)
z_type = self._element_type(sequence_nodes[-1]['pseudo_type'])
sketchup['iterators']['iterators'].append({
'type': 'local',
'pseudo_type': z_type,
'name': z.id
})
env[z.id] = z_type
sketchup['sequences'] = {'type': 'for_sequence_zip', 'sequences': sequence_nodes}
return sketchup, env
def get_version():
with open(os.path.join('settei', 'version.py')) as f:
tree = ast.parse(f.read(), f.name)
for node in ast.walk(tree):
if not (isinstance(node, ast.Assign) and len(node.targets) == 1):
continue
target, = node.targets
value = node.value
if not (isinstance(target, ast.Name) and
target.id == 'VERSION_INFO' and
isinstance(value, ast.Tuple)):
continue
elts = value.elts
if any(not isinstance(elt, ast.Num) for elt in elts):
continue
return '.'.join(str(elt.n) for elt in elts)
def visit_DictComp(self, node):
"""
DictComp(expr key, expr value, comprehension* generators)
"""
i = self.visit(node.generators[0].iter) # ast.Tuple, ast.List, ast.*
if isinstance(node.generators[0].target, ast.Name):
t = self.visit(node.generators[0].target)
else:
# ast.Tuple
self._tuple_type = ''
t = self.visit(node.generators[0].target)
self._tuple_type = '[]'
if len(node.generators[0].ifs) == 0:
""" <Python> {key: data for key, data in {'a': 7}.items()}
<Ruby> {'a', 7}.to_a.map{|key, data| [key, data]}.to_h """
return "%s.map{|%s|[%s, %s]}.to_h" % (i, t, self.visit(node.key), self.visit(node.value))
else:
""" <Python> {key: data for key, data in {'a': 7}.items() if data > 6}
<Ruby> {'a', 7}.to_a.select{|key, data| data > 6}.map{|key, data| [key, data]}.to_h """
return "%s.select{|%s| %s}.map{|%s|[%s, %s]}.to_h" % \
(i, t, self.visit(node.generators[0].ifs[0]), t, \
self.visit(node.key), self.visit(node.value))
def visit_Call(self, node):
# This will not visit Flask in Flask(__name__) but it will visit request in `request.args.get()
if not isinstance(node.func, ast.Name):
self.visit(node.func)
for arg in itertools.chain(node.args, node.keywords):
if isinstance(arg, ast.Call):
if isinstance(arg.func, ast.Name):
# We can't just visit because we need to add 'ret_'
self.result.append('ret_' + arg.func.id)
elif isinstance(arg.func, ast.Attribute):
# e.g. html.replace('{{ param }}', param)
# func.attr is replace
# func.value.id is html
# We want replace
self.result.append('ret_' + arg.func.attr)
else:
# Deal with it when we have code that triggers it.
raise
else:
self.visit(arg)
def get_call_names_helper(node, result):
"""Recursively finds all function names."""
if isinstance(node, ast.Name):
if node.id not in BLACK_LISTED_CALL_NAMES:
result.append(node.id)
return result
elif isinstance(node, ast.Call):
return result
elif isinstance(node, ast.Subscript):
return get_call_names_helper(node.value, result)
elif isinstance(node, ast.Str):
result.append(node.s)
return result
else:
result.append(node.attr)
return get_call_names_helper(node.value, result)
def _transform_function_arguments(left):
if type(left) is ast.Name:
names = [left]
else:
names = left.elts
# Python3
if hasattr(_ast, 'arg'):
args = [_ast.arg(annotation=None, arg=name.id, col_offset = name.col_offset, lineno=name.lineno) for name in names]
return ast.arguments(args=args, defaults=[], kwonlyargs=[], kw_defaults=[])
# Python 2
arguments = ast.arguments(args=names, defaults=[])
for argument in arguments.args:
argument.ctx = ast.Param()
return arguments
def visit_Compare(self, node):
"""
:type node: _ast.FunctionDef
"""
is_lambda_def = len(node.ops) == 1\
and type(node.ops[0]) is _ast.Gt \
and (type(node.left) is _ast.Tuple or type(node.left) is _ast.Name) \
and all(map(lambda t: type(t) == _ast.Name, getattr(node.left, 'elts', [])))
if not is_lambda_def:
return node
arguments = _transform_function_arguments(node.left)
function_body = node.comparators[0]
lambda_ast_transform = ast.Lambda(args=arguments,
body=function_body,
lineno=node.lineno,
col_offset=node.col_offset)
return lambda_ast_transform
def _get_attribute_full_path(self, node):
"""Traverse an attribute to generate a full name e.g. tf.foo.bar.
Args:
node: A Node of type Attribute.
Returns:
a '.'-delimited full-name or None if the tree was not a simple form.
i.e. `foo()+b).bar` returns None, while `a.b.c` would return "a.b.c".
"""
curr = node
items = []
while not isinstance(curr, ast.Name):
if not isinstance(curr, ast.Attribute):
return None
items.append(curr.attr)
curr = curr.value
items.append(curr.id)
return ".".join(reversed(items))
def _get_attribute_full_path(self, node):
"""Traverse an attribute to generate a full name e.g. tf.foo.bar.
Args:
node: A Node of type Attribute.
Returns:
a '.'-delimited full-name or None if the tree was not a simple form.
i.e. `foo()+b).bar` returns None, while `a.b.c` would return "a.b.c".
"""
curr = node
items = []
while not isinstance(curr, ast.Name):
if not isinstance(curr, ast.Attribute):
return None
items.append(curr.attr)
curr = curr.value
items.append(curr.id)
return ".".join(reversed(items))