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 # Statements
ExpressionStatement = "ExpressionStatement" ExpressionStatement = "ExpressionStatement"
AssignmentStatement = "AssignmentStatement" AssignmentStatement = "AssignmentStatement"
ReassignStatement = "ReassignStatement"
FunctionStatement = "FunctionStatement" FunctionStatement = "FunctionStatement"
BlockStatement = "BlockStatement" BlockStatement = "BlockStatement"
ReturnStatement = "ReturnStatement" ReturnStatement = "ReturnStatement"
@@ -164,6 +165,21 @@ class FunctionStatement(Statement):
"parameters": [p.json() for p in self.parameters], "parameters": [p.json() for p in self.parameters],
"body": self.body.json() "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 # endregion
# region Expressions # region Expressions

View File

@@ -80,7 +80,8 @@ class Compiler:
def __visit_return_statement(self, node: ReturnStatement) -> None: def __visit_return_statement(self, node: ReturnStatement) -> None:
value: Expression = node.return_value value: Expression = node.return_value
value, Type = self.__resolve_value(node)
value, Type = self.__resolve_value(value)
self.builder.ret(value) self.builder.ret(value)

View File

@@ -21,24 +21,35 @@
}, },
"value": { "value": {
"type": "IntegerLiteral", "type": "IntegerLiteral",
"value": 123 "value": 0
}, },
"value_type": "Int" "value_type": "Int"
}, },
{ {
"type": "ReturnStatement", "type": "ReassignStatement",
"return_value": { "ident": {
"type": "IdentifierLiteral",
"value": "x"
},
"right_value": {
"type": "InfixExpression", "type": "InfixExpression",
"left_node": { "left_node": {
"type": "IdentifierLiteral", "type": "IdentifierLiteral",
"value": "x" "value": "x"
}, },
"operator": "+", "operator": "*",
"right_node": { "right_node": {
"type": "IntegerLiteral", "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 compiler import Compiler
from AST import Program from AST import Program
import json import json
import time
from llvmlite import ir from llvmlite import ir
from llvmlite.binding import targets import llvmlite.binding as llvm
from ctypes import CFUNCTYPE, c_int, c_float from ctypes import CFUNCTYPE, c_int, c_float
LEXER_DEBUG: bool = False LEXER_DEBUG: bool = False
PARSER_DEBUG: bool = False PARSER_DEBUG: bool = False
COMPILER_DEBUG: bool = True COMPILER_DEBUG: bool = True
RUN_CODE: bool = False
if __name__ == "__main__": if __name__ == "__main__":
@@ -44,8 +46,37 @@ if __name__ == "__main__":
c.compile(program) c.compile(program)
module: ir.Module = c.module module: ir.Module = c.module
module.triple = targets.get_default_triple() module.triple = llvm.get_default_triple()
if COMPILER_DEBUG: if COMPILER_DEBUG:
with open("debug/ir.ll", "w") as f: 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. ===")

View File

@@ -4,7 +4,7 @@ from typing import Callable
from enum import Enum, auto from enum import Enum, auto
from AST import Statement, Expression, Program 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 InfixExpression
from AST import IntegerLiteral, FloatLiteral, IdentifierLiteral from AST import IntegerLiteral, FloatLiteral, IdentifierLiteral
@@ -136,17 +136,18 @@ class Parser:
if self.__peek_token_is(TokenType.EQ): # function definition if self.__peek_token_is(TokenType.EQ): # function definition
# x = Func(): Int { return 10; } # x = Func(): Int { return 10; }
self.__next_token() self.__next_token()
if self.__peek_token_is(TokenType.TYPE):
func_stmt: FunctionStatement = FunctionStatement(name=stmt.name) func_stmt: FunctionStatement = FunctionStatement(name=stmt.name)
if not self.__expect_peek(TokenType.TYPE): # Func word if self.peek_token.literal != "Func":
return None
if self.current_token.literal != "Func":
self.errors.append(f"Expected next token to be \"Func\", got {self.current_token.literal} instead.") self.errors.append(f"Expected next token to be \"Func\", got {self.current_token.literal} instead.")
return None return None
self.__next_token()
if not self.__expect_peek(TokenType.LPAREN): if not self.__expect_peek(TokenType.LPAREN):
return None return None
@@ -169,6 +170,18 @@ class Parser:
func_stmt.body = self.__parse_block_statement() func_stmt.body = self.__parse_block_statement()
return func_stmt 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: else:
if not self.__expect_peek(TokenType.COLON): if not self.__expect_peek(TokenType.COLON):

View File

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