def testGlobalIsParam(self): visitor = block.BlockVisitor() visitor.vars['foo'] = block.Var('foo', block.Var.TYPE_PARAM, arg_index=0) self.assertRaisesRegex(util.ParseError, 'is parameter and global', visitor.visit, _ParseStmt('global foo'))
def testAssignNested(self): visitor = block.BlockVisitor() visitor.visit(_ParseStmt('foo, (bar, baz) = "a", ("b", "c")')) self.assertEqual(sorted(visitor.vars.keys()), ['bar', 'baz', 'foo']) self.assertRegexpMatches(visitor.vars['foo'].init_expr, r'UnboundLocal') self.assertRegexpMatches(visitor.vars['bar'].init_expr, r'UnboundLocal') self.assertRegexpMatches(visitor.vars['baz'].init_expr, r'UnboundLocal')
def testImportFrom(self): visitor = block.BlockVisitor() visitor.visit(_ParseStmt('from foo.bar import baz, qux')) self.assertEqual(sorted(visitor.vars.keys()), ['baz', 'qux']) self.assertRegexpMatches(visitor.vars['baz'].init_expr, r'UnboundLocal') self.assertRegexpMatches(visitor.vars['qux'].init_expr, r'UnboundLocal')
def testImport(self): visitor = block.BlockVisitor() visitor.visit(_ParseStmt('import foo.bar, baz')) self.assertEqual(sorted(visitor.vars.keys()), ['baz', 'foo']) self.assertRegexpMatches(visitor.vars['foo'].init_expr, r'UnboundLocal') self.assertRegexpMatches(visitor.vars['baz'].init_expr, r'UnboundLocal')
def testAssignMultiple(self): visitor = block.BlockVisitor() visitor.visit(_ParseStmt('foo = bar = 123')) self.assertEqual(sorted(visitor.vars.keys()), ['bar', 'foo']) self.assertRegexpMatches(visitor.vars['foo'].init_expr, r'UnboundLocal') self.assertRegexpMatches(visitor.vars['bar'].init_expr, r'UnboundLocal')
def testExceptHandler(self): visitor = block.BlockVisitor() visitor.visit(_ParseStmt(textwrap.dedent("""\ try: pass except Exception as foo: pass except TypeError as bar: pass"""))) self.assertEqual(sorted(visitor.vars.keys()), ['bar', 'foo']) self.assertRegexpMatches(visitor.vars['foo'].init_expr, r'UnboundLocal') self.assertRegexpMatches(visitor.vars['bar'].init_expr, r'UnboundLocal')
def testGlobalUsedPriorToDeclaration(self): node = pythonparser.parse('foo = 42\nglobal foo') visitor = block.BlockVisitor() self.assertRaisesRegexp(util.ParseError, 'used prior to global declaration', visitor.generic_visit, node)
def testGlobal(self): visitor = block.BlockVisitor() visitor.visit(_ParseStmt('global foo, bar')) self.assertEqual(sorted(visitor.vars.keys()), ['bar', 'foo']) self.assertIsNone(visitor.vars['foo'].init_expr) self.assertIsNone(visitor.vars['bar'].init_expr)
def testFunctionDef(self): visitor = block.BlockVisitor() visitor.visit(_ParseStmt('def foo(): pass')) self.assertEqual(visitor.vars.keys(), ['foo']) self.assertRegexpMatches(visitor.vars['foo'].init_expr, r'UnboundLocal')
def testFor(self): visitor = block.BlockVisitor() visitor.visit(_ParseStmt('for i in foo: pass')) self.assertEqual(visitor.vars.keys(), ['i']) self.assertRegexpMatches(visitor.vars['i'].init_expr, r'UnboundLocal')
def testVisitClassDef(self): visitor = block.BlockVisitor() visitor.visit(_ParseStmt('class Foo(object): pass')) self.assertEqual(visitor.vars.keys(), ['Foo']) self.assertRegexpMatches(visitor.vars['Foo'].init_expr, r'UnboundLocal')
def testAugAssignSingle(self): visitor = block.BlockVisitor() visitor.visit(_ParseStmt('foo += 3')) self.assertEqual(visitor.vars.keys(), ['foo']) self.assertRegexpMatches(visitor.vars['foo'].init_expr, r'UnboundLocal')
def testAssignTuple(self): visitor = block.BlockVisitor() visitor.visit(_ParseStmt('foo, bar = "a", "b"')) self.assertEqual(sorted(visitor.vars.keys()), ['bar', 'foo']) self.assertRegex(visitor.vars['foo'].init_expr, r'UnboundLocal') self.assertRegex(visitor.vars['bar'].init_expr, r'UnboundLocal')
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)