def parse(tokens): if tokens.peek() is not token.BEGIN_BLOCK: return None attributes = [] decls = [] tokens.expect(token.BEGIN_BLOCK) while tokens.peek() is not token.END_BLOCK: decl = None attr = Attribute.parse(tokens) if attr is not None: attributes.append(attr) else: decl = ( FunctionDecl.parse(tokens) or VarDecl.parse(tokens) or PassStatement.parse(tokens) ) if decl is None: raise error.SyntaxError(tokens.peek().position, 'Expected end block, variable or class declaration, or pass statement. Got %r' % tokens.peek()) if not isinstance(decl, PassStatement): decls.append(decl) while tokens.peek() is token.END_OF_STATEMENT: tokens.getNext() tokens.expect(token.END_BLOCK) return ClassBody(decls, attributes)
def testSemantic(self): tokens = lex('var x as int') scope = Scope(parent=None) decl = VarDecl.parse(tokens) result = decl.semantic(scope) self.failUnless(isinstance(result, VarDecl), result) self.failUnless('x' in scope) # x is already defined in the scope, this should fail, as it is a duplicate self.failUnlessRaises(Exception, lambda: tokens.semantic(scope) )
def semantic(self, scope): ''' Slightly nasty. We do an AST replacement here, turning the for loop into an equivalent while loop using an IEnumerator instance. Long story short, this: for iterator as T in y: stmts becomes this: var _e = y.GetEnumerator() while _e.MoveNext(): var iterator = _e.Current as T stmts ''' from ast.blockstatement import BlockStatement from ast.whilestatement import WhileStatement from ast.assignstatement import AssignStatement from ast.castexpression import CastExpression from ast.arraytype import ArrayType from ast.vardecl import VarDecl from nine.scope import Scope IEnumerator = util.getNineType(System.Collections.IEnumerator) Object = util.getNineType(System.Object) Boolean = util.getNineType(System.Boolean) elementType = Object sequence = self.sequence.semantic(scope) seqType = sequence.getType() if isinstance(seqType, ArrayType): elementType = seqType.arrayType elif self.iterator.type is not None: elementType = self.iterator.type enumerator = VarDecl('$$$ secret enumerator 0x%08X $$$' % id(self), self.position, IEnumerator, initializer=seqType.getMember(sequence, 'GetEnumerator').apply(()) ) miniScope = Scope(parent=scope) enumerator = enumerator.semantic(miniScope) # var iterator = enumerator.get_Current() as ElementType assert self.iterator.initializer is None, self self.iterator.initializer = CastExpression(self.position, IEnumerator.getMember(enumerator, 'get_Current').apply(()), elementType) # Finally, create the new replacement AST, do the usual semantic # testing on it, and return it as a replacement for our ForStatement # expression. return BlockStatement(( enumerator, WhileStatement( IEnumerator.getMember(enumerator, 'MoveNext').apply(()), BlockStatement(( self.iterator, self.body, )) ) )).semantic(miniScope)
def testBadParse(self): tokens = lex('var 42') self.failUnlessRaises(error.SyntaxError, lambda: VarDecl.parse(tokens) )
def testInitializer(self): tokens = lex('var x = 291') result = VarDecl.parse(tokens) assert isinstance(result, VarDecl), result
def testTypeDefinition(self): tokens = lex('var x as int') VarDecl.parse(tokens)
def testFailParse(self): tokens = lex('print 4') result = VarDecl.parse(tokens) self.failUnless(result is None, result)
def testGoodParse(self): tokens = lex('var foo') result = VarDecl.parse(tokens) self.failUnless(isinstance(result, VarDecl), result)