while loops work!

This commit is contained in:
SpookyDervish
2025-10-15 18:44:15 +11:00
parent 549f650b54
commit 9f6fff9977
7 changed files with 155 additions and 86 deletions

16
AST.py
View File

@@ -13,6 +13,7 @@ class NodeType(Enum):
BlockStatement = "BlockStatement" BlockStatement = "BlockStatement"
ReturnStatement = "ReturnStatement" ReturnStatement = "ReturnStatement"
IfStatement = "IfStatement" IfStatement = "IfStatement"
WhileStatement = "WhileStatement"
# Expressions # Expressions
InfixExpression = "InfixExpression" InfixExpression = "InfixExpression"
@@ -247,6 +248,21 @@ class IfStatement(Statement):
"consequence": self.consequence.json(), "consequence": self.consequence.json(),
"alternative": self.alternative.json() if self.alternative is not None else None "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 # endregion
# region Expressions # region Expressions

View File

@@ -2,6 +2,7 @@ from llvmlite import ir
from AST import Node, NodeType, Program, Expression from AST import Node, NodeType, Program, Expression
from AST import ExpressionStatement, AssignmentStatement, BlockStatement, ReturnStatement, FunctionStatement, ReassignStatement, IfStatement from AST import ExpressionStatement, AssignmentStatement, BlockStatement, ReturnStatement, FunctionStatement, ReassignStatement, IfStatement
from AST import WhileStatement
from AST import InfixExpression, CallExpression from AST import InfixExpression, CallExpression
from AST import IntegerLiteral, FloatLiteral, IdentifierLiteral, BooleanLiteral, StringLiteral from AST import IntegerLiteral, FloatLiteral, IdentifierLiteral, BooleanLiteral, StringLiteral
from AST import FunctionParameter from AST import FunctionParameter
@@ -84,6 +85,8 @@ class Compiler:
self.__visit_reassign_statement(node) self.__visit_reassign_statement(node)
case NodeType.IfStatement: case NodeType.IfStatement:
self.__visit_if_statement(node) self.__visit_if_statement(node)
case NodeType.WhileStatement:
self.__visit_while_statement(node)
# Expressions # Expressions
case NodeType.InfixExpression: case NodeType.InfixExpression:
@@ -211,6 +214,30 @@ class Compiler:
with otherwise: with otherwise:
self.compile(alternative) 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 # endregion
# region Expressions # region Expressions

View File

@@ -1,48 +1,6 @@
{ {
"type": "Program", "type": "Program",
"statements": [ "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": { "FunctionStatement": {
"type": "FunctionStatement", "type": "FunctionStatement",
@@ -52,6 +10,35 @@
}, },
"return_type": "Int", "return_type": "Int",
"parameters": [], "parameters": [],
"body": {
"type": "BlockStatement",
"statements": [
{
"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": "a"
},
"operator": "<",
"right_node": {
"type": "IntegerLiteral",
"value": 10
}
},
"body": { "body": {
"type": "BlockStatement", "type": "BlockStatement",
"statements": [ "statements": [
@@ -66,33 +53,42 @@
"arguments": [ "arguments": [
{ {
"type": "StringLiteral", "type": "StringLiteral",
"value": "apples %i" "value": "a = %i\\n"
}, },
{ {
"type": "CallExpression",
"function": {
"type": "IdentifierLiteral", "type": "IdentifierLiteral",
"value": "add" "value": "a"
},
"arguments": [
{
"type": "IntegerLiteral",
"value": 1
},
{
"type": "IntegerLiteral",
"value": 2
} }
] ]
} }
},
{
"type": "ReassignStatement",
"ident": {
"type": "IdentifierLiteral",
"value": "a"
},
"right_value": {
"type": "InfixExpression",
"left_node": {
"type": "IdentifierLiteral",
"value": "a"
},
"operator": "+",
"right_node": {
"type": "IntegerLiteral",
"value": 1
}
}
}
] ]
} }
}, },
{ {
"type": "ReturnStatement", "type": "ReturnStatement",
"return_value": { "return_value": {
"type": "IntegerLiteral", "type": "IdentifierLiteral",
"value": 0 "value": "a"
} }
} }
] ]

