def visit_function_inline(self, node): """Returns an GeneratedExpr for a function with the given body.""" # First pass collects the names of locals used in this function. Do this in # a separate pass so that we know whether to resolve a name as a local or a # global during the second pass. func_visitor = block.FunctionBlockVisitor(node) for child in node.body: func_visitor.visit(child) func_block = block.FunctionBlock(self.block, node.name, func_visitor.vars, func_visitor.is_generator) visitor = StatementVisitor(func_block, self.future_node) # Indent so that the function body is aligned with the goto labels. with visitor.writer.indent_block(): visitor._visit_each(node.body) # pylint: disable=protected-access result = self.block.alloc_temp() with self.block.alloc_temp('[]πg.Param') as func_args: args = node.args argc = len(args.args) self.writer.write('{} = make([]πg.Param, {})'.format( func_args.expr, argc)) # The list of defaults only contains args for which a default value is # specified so pad it with None to make it the same length as args. defaults = [None] * (argc - len(args.defaults)) + args.defaults for i, (a, d) in enumerate(zip(args.args, defaults)): with self.visit_expr(d) if d else expr.nil_expr as default: tmpl = '$args[$i] = πg.Param{Name: $name, Def: $default}' self.writer.write_tmpl(tmpl, args=func_args.expr, i=i, name=util.go_str(a.arg), default=default.expr) flags = [] if args.vararg: flags.append('πg.CodeFlagVarArg') if args.kwarg: flags.append('πg.CodeFlagKWArg') # The function object gets written to a temporary writer because we need # it as an expression that we subsequently bind to some variable. self.writer.write_tmpl( '$result = πg.NewFunction(πg.NewCode($name, $filename, $args, ' '$flags, func(πF *πg.Frame, πArgs []*πg.Object) ' '(*πg.Object, *πg.BaseException) {', result=result.name, name=util.go_str(node.name), filename=util.go_str(self.block.root.filename), args=func_args.expr, flags=' | '.join(flags) if flags else 0) with self.writer.indent_block(): for var in func_block.vars.values(): if var.type != block.Var.TYPE_GLOBAL: fmt = 'var {0} *πg.Object = {1}; _ = {0}' self.writer.write(fmt.format( util.adjust_local_name(var.name), var.init_expr)) self.writer.write_temp_decls(func_block) if func_block.is_generator: self.writer.write('return πg.NewGenerator(πF, func(πSent *πg.Object) ' '(*πg.Object, *πg.BaseException) {') with self.writer.indent_block(): self.writer.write_block(func_block, visitor.writer.getvalue()) self.writer.write('}).ToObject(), nil') else: self.writer.write_block(func_block, visitor.writer.getvalue()) self.writer.write('}), πF.Globals()).ToObject()') return result
def del_var(self, writer, name): var = self.vars.get(name) if not var: raise util.ParseError( None, 'cannot delete nonexistent local: {}'.format(name)) if var.type == Var.TYPE_GLOBAL: return self._module_block.del_var(writer, name) adjusted_name = util.adjust_local_name(name) # Resolve local first to ensure the variable is already bound. writer.write_checked_call1('πg.CheckLocal(πF, {}, {})', adjusted_name, util.go_str(name)) writer.write('{} = πg.UnboundLocal'.format(adjusted_name))
def del_var(self, writer, name): var = self.vars.get(name) if not var: raise util.ParseError( None, 'cannot delete nonexistent local: {}'.format(name)) if var.type == Var.TYPE_GLOBAL: return self._module_block.del_var(writer, name) adjusted_name = util.adjust_local_name(name) # Resolve local first to ensure the variable is already bound. writer.write_checked_call1('πg.CheckLocal(πF, {}, {})', adjusted_name, util.go_str(name)) writer.write('{} = πg.UnboundLocal'.format(adjusted_name))
def resolve_name(self, writer, name): block = self while not isinstance(block, ModuleBlock): if isinstance(block, FunctionBlock): var = block.vars.get(name) if var: if var.type == Var.TYPE_GLOBAL: return self._resolve_global(writer, name) writer.write_checked_call1('πg.CheckLocal(πF, {}, {})', util.adjust_local_name(name), util.go_str(name)) return expr.GeneratedLocalVar(name) block = block.parent_block return self._resolve_global(writer, name)
def resolve_name(self, writer, name): block = self while not isinstance(block, ModuleBlock): if isinstance(block, FunctionBlock): var = block.vars.get(name) if var: if var.type == Var.TYPE_GLOBAL: return self._resolve_global(writer, name) writer.write_checked_call1('πg.CheckLocal(πF, {}, {})', util.adjust_local_name(name), util.go_str(name)) return expr.GeneratedLocalVar(name) block = block.parent_block return self._resolve_global(writer, name)
def resolve_name(self, writer, name): local = 'nil' if name not in self.global_vars: # Only look for a local in an outer block when name hasn't been declared # global in this block. If it has been declared global then we fallback # straight to the global dict. block = self.parent_block while not isinstance(block, ModuleBlock): if isinstance(block, FunctionBlock) and name in block.vars: var = block.vars[name] if var.type != Var.TYPE_GLOBAL: local = util.adjust_local_name(name) # When it is declared global, prefer it to anything in outer blocks. break block = block.parent_block result = self.alloc_temp() writer.write_checked_call2( result, 'πg.ResolveClass(πF, πClass, {}, {})', local, self.intern(name)) return result
def resolve_name(self, writer, name): local = 'nil' if name not in self.global_vars: # Only look for a local in an outer block when name hasn't been declared # global in this block. If it has been declared global then we fallback # straight to the global dict. block = self.parent_block while not isinstance(block, ModuleBlock): if isinstance(block, FunctionBlock) and name in block.vars: var = block.vars[name] if var.type != Var.TYPE_GLOBAL: local = util.adjust_local_name(name) # When it is declared global, prefer it to anything in outer blocks. break block = block.parent_block result = self.alloc_temp() writer.write_checked_call2( result, 'πg.ResolveClass(πF, πClass, {}, {})', local, self.intern(name)) return result
def bind_var(self, writer, name, value): if self.vars[name].type == Var.TYPE_GLOBAL: return self._module_block.bind_var(writer, name, value) writer.write('{} = {}'.format(util.adjust_local_name(name), value))
def expr(self): return util.adjust_local_name(self._name)
def bind_var(self, writer, name, value): if self.vars[name].type == Var.TYPE_GLOBAL: return self._module_block.bind_var(writer, name, value) writer.write('{} = {}'.format(util.adjust_local_name(name), value))
def expr(self): return util.adjust_local_name(self._name)
def visit_function_inline(self, node): """Returns an GeneratedExpr for a function with the given body.""" # First pass collects the names of locals used in this function. Do this in # a separate pass so that we know whether to resolve a name as a local or a # global during the second pass. func_visitor = block.FunctionBlockVisitor(node) for child in node.body: func_visitor.visit(child) func_block = block.FunctionBlock(self.block, node.name, func_visitor.vars, func_visitor.is_generator) visitor = StatementVisitor(func_block, self.future_node) # Indent so that the function body is aligned with the goto labels. with visitor.writer.indent_block(): visitor._visit_each(node.body) # pylint: disable=protected-access result = self.block.alloc_temp() with self.block.alloc_temp('[]πg.Param') as func_args: args = node.args argc = len(args.args) self.writer.write('{} = make([]πg.Param, {})'.format( func_args.expr, argc)) # The list of defaults only contains args for which a default value is # specified so pad it with None to make it the same length as args. defaults = [None] * (argc - len(args.defaults)) + args.defaults for i, (a, d) in enumerate(zip(args.args, defaults)): with self.visit_expr(d) if d else expr.nil_expr as default: tmpl = '$args[$i] = πg.Param{Name: $name, Def: $default}' self.writer.write_tmpl(tmpl, args=func_args.expr, i=i, name=util.go_str(a.arg), default=default.expr) flags = [] if args.vararg: flags.append('πg.CodeFlagVarArg') if args.kwarg: flags.append('πg.CodeFlagKWArg') # The function object gets written to a temporary writer because we need # it as an expression that we subsequently bind to some variable. self.writer.write_tmpl( '$result = πg.NewFunction(πg.NewCode($name, $filename, $args, ' '$flags, func(πF *πg.Frame, πArgs []*πg.Object) ' '(*πg.Object, *πg.BaseException) {', result=result.name, name=util.go_str(node.name), filename=util.go_str(self.block.root.filename), args=func_args.expr, flags=' | '.join(flags) if flags else 0) with self.writer.indent_block(): for var in func_block.vars.values(): if var.type != block.Var.TYPE_GLOBAL: fmt = 'var {0} *πg.Object = {1}; _ = {0}' self.writer.write(fmt.format( util.adjust_local_name(var.name), var.init_expr)) self.writer.write_temp_decls(func_block) self.writer.write('var πR *πg.Object; _ = πR') self.writer.write('var πE *πg.BaseException; _ = πE') if func_block.is_generator: self.writer.write( 'return πg.NewGenerator(πF, func(πSent *πg.Object) ' '(*πg.Object, *πg.BaseException) {') with self.writer.indent_block(): self.writer.write_block(func_block, visitor.writer.getvalue()) self.writer.write('return nil, πE') self.writer.write('}).ToObject(), nil') else: self.writer.write_block(func_block, visitor.writer.getvalue()) self.writer.write(textwrap.dedent("""\ if πE != nil { \tπR = nil } else if πR == nil { \tπR = πg.None } return πR, πE""")) self.writer.write('}), πF.Globals()).ToObject()') return result