def py_transform(name, args, machine): """ transform a generator function into a state machine def generator(args): yield x << into >> def generator(args): class iterator: def __init__(self): self.state = 0 def __iter__(self): return iterator() def __next__(self): # iterator body if self.state==0: return x return iterator() """ # FunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns) # ClassDef(identifier name, expr* bases, keyword* keywords, expr? starargs, expr? kwargs, stmt* body, expr *decorator_list) # arguments = (arg* args, identifier? vararg, expr? varargannotation, arg* kwonlyargs, identifier? kwarg, # expr? kwargannotation, expr* defaults, expr* kw_defaults) # arg = (identifier arg, expr? annotation) if isinstance(machine, ast.AST): return py_transform(name,args, MachineTranslator()) else: body = ast.If() template=\ """ def generator(): class iterator: def __init__(self): self.state = 0 def __iter__(self): return iterator() def __next__(self): import body return iterator() """ func = templated_ast(template, body=body, generator=name) func.args=args return func
def visit_While(self, node, scope): # While(expr test, stmt* body, stmt* orelse) if not node.orelse: template = """while (bool(%(test)s)) { %(body)s }""" return template % { "test": self.visit(node.test, PhantomScope(scope, False)), "body": JCompiler.indent(self.visit_stmt_list(node.body, PhantomScope(scope, True))), } else: # rewrite the expression code = """ while True: if test: import body else: import orelse break """ transformed = templated_ast(code, test=node.test, body=node.body, orelse=node.orelse) return self.visit(transformed, scope)
def map_handler(handlers): # maps a catch block into the corresponding if # catch <Exception> <e>: <body> # into --> # if (isinstance(e$, <Exception>)): e=e$; <body> if not handlers: return ast.Pass first = handlers[0] code = "" code += "if isinstance(temp, exception): " if first.type else "" code += "var = temp; " if first.name else "" code += "import body; " code += "\nelse: import orelse; " if len(handlers) > 1 else "" return templated_ast( code, temp=ast.Name(id=catch_variable_name, ctx=ast.Load()), exception=first.type, var=ast.Name(id=first.name, ctx=ast.Store()), body=first.body, orelse=map_handler(handlers[1:]), )
def visit_For(self, node, scope): # For(expr target, expr iter, stmt* body, stmt* orelse) # the for statement is rewritten as follows code = """temp_store = iter(iterable) while True: try: target=next(temp_load) import body except StopIteration: import orelse break """ temp_iterable = JCompiler.inc_temp_var(getattr(scope, "temp_iterable", "$i")) for_scope = PhantomScope(scope, True, temp_iterable=temp_iterable) template = templated_ast( code, temp_store=ast.Name(id=temp_iterable, ctx=ast.Store()), temp_load=ast.Name(id=temp_iterable, ctx=ast.Load()), iterable=node.iter, target=node.target, body=node.body, orelse=node.orelse, ) return self.generic_visit_list(template, for_scope)