diff --git a/AST.py b/AST.py index a7bd515..c8cfca8 100644 --- a/AST.py +++ b/AST.py @@ -13,6 +13,7 @@ class NodeType(Enum): BlockStatement = "BlockStatement" ReturnStatement = "ReturnStatement" IfStatement = "IfStatement" + WhileStatement = "WhileStatement" # Expressions InfixExpression = "InfixExpression" @@ -247,6 +248,21 @@ class IfStatement(Statement): "consequence": self.consequence.json(), "alternative": self.alternative.json() if self.alternative is not None else None } + +class WhileStatement(Statement): + def __init__(self, condition: Expression, body: BlockStatement = None): + self.condition = condition + self.body = body + + def type(self) -> NodeType: + return NodeType.WhileStatement + + def json(self) -> dict: + return { + "type": self.type().value, + "condition": self.condition.json(), + "body": self.body.json() + } # endregion # region Expressions diff --git a/compiler.py b/compiler.py index aeda6cb..50b11fd 100644 --- a/compiler.py +++ b/compiler.py @@ -2,6 +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 InfixExpression, CallExpression from AST import IntegerLiteral, FloatLiteral, IdentifierLiteral, BooleanLiteral, StringLiteral from AST import FunctionParameter @@ -84,6 +85,8 @@ class Compiler: self.__visit_reassign_statement(node) case NodeType.IfStatement: self.__visit_if_statement(node) + case NodeType.WhileStatement: + self.__visit_while_statement(node) # Expressions case NodeType.InfixExpression: @@ -211,6 +214,30 @@ class Compiler: with otherwise: self.compile(alternative) + + def __visit_while_statement(self, node: WhileStatement) -> None: + condition: Expression = node.condition + body: BlockStatement = node.body + + test, _ = self.__resolve_value(condition) + + while_loop_entry = self.builder.append_basic_block(f"while_loop_entry_{self.__increment_counter()}") + while_loop_otherwise = self.builder.append_basic_block(f"while_loop_otherwise_{self.counter}") + + # Creating a condition branch + # condition + # / \ + # true false + # / \ + # / \ + # if block else block + self.builder.cbranch(test, while_loop_entry, while_loop_otherwise) + + self.builder.position_at_start(while_loop_entry) + self.compile(body) + test, _ = self.__resolve_value(condition) + self.builder.cbranch(test, while_loop_entry, while_loop_otherwise) + self.builder.position_at_start(while_loop_otherwise) # endregion # region Expressions diff --git a/debug/ast.json b/debug/ast.json index 7091861..edc4ef0 100644 --- a/debug/ast.json +++ b/debug/ast.json @@ -1,48 +1,6 @@ { "type": "Program", "statements": [ - { - "FunctionStatement": { - "type": "FunctionStatement", - "name": { - "type": "IdentifierLiteral", - "value": "add" - }, - "return_type": "Int", - "parameters": [ - { - "type": "FunctionParameter", - "name": "a", - "value_type": "Int" - }, - { - "type": "FunctionParameter", - "name": "b", - "value_type": "Int" - } - ], - "body": { - "type": "BlockStatement", - "statements": [ - { - "type": "ReturnStatement", - "return_value": { - "type": "InfixExpression", - "left_node": { - "type": "IdentifierLiteral", - "value": "a" - }, - "operator": "+", - "right_node": { - "type": "IdentifierLiteral", - "value": "b" - } - } - } - ] - } - } - }, { "FunctionStatement": { "type": "FunctionStatement", @@ -56,34 +14,72 @@ "type": "BlockStatement", "statements": [ { - "type": "ExpressionStatement", - "expr": { - "type": "CallExpression", - "function": { + "type": "AssignmentStatement", + "name": { + "type": "IdentifierLiteral", + "value": "a" + }, + "value": { + "type": "IntegerLiteral", + "value": 0 + }, + "value_type": "Int" + }, + { + "type": "WhileStatement", + "condition": { + "type": "InfixExpression", + "left_node": { "type": "IdentifierLiteral", - "value": "print" + "value": "a" }, - "arguments": [ + "operator": "<", + "right_node": { + "type": "IntegerLiteral", + "value": 10 + } + }, + "body": { + "type": "BlockStatement", + "statements": [ { - "type": "StringLiteral", - "value": "apples %i" + "type": "ExpressionStatement", + "expr": { + "type": "CallExpression", + "function": { + "type": "IdentifierLiteral", + "value": "print" + }, + "arguments": [ + { + "type": "StringLiteral", + "value": "a = %i\\n" + }, + { + "type": "IdentifierLiteral", + "value": "a" + } + ] + } }, { - "type": "CallExpression", - "function": { + "type": "ReassignStatement", + "ident": { "type": "IdentifierLiteral", - "value": "add" + "value": "a" }, - "arguments": [ - { + "right_value": { + "type": "InfixExpression", + "left_node": { + "type": "IdentifierLiteral", + "value": "a" + }, + "operator": "+", + "right_node": { "type": "IntegerLiteral", "value": 1 - }, - { - "type": "IntegerLiteral", - "value": 2 } - ] + } } ] } @@ -91,8 +87,8 @@ { "type": "ReturnStatement", "return_value": { - "type": "IntegerLiteral", - "value": 0 + "type": "IdentifierLiteral", + "value": "a" } } ] diff --git a/debug/ir.ll b/debug/ir.ll index 0bd30e3..f92aa4b 100644 --- a/debug/ir.ll +++ b/debug/ir.ll @@ -1,30 +1,34 @@ ; ModuleID = "main" -target triple = "arm64-apple-darwin24.5.0" +target triple = "x86_64-pc-windows-msvc" target datalayout = "" declare i32 @"printf"(i8* %".1", ...) @"true" = constant i1 1 @"false" = constant i1 0 -define i32 @"add"(i32 %".1", i32 %".2") -{ -add_entry: - %".4" = alloca i32 - store i32 %".1", i32* %".4" - %".6" = alloca i32 - store i32 %".2", i32* %".6" - %".8" = load i32, i32* %".4" - %".9" = load i32, i32* %".6" - %".10" = add i32 %".8", %".9" - ret i32 %".10" -} - define i32 @"main"() { main_entry: - %".2" = call i32 @"add"(i32 1, i32 2) - %".3" = alloca i32 - store i32 %".2", i32* %".3" - %".5" = load i32, i32* %".3" - ret i32 %".5" + %".2" = alloca i32 + store i32 0, i32* %".2" + %".4" = load i32, i32* %".2" + %".5" = icmp slt i32 %".4", 10 + br i1 %".5", label %"while_loop_entry_1", label %"while_loop_otherwise_1" +while_loop_entry_1: + %".7" = load i32, i32* %".2" + %".8" = alloca [9 x i8]* + store [9 x i8]* @"__str_2", [9 x i8]** %".8" + %".10" = bitcast [9 x i8]* @"__str_2" to i8* + %".11" = call i32 (i8*, ...) @"printf"(i8* %".10", i32 %".7") + %".12" = load i32, i32* %".2" + %".13" = add i32 %".12", 1 + store i32 %".13", i32* %".2" + %".15" = load i32, i32* %".2" + %".16" = icmp slt i32 %".15", 10 + br i1 %".16", label %"while_loop_entry_1", label %"while_loop_otherwise_1" +while_loop_otherwise_1: + %".18" = load i32, i32* %".2" + ret i32 %".18" } + +@"__str_2" = internal constant [9 x i8] c"a = %i\0a\00\00" \ No newline at end of file diff --git a/lexer_token.py b/lexer_token.py index 4c1a0ff..1b7dc1c 100644 --- a/lexer_token.py +++ b/lexer_token.py @@ -50,6 +50,7 @@ class TokenType(Enum): UNLESS = "UNLESS" TRUE = "TRUE" FALSE = "FALSE" + WHILE = "WHILE" # Typing TYPE = "TYPE" @@ -73,11 +74,13 @@ KEYWORDS: dict[str, TokenType] = { "if": TokenType.IF, "unless": TokenType.UNLESS, "true": TokenType.TRUE, - "false": TokenType.FALSE + "false": TokenType.FALSE, + "while": TokenType.WHILE } ALT_KEYWORDS: dict[str, TokenType] = { - + "else": TokenType.UNLESS, + "ret": TokenType.RETURN } TYPE_KEYWORDS: list[str] = ["Int", "Float", "String", "Bool", "List", "Nil", "Func"] diff --git a/plasma_parser.py b/plasma_parser.py index f87481d..b988cc0 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, ReassignStatement, IfStatement +from AST import ExpressionStatement, AssignmentStatement, FunctionStatement, ReturnStatement, BlockStatement, ReassignStatement, IfStatement, WhileStatement from AST import InfixExpression, CallExpression from AST import IntegerLiteral, FloatLiteral, IdentifierLiteral, BooleanLiteral, StringLiteral from AST import FunctionParameter @@ -136,6 +136,8 @@ class Parser: return self.__parse_assignment_statement() case TokenType.RETURN: return self.__parse_return_statement() + case TokenType.WHILE: + return self.__parse_while_statement() case _: return self.__parse_expression_statement() @@ -301,6 +303,21 @@ class Parser: alternative = self.__parse_block_statement() return IfStatement(condition, consequence, alternative) + + def __parse_while_statement(self) -> WhileStatement: + condition: Expression = None + body: BlockStatement = None + + self.__next_token() + + condition = self.__parse_expression(PrecedenceType.P_LOWEST) + + if not self.__expect_peek(TokenType.LBRACE): + return None + + body = self.__parse_block_statement() + + return WhileStatement(condition, body) # endregion # region Expression Methods diff --git a/tests/test.pla b/tests/test.pla index 3ffcb1c..6d56f62 100644 --- a/tests/test.pla +++ b/tests/test.pla @@ -1,4 +1,10 @@ main = Func(): Int { - $print("Hello, World!"); - return 0; + a: Int = 0; + + while a < 10 { + $print("a = %i\n", a); + a = a + 1; + } + + return a; } \ No newline at end of file