def test_call_expression_parsing(): source = "add(1, 2 * 3, 4 + 5);" l = Lexer(source) p = Parser(l) program = p.parse_program() assert p.errors == [] assert len(program.statements) == 1 stmt = program.statements[0] assert isinstance(stmt, ast.ExpressionStatement) assert isinstance(stmt.expression, ast.CallExpression) assert stmt.expression.function.value == "add" assert len(stmt.expression.arguments) == 3 assert stmt.expression == ast.CallExpression( token=Token(tok_type="(", literal="("), function=ast.Identifier(token=Token(tok_type="IDENT", literal="add"), value="add"), arguments=[ ast.IntegerLiteral(token=Token(tok_type="INT", literal="1"), value=1), ast.InfixExpression( token=Token(tok_type="*", literal="*"), left=ast.IntegerLiteral(token=Token(tok_type="INT", literal="2"), value=2), operator="*", right=ast.IntegerLiteral(token=Token(tok_type="INT", literal="3"), value=3), ), ast.InfixExpression( token=Token(tok_type="+", literal="+"), left=ast.IntegerLiteral(token=Token(tok_type="INT", literal="4"), value=4), operator="+", right=ast.IntegerLiteral(token=Token(tok_type="INT", literal="5"), value=5), ), ], ) assert str(stmt.expression) == "add(1, (2 * 3), (4 + 5))"
def parseIntegerLiteral(self) -> Optional[ast.Expression]: try: value = int(self.curToken.Literal) except ValueError: msg = 'could not parse %s as integer' % self.curToken.Literal self.errors.append(msg) return None lit = ast.IntegerLiteral(Token=self.curToken, Value=value) return lit
def parse_integer_literal(self) -> Union[ast.Expression, None]: lit = ast.IntegerLiteral(self.cur_token) if not self.cur_token.literal.isdigit(): msg = "could not parse '{}' as integer".format( self.cur_token.literal) self.errors.append(msg) return None lit.value = int(self.cur_token.literal) return lit
def parse_integer_literal(self): # begin = self.tracer.trace('parse_integer_literal') lit = ast.IntegerLiteral(self.cur_token) try: value = int(self.cur_token.Literal) lit.value = value # self.tracer.untrace(begin) return lit except ValueError: msg = 'could not parse {} as integer'.format(self.cur_token) self.errors.append(msg) return None
def convert_object_to_astnode(obj): if isinstance(obj, object.Integer): t = token.Token(Type=token.INT, Literal=str(obj.value)) return ast.IntegerLiteral(t, obj.value) if isinstance(obj, object.Boolean): if obj.value: t = token.Token(Type=token.TRUE, Literal='true') else: t = token.Token(Type=token.FALSE, Literal='false') return ast.Boolean(t, obj.value) if isinstance(obj, object.Quote): # Quote already has the ASTNode object so just return it! return obj.node return None
def convertObjectToASTNode(obj: object.Object) -> ast.Node: t: token.Token if type(obj) == object.Integer: t = token.Token(Type=token.INT, Literal='%s' % obj.Value) return ast.IntegerLiteral(Token=t, Value=obj.Value) elif type(obj) == object.Boolean: if obj.Value: t = token.Token(Type=token.TRUE, Literal='true') else: t = token.Token(Type=token.FALSE, Literal='false') return ast.Boolean(Token=t, Value=obj.Value) elif type(obj) == object.Quote: obj = cast(object.Quote, obj) return obj.Node else: # TODO: xxx return ast.Node()
def test_modify(self): one: Callable[[], ast.Expression] = lambda: ast.IntegerLiteral( Token=token.Token(token.INT, 'Unknown'), Value=1) two: Callable[[], ast.Expression] = lambda: ast.IntegerLiteral( Token=token.Token(token.INT, 'Unknown'), Value=2) def turnOneIntoTwo(node: ast.Node) -> ast.Node: integer = node if type(node) != ast.IntegerLiteral: return node if integer.Value != 1: return node integer.Value = 2 return integer @dataclass class Test: input: ast.Node expected: ast.Node tests: List[Test] = [ Test(one(), two()), Test( ast.Program(Statements=[ ast.ExpressionStatement(Token=token.Token( token.INT, 'Unknown'), ExpressionValue=one()), ]), ast.Program(Statements=[ ast.ExpressionStatement(Token=token.Token( token.INT, 'Unknown'), ExpressionValue=two()), ])), Test( ast.InfixExpression(Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Left=one(), Operator='+', Right=two()), ast.InfixExpression(Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Left=two(), Operator='+', Right=two())), Test( ast.InfixExpression(Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Left=two(), Operator='+', Right=one()), ast.InfixExpression(Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Left=two(), Operator='+', Right=two())), Test( ast.IndexExpression(Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Left=one(), Index=one()), ast.IndexExpression(Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Left=two(), Index=two())), Test( ast.PrefixExpression(Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Operator='-', Right=one()), ast.PrefixExpression(Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Operator='-', Right=two())), Test( ast.IfExpression( Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Condition=one(), Consequence=ast.BlockStatement( Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Statements=[ ast.ExpressionStatement(Token=token.Token( token.ILLEGAL, 'ILLEGAL'), ExpressionValue=one()) ]), Alternative=ast.BlockStatement( Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Statements=[ ast.ExpressionStatement(Token=token.Token( token.ILLEGAL, 'ILLEGAL'), ExpressionValue=one()) ]), ), ast.IfExpression( Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Condition=two(), Consequence=ast.BlockStatement( Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Statements=[ ast.ExpressionStatement(Token=token.Token( token.ILLEGAL, 'ILLEGAL'), ExpressionValue=two()) ]), Alternative=ast.BlockStatement( Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Statements=[ ast.ExpressionStatement(Token=token.Token( token.ILLEGAL, 'ILLEGAL'), ExpressionValue=two()) ]))), Test( ast.IndexExpression(Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Left=one(), Index=one()), ast.IndexExpression(Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Left=two(), Index=two())), Test( ast.ReturnStatement(Token=token.Token(token.ILLEGAL, 'ILLEGAL'), ReturnValue=one()), ast.ReturnStatement(Token=token.Token(token.ILLEGAL, 'ILLEGAL'), ReturnValue=two())), Test( ast.LetStatement(Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Value=one(), Name=''), ast.LetStatement(Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Value=two(), Name=''), ), Test( ast.FunctionLiteral( Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Parameters=[], Body=ast.BlockStatement( Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Statements=[ ast.ExpressionStatement(Token=token.Token( token.ILLEGAL, 'ILLEGAL'), ExpressionValue=one()), ])), ast.FunctionLiteral( Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Parameters=[], Body=ast.BlockStatement( Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Statements=[ ast.ExpressionStatement(Token=token.Token( token.ILLEGAL, 'ILLEGAL'), ExpressionValue=two()), ])), ), Test( ast.ArrayLiteral(Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Elements=[one(), one()]), ast.ArrayLiteral(Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Elements=[two(), two()]), ), ] for tt in tests: modified = ast.Modify(tt.input, turnOneIntoTwo) if modified != tt.expected: self.fail('not equal. got=%s, want=%s' % (modified, tt.expected)) hashLiteral = ast.HashLiteral( Token=token.Token(token.ILLEGAL, 'ILLEGAL'), Pairs=[ (one(), one()), (one(), one()), ], ) ast.Modify(hashLiteral, turnOneIntoTwo) for key, val in hashLiteral.Pairs: if key.Value != 2: self.fail('value is not %s, got=%s' % (2, key.Value)) if val.Value != 2: self.fail('value is not %s, got=%s' % (2, val.Value))
def parse_integer_literal(self) -> ast.Node: return ast.IntegerLiteral(token=self.cur_token, value=int(self.cur_token.literal))
def test_modify(self): one = lambda: ast.ExpressionStatement(expression=ast.IntegerLiteral( value=1)) two = lambda: ast.ExpressionStatement(expression=ast.IntegerLiteral( value=2)) def turn_one_into_two(node): """ Modifier function to convert IntegerLiteral of value 1 to 2 """ integer = node if not isinstance(integer, ast.IntegerLiteral): return node elif integer.value != 1: return node integer.value = 2 return integer tests = [ (one(), ast.ExpressionStatement(expression=ast.IntegerLiteral(value=2))), (two(), ast.ExpressionStatement(expression=ast.IntegerLiteral(value=2))), (ast.InfixExpression(operator="+", left=one(), right=two()), ast.InfixExpression(operator="+", left=two(), right=two())), (ast.InfixExpression(operator="+", left=two(), right=one()), ast.InfixExpression(operator="+", left=two(), right=two())), (ast.PrefixExpression(operator="-", right=one()), ast.PrefixExpression(operator="-", right=two())), (ast.IndexExpression(left=one(), index=one()), ast.IndexExpression(left=two(), index=two())), (ast.IfExpression( condition=one(), consequence=ast.BlockStatement( statements=[ast.ExpressionStatement(expression=one())]), alternative=ast.BlockStatement( statements=[ast.ExpressionStatement(expression=one())])), ast.IfExpression( condition=two(), consequence=ast.BlockStatement( statements=[ast.ExpressionStatement(expression=two())]), alternative=ast.BlockStatement( statements=[ast.ExpressionStatement(expression=two())]))), (ast.ReturnStatement(return_value=one()), ast.ReturnStatement(return_value=two())), (ast.LetStatement(value=one()), ast.LetStatement(value=two())), (ast.FunctionLiteral( parameters=[], body=ast.BlockStatement( statements=[ast.ExpressionStatement(expression=one())])), ast.FunctionLiteral( parameters=[], body=ast.BlockStatement( statements=[ast.ExpressionStatement(expression=two())]))), (ast.ArrayLiteral(elements=[one(), one()]), ast.ArrayLiteral(elements=[two(), two()])) ] for t in tests: modified = modify.Modify(t[0], turn_one_into_two) deep_equals = (modified == t[1]) self.assertTrue(deep_equals, 'not equal. got={} want={}'.format(modified, t[1])) # HashLiteral needs to be tested slightly different hash_literal = ast.HashLiteral(pairs={one(): one(), two(): two()}) hash_literal = modify.Modify(hash_literal, turn_one_into_two) for key, value in hash_literal.pairs.items(): self.assertTrue(key == two(), 'value is not {}. got={}'.format(2, key)) self.assertTrue(value == two(), 'value is not {}. got={}'.format(2, value))