View File

@@ -1,30 +1,34 @@
; ModuleID = "main" ; ModuleID = "main"
target triple = "arm64-apple-darwin24.5.0" target triple = "x86_64-pc-windows-msvc"
target datalayout = "" target datalayout = ""
declare i32 @"printf"(i8* %".1", ...) declare i32 @"printf"(i8* %".1", ...)
@"true" = constant i1 1 @"true" = constant i1 1
@"false" = constant i1 0 @"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"() define i32 @"main"()
{ {
main_entry: main_entry:
%".2" = call i32 @"add"(i32 1, i32 2) %".2" = alloca i32
%".3" = alloca i32 store i32 0, i32* %".2"
store i32 %".2", i32* %".3" %".4" = load i32, i32* %".2"
%".5" = load i32, i32* %".3" %".5" = icmp slt i32 %".4", 10
ret i32 %".5" 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"

View File

@@ -50,6 +50,7 @@ class TokenType(Enum):
UNLESS = "UNLESS" UNLESS = "UNLESS"
TRUE = "TRUE" TRUE = "TRUE"
FALSE = "FALSE" FALSE = "FALSE"
WHILE = "WHILE"
# Typing # Typing
TYPE = "TYPE" TYPE = "TYPE"
@@ -73,11 +74,13 @@ KEYWORDS: dict[str, TokenType] = {
"if": TokenType.IF, "if": TokenType.IF,
"unless": TokenType.UNLESS, "unless": TokenType.UNLESS,
"true": TokenType.TRUE, "true": TokenType.TRUE,
"false": TokenType.FALSE "false": TokenType.FALSE,
"while": TokenType.WHILE
} }
ALT_KEYWORDS: dict[str, TokenType] = { ALT_KEYWORDS: dict[str, TokenType] = {
"else": TokenType.UNLESS,
"ret": TokenType.RETURN
} }
TYPE_KEYWORDS: list[str] = ["Int", "Float", "String", "Bool", "List", "Nil", "Func"] TYPE_KEYWORDS: list[str] = ["Int", "Float", "String", "Bool", "List", "Nil", "Func"]

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, ReassignStatement, IfStatement from AST import ExpressionStatement, AssignmentStatement, FunctionStatement, ReturnStatement, BlockStatement, ReassignStatement, IfStatement, WhileStatement
from AST import InfixExpression, CallExpression from AST import InfixExpression, CallExpression
from AST import IntegerLiteral, FloatLiteral, IdentifierLiteral, BooleanLiteral, StringLiteral from AST import IntegerLiteral, FloatLiteral, IdentifierLiteral, BooleanLiteral, StringLiteral
from AST import FunctionParameter from AST import FunctionParameter
@@ -136,6 +136,8 @@ class Parser:
return self.__parse_assignment_statement() return self.__parse_assignment_statement()
case TokenType.RETURN: case TokenType.RETURN:
return self.__parse_return_statement() return self.__parse_return_statement()
case TokenType.WHILE:
return self.__parse_while_statement()
case _: case _:
return self.__parse_expression_statement() return self.__parse_expression_statement()
@@ -301,6 +303,21 @@ class Parser:
alternative = self.__parse_block_statement() alternative = self.__parse_block_statement()
return IfStatement(condition, consequence, alternative) 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 # endregion
# region Expression Methods # region Expression Methods

View File

@@ -1,4 +1,10 @@
main = Func(): Int { main = Func(): Int {
$print("Hello, World!"); a: Int = 0;
return 0;
while a < 10 {
$print("a = %i\n", a);
a = a + 1;
}
return a;
} }