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
|
# 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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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
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
|
||||||
|
}
|
||||||
35
main.py
35
main.py
@@ -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. ===")
|
||||||
@@ -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):
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
main = Func(): Int {
|
main = Func(): Int {
|
||||||
x: Int = 123;
|
x: Int = 0;
|
||||||
return x + 5;
|
|
||||||
|
x = x * 2;
|
||||||
|
|
||||||
|
return x;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user