def _import_native(self, name, values): reflect_package = self.block.add_native_import('reflect') package_name = name[len(_NATIVE_MODULE_PREFIX):].replace('.', '/') package = self.block.add_native_import(package_name) mod = self.block.alloc_temp() with self.block.alloc_temp('map[string]*πg.Object') as members: self.writer.write_tmpl('$members = map[string]*πg.Object{}', members=members.name) for v in values: module_attr = v with self.block.alloc_temp() as wrapped: if v.startswith(_NATIVE_TYPE_PREFIX): module_attr = v[len(_NATIVE_TYPE_PREFIX):] with self.block.alloc_temp('{}.{}'.format( package.alias, module_attr)) as type_: self.writer.write_checked_call2( wrapped, 'πg.WrapNative(πF, {}.ValueOf({}))', reflect_package.alias, type_.expr) self.writer.write( '{} = {}.Type().ToObject()'.format( wrapped.name, wrapped.expr)) else: self.writer.write_checked_call2( wrapped, 'πg.WrapNative(πF, {}.ValueOf({}.{}))', reflect_package.alias, package.alias, v) self.writer.write('{}[{}] = {}'.format( members.name, util.go_str(module_attr), wrapped.expr)) self.writer.write_checked_call2( mod, 'πg.ImportNativeModule(πF, {}, {})', util.go_str(name), members.expr) return mod
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 _import_and_bind(self, imp): """Generates code that imports a module and binds it to a variable. Args: imp: Import object representing an import of the form "import x.y.z" or "from x.y import z". Expects only a single binding. """ # Acquire handles to the Code objects in each Go package and call # ImportModule to initialize all modules. with self.block.alloc_temp() as mod, \ self.block.alloc_temp('[]*πg.Object') as mod_slice: self.writer.write_checked_call2( mod_slice, 'πg.ImportModule(πF, {})', util.go_str(imp.name)) # Bind the imported modules or members to variables in the current scope. for binding in imp.bindings: if binding.bind_type == imputil.Import.MODULE: self.writer.write('{} = {}[{}]'.format( mod.name, mod_slice.expr, binding.value)) self.block.bind_var(self.writer, binding.alias, mod.expr) else: self.writer.write('{} = {}[{}]'.format( mod.name, mod_slice.expr, imp.name.count('.'))) # Binding a member of the imported module. with self.block.alloc_temp() as member: self.writer.write_checked_call2( member, 'πg.GetAttr(πF, {}, {}, nil)', mod.expr, self.block.root.intern(binding.value)) self.block.bind_var(self.writer, binding.alias, member.expr)
def _import_and_bind(self, imp): """Generates code that imports a module and binds it to a variable. Args: imp: Import object representing an import of the form "import x.y.z" or "from x.y import z". Expects only a single binding. """ parts = imp.name.split('.') code_objs = [] for i in xrange(len(parts)): package_name = '/'.join(parts[:i + 1]) if package_name != self.block.root.full_package_name: package = self.block.root.add_import(package_name) code_objs.append('{}.Code'.format(package.alias)) else: code_objs.append('Code') with self.block.alloc_temp() as mod, \ self.block.alloc_temp('[]*πg.Object') as mod_slice: handles_expr = '[]*πg.Code{' + ', '.join(code_objs) + '}' self.writer.write_checked_call2( mod_slice, 'πg.ImportModule(πF, {}, {})', util.go_str(imp.name), handles_expr) # This method only handles simple module imports (i.e. not member # imports) which always have a single binding. binding = imp.bindings[0] if binding.value == util.Import.ROOT: index = 0 else: index = len(parts) - 1 self.writer.write('{} = {}[{}]'.format(mod.name, mod_slice.expr, index)) self.block.bind_var(self.writer, binding.alias, mod.expr)
def visit_Str(self, node): if isinstance(node.s, unicode): expr_str = 'πg.NewUnicode({}).ToObject()'.format( util.go_str(node.s.encode('utf-8'))) else: expr_str = '{}.ToObject()'.format(self.block.intern(node.s)) return expr.GeneratedLiteral(expr_str)
def visit_Str(self, node): if isinstance(node.s, unicode): expr_str = 'πg.NewUnicode({}).ToObject()'.format( util.go_str(node.s.encode('utf-8'))) else: expr_str = '{}.ToObject()'.format(self.block.root.intern(node.s)) return expr.GeneratedLiteral(expr_str)
def _import(self, name, index): """Returns an expression for a Module object returned from ImportModule. Args: name: The fully qualified Python module name, e.g. foo.bar. index: The element in the list of modules that this expression should select. E.g. for 'foo.bar', 0 corresponds to the package foo and 1 corresponds to the module bar. Returns: A Go expression evaluating to an *Object (upcast from a *Module.) """ parts = name.split('.') code_objs = [] for i in xrange(len(parts)): package_name = '/'.join(parts[:i + 1]) if package_name != self.block.full_package_name: package = self.block.add_import(package_name) code_objs.append('{}.Code'.format(package.alias)) else: code_objs.append('Code') mod = self.block.alloc_temp() with self.block.alloc_temp('[]*πg.Object') as mod_slice: handles_expr = '[]*πg.Code{' + ', '.join(code_objs) + '}' self.writer.write_checked_call2( mod_slice, 'πg.ImportModule(πF, {}, {})', util.go_str(name), handles_expr) self.writer.write('{} = {}[{}]'.format(mod.name, mod_slice.expr, index)) return mod
def _import(self, name, index): """Returns an expression for a Module object returned from ImportModule. Args: name: The fully qualified Python module name, e.g. foo.bar. index: The element in the list of modules that this expression should select. E.g. for 'foo.bar', 0 corresponds to the package foo and 1 corresponds to the module bar. Returns: A Go expression evaluating to an *Object (upcast from a *Module.) """ parts = name.split('.') code_objs = [] for i in xrange(len(parts)): package_name = '/'.join(parts[:i + 1]) if package_name != self.block.full_package_name: package = self.block.add_import(package_name) code_objs.append('{}.Code'.format(package.alias)) else: code_objs.append('Code') mod = self.block.alloc_temp() with self.block.alloc_temp('[]*πg.Object') as mod_slice: handles_expr = '[]*πg.Code{' + ', '.join(code_objs) + '}' self.writer.write_checked_call2(mod_slice, 'πg.ImportModule(πF, {}, {})', util.go_str(name), handles_expr) self.writer.write('{} = {}[{}]'.format(mod.name, mod_slice.expr, index)) return mod
def _import_native(self, name, values): reflect_package = self.block.add_native_import('reflect') import_name = name[len(_NATIVE_MODULE_PREFIX):] # Work-around for importing go module from VCS # TODO: support bzr|git|hg|svn from any server package_name = None for x in _KNOWN_VCS: if import_name.startswith(x): package_name = x + import_name[len(x):].replace('.', '/') break if not package_name: package_name = import_name.replace('.', '/') package = self.block.add_native_import(package_name) mod = self.block.alloc_temp() with self.block.alloc_temp('map[string]*πg.Object') as members: self.writer.write_tmpl('$members = map[string]*πg.Object{}', members=members.name) for v in values: module_attr = v with self.block.alloc_temp() as wrapped: if v.startswith(_NATIVE_TYPE_PREFIX): module_attr = v[len(_NATIVE_TYPE_PREFIX):] with self.block.alloc_temp('{}.{}'.format( package.alias, module_attr)) as type_: self.writer.write_checked_call2( wrapped, 'πg.WrapNative(πF, {}.ValueOf({}))', reflect_package.alias, type_.expr) self.writer.write( '{} = {}.Type().ToObject()'.format( wrapped.name, wrapped.expr)) else: self.writer.write_checked_call2( wrapped, 'πg.WrapNative(πF, {}.ValueOf({}.{}))', reflect_package.alias, package.alias, v) self.writer.write('{}[{}] = {}'.format( members.name, util.go_str(module_attr), wrapped.expr)) self.writer.write_checked_call2( mod, 'πg.ImportNativeModule(πF, {}, {})', util.go_str(name), members.expr) return mod
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 _import_native(self, name, values): reflect_package = self.block.add_native_import('reflect') import_name = name[len(_NATIVE_MODULE_PREFIX):] # Work-around for importing go module from VCS # TODO: support bzr|git|hg|svn from any server package_name = None for x in _KNOWN_VCS: if import_name.startswith(x): package_name = x + import_name[len(x):].replace('.', '/') break if not package_name: package_name = import_name.replace('.', '/') package = self.block.add_native_import(package_name) mod = self.block.alloc_temp() with self.block.alloc_temp('map[string]*πg.Object') as members: self.writer.write_tmpl('$members = map[string]*πg.Object{}', members=members.name) for v in values: module_attr = v with self.block.alloc_temp() as wrapped: if v.startswith(_NATIVE_TYPE_PREFIX): module_attr = v[len(_NATIVE_TYPE_PREFIX):] with self.block.alloc_temp( '{}.{}'.format(package.alias, module_attr)) as type_: self.writer.write_checked_call2( wrapped, 'πg.WrapNative(πF, {}.ValueOf({}))', reflect_package.alias, type_.expr) self.writer.write('{} = {}.Type().ToObject()'.format( wrapped.name, wrapped.expr)) else: self.writer.write_checked_call2( wrapped, 'πg.WrapNative(πF, {}.ValueOf({}.{}))', reflect_package.alias, package.alias, v) self.writer.write('{}[{}] = {}'.format( members.name, util.go_str(module_attr), wrapped.expr)) self.writer.write_checked_call2(mod, 'πg.ImportNativeModule(πF, {}, {})', util.go_str(name), members.expr) return mod
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 visit_Call(self, node): # Build positional arguments. args = expr.nil_expr if node.args: args = self.block.alloc_temp('[]*πg.Object') self.writer.write('{} = πF.MakeArgs({})'.format( args.expr, len(node.args))) for i, n in enumerate(node.args): with self.visit(n) as a: self.writer.write('{}[{}] = {}'.format( args.expr, i, a.expr)) varg = expr.nil_expr if node.starargs: varg = self.visit(node.starargs) # Build keyword arguments keywords = expr.nil_expr if node.keywords: values = [] for k in node.keywords: values.append((util.go_str(k.arg), self.visit(k.value))) keywords = self.block.alloc_temp('πg.KWArgs') self.writer.write_tmpl('$keywords = πg.KWArgs{', keywords=keywords.name) with self.writer.indent_block(): for k, v in values: with v: self.writer.write_tmpl('{$name, $value},', name=k, value=v.expr) self.writer.write('}') kwargs = expr.nil_expr if node.kwargs: kwargs = self.visit(node.kwargs) # Invoke function with all parameters. with args, varg, keywords, kwargs, self.visit(node.func) as func: result = self.block.alloc_temp() if varg is expr.nil_expr and kwargs is expr.nil_expr: self.writer.write_checked_call2(result, '{}.Call(πF, {}, {})', func.expr, args.expr, keywords.expr) else: self.writer.write_checked_call2( result, 'πg.Invoke(πF, {}, {}, {}, {}, {})', func.expr, args.expr, varg.expr, keywords.expr, kwargs.expr) if node.args: self.writer.write('πF.FreeArgs({})'.format(args.expr)) return result
def visit_Call(self, node): # Build positional arguments. args = expr.nil_expr if node.args: args = self.block.alloc_temp('[]*πg.Object') self.writer.write('{} = πF.MakeArgs({})'.format(args.expr, len(node.args))) for i, n in enumerate(node.args): with self.visit(n) as a: self.writer.write('{}[{}] = {}'.format(args.expr, i, a.expr)) varg = expr.nil_expr if node.starargs: varg = self.visit(node.starargs) # Build keyword arguments keywords = expr.nil_expr if node.keywords: values = [] for k in node.keywords: values.append((util.go_str(k.arg), self.visit(k.value))) keywords = self.block.alloc_temp('πg.KWArgs') self.writer.write_tmpl('$keywords = πg.KWArgs{', keywords=keywords.name) with self.writer.indent_block(): for k, v in values: with v: self.writer.write_tmpl('{$name, $value},', name=k, value=v.expr) self.writer.write('}') kwargs = expr.nil_expr if node.kwargs: kwargs = self.visit(node.kwargs) # Invoke function with all parameters. with args, varg, keywords, kwargs, self.visit(node.func) as func: result = self.block.alloc_temp() if varg is expr.nil_expr and kwargs is expr.nil_expr: self.writer.write_checked_call2(result, '{}.Call(πF, {}, {})', func.expr, args.expr, keywords.expr) else: self.writer.write_checked_call2(result, 'πg.Invoke(πF, {}, {}, {}, {}, {})', func.expr, args.expr, varg.expr, keywords.expr, kwargs.expr) if node.args: self.writer.write('πF.FreeArgs({})'.format(args.expr)) return result
def _import_and_bind(self, imp): """Generates code that imports a module and binds it to a variable. Args: imp: Import object representing an import of the form "import x.y.z" or "from x.y import z". Expects only a single binding. """ # Acquire handles to the Code objects in each Go package and call # ImportModule to initialize all modules. parts = imp.name.split('.') code_objs = [] for i in xrange(len(parts)): package_name = '/'.join(parts[:i + 1]) if package_name != self.block.root.full_package_name: package = self.block.root.add_import(package_name) code_objs.append('{}.Code'.format(package.alias)) else: code_objs.append('Code') with self.block.alloc_temp() as mod, \ self.block.alloc_temp('[]*πg.Object') as mod_slice: handles_expr = '[]*πg.Code{' + ', '.join(code_objs) + '}' self.writer.write_checked_call2(mod_slice, 'πg.ImportModule(πF, {}, {})', util.go_str(imp.name), handles_expr) # Bind the imported modules or members to variables in the current scope. for binding in imp.bindings: if binding.bind_type == imputil.Import.MODULE: self.writer.write('{} = {}[{}]'.format( mod.name, mod_slice.expr, binding.value)) self.block.bind_var(self.writer, binding.alias, mod.expr) else: self.writer.write('{} = {}[{}]'.format( mod.name, mod_slice.expr, imp.name.count('.'))) # Binding a member of the imported module. with self.block.alloc_temp() as member: self.writer.write_checked_call2( member, 'πg.GetAttr(πF, {}, {}, nil)', mod.expr, self.block.root.intern(binding.value)) self.block.bind_var(self.writer, binding.alias, member.expr)
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
def visit_ClassDef(self, node): # Since we only care about global vars, we end up throwing away the locals # collected by BlockVisitor. But use it anyway since it buys us detection of # assignment to vars that are later declared global. block_visitor = block.BlockVisitor() for child in node.body: block_visitor.visit(child) global_vars = {v.name for v in block_visitor.vars.values() if v.type == block.Var.TYPE_GLOBAL} # Visit all the statements inside body of the class definition. body_visitor = StatementVisitor(block.ClassBlock( self.block, node.name, global_vars)) # Indent so that the function body is aligned with the goto labels. with body_visitor.writer.indent_block(): body_visitor._visit_each(node.body) # pylint: disable=protected-access self._write_py_context(node.lineno) with self.block.alloc_temp('*πg.Dict') as cls, \ self.block.alloc_temp() as mod_name, \ self.block.alloc_temp('[]*πg.Object') as bases, \ self.block.alloc_temp() as meta: self.writer.write('{} = make([]*πg.Object, {})'.format( bases.expr, len(node.bases))) for i, b in enumerate(node.bases): with self.expr_visitor.visit(b) as b: self.writer.write('{}[{}] = {}'.format(bases.expr, i, b.expr)) self.writer.write('{} = πg.NewDict()'.format(cls.name)) self.writer.write_checked_call2( mod_name, 'πF.Globals().GetItem(πF, {}.ToObject())', self.block.intern('__name__')) self.writer.write_checked_call1( '{}.SetItem(πF, {}.ToObject(), {})', cls.expr, self.block.intern('__module__'), mod_name.expr) tmpl = textwrap.dedent(""" _, πE = πg.NewCode($name, $filename, nil, 0, func(πF *πg.Frame, _ []*πg.Object) (*πg.Object, *πg.BaseException) { \tπClass := $cls \t_ = πClass""") self.writer.write_tmpl(tmpl, name=util.go_str(node.name), filename=util.go_str(self.block.filename), cls=cls.expr) with self.writer.indent_block(): self.writer.write_temp_decls(body_visitor.block) self.writer.write_block(body_visitor.block, body_visitor.writer.out.getvalue()) tmpl = textwrap.dedent("""\ }).Eval(πF, πF.Globals(), nil, nil) if πE != nil { \treturn nil, πE } if $meta, πE = $cls.GetItem(πF, $metaclass_str.ToObject()); πE != nil { \treturn nil, πE } if $meta == nil { \t$meta = πg.TypeType.ToObject() }""") self.writer.write_tmpl(tmpl, meta=meta.name, cls=cls.expr, metaclass_str=self.block.intern('__metaclass__')) with self.block.alloc_temp() as type_: type_expr = ('{}.Call(πF, []*πg.Object{{πg.NewStr({}).ToObject(), ' 'πg.NewTuple({}...).ToObject(), {}.ToObject()}}, nil)') self.writer.write_checked_call2( type_, type_expr, meta.expr, util.go_str(node.name), bases.expr, cls.expr) self.block.bind_var(self.writer, node.name, type_.expr)
def intern(self, s): if len(s) > 64 or _non_word_re.search(s): return 'πg.NewStr({})'.format(util.go_str(s)) self.strings.add(s) return 'ß' + s
def main(script=None, modname=None): assert script and modname, 'Script "%s" or Modname "%s" is empty' % ( script, modname) gopath = os.getenv('GOPATH', None) if not gopath: print >> sys.stderr, 'GOPATH not set' return 1 with open(script) as py_file: py_contents = py_file.read() try: mod = pythonparser.parse(py_contents) except SyntaxError as e: print >> sys.stderr, '{}: line {}: invalid syntax: {}'.format( e.filename, e.lineno, e.text) return 2 # Do a pass for compiler directives from `from __future__ import *` statements try: future_node, future_features = imputil.parse_future_features(mod) except util.CompileError as e: print >> sys.stderr, str(e) return 2 importer = imputil.Importer(gopath, modname, script, future_features.absolute_import) full_package_name = modname.replace('.', '/') mod_block = block.ModuleBlock(importer, full_package_name, script, py_contents, future_features) visitor = stmt.StatementVisitor(mod_block, future_node) # Indent so that the module body is aligned with the goto labels. with visitor.writer.indent_block(): try: visitor.visit(mod) except util.ParseError as e: print >> sys.stderr, str(e) return 2 writer = util.Writer(sys.stdout) tmpl = textwrap.dedent("""\ package $package import πg "grumpy" var Code *πg.Code func init() { \tCode = πg.NewCode("<module>", $script, nil, 0, func(πF *πg.Frame, _ []*πg.Object) (*πg.Object, *πg.BaseException) { \t\tvar πR *πg.Object; _ = πR \t\tvar πE *πg.BaseException; _ = πE""") writer.write_tmpl(tmpl, package=modname.split('.')[-1], script=util.go_str(script)) with writer.indent_block(2): for s in sorted(mod_block.strings): writer.write('ß{} := πg.InternStr({})'.format(s, util.go_str(s))) writer.write_temp_decls(mod_block) writer.write_block(mod_block, visitor.writer.getvalue()) writer.write_tmpl(textwrap.dedent("""\ \t\treturn nil, πE \t}) \tπg.RegisterModule($modname, Code) }"""), modname=util.go_str(modname)) return 0
def visit_ClassDef(self, node): # Since we only care about global vars, we end up throwing away the locals # collected by BlockVisitor. But use it anyway since it buys us detection of # assignment to vars that are later declared global. block_visitor = block.BlockVisitor() for child in node.body: block_visitor.visit(child) global_vars = {v.name for v in block_visitor.vars.values() if v.type == block.Var.TYPE_GLOBAL} # Visit all the statements inside body of the class definition. body_visitor = StatementVisitor(block.ClassBlock( self.block, node.name, global_vars)) # Indent so that the function body is aligned with the goto labels. with body_visitor.writer.indent_block(): body_visitor._visit_each(node.body) # pylint: disable=protected-access self._write_py_context(node.lineno) with self.block.alloc_temp('*πg.Dict') as cls, \ self.block.alloc_temp() as mod_name, \ self.block.alloc_temp('[]*πg.Object') as bases, \ self.block.alloc_temp() as meta: self.writer.write('{} = make([]*πg.Object, {})'.format( bases.expr, len(node.bases))) for i, b in enumerate(node.bases): with self.expr_visitor.visit(b) as b: self.writer.write('{}[{}] = {}'.format(bases.expr, i, b.expr)) self.writer.write('{} = πg.NewDict()'.format(cls.name)) self.writer.write_checked_call2( mod_name, 'πF.Globals().GetItem(πF, {}.ToObject())', self.block.root.intern('__name__')) self.writer.write_checked_call1( '{}.SetItem(πF, {}.ToObject(), {})', cls.expr, self.block.root.intern('__module__'), mod_name.expr) tmpl = textwrap.dedent(""" _, πE = πg.NewCode($name, $filename, nil, 0, func(πF *πg.Frame, _ []*πg.Object) (*πg.Object, *πg.BaseException) { \tπClass := $cls \t_ = πClass""") self.writer.write_tmpl(tmpl, name=util.go_str(node.name), filename=util.go_str(self.block.root.filename), cls=cls.expr) with self.writer.indent_block(): self.writer.write_temp_decls(body_visitor.block) self.writer.write_block(body_visitor.block, body_visitor.writer.getvalue()) tmpl = textwrap.dedent("""\ }).Eval(πF, πF.Globals(), nil, nil) if πE != nil { \tcontinue } if $meta, πE = $cls.GetItem(πF, $metaclass_str.ToObject()); πE != nil { \tcontinue } if $meta == nil { \t$meta = πg.TypeType.ToObject() }""") self.writer.write_tmpl( tmpl, meta=meta.name, cls=cls.expr, metaclass_str=self.block.root.intern('__metaclass__')) with self.block.alloc_temp() as type_: type_expr = ('{}.Call(πF, []*πg.Object{{πg.NewStr({}).ToObject(), ' 'πg.NewTuple({}...).ToObject(), {}.ToObject()}}, nil)') self.writer.write_checked_call2( type_, type_expr, meta.expr, util.go_str(node.name), bases.expr, cls.expr) self.block.bind_var(self.writer, node.name, type_.expr)