from runtime.ast.tokenizer import Tokenizer class Parser: def __init__(self) -> None: self.script = "" self.tokenizer = Tokenizer() self.current_token = None def parse(self, script: str): self.script = script self.tokenizer.init(script) self.current_token = self.tokenizer.get_next_token() return self.program() def program(self): return { "type": 'Program', "body": { "type": "BlockStatement", "body": self.statement_list() }, } def return_statement(self): self.eat('return') return { "type": 'ReturnStatement', "value": self.expression_statement(), } def statement_list(self): statment_list = [self.statement()] while self.current_token != None: statment_list.append(self.statement()) return statment_list def statement(self): if self.token_type() == "let": return self.variable_statement() return self.expression_statement() def block_statement(self): if self.token_type() != "{": self.eat('{') body = self.statement_list() if self.token_type() != "}": self.eat('}') return { "type": 'BlockStatement', "body": body, } def if_statement(self): self.eat('if') return { "type": 'IfStatement', } def expression_statement(self): if self.token_type() == "if": return self.if_statement() if self.token_type() == "return": return self.return_statement() if self._is_literal(): return self.literal() if self.token_type() == "IDENTIFIER": identifier = self.identifier() if self.token_type() == "(": return self.call_expression(identifier) if self.token_type() == "SIMPLE_ASSIGN": return self.assignment_expression(identifier) return identifier raise Exception("Unexpected token: " + self.token_type()) def assignment_expression(self,identifier): self.eat('SIMPLE_ASSIGN') return { "type": 'AssignmentExpression', "identifier": identifier, "value": self.statement(), } def call_expression(self, identifier): self.eat('(') arguments = self.argument_list() self.eat(')') return { "type": 'CallExpression', "arguments": arguments, "callee": identifier, } def token_type(self): if self.current_token == None: return None return self.current_token["type"] def _is_literal(self): return self.current_token["type"] in ["NUMBER", "STRING", "FLOAT", "true", "false"] # variable def variable_statement(self): self.eat('let') identifier = self.identifier() self.eat('SIMPLE_ASSIGN') return { "type": 'VariableDeclaration', "identifier": identifier, "value": self.statement(), } def eat(self, tokenType): token = self.current_token if token == None: raise Exception("Unexpected EOF") if token["type"] != tokenType: raise Exception("Unexpected token: " + token["type"]) self.current_token = self.tokenizer.get_next_token() return token def identifier(self): name = self.eat('IDENTIFIER') return { "type": 'Identifier', "name": name["value"], } def literal(self): token_type = self.current_token["type"] if token_type == "true" or token_type == "false": return self.boolean_literal() if token_type == "NUMBER": return self.numberic_literal() if token_type == "STRING": return self.string_literal() if token_type == "FLOAT": return self.float_literal() raise Exception("Unexpected token: " + token_type) def boolean_literal(self): if self.token_type() == "true": self.eat('true') value = "True" else: self.eat("false") value = "False" return { "type": 'BooleanLiteral', "value": value, } def numberic_literal(self): token = self.eat('NUMBER') return { "type": 'NumericLiteral', "value": token["value"], } def string_literal(self): token = self.eat('STRING') return { "type": 'StringLiteral', "value": token["value"][1:-1], } def float_literal(self): token = self.eat('FLOAT') return { "type": 'FloatLiteral', "value": token["value"], } def argument_list(self): args = [] while self.token_type() != ")": args.append(self.statement()) if self.token_type() == ",": self.eat(',') return args