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"
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

View File

@@ -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

View File

@@ -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",
@@ -52,6 +10,35 @@
},
"return_type": "Int",
"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": {
"type": "BlockStatement",
"statements": [
@@ -66,33 +53,42 @@
"arguments": [
{
"type": "StringLiteral",
"value": "apples %i"
"value": "a = %i\\n"
},
{
"type": "CallExpression",
"function": {
"type": "IdentifierLiteral",
"value": "add"
},
"arguments": [
{
"type": "IntegerLiteral",
"value": 1
},
{
"type": "IntegerLiteral",
"value": 2
"value": "a"
}
]
}
},
{
"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",
"return_value": {
"type": "IntegerLiteral",
"value": 0
"type": "IdentifierLiteral",
"value": "a"
}
}
]

View File

@@ -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"

View File

@@ -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"]

View File

@@ -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

View File

@@ -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;
}