def raw_log(expr, args, kwargs, context):
if not isinstance(args[0], ast.List) or len(args[0].elts) > 4:
raise StructureException("Expecting a list of 0-4 topics as first argument", args[0])
topics = []
for elt in args[0].elts:
arg = Expr.parse_value_expr(elt, context)
if not is_base_type(arg.typ, 'bytes32'):
raise TypeMismatchException("Expecting a bytes32 argument as topic", elt)
topics.append(arg)
if args[1].location == "memory":
return LLLnode.from_list(["with", "_arr", args[1], ["log" + str(len(topics)), ["add", "_arr", 32], ["mload", "_arr"]] + topics],
typ=None, pos=getpos(expr))
placeholder = context.new_placeholder(args[1].typ)
placeholder_node = LLLnode.from_list(placeholder, typ=args[1].typ, location='memory')
copier = make_byte_array_copier(placeholder_node, LLLnode.from_list('_sub', typ=args[1].typ, location=args[1].location))
return LLLnode.from_list(
["with", "_sub", args[1],
["seq",
copier,
["log" + str(len(topics)), ["add", placeholder_node, 32], ["mload", placeholder_node]] + topics]],
typ=None, pos=getpos(expr))
python类List()的实例源码
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 __init__(self, expr, context):
self.expr = expr
self.context = context
self.expr_table = {
LLLnode: self.get_expr,
ast.Num: self.number,
ast.Str: self.string,
ast.NameConstant: self.constants,
ast.Name: self.variables,
ast.Attribute: self.attribute,
ast.Subscript: self.subscript,
ast.BinOp: self.arithmetic,
ast.Compare: self.compare,
ast.BoolOp: self.boolean_operations,
ast.UnaryOp: self.unary_operations,
ast.Call: self.call,
ast.List: self.list_literals,
ast.Dict: self.struct_literals,
ast.Tuple: self.tuple_literals,
}
expr_type = self.expr.__class__
if expr_type in self.expr_table:
self.lll_node = self.expr_table[expr_type]()
else:
raise Exception("Unsupported operator: %r" % ast.dump(self.expr))
def mapVariable(a, varId, assn):
"""Map the variable assignment into the function, if it's needed"""
if type(a) != ast.FunctionDef:
return a
for arg in a.args.args:
if arg.arg == varId:
return a # overriden by local variable
for i in range(len(a.body)):
line = a.body[i]
if type(line) == ast.Assign:
for target in line.targets:
if type(target) == ast.Name and target.id == varId:
break
elif type(target) in [ast.Tuple, ast.List]:
for elt in target.elts:
if type(elt) == ast.Name and elt.id == varId:
break
if countVariables(line, varId) > 0:
a.body[i:i+1] = [deepcopy(assn), line]
break
return a
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 parse_args(args):
arg_list = []
for arg in args:
if isinstance(arg, ast.Str):
arg_list.append("%s" % arg.s)
elif isinstance(arg, ast.Name):
value = arg.id
if value == "None":
arg_list.append(None)
else:
arg_list.append(value)
elif isinstance(arg, ast.Num):
arg_list.append(arg.n)
elif isinstance(arg, ast.List):
arg_list.append(parse_args(arg.elts))
elif isinstance(arg, ast.Tuple):
arg_list.append(tuple(parse_args(arg.elts)))
elif isinstance(arg, ast.Attribute):
arg_list.append(str(arg.value.id) + "." + str(arg.attr))
else:
print(arg, type(arg))
return arg_list
def visit_Call(self, node):
if (
isinstance(node.func, ast.Name) and
node.func.id == 'set' and
len(node.args) == 1 and
not _has_kwargs(node) and
isinstance(node.args[0], SET_TRANSFORM)
):
arg, = node.args
key = Offset(node.func.lineno, node.func.col_offset)
if (
isinstance(arg, (ast.List, ast.Tuple)) and
len(arg.elts) == 0
):
self.set_empty_literals[key] = arg
else:
self.sets[key] = arg
self.generic_visit(node)
def _adjust_arg(tokens, i, arg):
# Adjust `arg` to be the position of the first element.
# listcomps, generators, and tuples already point to the first element
if isinstance(arg, ast.List) and not isinstance(arg.elts[0], ast.Tuple):
arg = arg.elts[0]
elif isinstance(arg, ast.List):
# If the first element is a tuple, the ast lies to us about its col
# offset. We must find the first `(` token after the start of the
# list element.
while not _is_arg(tokens[i], arg):
i += 1
while tokens[i].src != '(':
i += 1
arg = copy.copy(arg.elts[0])
arg.lineno = tokens[i].line
arg.col_offset = tokens[i].utf8_byte_offset
return arg
def compare_contains(self, node):
seq_ast = node.comparators[0]
if not isinstance(seq_ast, (ast.Set, ast.List)):
return
# elements must be hashable
seq = get_literal(seq_ast, constant_items=True)
if seq is UNSET:
return
if isinstance(seq_ast, ast.Set):
seq = frozenset(seq)
else:
seq = tuple(seq)
new_seq_ast = self.new_constant(seq_ast, seq)
if new_seq_ast is None:
return
new_node = copy_node(node)
new_node.comparators[0] = new_seq_ast
return new_node
def TRY(self, node):
handler_names = []
# List the exception handlers
for i, handler in enumerate(node.handlers):
if isinstance(handler.type, ast.Tuple):
for exc_type in handler.type.elts:
handler_names.append(getNodeName(exc_type))
elif handler.type:
handler_names.append(getNodeName(handler.type))
if handler.type is None and i < len(node.handlers) - 1:
self.report(messages.DefaultExceptNotLast, handler)
# Memorize the except handlers and process the body
self.exceptHandlers.append(handler_names)
for child in node.body:
self.handleNode(child, node)
self.exceptHandlers.pop()
# Process the other nodes: "except:", "else:", "finally:"
self.handleChildren(node, omit='body')
def get_type(expr):
"""Find the type of an expression.
Args:
expr: The expression to check.
Returns:
The type of the expression.
"""
if isinstance(expr, ast.Num):
return build_pb2.Attribute.INTEGER
elif isinstance(expr, ast.Str):
return build_pb2.Attribute.STRING
elif isinstance(expr, ast.List):
return build_pb2.Attribute.STRING_LIST
elif isinstance(expr, ast.Name) and (expr.id == "True" or expr.id == "False"):
return build_pb2.Attribute.BOOLEAN
else:
return build_pb2.Attribute.UNKNOWN
def _get_elements_type(elts, context, lineno, solver):
"""Return the elements type of a collection"""
elts_type = solver.new_z3_const("elts")
if len(elts) == 0:
return elts_type
all_types = []
for i in range(0, len(elts)):
cur_type = infer(elts[i], context, solver)
all_types.append(cur_type)
solver.add(solver.z3_types.subtype(cur_type, elts_type),
fail_message="List literal in line {}".format(lineno))
solver.optimize.add_soft(z3.Or([elts_type == elt for elt in all_types]))
return elts_type
def _infer_assignment_target(target, context, value_type, solver):
"""Infer the type of a target in an assignment
Attributes:
target: the target whose type is to be inferred
context: the current context level
value_type: the type of the value assigned to the target
Target cases:
- Variable name. Ex: x = 1
- Tuple. Ex: a, b = 1, "string"
- List. Ex: [a, b] = [1, "string"]
- Subscript. Ex: x[0] = 1, x[1 : 2] = [2,3], x["key"] = value
- Compound: Ex: a, b[0], [c, d], e["key"] = 1, 2.0, [True, False], "value"
"""
target_type = _infer_one_target(target, context, solver)
solver.add(axioms.assignment(target_type, value_type, solver.z3_types),
fail_message="Assignment in line {}".format(target.lineno))
# Adding weight of 2 to give the assignment soft constraint a higher priority over others.
solver.optimize.add_soft(target_type == value_type, weight=2)
def _infer_for(node, context, solver):
"""Infer the type for a for loop node
Limitation:
- The iterable can't be a tuple.
For example: the following is not allowed:
for x in (1, 2.0, "string"):
....
"""
iter_type = expr.infer(node.iter, context, solver)
# Infer the target in the loop, inside the global context
# Cases:
# - Var name. Ex: for i in range(5)..
# - Tuple. Ex: for (a,b) in [(1,"st"), (3,"st2")]..
# - List. Ex: for [a,b] in [(1, "st"), (3, "st2")]..
target_type = solver.new_z3_const("for_target")
solver.add(axioms.for_loop(iter_type, target_type, solver.z3_types),
fail_message="For loop in line {}".format(node.lineno))
_infer_assignment_target(node.target, context, target_type, solver)
return _infer_control_flow(node, context, solver)
def TRY(self, node):
handler_names = []
# List the exception handlers
for i, handler in enumerate(node.handlers):
if isinstance(handler.type, ast.Tuple):
for exc_type in handler.type.elts:
handler_names.append(getNodeName(exc_type))
elif handler.type:
handler_names.append(getNodeName(handler.type))
if handler.type is None and i < len(node.handlers) - 1:
self.report(messages.DefaultExceptNotLast, handler)
# Memorize the except handlers and process the body
self.exceptHandlers.append(handler_names)
for child in node.body:
self.handleNode(child, node)
self.exceptHandlers.pop()
# Process the other nodes: "except:", "else:", "finally:"
self.handleChildren(node, omit='body')
def Call_issubclass(t, x):
"""Translate ``issubclass(Foo, Bar)`` to ``Foo.prototype instanceof Bar``.
"""
with switch(x):
if ast.Call(func=ast.Name(id='issubclass'), args=[target, classes]):
tproto = q[ast_literal[target].prototype]
if isinstance(classes, (ast.Tuple, ast.List, ast.Set)):
classes = classes.elts
else:
classes = [classes]
prev = None
for c in classes:
cur = q[ast_literal[c].prototype.isPrototypeOf(
ast_literal[tproto])]
if prev is not None:
cur = q[ast_literal[prev] or ast_literal[cur]]
prev = cur
return JSExpressionStatement(cur)
def TRY(self, node):
handler_names = []
# List the exception handlers
for handler in node.handlers:
if isinstance(handler.type, ast.Tuple):
for exc_type in handler.type.elts:
handler_names.append(getNodeName(exc_type))
elif handler.type:
handler_names.append(getNodeName(handler.type))
# Memorize the except handlers and process the body
self.exceptHandlers.append(handler_names)
for child in node.body:
self.handleNode(child, node)
self.exceptHandlers.pop()
# Process the other nodes: "except:", "else:", "finally:"
self.handleChildren(node, omit='body')
def visit_ListComp(self, t):
result_append = ast.Attribute(ast.Name('.0', load), 'append', load)
body = ast.Expr(Call(result_append, [t.elt]))
for loop in reversed(t.generators):
for test in reversed(loop.ifs):
body = ast.If(test, [body], [])
body = ast.For(loop.target, loop.iter, [body], [])
fn = [body,
ast.Return(ast.Name('.0', load))]
args = ast.arguments([ast.arg('.0', None)], None, [], None, [], [])
return Call(Function('<listcomp>', args, fn),
[ast.List([], load)])
def visit_ListComp(self, t):
t = self.generic_visit(t)
add_element = ast.Attribute(ast.Name('.elements', load), 'append', load)
body = ast.Expr(Call(add_element, [t.elt]))
for loop in reversed(t.generators):
for test in reversed(loop.ifs):
body = ast.If(test, [body], [])
body = ast.For(loop.target, loop.iter, [body], [])
fn = [body,
ast.Return(ast.Name('.elements', load))]
args = ast.arguments([ast.arg('.elements', None)], None, [], None, [], [])
result = Call(Function('<listcomp>', args, fn),
[ast.List([], load)])
return ast.copy_location(result, t)
def visit_ListComp(self, t):
t = self.generic_visit(t)
add_element = ast.Attribute(ast.Name('.elements', load), 'append', load)
body = ast.Expr(Call(add_element, [t.elt]))
for loop in reversed(t.generators):
for test in reversed(loop.ifs):
body = ast.If(test, [body], [])
body = ast.For(loop.target, loop.iter, [body], [])
fn = [body,
ast.Return(ast.Name('.elements', load))]
args = ast.arguments([ast.arg('.elements', None)], None, [], None, [], [])
result = Call(Function('<listcomp>', args, fn),
[ast.List([], load)])
return ast.copy_location(result, t)
def visit_ListComp(self, t):
t = self.generic_visit(t)
add_element = ast.Attribute(ast.Name('.elements', load), 'append', load)
body = ast.Expr(Call(add_element, [t.elt]))
for loop in reversed(t.generators):
for test in reversed(loop.ifs):
body = ast.If(test, [body], [])
body = ast.For(loop.target, loop.iter, [body], [])
fn = [body,
ast.Return(ast.Name('.elements', load))]
args = ast.arguments([ast.arg('.elements', None)], None, [], None, [], [])
result = Call(Function('<listcomp>', args, fn),
[ast.List([], load)])
return ast.copy_location(result, t)
def list_literals(self):
if not len(self.expr.elts):
raise StructureException("List must have elements", self.expr)
o = []
out_type = None
for elt in self.expr.elts:
o.append(Expr(elt, self.context).lll_node)
if not out_type:
out_type = o[-1].typ
elif len(o) > 1 and o[-1].typ != out_type:
out_type = MixedType()
return LLLnode.from_list(["multi"] + o, typ=ListType(out_type, len(o)), pos=getpos(self.expr))
def visit_BoolOp(self, boolop):
res_var = self.variable()
expl_list = self.assign(ast.List([], ast.Load()))
app = ast.Attribute(expl_list, "append", ast.Load())
is_or = int(isinstance(boolop.op, ast.Or))
body = save = self.statements
fail_save = self.on_failure
levels = len(boolop.values) - 1
self.push_format_context()
# Process each operand, short-circuting if needed.
for i, v in enumerate(boolop.values):
if i:
fail_inner = []
# cond is set in a prior loop iteration below
self.on_failure.append(ast.If(cond, fail_inner, [])) # noqa
self.on_failure = fail_inner
self.push_format_context()
res, expl = self.visit(v)
body.append(ast.Assign([ast.Name(res_var, ast.Store())], res))
expl_format = self.pop_format_context(ast.Str(expl))
call = ast_Call(app, [expl_format], [])
self.on_failure.append(ast.Expr(call))
if i < levels:
cond = res
if is_or:
cond = ast.UnaryOp(ast.Not(), cond)
inner = []
self.statements.append(ast.If(cond, inner, []))
self.statements = body = inner
self.statements = save
self.on_failure = fail_save
expl_template = self.helper("format_boolop", expl_list, ast.Num(is_or))
expl = self.pop_format_context(expl_template)
return ast.Name(res_var, ast.Load()), self.explanation_param(expl)
def listNotEmpty(a):
"""Determines that the iterable is NOT empty, if we can know that"""
"""Used for For objects"""
if not isinstance(a, ast.AST):
return False
if type(a) == ast.Call:
if type(a.func) == ast.Name and a.func.id in ["range"]:
if len(a.args) == 1: # range(x)
return type(a.args[0]) == ast.Num and type(a.args[0].n) != complex and a.args[0].n > 0
elif len(a.args) == 2: # range(start, x)
if type(a.args[0]) == ast.Num and type(a.args[1]) == ast.Num and \
type(a.args[0].n) != complex and type(a.args[1].n) != complex and \
a.args[0].n < a.args[1].n:
return True
elif type(a.args[1]) == ast.BinOp and type(a.args[1].op) == ast.Add:
if type(a.args[1].right) == ast.Num and type(a.args[1].right) != complex and a.args[1].right.n > 0 and \
compareASTs(a.args[0], a.args[1].left, checkEquality=True) == 0:
return True
elif type(a.args[1].left) == ast.Num and type(a.args[1].left) != complex and a.args[1].left.n > 0 and \
compareASTs(a.args[0], a.args[1].right, checkEquality=True) == 0:
return True
elif type(a) in [ast.List, ast.Tuple]:
return len(a.elts) > 0
elif type(a) == ast.Str:
return len(a.s) > 0
return False
def allVariableNamesUsed(a):
"""Gathers all the variable names used in the ast"""
if not isinstance(a, ast.AST):
return []
elif type(a) == ast.Name:
return [a.id]
elif type(a) == ast.Assign:
"""In assignments, ignore all pure names used- they're being assigned to, not used"""
variables = allVariableNamesUsed(a.value)
for target in a.targets:
if type(target) == ast.Name:
pass
elif type(target) in [ast.Tuple, ast.List]:
for elt in target.elts:
if type(elt) != ast.Name:
variables += allVariableNamesUsed(elt)
else:
variables += allVariableNamesUsed(target)
return variables
elif type(a) == ast.AugAssign:
variables = allVariableNamesUsed(a.value)
variables += allVariableNamesUsed(a.target)
return variables
variables = []
for child in ast.iter_child_nodes(a):
variables += allVariableNamesUsed(child)
return variables
def allVariablesUsed(a):
"""Gathers all the variable names used in the ast"""
if type(a) == list:
variables = []
for x in a:
variables += allVariablesUsed(x)
return variables
if not isinstance(a, ast.AST):
return []
elif type(a) == ast.Name:
return [a]
elif type(a) == ast.Assign:
variables = allVariablesUsed(a.value)
for target in a.targets:
if type(target) == ast.Name:
pass
elif type(target) in [ast.Tuple, ast.List]:
for elt in target.elts:
if type(elt) == ast.Name:
pass
else:
variables += allVariablesUsed(elt)
else:
variables += allVariablesUsed(target)
return variables
else:
variables = []
for child in ast.iter_child_nodes(a):
variables += allVariablesUsed(child)
return variables
def gatherAssignedVars(targets):
"""Take a list of assigned variables and extract the names/subscripts/attributes"""
if type(targets) != list:
targets = [targets]
newTargets = []
for target in targets:
if type(target) in [ast.Tuple, ast.List]:
newTargets += gatherAssignedVars(target.elts)
elif type(target) in [ast.Name, ast.Subscript, ast.Attribute]:
newTargets.append(target)
else:
log("astTools\tgatherAssignedVars\tWeird Assign Type: " + str(type(target)),"bug")
return newTargets
def astFormat(x, gid=None):
"""Given a value, turn it into an AST if it's a constant; otherwise, leave it alone."""
if type(x) in [int, float, complex]:
return ast.Num(x)
elif type(x) == bool or x == None:
return ast.NameConstant(x)
elif type(x) == type:
types = { bool : "bool", int : "int", float : "float",
complex : "complex", str : "str", bytes : "bytes", unicode : "unicode",
list : "list", tuple : "tuple", dict : "dict" }
return ast.Name(types[x], ast.Load())
elif type(x) == str: # str or unicode
return ast.Str(x)
elif type(x) == bytes:
return ast.Bytes(x)
elif type(x) == list:
elts = [astFormat(val) for val in x]
return ast.List(elts, ast.Load())
elif type(x) == dict:
keys = []
vals = []
for key in x:
keys.append(astFormat(key))
vals.append(astFormat(x[key]))
return ast.Dict(keys, vals)
elif type(x) == tuple:
elts = [astFormat(val) for val in x]
return ast.Tuple(elts, ast.Load())
elif type(x) == set:
elts = [astFormat(val) for val in x]
if len(elts) == 0: # needs to be a call instead
return ast.Call(ast.Name("set", ast.Load()), [], [])
else:
return ast.Set(elts)
elif type(x) == slice:
return ast.Slice(astFormat(x.start), astFormat(x.stop), astFormat(x.step))
elif isinstance(x, ast.AST):
return x # Do not change if it's not constant!
else:
log("astTools\tastFormat\t" + str(type(x)) + "," + str(x),"bug")
return None
def _translate_node(self, node, in_call=False):
if isinstance(node, ast.AST):
if self.current_constant and type(node) not in [ast.Num, ast.Str, ast.List]:
raise translation_error(
'You can initialize constants only with literals',
(node[0].lineno, node[0].col_offset),
self.lines[node[0].lineno],
right='K = [2, 4]',
wrong='K = [2, x]')
fields = {field: getattr(node, field) for field in node._fields}
l = getattr(node, 'lineno', None)
if l:
fields['location'] = l, node.col_offset
else:
fields['location'] = None
if isinstance(node, ast.Attribute):
fields['in_call'] = in_call
return getattr(self, '_translate_%s' % type(node).__name__.lower())(**fields)
elif isinstance(node, list):
results = []
for n in node:
x = self._translate_node(n)
if isinstance(x, list):
results.extend(x)
else:
results.append(x)
return results
elif isinstance(node, dict):
return {k: self._translate_node(v) for k, v in node.items()}
else:
return node
def _translate_list(self, elts, ctx, location):
if not elts:
return {'type': 'list', 'elements': [], 'pseudo_type': ['List', None]}
element_nodes, element_type = self._translate_elements(elts, 'list')
return {
'type': 'list',
'pseudo_type': ['List', element_type],
'elements': element_nodes
}