diff --git a/Nub.Lang/Nub.Lang/Backend/Custom/Generator.cs b/Nub.Lang/Nub.Lang/Backend/Custom/Generator.cs index 1b9e4c9..852191b 100644 --- a/Nub.Lang/Nub.Lang/Backend/Custom/Generator.cs +++ b/Nub.Lang/Nub.Lang/Backend/Custom/Generator.cs @@ -12,6 +12,7 @@ public class Generator private readonly SymbolTable _symbolTable; private readonly StringBuilder _builder; private readonly LabelFactory _labelFactory; + private readonly Stack<(string StartLabel, string EndLabel)> _loops; public Generator(List definitions) { @@ -19,6 +20,7 @@ public class Generator _builder = new StringBuilder(); _labelFactory = new LabelFactory(); _symbolTable = new SymbolTable(_labelFactory); + _loops = []; foreach (var globalVariableDefinition in definitions.OfType()) { @@ -213,6 +215,12 @@ public class Generator case ArrayIndexAssignmentNode arrayIndexAssignment: GenerateArrayIndexAssignment(arrayIndexAssignment, func); break; + case BreakNode: + GenerateBreak(); + break; + case ContinueNode: + GenerateContinue(); + break; case FuncCallStatementNode funcCallStatement: GenerateFuncCall(funcCallStatement.FuncCall, func); break; @@ -239,6 +247,16 @@ public class Generator } } + private void GenerateBreak() + { + _builder.AppendLine($" jmp {_loops.Peek().EndLabel}"); + } + + private void GenerateContinue() + { + _builder.AppendLine($" jmp {_loops.Peek().StartLabel}"); + } + private void GenerateArrayIndexAssignment(ArrayIndexAssignmentNode arrayIndexAssignment, LocalFunc func) { GenerateExpression(arrayIndexAssignment.Value, func); @@ -303,11 +321,14 @@ public class Generator { var startLabel = _labelFactory.Create(); var endLabel = _labelFactory.Create(); + _builder.AppendLine($"{startLabel}:"); GenerateExpression(whileStatement.Condition, func); _builder.AppendLine(" cmp rax, 0"); _builder.AppendLine($" je {endLabel}"); + _loops.Push((startLabel, endLabel)); GenerateBlock(whileStatement.Body, func); + _loops.Pop(); _builder.AppendLine($" jmp {startLabel}"); _builder.AppendLine($"{endLabel}:"); } @@ -627,25 +648,25 @@ public class Generator GenerateExpression(index, func); _builder.AppendLine(" push rax"); GenerateIdentifier(identifier, func); - _builder.AppendLine(" pop rcx"); + _builder.AppendLine(" pop rdx"); // rcx now holds the length of the array which we can use to check bounds _builder.AppendLine(" mov rcx, [rax]"); - _builder.AppendLine(" cmp rcx, rcx"); + _builder.AppendLine(" cmp rdx, rcx"); if (ZeroBasedIndexing) { _builder.AppendLine(" jge array_out_of_bounds"); - _builder.AppendLine(" cmp rcx, 0"); + _builder.AppendLine(" cmp rdx, 0"); } else { _builder.AppendLine(" jg array_out_of_bounds"); - _builder.AppendLine(" cmp rcx, 1"); + _builder.AppendLine(" cmp rdx, 1"); } _builder.AppendLine(" jl array_out_of_bounds"); - _builder.AppendLine(" inc rcx"); - _builder.AppendLine(" shl rcx, 3"); - _builder.AppendLine(" add rax, rcx"); + _builder.AppendLine(" inc rdx"); + _builder.AppendLine(" shl rdx, 3"); + _builder.AppendLine(" add rax, rdx"); } } \ No newline at end of file diff --git a/Nub.Lang/Nub.Lang/Frontend/Lexing/Lexer.cs b/Nub.Lang/Nub.Lang/Frontend/Lexing/Lexer.cs index 8561c20..7a60d85 100644 --- a/Nub.Lang/Nub.Lang/Frontend/Lexing/Lexer.cs +++ b/Nub.Lang/Nub.Lang/Frontend/Lexing/Lexer.cs @@ -13,6 +13,8 @@ public class Lexer ["if"] = Symbol.If, ["else"] = Symbol.Else, ["while"] = Symbol.While, + ["break"] = Symbol.Break, + ["continue"] = Symbol.Continue, ["return"] = Symbol.Return, ["new"] = Symbol.New, }; diff --git a/Nub.Lang/Nub.Lang/Frontend/Lexing/SymbolToken.cs b/Nub.Lang/Nub.Lang/Frontend/Lexing/SymbolToken.cs index 8b58839..a86357a 100644 --- a/Nub.Lang/Nub.Lang/Frontend/Lexing/SymbolToken.cs +++ b/Nub.Lang/Nub.Lang/Frontend/Lexing/SymbolToken.cs @@ -16,6 +16,8 @@ public enum Symbol If, Else, While, + Break, + Continue, Semicolon, Colon, OpenParen, diff --git a/Nub.Lang/Nub.Lang/Frontend/Parsing/BreakNode.cs b/Nub.Lang/Nub.Lang/Frontend/Parsing/BreakNode.cs new file mode 100644 index 0000000..bc5277d --- /dev/null +++ b/Nub.Lang/Nub.Lang/Frontend/Parsing/BreakNode.cs @@ -0,0 +1,3 @@ +namespace Nub.Lang.Frontend.Parsing; + +public class BreakNode : StatementNode; \ No newline at end of file diff --git a/Nub.Lang/Nub.Lang/Frontend/Parsing/ContinueNode.cs b/Nub.Lang/Nub.Lang/Frontend/Parsing/ContinueNode.cs new file mode 100644 index 0000000..484f7d3 --- /dev/null +++ b/Nub.Lang/Nub.Lang/Frontend/Parsing/ContinueNode.cs @@ -0,0 +1,3 @@ +namespace Nub.Lang.Frontend.Parsing; + +public class ContinueNode : StatementNode; \ No newline at end of file diff --git a/Nub.Lang/Nub.Lang/Frontend/Parsing/Parser.cs b/Nub.Lang/Nub.Lang/Frontend/Parsing/Parser.cs index f5aa0c6..d2f0904 100644 --- a/Nub.Lang/Nub.Lang/Frontend/Parsing/Parser.cs +++ b/Nub.Lang/Nub.Lang/Frontend/Parsing/Parser.cs @@ -178,6 +178,8 @@ public class Parser Symbol.Let => ParseVariableAssignment(), Symbol.If => ParseIf(), Symbol.While => ParseWhile(), + Symbol.Break => ParseBreak(), + Symbol.Continue => ParseContinue(), _ => throw new Exception($"Unexpected symbol {symbol.Symbol}") }; } @@ -233,6 +235,18 @@ public class Parser return new WhileNode(condition, body); } + private BreakNode ParseBreak() + { + ExpectSymbol(Symbol.Semicolon); + return new BreakNode(); + } + + private ContinueNode ParseContinue() + { + ExpectSymbol(Symbol.Semicolon); + return new ContinueNode(); + } + private ExpressionNode ParseExpression(int precedence = 0) { var left = ParsePrimaryExpression(); diff --git a/Nub.Lang/Nub.Lang/Frontend/Typing/ExpressionTyper.cs b/Nub.Lang/Nub.Lang/Frontend/Typing/ExpressionTyper.cs index 905a7df..bad0be9 100644 --- a/Nub.Lang/Nub.Lang/Frontend/Typing/ExpressionTyper.cs +++ b/Nub.Lang/Nub.Lang/Frontend/Typing/ExpressionTyper.cs @@ -86,6 +86,9 @@ public class ExpressionTyper case ArrayIndexAssignmentNode arrayIndexAssignment: PopulateArrayIndexAssignment(arrayIndexAssignment); break; + case BreakNode: + case ContinueNode: + break; case FuncCallStatementNode funcCall: PopulateFuncCallStatement(funcCall); break; diff --git a/input/program.nub b/input/program.nub index 93c20fb..4441101 100644 --- a/input/program.nub +++ b/input/program.nub @@ -1,5 +1,20 @@ import "core"; func main() { - println(69); + let some_string = "test"; + println(some_string); + + let some_array = new Array(2); + some_array[1] = 1; + some_array[2] = 2; + + let i = 1; + + println(some_array[1]); + println(some_array[2]); + + while i <= arr_size(some_array) { + println(some_array[i]); + i = i + 1; + } }