while loops work!
This commit is contained in:
16
AST.py
16
AST.py
@@ -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
|
||||||
|
|||||||
27
compiler.py
27
compiler.py
@@ -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
|
||||||
|
|||||||
120
debug/ast.json
120
debug/ast.json
@@ -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",
|
||||||
@@ -56,34 +14,72 @@
|
|||||||
"type": "BlockStatement",
|
"type": "BlockStatement",
|
||||||
"statements": [
|
"statements": [
|
||||||
{
|
{
|
||||||
"type": "ExpressionStatement",
|
"type": "AssignmentStatement",
|
||||||
"expr": {
|
"name": {
|
||||||
"type": "CallExpression",
|
"type": "IdentifierLiteral",
|
||||||
"function": {
|
"value": "a"
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"type": "IntegerLiteral",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
"value_type": "Int"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "WhileStatement",
|
||||||
|
"condition": {
|
||||||
|
"type": "InfixExpression",
|
||||||
|
"left_node": {
|
||||||
"type": "IdentifierLiteral",
|
"type": "IdentifierLiteral",
|
||||||
"value": "print"
|
"value": "a"
|
||||||
},
|
},
|
||||||
"arguments": [
|
"operator": "<",
|
||||||
|
"right_node": {
|
||||||
|
"type": "IntegerLiteral",
|
||||||
|
"value": 10
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"type": "BlockStatement",
|
||||||
|
"statements": [
|
||||||
{
|
{
|
||||||
"type": "StringLiteral",
|
"type": "ExpressionStatement",
|
||||||
"value": "apples %i"
|
"expr": {
|
||||||
|
"type": "CallExpression",
|
||||||
|
"function": {
|
||||||
|
"type": "IdentifierLiteral",
|
||||||
|
"value": "print"
|
||||||
|
},
|
||||||
|
"arguments": [
|
||||||
|
{
|
||||||
|
"type": "StringLiteral",
|
||||||
|
"value": "a = %i\\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "IdentifierLiteral",
|
||||||
|
"value": "a"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "CallExpression",
|
"type": "ReassignStatement",
|
||||||
"function": {
|
"ident": {
|
||||||
"type": "IdentifierLiteral",
|
"type": "IdentifierLiteral",
|
||||||
"value": "add"
|
"value": "a"
|
||||||
},
|
},
|
||||||
"arguments": [
|
"right_value": {
|
||||||
{
|
"type": "InfixExpression",
|
||||||
|
"left_node": {
|
||||||
|
"type": "IdentifierLiteral",
|
||||||
|
"value": "a"
|
||||||
|
},
|
||||||
|
"operator": "+",
|
||||||
|
"right_node": {
|
||||||
"type": "IntegerLiteral",
|
"type": "IntegerLiteral",
|
||||||
"value": 1
|
"value": 1
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "IntegerLiteral",
|
|
||||||
"value": 2
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -91,8 +87,8 @@
|
|||||||
{
|
{
|
||||||
"type": "ReturnStatement",
|
"type": "ReturnStatement",
|
||||||
"return_value": {
|
"return_value": {
|
||||||
"type": "IntegerLiteral",
|
"type": "IdentifierLiteral",
|
||||||
"value": 0
|
"value": "a"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
42
debug/ir.ll
42
debug/ir.ll
@@ -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"
|
||||||
@@ -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"]
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user