From 655e5d1d12f2e0746ca35630042a4c7e46973f4f Mon Sep 17 00:00:00 2001 From: SpookyDervish <78246495+SpookyDervish@users.noreply.github.com> Date: Tue, 14 Oct 2025 19:22:59 +1100 Subject: [PATCH] AST works for variable reassignment kinda coded horribly tho lol --- AST.py | 16 +++++++++++ compiler.py | 3 ++- debug/ast.json | 21 +++++++++++---- debug/ir.ll | 18 +++++++++++++ main.py | 37 +++++++++++++++++++++++--- plasma_parser.py | 69 ++++++++++++++++++++++++++++-------------------- tests/test.pla | 7 +++-- 7 files changed, 132 insertions(+), 39 deletions(-) create mode 100644 debug/ir.ll diff --git a/AST.py b/AST.py index a3f4203..228a0bb 100644 --- a/AST.py +++ b/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 diff --git a/compiler.py b/compiler.py index 5c74811..7e391a8 100644 --- a/compiler.py +++ b/compiler.py @@ -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) diff --git a/debug/ast.json b/debug/ast.json index aa118d2..b19efb1 100644 --- a/debug/ast.json +++ b/debug/ast.json @@ -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" + } } ] } diff --git a/debug/ir.ll b/debug/ir.ll new file mode 100644 index 0000000..90aff47 --- /dev/null +++ b/debug/ir.ll @@ -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 +} diff --git a/main.py b/main.py index 31fd052..4d9a900 100644 --- a/main.py +++ b/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)) \ No newline at end of file + 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. ===") \ No newline at end of file diff --git a/plasma_parser.py b/plasma_parser.py index c05d702..bd28d94 100644 --- a/plasma_parser.py +++ b/plasma_parser.py @@ -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): diff --git a/tests/test.pla b/tests/test.pla index 0bb8372..71f2359 100644 --- a/tests/test.pla +++ b/tests/test.pla @@ -1,4 +1,7 @@ main = Func(): Int { - x: Int = 123; - return x + 5; + x: Int = 0; + + x = x * 2; + + return x; } \ No newline at end of file