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): 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_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): 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_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 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]
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_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 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_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_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_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 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_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_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_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_Import(self, node): statements = [] for alias in node.names: module_expr = self.import_call_expr(alias.name) identifier = alias.asname if alias.asname else alias.name identifier = identifier.split(".")[0] statement = mk_assign(identifier, module_expr) statements.append(statement) return statements
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 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 process_body(self, stmts): """ Processes a sequence of statements. The returned code contains no interrupt statements and acts the same way the original code would, assuming that the first statement is executed (we don't handle interrupts that happen before). Returns a list of statements and a set with all interrupts that might be triggered within those statements. """ stmt_iter = iter(stmts) body = [] for stmt in stmt_iter: stmt, candidates, guaranteed = self.visit_with_interrupts(stmt) # If we know for sure that an interrupt will trigger, we # can remove the reminder of the statements. if guaranteed: self._merge(body, stmt) return body, candidates, guaranteed # If the previous statement might have interrupted, # we wrap all the remaining statements in an `if` # statement. elif candidates: # initialize the flag varible, so that it is defined # even if the interrupt does not trigger. # This happens before the statement that might trigger. init = mk_assign(self.flag_id, mk_str(self.NONE)) body.insert(-1, init) self._merge(body, stmt) ifstmts, more_candidates, _ = self.wrap_with_if( stmt_iter, candidates) body.extend(ifstmts) # The rest of the body might trigger other # interrupts as well. return body, candidates | more_candidates, set() else: self._merge(body, stmt) return body, set(), set()
def process_body(self, stmts): """ Processes a sequence of statements. The returned code contains no interrupt statements and acts the same way the original code would, assuming that the first statement is executed (we don't handle interrupts that happen before). Returns a list of statements and a set with all interrupts that might be triggered within those statements. """ stmt_iter = iter(stmts) body = [] for stmt in stmt_iter: stmt, candidates, guaranteed = self.visit_with_interrupts(stmt) # If we know for sure that an interrupt will trigger, we # can remove the reminder of the statements. if guaranteed: self._merge(body, stmt) return body, candidates, guaranteed # If the previous statement might have interrupted, # we wrap all the remaining statements in an `if` # statement. elif candidates: # initialize the flag varible, so that it is defined # even if the interrupt does not trigger. # This happens before the statement that might trigger. init = mk_assign(self.flag_id, mk_str(self.NONE)) body.insert(-1, init) self._merge(body, stmt) ifstmts, more_candidates, _ = self.wrap_with_if(stmt_iter, candidates) body.extend(ifstmts) # The rest of the body might trigger other # interrupts as well. return body, candidates | more_candidates, set() else: self._merge(body, stmt) return body, set(), set()
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 _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_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_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 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_ClassDef(self, node): node = self.generic_visit(node) # free variables of the class block become parameters of the function scopes = getattr(node, 'scopes', {}) free = [var for var,scope in scopes.iteritems() if scope == scoping.Scope.FREE] free_param = [ast.Name(id=var, ctx=ast.Param()) for var in free] free_args = [ast.Name(id=var, ctx=ast.Load()) for var in free] # free variables of sub-blocks. Those need name mangling to avoid # collisions with variables local to the class block. passthrough = self.find_passthrough_vars(node) pt_param = [ast.Name(id=naming.passthrough_var(var), ctx=ast.Param()) for var in passthrough] pt_args = [ast.Name(id=var, ctx=ast.Load()) for var in passthrough] # function to execute the class body and collect the attributes func = ast.FunctionDef() func.name = self.id_factory("class_" + node.name) func.args = ast.arguments(args=free_param + pt_param, vararg=None, kwarg=None, defaults=[]) func.body = node.body + [ast.Return(value=mk_name('__pydron_members__')) ] func.decorator_list = [] # replicate name mangling of `LocalizeFreeVariables` all_args = free_args + pt_args if self._inside_class(): for arg in all_args: arg.id = naming.passthrough_var(arg.id) # create the class typefunc = mk_call('__pydron_read_global__', [mk_str('type')]) class_expr = mk_call_expr(typefunc, [mk_str(node.name), mk_tuple(node.bases), mk_call(func.name, all_args)]) for decorator in reversed(node.decorator_list): class_expr = mk_call_expr(decorator, [class_expr]) stmt = mk_assign(node.name, class_expr) return [func, stmt]
def visit_ClassDef(self, node): node = self.generic_visit(node) # free variables of the class block become parameters of the function scopes = getattr(node, "scopes", {}) free = [var for var, scope in scopes.iteritems() if scope == scoping.Scope.FREE] free_param = [ast.Name(id=var, ctx=ast.Param()) for var in free] free_args = [ast.Name(id=var, ctx=ast.Load()) for var in free] # free variables of sub-blocks. Those need name mangling to avoid # collisions with variables local to the class block. passthrough = self.find_passthrough_vars(node) pt_param = [ast.Name(id=naming.passthrough_var(var), ctx=ast.Param()) for var in passthrough] pt_args = [ast.Name(id=var, ctx=ast.Load()) for var in passthrough] # function to execute the class body and collect the attributes func = ast.FunctionDef() func.name = self.id_factory("class_" + node.name) func.args = ast.arguments(args=free_param + pt_param, vararg=None, kwarg=None, defaults=[]) func.body = node.body + [ast.Return(value=mk_name("__pydron_members__"))] func.decorator_list = [] # replicate name mangling of `LocalizeFreeVariables` all_args = free_args + pt_args if self._inside_class(): for arg in all_args: arg.id = naming.passthrough_var(arg.id) # create the class typefunc = mk_call("__pydron_read_global__", [mk_str("type")]) class_expr = mk_call_expr(typefunc, [mk_str(node.name), mk_tuple(node.bases), mk_call(func.name, all_args)]) for decorator in reversed(node.decorator_list): class_expr = mk_call_expr(decorator, [class_expr]) stmt = mk_assign(node.name, class_expr) return [func, stmt]
def visit_ClassDef(self, node): self.generic_visit(node) stmt = mk_assign('__pydron_members__', mk_call('locals')) node.body.append(stmt) return node
def visit_With(self, node): node = self.generic_visit(node) # Build equivalent code with try catch finally. # PEP-0343 provides the equivalent code for us. statements = [] # mgr = node.expr mgr_id = self.id_factory("mgr") s = mk_assign(mgr_id, node.context_expr) statements.append(s) # exit = type(msg).__exit__ exit_id = self.id_factory("exit") s = mk_assign(exit_id, mk_attr(mk_call('type', [mk_name(mgr_id)]), "__exit__")) statements.append(s) # value = type(msg).__enter__(mgr) value_id = self.id_factory("value") s = mk_assign(value_id, mk_call_expr(mk_attr(mk_call('type', [mk_name(mgr_id)]), "__enter__"), [mk_name(mgr_id)])) statements.append(s) # exc = True exc_id = self.id_factory("exc") s = mk_assign(exc_id, mk_name("True")) statements.append(s) # try: tryfinally_body = [] tryfinally_finalbody = [] s = ast.TryFinally(body=tryfinally_body, finalbody=tryfinally_finalbody) statements.append(s) # try: tryexcept_body = [] tryexcept_except = [] expt_handler = ast.ExceptHandler(type=None,name=None,body=tryexcept_except) s = ast.TryExcept(body=tryexcept_body, handlers=[expt_handler], orelse=[]) tryfinally_body.append(s) # node.optional_vars = value if node.optional_vars: s = ast.Assign(targets=[node.optional_vars], value=mk_name(value_id)) tryexcept_body.append(s) # body tryexcept_body.extend(node.body) # except: # exc = False s = mk_assign(exc_id, mk_name("False")) tryexcept_except.append(s) # sys.exc_info() sys_exc_info = mk_call_expr(mk_attr(mk_name('sys'), "exc_info"), []) # exit(mgr, *sys.exc_info()) exit_call = mk_call(exit_id, [mk_name(mgr_id)], vararg=sys_exc_info) # not exit(mgr, *sys.exc_info()) test = ast.UnaryOp(op=ast.Not(), operand=exit_call) # if not exit(mgr, *sys.exc_info()): # raise s = ast.If(test=test, body=[ast.Raise(type=None, inst=None, tback=None)], orelse=[]) tryexcept_except.append(s) # finally: # if exc: # exit(mgr, None, None, None) exit_call = mk_call(exit_id, [mk_name(mgr_id), mk_name("None"), mk_name("None"), mk_name("None")]) s = ast.If(test=mk_name(exc_id), body=[ast.Expr(value=exit_call)], orelse=[]) tryfinally_finalbody.append(s) return statements
def visit_Break(self, node): node = self.generic_visit(node) return mk_assign(self.flag_id, mk_str(self.BREAK)), {"break"}, {"break"}
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 ] fixed_arguments = [] for arg in node.args.args: if isinstance(arg, ast.Attribute) and arg.attr == "cell_contents": # the generic_visit above made a mess. The attribute is # a free/shared variable and visit_Name replaced it with # an attribute. This makes no sense, so lets repair the damage. # # We don't want to change the parameter name. And I don't # want to change the variable name either. To solve this # we temporarily assign it to another variable: # # def foo(freevar): # freevar__U0 = freevar # freevar = __pydron_new_cell__('freevar') # freevar.cell_contents = freevar__U0 varname = arg.value.id tmp = self.id_factory(varname) # freevar__U0 = freevar shared_stmts.insert(0, mk_assign(tmp, mk_name(varname))) # freevar = __pydron_new_cell__('freevar') # is already in shared_stmts # reevar.cell_contents = freevar__U0 arg.ctx = ast.Store() shared_stmts.append( ast.Assign(targets=[arg], value=mk_name(tmp))) fixed_arguments.append(ast.Name(id=varname, ctx=ast.Param())) else: fixed_arguments.append(arg) node.args.args = fixed_arguments 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_Continue(self, node): node = self.generic_visit(node) return mk_assign(self.flag_id, mk_str(self.CONTINUE)), {"continue"}, {"continue"}
def _visit_loop(self, node, stop_iteration): body, body_interrupts, body_guranteed = self.process_body(node.body) orelse, orelse_interrupts, orelse_guranteed = self.process_body( node.orelse) # All interrupts of `orelse` propagate. Of `body` both `break` and `continue` are consumed # and only `return` goes on. for_interrupts = orelse_interrupts if "return" in body_interrupts: for_interrupts.add("return") if "break" not in body_interrupts and "return" not in body_interrupts: for_guranteed = orelse_guranteed else: for_guranteed = set() statements = [] # Clear the 'continue' at the end of the body if "continue" in body_interrupts: # if flag == "continue": # flag == None clearflag = mk_assign(self.flag_id, mk_str(self.NONE)) if "continue" not in body_guranteed: comparison = ast.Compare(left=mk_name(self.flag_id), ops=[ast.Eq()], comparators=[mk_str(self.CONTINUE)]) ifstmt = ast.If(test=comparison, body=[clearflag], orelse=[]) body.append(ifstmt) else: body.append(clearflag) # init the flags for "break" for the case when there isn't a single iteration. # If we 'pass on' some interrupts then body_visit will take care of this. if "break" in body_interrupts and "return" not in for_interrupts: statements.append(mk_assign(self.flag_id, mk_str(self.NONE))) # Assemble modified loop. node.body = body node.orelse = [] # make the loop stop on 'break' and 'return' if "break" in body_interrupts or "return" in body_interrupts: stop_iteration(node) # Add the loop to the result statements.append(node) # `orelse` if "break" in body_interrupts or "return" in body_interrupts: # the `orelse` section may or may not execute if "break" in body_interrupts: # if flag == "break": # flag == None clearflag = mk_assign(self.flag_id, mk_str(self.NONE)) comparison = ast.Compare(left=mk_name(self.flag_id), ops=[ast.Eq()], comparators=[mk_str(self.BREAK)]) clear_break = [ ast.If(test=comparison, body=[clearflag], orelse=[]) ] else: clear_break = [] if not orelse: statements.extend(clear_break) else: # if flag == None # ORELSSE # else: # clear_break comparison = ast.Compare(left=mk_name(self.flag_id), ops=[ast.Eq()], comparators=[mk_str(self.NONE)]) orelse_if = ast.If(test=comparison, body=orelse, orelse=clear_break) statements.append(orelse_if) else: # there is no `break` therefore `orelse` is always executed. statements.extend(orelse) return statements, for_interrupts, for_guranteed
def visit_With(self, node): node = self.generic_visit(node) # Build equivalent code with try catch finally. # PEP-0343 provides the equivalent code for us. statements = [] # mgr = node.expr mgr_id = self.id_factory("mgr") s = mk_assign(mgr_id, node.context_expr) statements.append(s) # exit = type(msg).__exit__ exit_id = self.id_factory("exit") s = mk_assign(exit_id, mk_attr(mk_call('type', [mk_name(mgr_id)]), "__exit__")) statements.append(s) # value = type(msg).__enter__(mgr) value_id = self.id_factory("value") s = mk_assign( value_id, mk_call_expr( mk_attr(mk_call('type', [mk_name(mgr_id)]), "__enter__"), [mk_name(mgr_id)])) statements.append(s) # exc = True exc_id = self.id_factory("exc") s = mk_assign(exc_id, mk_name("True")) statements.append(s) # try: tryfinally_body = [] tryfinally_finalbody = [] s = ast.TryFinally(body=tryfinally_body, finalbody=tryfinally_finalbody) statements.append(s) # try: tryexcept_body = [] tryexcept_except = [] expt_handler = ast.ExceptHandler(type=None, name=None, body=tryexcept_except) s = ast.TryExcept(body=tryexcept_body, handlers=[expt_handler], orelse=[]) tryfinally_body.append(s) # node.optional_vars = value if node.optional_vars: s = ast.Assign(targets=[node.optional_vars], value=mk_name(value_id)) tryexcept_body.append(s) # body tryexcept_body.extend(node.body) # except: # exc = False s = mk_assign(exc_id, mk_name("False")) tryexcept_except.append(s) # sys.exc_info() sys_exc_info = mk_call_expr(mk_attr(mk_name('sys'), "exc_info"), []) # exit(mgr, *sys.exc_info()) exit_call = mk_call(exit_id, [mk_name(mgr_id)], vararg=sys_exc_info) # not exit(mgr, *sys.exc_info()) test = ast.UnaryOp(op=ast.Not(), operand=exit_call) # if not exit(mgr, *sys.exc_info()): # raise s = ast.If(test=test, body=[ast.Raise(type=None, inst=None, tback=None)], orelse=[]) tryexcept_except.append(s) # finally: # if exc: # exit(mgr, None, None, None) exit_call = mk_call(exit_id, [ mk_name(mgr_id), mk_name("None"), mk_name("None"), mk_name("None") ]) s = ast.If(test=mk_name(exc_id), body=[ast.Expr(value=exit_call)], orelse=[]) tryfinally_finalbody.append(s) return statements
def _visit_loop(self, node, stop_iteration): body, body_interrupts, body_guranteed = self.process_body(node.body) orelse, orelse_interrupts, orelse_guranteed = self.process_body(node.orelse) # All interrupts of `orelse` propagate. Of `body` both `break` and `continue` are consumed # and only `return` goes on. for_interrupts = orelse_interrupts if "return" in body_interrupts: for_interrupts.add("return") if "break" not in body_interrupts and "return" not in body_interrupts: for_guranteed = orelse_guranteed else: for_guranteed = set() statements = [] # Clear the 'continue' at the end of the body if "continue" in body_interrupts: # if flag == "continue": # flag == None clearflag = mk_assign(self.flag_id, mk_str(self.NONE)) if "continue" not in body_guranteed: comparison = ast.Compare(left=mk_name(self.flag_id), ops=[ast.Eq()], comparators=[mk_str(self.CONTINUE)]) ifstmt = ast.If(test=comparison, body=[clearflag], orelse=[]) body.append(ifstmt) else: body.append(clearflag) # init the flags for "break" for the case when there isn't a single iteration. # If we 'pass on' some interrupts then body_visit will take care of this. if "break" in body_interrupts and "return" not in for_interrupts: statements.append(mk_assign(self.flag_id, mk_str(self.NONE))) # Assemble modified loop. node.body = body node.orelse = [] # make the loop stop on 'break' and 'return' if "break" in body_interrupts or "return" in body_interrupts: stop_iteration(node) # Add the loop to the result statements.append(node) # `orelse` if "break" in body_interrupts or "return" in body_interrupts: # the `orelse` section may or may not execute if "break" in body_interrupts: # if flag == "break": # flag == None clearflag = mk_assign(self.flag_id, mk_str(self.NONE)) comparison = ast.Compare(left=mk_name(self.flag_id), ops=[ast.Eq()], comparators=[mk_str(self.BREAK)]) clear_break = [ast.If(test=comparison, body=[clearflag], orelse=[])] else: clear_break = [] if not orelse: statements.extend(clear_break) else: # if flag == None # ORELSSE # else: # clear_break comparison = ast.Compare(left=mk_name(self.flag_id), ops=[ast.Eq()], comparators=[mk_str(self.NONE)]) orelse_if = ast.If(test=comparison, body=orelse, orelse=clear_break) statements.append(orelse_if) else: # there is no `break` therefore `orelse` is always executed. statements.extend(orelse) return statements, for_interrupts, for_guranteed