AST works for variable reassignment
kinda coded horribly tho lol
This commit is contained in:
16
AST.py
16
AST.py
@@ -8,6 +8,7 @@ class NodeType(Enum):
|
||||
# Statements
|
||||
ExpressionStatement = "ExpressionStatement"
|
||||
AssignmentStatement = "AssignmentStatement"
|
||||
ReassignStatement = "ReassignStatement"
|
||||
FunctionStatement = "FunctionStatement"
|
||||
BlockStatement = "BlockStatement"
|
||||
ReturnStatement = "ReturnStatement"
|
||||
@@ -164,6 +165,21 @@ class FunctionStatement(Statement):
|
||||
"parameters": [p.json() for p in self.parameters],
|
||||
"body": self.body.json()
|
||||
}
|
||||
|
||||
class ReassignStatement(Statement):
|
||||
def __init__(self, ident: Expression = None, right_value: Expression = None) -> None:
|
||||
self.ident = ident
|
||||
self.right_value = right_value
|
||||
|
||||
def type(self) -> NodeType:
|
||||
return NodeType.ReassignStatement
|
||||
|
||||
def json(self) -> dict:
|
||||
return {
|
||||
"type": self.type().value,
|
||||
"ident": self.ident.json(),
|
||||
"right_value": self.right_value.json()
|
||||
}
|
||||
# endregion
|
||||
|
||||
# region Expressions
|
||||
|
||||
@@ -80,7 +80,8 @@ class Compiler:
|
||||
|
||||
def __visit_return_statement(self, node: ReturnStatement) -> None:
|
||||
value: Expression = node.return_value
|
||||
value, Type = self.__resolve_value(node)
|
||||
|
||||
value, Type = self.__resolve_value(value)
|
||||
|
||||
self.builder.ret(value)
|
||||
|
||||
|
||||
@@ -21,24 +21,35 @@
|
||||
},
|
||||
"value": {
|
||||
"type": "IntegerLiteral",
|
||||
"value": 123
|
||||
"value": 0
|
||||
},
|
||||
"value_type": "Int"
|
||||
},
|
||||
{
|
||||
"type": "ReturnStatement",
|
||||
"return_value": {
|
||||
"type": "ReassignStatement",
|
||||
"ident": {
|
||||
"type": "IdentifierLiteral",
|
||||
"value": "x"
|
||||
},
|
||||
"right_value": {
|
||||
"type": "InfixExpression",
|
||||
"left_node": {
|
||||
"type": "IdentifierLiteral",
|
||||
"value": "x"
|
||||
},
|
||||
"operator": "+",
|
||||
"operator": "*",
|
||||
"right_node": {
|
||||
"type": "IntegerLiteral",
|
||||
"value": 5
|
||||
"value": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ReturnStatement",
|
||||
"return_value": {
|
||||
"type": "IdentifierLiteral",
|
||||
"value": "x"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
18
debug/ir.ll
Normal file
18
debug/ir.ll
Normal file
@@ -0,0 +1,18 @@
|
||||
; ModuleID = "main"
|
||||
target triple = "x86_64-pc-windows-msvc"
|
||||
target datalayout = ""
|
||||
|
||||
define i32 @"main"()
|
||||
{
|
||||
main_entry:
|
||||
%".2" = alloca i32
|
||||
store i32 0, i32* %".2"
|
||||
%".4" = load i32, i32* %".2"
|
||||
ret i32 %".4"
|
||||
}
|
||||
|
||||
define i32 @"test"()
|
||||
{
|
||||
test_entry:
|
||||
ret i32 123
|
||||
}
|
||||
37
main.py
37
main.py
@@ -3,14 +3,16 @@ from plasma_parser import Parser
|
||||
from compiler import Compiler
|
||||
from AST import Program
|
||||
import json
|
||||
import time
|
||||
|
||||
from llvmlite import ir
|
||||
from llvmlite.binding import targets
|
||||
import llvmlite.binding as llvm
|
||||
from ctypes import CFUNCTYPE, c_int, c_float
|
||||
|
||||
LEXER_DEBUG: bool = False
|
||||
PARSER_DEBUG: bool = False
|
||||
COMPILER_DEBUG: bool = True
|
||||
RUN_CODE: bool = False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@@ -44,8 +46,37 @@ if __name__ == "__main__":
|
||||
c.compile(program)
|
||||
|
||||
module: ir.Module = c.module
|
||||
module.triple = targets.get_default_triple()
|
||||
module.triple = llvm.get_default_triple()
|
||||
|
||||
if COMPILER_DEBUG:
|
||||
with open("debug/ir.ll", "w") as f:
|
||||
f.write(str(module))
|
||||
f.write(str(module))
|
||||
|
||||
if RUN_CODE:
|
||||
#llvm.initialize()
|
||||
llvm.initialize_native_target()
|
||||
llvm.initialize_native_asmparser()
|
||||
llvm.initialize_native_asmprinter()
|
||||
|
||||
try:
|
||||
llvm_ir_parsed = llvm.parse_assembly(str(module))
|
||||
llvm_ir_parsed.verify()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
raise
|
||||
|
||||
target_machine = llvm.Target.from_default_triple().create_target_machine()
|
||||
|
||||
engine = llvm.create_mcjit_compiler(llvm_ir_parsed, target_machine)
|
||||
engine.finalize_object()
|
||||
|
||||
entry = engine.get_function_address("main")
|
||||
cfunc = CFUNCTYPE(c_int)(entry)
|
||||
|
||||
st = time.time()
|
||||
|
||||
result = cfunc()
|
||||
|
||||
et = time.time()
|
||||
|
||||
print(f"\n\nProgram returned: {result}\n=== Executed in {round((et - st) * 1000, 6)} ms. ===")
|
||||
@@ -4,7 +4,7 @@ from typing import Callable
|
||||
from enum import Enum, auto
|
||||
|
||||
from AST import Statement, Expression, Program
|
||||
from AST import ExpressionStatement, AssignmentStatement, FunctionStatement, ReturnStatement, BlockStatement
|
||||
from AST import ExpressionStatement, AssignmentStatement, FunctionStatement, ReturnStatement, BlockStatement, ReassignStatement
|
||||
from AST import InfixExpression
|
||||
from AST import IntegerLiteral, FloatLiteral, IdentifierLiteral
|
||||
|
||||
@@ -136,39 +136,52 @@ class Parser:
|
||||
|
||||
if self.__peek_token_is(TokenType.EQ): # function definition
|
||||
# x = Func(): Int { return 10; }
|
||||
|
||||
self.__next_token()
|
||||
|
||||
func_stmt: FunctionStatement = FunctionStatement(name=stmt.name)
|
||||
if self.__peek_token_is(TokenType.TYPE):
|
||||
func_stmt: FunctionStatement = FunctionStatement(name=stmt.name)
|
||||
|
||||
if self.peek_token.literal != "Func":
|
||||
self.errors.append(f"Expected next token to be \"Func\", got {self.current_token.literal} instead.")
|
||||
return None
|
||||
|
||||
self.__next_token()
|
||||
|
||||
if not self.__expect_peek(TokenType.LPAREN):
|
||||
return None
|
||||
|
||||
func_stmt.parameters = []
|
||||
|
||||
if not self.__expect_peek(TokenType.TYPE): # Func word
|
||||
return None
|
||||
|
||||
if self.current_token.literal != "Func":
|
||||
self.errors.append(f"Expected next token to be \"Func\", got {self.current_token.literal} instead.")
|
||||
return None
|
||||
|
||||
if not self.__expect_peek(TokenType.LPAREN):
|
||||
return None
|
||||
|
||||
func_stmt.parameters = []
|
||||
if not self.__expect_peek(TokenType.RPAREN):
|
||||
return None
|
||||
|
||||
if not self.__expect_peek(TokenType.COLON):
|
||||
return None
|
||||
|
||||
if not self.__expect_peek(TokenType.TYPE):
|
||||
return None
|
||||
|
||||
func_stmt.return_type = self.current_token.literal
|
||||
|
||||
if not self.__expect_peek(TokenType.RPAREN):
|
||||
return None
|
||||
|
||||
if not self.__expect_peek(TokenType.COLON):
|
||||
return None
|
||||
|
||||
if not self.__expect_peek(TokenType.TYPE):
|
||||
return None
|
||||
|
||||
func_stmt.return_type = self.current_token.literal
|
||||
if not self.__expect_peek(TokenType.LBRACE):
|
||||
return None
|
||||
|
||||
func_stmt.body = self.__parse_block_statement()
|
||||
|
||||
if not self.__expect_peek(TokenType.LBRACE):
|
||||
return None
|
||||
|
||||
func_stmt.body = self.__parse_block_statement()
|
||||
return func_stmt
|
||||
else: # reassignment statement
|
||||
assign_stmt: ReassignStatement = ReassignStatement()
|
||||
|
||||
return func_stmt
|
||||
self.__next_token()
|
||||
|
||||
assign_stmt.ident = stmt.name
|
||||
assign_stmt.right_value = self.__parse_expression(PrecedenceType.P_LOWEST)
|
||||
|
||||
while not self.__current_token_is(TokenType.SEMICOLON) and not self.__current_token_is(TokenType.EOF):
|
||||
self.__next_token()
|
||||
|
||||
return assign_stmt
|
||||
|
||||
else:
|
||||
if not self.__expect_peek(TokenType.COLON):
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
main = Func(): Int {
|
||||
x: Int = 123;
|
||||
return x + 5;
|
||||
x: Int = 0;
|
||||
|
||||
x = x * 2;
|
||||
|
||||
return x;
|
||||
}
|
||||
Reference in New Issue
Block a user