mirror of
https://github.com/BoardWare-Genius/jarvis-models.git
synced 2025-12-13 16:53:24 +00:00
164 lines
4.5 KiB
Python
164 lines
4.5 KiB
Python
|
|
|
|
|
|
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 expression_statement(self):
|
|
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"]
|
|
|
|
# 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 == "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 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 |