def visit_FunctionDef(self, node): args = node.args if not args.defaults: return node orig_id = node.name node.name = self.id_factory(orig_id) parameters = mk_tuple(mk_str(arg.id) for arg in args.args) defaults = mk_tuple(args.defaults) parameters_id = self.id_factory("tuple") parameters_stmt = mk_assign(parameters_id, parameters) parameters = mk_name(parameters_id) defaults_id = self.id_factory("tuple") default_stmt = mk_assign(defaults_id, defaults) defaults = mk_name(defaults_id) args.defaults = [] func_expr = mk_call("__pydron_defaults__", [mk_name(node.name), parameters, defaults]) assign_stmt = mk_assign(orig_id, func_expr) return [node, parameters_stmt, default_stmt, assign_stmt]
def visit_Compare(self, node): if len(node.ops) == 1: node.left = self.make_primitive(node.left) node.comparators = [self.make_primitive(node.comparators[0])] return node def check(left, ops, rights): self.start_frame() op = ops.pop(0) right = self.make_primitive(rights.pop(0)) if ops: body = check(right, ops, rights) else: body = [mk_assign(target, mk_name("True"))] test = self.id_factory("test") self.execute(mk_assign(test, ast.Compare(left=left, ops=[op], comparators=[right]))) self.execute(ast.If(test=mk_name(test), body=body, orelse=[])) return self.end_frame() target = self.id_factory("compare") self.execute(mk_assign(target, mk_name("False"))) left = self.make_primitive(node.left) body = check(left, list(node.ops), list(node.comparators)) self.execute(body) return mk_name(target)
def stop_iteration(node): cmp_break = ast.Compare(left=mk_name(self.flag_id), ops=[ast.Eq()], comparators=[mk_str(self.BREAK)]) cmp_return = ast.Compare(left=mk_name(self.flag_id), ops=[ast.Eq()], comparators=[mk_str(self.RETURN)]) test = ast.BoolOp(op=ast.Or(), values = [cmp_break, cmp_return]) break_stmt = ast.Break() ifstmt = ast.If(test=test, body=[break_stmt], orelse=[]) node.body.append(ifstmt)
def visit_Compare(self, node): if len(node.ops) == 1: node.left = self.make_primitive(node.left) node.comparators = [self.make_primitive(node.comparators[0])] return node def check(left, ops, rights): self.start_frame() op = ops.pop(0) right = self.make_primitive(rights.pop(0)) if ops: body = check(right, ops, rights) else: body = [mk_assign(target, mk_name("True"))] test = self.id_factory("test") self.execute( mk_assign( test, ast.Compare(left=left, ops=[op], comparators=[right]))) self.execute(ast.If(test=mk_name(test), body=body, orelse=[])) return self.end_frame() target = self.id_factory("compare") self.execute(mk_assign(target, mk_name("False"))) left = self.make_primitive(node.left) body = check(left, list(node.ops), list(node.comparators)) self.execute(body) return mk_name(target)
def visit_FunctionDef(self, node): self.generic_visit(node) scopes = node.scopes shared = [var for var,scope in scopes.iteritems() if scope == scoping.Scope.SHARED] free = [var for var,scope in scopes.iteritems() if scope == scoping.Scope.FREE] # create cells first thing in body shared_stmts = [mk_assign(var, mk_call("__pydron_new_cell__", [mk_str(var)])) for var in shared] node.body = shared_stmts + node.body if free: # free vars become arguments free_args = [ast.Name(id=var, ctx=ast.Param()) for var in free] node.args.args = free_args + node.args.args # rename the function orig_name = node.name tmp_name = self.id_factory(node.name) node.name = tmp_name # wrap it if self._inside_class(): wrap_args = [mk_name(naming.passthrough_var(var)) for var in free] else: wrap_args = [mk_name(var) for var in free] wrap_call = mk_call("__pydron_wrap_closure__", [mk_name(tmp_name), mk_tuple(wrap_args)]) wrap_stmt = mk_assign(orig_name, wrap_call) return [node, wrap_stmt] else: return node
def stop_iteration(node): cmp_break = ast.Compare(left=mk_name(self.flag_id), ops=[ast.Eq()], comparators=[mk_str(self.BREAK)]) cmp_return = ast.Compare(left=mk_name(self.flag_id), ops=[ast.Eq()], comparators=[mk_str(self.RETURN)]) test = ast.BoolOp(op=ast.Or(), values=[cmp_break, cmp_return]) break_stmt = ast.Break() ifstmt = ast.If(test=test, body=[break_stmt], orelse=[]) node.body.append(ifstmt)
def visit_Assert(self, node): node = self.generic_visit(node) if node.msg: inst = mk_call("AssertionError", [node.msg]) raise_stmt = ast.Raise(type=inst, inst=None, tback=None) else: raise_stmt = ast.Raise(type=mk_name("AssertionError"), inst=None, tback=None) check = ast.If(test=mk_not(node.test), body=[raise_stmt], orelse=[]) return ast.If(test=mk_name("__debug__"), body=[check], orelse=[])
def visit_Exec(self, node): if not node.locals and not node.globals: l = mk_call("locals") g = mk_call("globals") else: l = node.locals g = node.globals if l is None: l = mk_name("None") if g is None: g = mk_name("None") return ast.Expr(value=mk_call("__pydron_exec__", args=[node.body, l, g]))
def visit_Exec(self, node): if not node.locals and not node.globals: l = mk_call("locals") g = mk_call("globals") else: l = node.locals g = node.globals if l is None: l = mk_name("None") if g is None: g = mk_name("None") return ast.Expr( value=mk_call("__pydron_exec__", args=[node.body, l, g]))
def visit_ListComp(self, node): listvar = self.id_factory("listcomp") self.execute(mk_assign(listvar, mk_list([]))) self.start_frame() add = ast.AugAssign() add.target = ast.Name(id=listvar, ctx=ast.Store()) add.value = self.make_primitive( mk_list([self.make_primitive(node.elt)])) add.op = ast.Add() body = self.end_frame() body.append(add) for generator in reversed(node.generators): loop = self.build_comprehension(generator, body) body = [loop] outermost_loop = body[0] # Now simplify all expressions inside the generator. # We can do this now as we have a proper function outermost_loop = self.visit(outermost_loop) self.execute(outermost_loop) return mk_name(listvar)
def visit_BoolOp_old(self, node): if len(node.values) > 2: raise ValueError( "cannot handle that yet. Maybe reduce in a separate step") left = node.values[0] left = self.visit(left) left = self.make_primitive(left) if isinstance(node.op, ast.And): condition = mk_not(left) condition = self.make_primitive(condition) else: condition = left self.start_frame() right = node.values[1] right = self.visit(right) right = self.make_primitive(right) right_statements = self.end_frame() result = self.id_factory("boolop") # if condition: # result = left # else: # right_statements # result = right ifs = ast.If() ifs.test = condition ifs.body = [mk_assign(result, left)] ifs.orelse = right_statements + [mk_assign(result, right)] self.execute(ifs) return mk_name(result)
def visit_Call(self, node): node = self.generic_visit(node) if not isinstance(node.func, ast.Name): # only direct calls, we cannot detect them otherwise return node if node.func.id_scope != Scope.GLOBAL: # `locals` is a python built-in. return node if node.func.id != "locals": return node block = self._stack[-1] def condition(var, scope): if naming.decode_id(var)[1]: # no variables we introduced return False elif var.startswith("__pydron"): return False elif scope == Scope.LOCAL or scope == Scope.SHARED: # local variables are welcome return True elif not isinstance(block, ast.ClassDef): # free variables too... return scope == Scope.FREE else: # ... unless we are in a class return False localvars = set([var for var,scope in block.scopes.iteritems() if condition(var, scope)]) args = mk_dict((mk_str(var), mk_call('__pydron_unbound_unchecked__', [mk_name(var)])) for var in localvars) return mk_call('__pydron_locals__', [args])
def visit_BoolOp_old(self, node): if len(node.values) > 2: raise ValueError("cannot handle that yet. Maybe reduce in a separate step") left = node.values[0] left = self.visit(left) left = self.make_primitive(left) if isinstance(node.op, ast.And): condition = mk_not(left) condition = self.make_primitive(condition) else: condition = left self.start_frame() right = node.values[1] right = self.visit(right) right = self.make_primitive(right) right_statements = self.end_frame() result = self.id_factory("boolop") # if condition: # result = left # else: # right_statements # result = right ifs = ast.If() ifs.test = condition ifs.body = [mk_assign(result, left)] ifs.orelse = right_statements + [mk_assign(result, right)] self.execute(ifs) return mk_name(result)
def visit_FunctionDef(self, node): body, interrupts, guaranteed = self.process_body(node.body) if "return" in interrupts: if "return" not in guaranteed: init = mk_assign(self.retval_id, mk_name("None")) body.insert(0, init) ret = ast.Return(value=mk_name(self.retval_id)) body.append(ret) else: ret = ast.Return(value=mk_name("None")) body.append(ret) node.body = body return node
def check(left, ops, rights): self.start_frame() op = ops.pop(0) right = self.make_primitive(rights.pop(0)) if ops: body = check(right, ops, rights) else: body = [mk_assign(target, mk_name("True"))] test = self.id_factory("test") self.execute(mk_assign(test, ast.Compare(left=left, ops=[op], comparators=[right]))) self.execute(ast.If(test=mk_name(test), body=body, orelse=[])) return self.end_frame()
def visit_ListComp(self, node): listvar = self.id_factory("listcomp") self.execute(mk_assign(listvar, mk_list([]))) self.start_frame() add = ast.AugAssign() add.target = ast.Name(id=listvar, ctx=ast.Store()) add.value = self.make_primitive(mk_list([self.make_primitive(node.elt)])) add.op = ast.Add() body = self.end_frame() body.append(add) for generator in reversed(node.generators): loop = self.build_comprehension(generator, body) body = [loop] outermost_loop = body[0] # Now simplify all expressions inside the generator. # We can do this now as we have a proper function outermost_loop = self.visit(outermost_loop) self.execute(outermost_loop) return mk_name(listvar)
def visit_Print(self, node): node = self.generic_visit(node) if node.dest: dest = node.dest else: dest = mk_name("None") if node.nl: nl = mk_name("True") else: nl = mk_name("False") values = mk_tuple(node.values) call = mk_call("__pydron_print__", [dest, values, nl]) return ast.Expr(value=call)
def visit_FunctionDef(self, node): self.generic_visit(node) scopes = node.scopes shared = [ var for var, scope in scopes.iteritems() if scope == scoping.Scope.SHARED ] free = [ var for var, scope in scopes.iteritems() if scope == scoping.Scope.FREE ] # create cells first thing in body shared_stmts = [ mk_assign(var, mk_call("__pydron_new_cell__", [mk_str(var)])) for var in shared ] node.body = shared_stmts + node.body if free: # free vars become arguments free_args = [ast.Name(id=var, ctx=ast.Param()) for var in free] node.args.args = free_args + node.args.args # rename the function orig_name = node.name tmp_name = self.id_factory(node.name) node.name = tmp_name # wrap it if self._inside_class(): wrap_args = [ mk_name(naming.passthrough_var(var)) for var in free ] else: wrap_args = [mk_name(var) for var in free] wrap_call = mk_call( "__pydron_wrap_closure__", [mk_name(tmp_name), mk_tuple(wrap_args)]) wrap_stmt = mk_assign(orig_name, wrap_call) return [node, wrap_stmt] else: return node
def visit_For(self, node): node = self.generic_visit(node) iterator_id = self.id_factory("iterator") iter_stmt = mk_assign(iterator_id, mk_call("__pydron_iter__", [node.iter])) test = mk_call("__pydron_hasnext__", [mk_name(iterator_id)]) lhs = ast.Tuple(elts=[node.target, ast.Name(id=iterator_id, ctx=ast.Store())], ctx=ast.Store()) next_stmt = ast.Assign(targets=[lhs], value=mk_call("__pydron_next__", [mk_name(iterator_id)])) node.body.insert(0, next_stmt) while_stmt = ast.While(test=test, body=node.body, orelse=node.orelse) ast.copy_location(while_stmt, node) return [iter_stmt, while_stmt]
def visit_Return(self, node): node = self.generic_visit(node) if node.value: retval = mk_assign(self.retval_id, node.value) else: retval = mk_assign(self.retval_id, mk_name("None")) flag = mk_assign(self.flag_id, mk_str(self.RETURN)) return [retval, flag], {"return"}, {"return"}
def visit_Slice(self, node): self.generic_visit(node) # ast.Slice becomes ast.Index with a slice() call. lower = node.lower upper = node.upper step = node.step if not lower: lower = mk_name("None") if not upper: upper = mk_name("None") if not step: step = mk_name("None") s = mk_call("slice", [lower, upper, step]) return ast.Index(value=s)
def visit_Delete(self, node): statements = [] for target in node.targets: if isinstance(target, ast.Name): statements.append(mk_assign(target.id, mk_name('__pydron_unbound__'))) else: statements.append(ast.Delete(targets=[target])) return statements
def visit_Name(self, node): if node.id_scope != scoping.Scope.FREE and node.id_scope != scoping.Scope.SHARED: return node expr = ast.Attribute() expr.value = mk_name(node.id) expr.attr = "cell_contents" expr.ctx = node.ctx return expr
def visit_Delete(self, node): statements = [] for target in node.targets: if isinstance(target, ast.Name): statements.append( mk_assign(target.id, mk_name('__pydron_unbound__'))) else: statements.append(ast.Delete(targets=[target])) return statements
def check(left, ops, rights): self.start_frame() op = ops.pop(0) right = self.make_primitive(rights.pop(0)) if ops: body = check(right, ops, rights) else: body = [mk_assign(target, mk_name("True"))] test = self.id_factory("test") self.execute( mk_assign( test, ast.Compare(left=left, ops=[op], comparators=[right]))) self.execute(ast.If(test=mk_name(test), body=body, orelse=[])) return self.end_frame()
def _visit_block(self, node, parameters): node = self.generic_visit(node) # initialize only variables that are not initialized at this point. localvars = set([var for var,scope in node.scopes.iteritems() if scope == scoping.Scope.LOCAL or scope == scoping.Scope.SHARED]) localvars -= parameters localvars = [v for v in localvars if not v.startswith("__pydron")] assignments = [mk_assign(var, mk_name('__pydron_unbound__')) for var in localvars] node.body = assignments + node.body return node
def visit_TryFinally(self, node): body, body_interrupts, _ = self.process_body(node.body) finalbody, finalbody_interrupts, _ = self.process_body(node.finalbody) orig_flag = self.id_factory("interrupted") # The finalbody statements are executed even if an interrupt was triggered. # Those statements might overwrite or reset the flag. We store # the original flag in a new variable so that we can 'merge' the two # flags afterwards. store = mk_assign(orig_flag, mk_name(self.flag_id)) finalbody.insert(0, store) # pick the flag with higher priority: # None < continue < break < return maxflag = mk_call('__pydron_max__', [mk_name(self.flag_id), mk_name(orig_flag)]) finalbody.append(mk_assign(self.flag_id, maxflag)) node.body = body node.finalbody = finalbody return node, body_interrupts | finalbody_interrupts, set()
def visit_BoolOp(self, node): target = self.id_factory("boolop") if isinstance(node.op, ast.And): def recursive(values): if len(values) == 1: self.start_frame() stmt = mk_assign(target, self.visit(values[0])) return self.end_frame() + [stmt] else: self.start_frame() value = self.make_primitive(values[0]) body = recursive(values[1:]) orelse = [mk_assign(target, value)] ifstmt = ast.If(test=value, body=body, orelse=orelse) return self.end_frame() + [ifstmt] self.execute(recursive(node.values)) return mk_name(target) elif isinstance(node.op, ast.Or): def recursive(values): if len(values) == 1: self.start_frame() stmt = mk_assign(target, self.visit(values[0])) return self.end_frame() + [stmt] else: self.start_frame() value = self.make_primitive(values[0]) orelse = recursive(values[1:]) body = [mk_assign(target, value)] ifstmt = ast.If(test=value, body=body, orelse=orelse) return self.end_frame() + [ifstmt] self.execute(recursive(node.values)) return mk_name(target) else: raise ValueError("invalid boolop")
def make_primitive(self, expr): if expr is None: return None if isinstance(expr, str): return expr expr = self.visit(expr) if isinstance(expr, ast.expr) and not is_primitive(expr): nicename = expr.__class__.__name__.lower() var = self.id_factory(nicename) self.execute(mk_assign(var, expr)) return mk_name(var) else: return expr
def visit_TryFinally(self, node): body, body_interrupts, _ = self.process_body(node.body) finalbody, finalbody_interrupts, _ = self.process_body(node.finalbody) orig_flag = self.id_factory("interrupted") # The finalbody statements are executed even if an interrupt was triggered. # Those statements might overwrite or reset the flag. We store # the original flag in a new variable so that we can 'merge' the two # flags afterwards. store = mk_assign(orig_flag, mk_name(self.flag_id)) finalbody.insert(0, store) # pick the flag with higher priority: # None < continue < break < return maxflag = mk_call( '__pydron_max__', [mk_name(self.flag_id), mk_name(orig_flag)]) finalbody.append(mk_assign(self.flag_id, maxflag)) node.body = body node.finalbody = finalbody return node, body_interrupts | finalbody_interrupts, set()
def unpack_star(self, module_id): tmp = self._unique_modattr_id() dir_expr = mk_call("dir", args=[mk_name(module_id)]) all_expr = mk_call("getattr", args=[mk_name(module_id), mk_str('__all__'), dir_expr]) value_expr = mk_call("getattr", args=[mk_name(module_id), mk_name(tmp)]) body_stmt = mk_subscript_assign(mk_call("globals"), mk_name(tmp), value_expr) return ast.For(target=mk_name(tmp), iter=all_expr, body=[body_stmt], orelse=[])
def _visit_block(self, node, parameters): node = self.generic_visit(node) # initialize only variables that are not initialized at this point. localvars = set([ var for var, scope in node.scopes.iteritems() if scope == scoping.Scope.LOCAL or scope == scoping.Scope.SHARED ]) localvars -= parameters localvars = [v for v in localvars if not v.startswith("__pydron")] assignments = [ mk_assign(var, mk_name('__pydron_unbound__')) for var in localvars ] node.body = assignments + node.body return node
def visit_ImportFrom(self, node): tmp_identifier = self._unique_mod_id() module_expr = self.import_call_expr(node.module, [alias.name for alias in node.names], node.level) statements = [mk_assign(tmp_identifier, module_expr)] if any(alias.name == "*" for alias in node.names): statements.append(self.unpack_star(tmp_identifier)) else: for alias in node.names: asname = alias.asname if alias.asname else alias.name attr_expr = mk_attr(mk_name(tmp_identifier), alias.name) statements.append(mk_assign(asname, attr_expr)) return statements
def visit_FunctionDef(self, node): self.stack.append(node) node = self.generic_visit(node) self.stack.pop() if self.inside_module(): return node if self.is_global(node, "name"): orig_name = node.name new_name = self.id_factory(orig_name) node.name = new_name stmt = mk_call("__pydron_assign_global__", args=[mk_str(orig_name), mk_name(new_name)]) return [node, ast.Expr(stmt)] else: return node
def visit_ExceptHandler(self, node): if self.inside_module(): return node if isinstance(node.name, ast.Name) and self.is_global_name(node.name): var = node.name.id stmt = mk_call("__pydron_assign_global__", args=[mk_str(var), mk_name(var)]) node.body = [ast.Expr(stmt)] + node.body elif node.name: node.name = self.visit(node.name) if node.type: node.type = self.visit(node.type) return node
def visit_For(self, node): self.start_frame() node.iter = self.make_primitive(node.iter) if not isinstance(node.target, ast.Name): self.start_frame() target_expr = self.visit(node.target) target_stmts = self.end_frame() target_name = self.id_factory("target") node.target = ast.Name(id=target_name, ctx=ast.Store()) assign = ast.Assign(targets=[target_expr], value=mk_name(target_name)) target_stmts.append(assign) node.body = target_stmts + node.body node = self.generic_visit(node) return self.end_frame() + [node]
def wrap_with_if(self, stmt_iter, candidates): """ Wraps statements in an `if` statement so that they only execute if no interrupts have triggered. Returns the `if` statement and a set of interrupts that might trigger inside the body. """ ifbody, additional_interrupts, _ = self.process_body(stmt_iter) if ifbody: comparison = ast.Compare(left=mk_name(self.flag_id), ops=[ast.Eq()], comparators=[mk_str(self.NONE)]) ifstmt = ast.If(test=comparison, body=ifbody, orelse=[]) return [ifstmt], additional_interrupts, set() else: # there are no statements, so we don't have to put an `if` around them. return [], additional_interrupts, set()
def visit_ImportFrom(self, node): tmp_identifier = self._unique_mod_id() module_expr = self.import_call_expr( node.module, [alias.name for alias in node.names], node.level) statements = [mk_assign(tmp_identifier, module_expr)] if any(alias.name == "*" for alias in node.names): statements.append(self.unpack_star(tmp_identifier)) else: for alias in node.names: asname = alias.asname if alias.asname else alias.name attr_expr = mk_attr(mk_name(tmp_identifier), alias.name) statements.append(mk_assign(asname, attr_expr)) return statements
def visit_Assign(self, node): if len(node.targets) <= 1: return node stmts = [] if not (isinstance(node.value, ast.Name) or isinstance( node.value, ast.Str) or isinstance(node.value, ast.Num)): value_id = self.id_factory("value") stmts.append(mk_assign(value_id, node.value)) value = mk_name(value_id) else: value = node.value for target in node.targets: s = ast.Assign(targets=[target], value=value) stmts.append(s) return stmts
def _dedecorate(self, node): if not node.decorator_list: return node # use a temporary name orig_id = node.name node.name = self.id_factory(orig_id) # call the decorators obj = mk_name(node.name) for decorator_expr in reversed(node.decorator_list): obj = mk_call_expr(decorator_expr, [obj]) # assign to the original name assignment_stmt = mk_assign(orig_id, obj) node.decorator_list = [] return [node, assignment_stmt]
def visit_Assign(self, node): if len(node.targets) <= 1: return node stmts = [] if not (isinstance(node.value, ast.Name) or isinstance(node.value, ast.Str) or isinstance(node.value, ast.Num)): value_id = self.id_factory("value") stmts.append(mk_assign(value_id, node.value)) value = mk_name(value_id) else: value = node.value for target in node.targets: s = ast.Assign(targets=[target], value=value) stmts.append(s) return stmts
def assign_to_tuple_or_list(self, target, value): """ Returns one or more statements that perform the equlivalent of `target = value`. `target` as to be either a `ast.Tuple` or `ast.List` with `Store` context. """ new_elts = [] stmts = [] for elt in target.elts: if isinstance(elt, ast.Name): new_elt = elt else: new_elt_id = self.id_factory("tuple") new_elt = ast.Name(id=new_elt_id, ctx=ast.Store()) stmts.extend(self.assign_special(elt, mk_name(new_elt_id))) new_elts.append(new_elt) target.elts = new_elts stmts.insert(0, ast.Assign(targets=[target], value=value)) return stmts
def visit_IfExp(self, node): target = self.id_factory("ifexp") self.start_frame() body = self.visit(node.body) body_stmts = self.end_frame() body_stmts.append(mk_assign(target, body)) self.start_frame() orelse = self.visit(node.orelse) orelse_stmts = self.end_frame() orelse_stmts.append(mk_assign(target, orelse)) ifstmt = ast.If() ifstmt.test = self.make_primitive(self.visit(node.test)) ifstmt.body = body_stmts ifstmt.orelse = orelse_stmts self.execute(ifstmt) return mk_name(target)
def visit_Lambda(self, node): function_name = self.id_factory("lambda") self.start_frame() body_expr = self.make_primitive(self.visit(node.body)) body = self.end_frame() ret = ast.Return() ret.value = body_expr body.append(ret) func = ast.FunctionDef() func.name = function_name func.args = self.visit(node.args) func.body = body func.decorator_list = [] self.execute(func) return mk_name(function_name)