diff --git a/AST.py b/AST.py index c8cfca8..8600dbb 100644 --- a/AST.py +++ b/AST.py @@ -14,6 +14,9 @@ class NodeType(Enum): ReturnStatement = "ReturnStatement" IfStatement = "IfStatement" WhileStatement = "WhileStatement" + BreakStatement = "BreakStatement" + ContinueStatement = "ContinueStatement" + ForStatement = "ForStatement" # Expressions InfixExpression = "InfixExpression" @@ -263,6 +266,48 @@ class WhileStatement(Statement): "condition": self.condition.json(), "body": self.body.json() } + +class BreakStatement(Statement): + def __init__(self) -> None: + pass + + def type(self) -> NodeType: + return NodeType.BreakStatement + + def json(self) -> dict: + return { + "type": self.type().value + } + +class ContinueStatement(Statement): + def __init__(self) -> None: + pass + + def type(self) -> NodeType: + return NodeType.ContinueStatement + + def json(self) -> dict: + return { + "type": self.type().value + } + +class ForStatement(Statement): + def __init__(self, var_declaration: AssignmentStatement = None, condition: Expression = None, action: ReassignStatement = None, body: BlockStatement = None) -> None: + self.var_declaration = var_declaration + self.condition = condition + self.action = action + self.body = body + + def type(self) -> NodeType: + return NodeType.ForStatement + + def json(self) -> dict: + return { + "type": self.type().value, + "var_declaration": self.var_declaration.json(), + "condition": self.condition.json(), + "body": self.body.json() + } # endregion # region Expressions diff --git a/compiler.py b/compiler.py index 50b11fd..6716ce3 100644 --- a/compiler.py +++ b/compiler.py @@ -2,7 +2,7 @@ from llvmlite import ir from AST import Node, NodeType, Program, Expression from AST import ExpressionStatement, AssignmentStatement, BlockStatement, ReturnStatement, FunctionStatement, ReassignStatement, IfStatement -from AST import WhileStatement +from AST import WhileStatement, BreakStatement, ContinueStatement, ForStatement from AST import InfixExpression, CallExpression from AST import IntegerLiteral, FloatLiteral, IdentifierLiteral, BooleanLiteral, StringLiteral from AST import FunctionParameter @@ -33,6 +33,9 @@ class Compiler: self.__initialize_builtins() + self.breakpoints: list[ir.Block] = [] + self.continues: list[ir.Block] = [] + def __initialize_builtins(self) -> None: def __init_print() -> ir.Function: fnty: ir.FunctionType = ir.FunctionType( @@ -87,6 +90,12 @@ class Compiler: self.__visit_if_statement(node) case NodeType.WhileStatement: self.__visit_while_statement(node) + case NodeType.BreakStatement: + self.__visit_break_statement(node) + case NodeType.ContinueStatement: + self.__visit_continue_statement(node) + case NodeType.ForStatement: + self.__visit_for_statement(node) # Expressions case NodeType.InfixExpression: @@ -238,6 +247,44 @@ class Compiler: test, _ = self.__resolve_value(condition) self.builder.cbranch(test, while_loop_entry, while_loop_otherwise) self.builder.position_at_start(while_loop_otherwise) + + def __visit_break_statement(self, node: BreakStatement) -> None: + self.builder.branch(self.breakpoints[-1]) + + def __visit_continue_statement(self, node: ContinueStatement) -> None: + self.builder.branch[self.continues[-1]] + + def __visit_for_statement(self, node: ForStatement) -> None: + var_declaration: AssignmentStatement = node.var_declaration + condition: Expression = node.condition + action: ReassignStatement = node.action + body: BlockStatement = node.body + + previous_env = self.environment + self.environment = Environment(parent=previous_env) + + self.compile(var_declaration) + + for_loop_entry = self.builder.append_basic_block(f"for_loop_entry_{self.__increment_counter()}") + for_loop_otherwise = self.builder.append_basic_block(f"for_loop_otherwise_{self.counter}") + + self.breakpoints.append(for_loop_otherwise) + self.continues.append(for_loop_entry) + + self.builder.branch(for_loop_entry) + self.builder.position_at_start(for_loop_entry) + + self.compile(body) + + self.compile(action) + + test, _ = self.__resolve_value(condition) + self.builder.cbranch(test, for_loop_entry, for_loop_otherwise) + + self.builder.position_at_start(for_loop_otherwise) + + self.breakpoints.pop() + self.continues.pop() # endregion # region Expressions diff --git a/lexer_token.py b/lexer_token.py index 1b7dc1c..764022c 100644 --- a/lexer_token.py +++ b/lexer_token.py @@ -51,6 +51,9 @@ class TokenType(Enum): TRUE = "TRUE" FALSE = "FALSE" WHILE = "WHILE" + CONTINUE = "CONTINUE" + BREAK = "BREAK" + FOR = "FOR" # Typing TYPE = "TYPE" @@ -75,7 +78,10 @@ KEYWORDS: dict[str, TokenType] = { "unless": TokenType.UNLESS, "true": TokenType.TRUE, "false": TokenType.FALSE, - "while": TokenType.WHILE + "while": TokenType.WHILE, + "break": TokenType.BREAK, + "continue": TokenType.CONTINUE, + "for": TokenType.FOR } ALT_KEYWORDS: dict[str, TokenType] = { diff --git a/main.py b/main.py index aaec4f1..b287b44 100644 --- a/main.py +++ b/main.py @@ -10,9 +10,9 @@ import llvmlite.binding as llvm from ctypes import CFUNCTYPE, c_int, c_float LEXER_DEBUG: bool = False -PARSER_DEBUG: bool = False +PARSER_DEBUG: bool = True COMPILER_DEBUG: bool = False -RUN_CODE: bool = True +RUN_CODE: bool = False if __name__ == "__main__": diff --git a/plasma_parser.py b/plasma_parser.py index b988cc0..5eca5c8 100644 --- a/plasma_parser.py +++ b/plasma_parser.py @@ -5,7 +5,7 @@ from enum import Enum, auto from AST import Statement, Expression, Program from AST import ExpressionStatement, AssignmentStatement, FunctionStatement, ReturnStatement, BlockStatement, ReassignStatement, IfStatement, WhileStatement -from AST import InfixExpression, CallExpression +from AST import InfixExpression, CallExpression, BreakStatement, ContinueStatement, ForStatement from AST import IntegerLiteral, FloatLiteral, IdentifierLiteral, BooleanLiteral, StringLiteral from AST import FunctionParameter @@ -138,6 +138,12 @@ class Parser: return self.__parse_return_statement() case TokenType.WHILE: return self.__parse_while_statement() + case TokenType.BREAK: + return self.__parse_break_statement() + case TokenType.CONTINUE: + return self.__parse_continue_statement() + case TokenType.FOR: + return self.__parse_for_statement() case _: return self.__parse_expression_statement() @@ -318,6 +324,47 @@ class Parser: body = self.__parse_block_statement() return WhileStatement(condition, body) + + def __parse_break_statement(self) -> BreakStatement: + self.__next_token() + return BreakStatement() + + def __parse_continue_statement(self) -> ContinueStatement: + self.__next_token() + return ContinueStatement() + + def __parse_for_statement(self) -> ForStatement: + stmt: ForStatement = ForStatement() + + if not self.__expect_peek(TokenType.LPAREN): + return None + + if not self.__expect_peek(TokenType.IDENT): + return None + + stmt.var_declaration = self.__parse_assignment_statement() + + self.__next_token() # skip ; + + stmt.condition = self.__parse_expression(PrecedenceType.P_LOWEST) + + if not self.__expect_peek(TokenType.SEMICOLON): + return None + + self.__next_token() # skip ; + + stmt.action = self.__parse_assignment_statement() + + print(stmt.action.json()) + + self.__next_token() + + if not self.__expect_peek(TokenType.LBRACE): + return None + + stmt.body = self.__parse_block_statement() + + return stmt # endregion # region Expression Methods diff --git a/tests/test.pla b/tests/test.pla index 6d56f62..e71bd54 100644 --- a/tests/test.pla +++ b/tests/test.pla @@ -1,10 +1,7 @@ main = Func(): Int { - a: Int = 0; - - while a < 10 { - $print("a = %i\n", a); - a = a + 1; + for (x: Int = 1; x <= 20; x = x + 1) { + print("i = %i\n", x) } - return a; + return x; } \ No newline at end of file