AST works for variable reassignment

kinda coded horribly tho lol
This commit is contained in:
SpookyDervish
2025-10-14 19:22:59 +11:00
parent 5741a48e73
commit 655e5d1d12
7 changed files with 132 additions and 39 deletions

16
AST.py
View File

@@ -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

View File

@@ -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)

View File

@@ -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
View 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
}

35
main.py
View File

@@ -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))
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. ===")

View File

@@ -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,17 +136,18 @@ class Parser:
if self.__peek_token_is(TokenType.EQ): # function definition
# x = Func(): Int { return 10; }
self.__next_token()
if self.__peek_token_is(TokenType.TYPE):
func_stmt: FunctionStatement = FunctionStatement(name=stmt.name)
if not self.__expect_peek(TokenType.TYPE): # Func word
return None
if self.current_token.literal != "Func":
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
@@ -169,6 +170,18 @@ class Parser:
func_stmt.body = self.__parse_block_statement()
return func_stmt
else: # reassignment statement
assign_stmt: ReassignStatement = ReassignStatement()
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):

View File

@@ -1,4 +1,7 @@
main = Func(): Int {
x: Int = 123;
return x + 5;
x: Int = 0;
x = x * 2;
return x;
}