diff --git a/compiler/Compiler/Generator.cs b/compiler/Compiler/Generator.cs index e0a7d29..effdd99 100644 --- a/compiler/Compiler/Generator.cs +++ b/compiler/Compiler/Generator.cs @@ -71,6 +71,9 @@ public sealed class Generator(List nodes) case NodeStatementAssignment statement: EmitStatementAssignment(statement); break; + case NodeStatementIf statement: + EmitStatementIf(statement); + break; default: throw new ArgumentOutOfRangeException(nameof(node), node, null); } @@ -114,6 +117,36 @@ public sealed class Generator(List nodes) writer.WriteLine($"{target} = {value};"); } + private void EmitStatementIf(NodeStatementIf statement) + { + var condition = EmitExpression(statement.Condition); + writer.WriteLine($"if ({condition})"); + writer.WriteLine("{"); + using (writer.Indent()) + { + EmitStatement(statement.ThenBlock); + } + + writer.WriteLine("}"); + + if (statement.ElseBlock != null) + { + writer.Write("else"); + if (statement.ElseBlock is NodeStatementIf) + writer.Write(" "); + else + writer.WriteLine(); + + writer.WriteLine("{"); + using (writer.Indent()) + { + EmitStatement(statement.ElseBlock); + } + + writer.WriteLine("}"); + } + } + private string EmitExpression(NodeExpression node) { return node switch diff --git a/compiler/Compiler/Parser.cs b/compiler/Compiler/Parser.cs index 3228ef3..7163ce3 100644 --- a/compiler/Compiler/Parser.cs +++ b/compiler/Compiler/Parser.cs @@ -80,6 +80,18 @@ public sealed class Parser(List tokens) return new NodeStatementVariableDeclaration(TokensFrom(startIndex), name, type, value); } + if (TryExpectKeyword(Keyword.If)) + { + var condition = ParseExpression(); + var thenBlock = ParseStatement(); + NodeStatement? elseBlock = null; + + if (TryExpectKeyword(Keyword.Else)) + elseBlock = ParseStatement(); + + return new NodeStatementIf(TokensFrom(startIndex), condition, thenBlock, elseBlock); + } + var target = ParseExpression(); if (TryExpectSymbol(Symbol.OpenParen)) @@ -308,7 +320,7 @@ public sealed class Parser(List tokens) public abstract class Node(List tokens) { - public List Tokens = tokens; + public readonly List Tokens = tokens; } public abstract class NodeDefinition(List tokens) : Node(tokens); @@ -358,6 +370,13 @@ internal class NodeStatementAssignment(List tokens, NodeExpression target public readonly NodeExpression Value = value; } +internal class NodeStatementIf(List tokens, NodeExpression condition, NodeStatement thenBlock, NodeStatement? elseBlock) : NodeStatement(tokens) +{ + public readonly NodeExpression Condition = condition; + public readonly NodeStatement ThenBlock = thenBlock; + public readonly NodeStatement? ElseBlock = elseBlock; +} + public abstract class NodeExpression(List tokens) : Node(tokens); public sealed class NodeExpressionIntLiteral(List tokens, TokenIntLiteral value) : NodeExpression(tokens) diff --git a/compiler/Compiler/Program.cs b/compiler/Compiler/Program.cs index 6a6d439..a8c32c4 100644 --- a/compiler/Compiler/Program.cs +++ b/compiler/Compiler/Program.cs @@ -4,6 +4,14 @@ const string contents = """ func main(): i32 { let x: i32 = 23 x = 24 + + if true { + x = 49 + } + else { + x = 3 + } + do_something("test") return x } diff --git a/compiler/Compiler/Tokenizer.cs b/compiler/Compiler/Tokenizer.cs index 629cfeb..4b4789b 100644 --- a/compiler/Compiler/Tokenizer.cs +++ b/compiler/Compiler/Tokenizer.cs @@ -279,6 +279,7 @@ public sealed class Tokenizer(string contents) "func" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Func), "let" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Let), "if" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.If), + "else" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Else), "return" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Return), "true" => new TokenBoolLiteral(line, startColumn, column - startColumn, true), "false" => new TokenBoolLiteral(line, startColumn, column - startColumn, false), @@ -398,6 +399,7 @@ public enum Keyword Func, Let, If, + Else, Return, }