about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBaitinq <[email protected]>2025-05-12 23:45:57 +0200
committerBaitinq <[email protected]>2025-05-12 23:45:57 +0200
commita1a1564a44a56fa9308c440e2e72f62af689e2d2 (patch)
treea228a968c7fc21a8398e8f7ead0596eb423f999d
parentboostrap: tokenizer: clean (diff)
downloadpry-lang-a1a1564a44a56fa9308c440e2e72f62af689e2d2.tar.gz
pry-lang-a1a1564a44a56fa9308c440e2e72f62af689e2d2.tar.bz2
pry-lang-a1a1564a44a56fa9308c440e2e72f62af689e2d2.zip
Feature: Add support for break statement
-rw-r--r--grammar.ebnf2
-rw-r--r--src/codegen.zig16
-rw-r--r--src/parser.zig16
-rw-r--r--src/tokenizer.zig2
4 files changed, 31 insertions, 5 deletions
diff --git a/grammar.ebnf b/grammar.ebnf
index a855e57..ec61e90 100644
--- a/grammar.ebnf
+++ b/grammar.ebnf
@@ -1,6 +1,6 @@
 Program      ::= Statement+
 
-Statement    ::= (AssignmentStatement | ImportDeclaration | ExternDeclaration | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement) SEMICOLON
+Statement    ::= (AssignmentStatement | ImportDeclaration | ExternDeclaration | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement | "break") SEMICOLON
 
 AssignmentStatement ::= ("let")? ("*")? Expression EQUALS Expression
 
diff --git a/src/codegen.zig b/src/codegen.zig
index ab34ea8..6b8e310 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -22,6 +22,8 @@ pub const CodeGen = struct {
 
     arena: std.mem.Allocator,
 
+    while_loop_exit: ?llvm.LLVMBasicBlockRef,
+
     pub fn init(arena: std.mem.Allocator) !*CodeGen {
         // Initialize LLVM
         llvm.LLVMInitializeAllTargetInfos();
@@ -40,6 +42,8 @@ pub const CodeGen = struct {
             .environment = try Environment.init(arena),
 
             .arena = arena,
+
+            .while_loop_exit = null,
         };
 
         return self;
@@ -114,6 +118,7 @@ pub const CodeGen = struct {
                 _ = try self.generate_function_call_statement(@ptrCast(function_call_statement));
             },
             .RETURN_STATEMENT => |*return_statement| return try self.generate_return_statement(@ptrCast(return_statement)),
+            .BREAK_STATEMENT => |*break_statement| return try self.generate_break_statement(@ptrCast(@alignCast(break_statement))),
             .IF_STATEMENT => |*if_statement| return try self.generate_if_statement(@ptrCast(if_statement)),
             .WHILE_STATEMENT => |*while_statement| return try self.generate_while_statement(@ptrCast(while_statement)),
             .IMPORT_DECLARATION => |*import_declaration| return try self.generate_import_declaration(@ptrCast(import_declaration)),
@@ -246,6 +251,14 @@ pub const CodeGen = struct {
         _ = llvm.LLVMBuildRet(self.builder, val.value);
     }
 
+    fn generate_break_statement(self: *CodeGen, statement: *parser.Node) !void {
+        errdefer std.debug.print("Error generating break statement\n", .{});
+        std.debug.assert(statement.* == parser.Node.BREAK_STATEMENT);
+        std.debug.assert(self.while_loop_exit != null);
+
+        _ = llvm.LLVMBuildBr(self.builder, self.while_loop_exit.?);
+    }
+
     fn generate_if_statement(self: *CodeGen, statement: *parser.Node) !void {
         errdefer std.debug.print("Error generating if statement\n", .{});
         std.debug.assert(statement.* == parser.Node.IF_STATEMENT);
@@ -287,6 +300,9 @@ pub const CodeGen = struct {
         const outer_block = llvm.LLVMAppendBasicBlock(llvm.LLVMGetLastFunction(self.llvm_module), "outer_block");
         _ = llvm.LLVMBuildCondBr(self.builder, condition_value.value, inner_block, outer_block);
 
+        self.while_loop_exit = outer_block;
+        defer self.while_loop_exit = null;
+
         _ = llvm.LLVMPositionBuilderAtEnd(self.builder, inner_block);
         for (while_statement.statements) |stmt| {
             try self.generate_statement(stmt);
diff --git a/src/parser.zig b/src/parser.zig
index 0318f26..7e1b695 100644
--- a/src/parser.zig
+++ b/src/parser.zig
@@ -92,6 +92,7 @@ pub const Node = union(enum) {
     RETURN_STATEMENT: struct {
         expression: ?*Node,
     },
+    BREAK_STATEMENT: void,
 };
 
 pub const EqualityExpressionType = enum {
@@ -146,23 +147,30 @@ pub const Parser = struct {
         } });
     }
 
-    // Statement    ::= (AssignmentStatement | ExternDeclaration | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement) SEMICOLON
+    // Statement    ::= (AssignmentStatement | ImportDeclaration | ExternDeclaration | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement | "break") SEMICOLON
     fn parse_statement(self: *Parser) ParserError!*Node {
         errdefer if (!self.try_context) std.debug.print("Error parsing statement {any}\n", .{self.peek_token()});
 
-        const statement = self.accept_parse(parse_function_call_statement) orelse
+        var statement = self.accept_parse(parse_function_call_statement) orelse
             self.accept_parse(parse_if_statement) orelse
             self.accept_parse(parse_while_statement) orelse
             self.accept_parse(parse_return_statement) orelse
             self.accept_parse(parse_assignment_statement) orelse
             self.accept_parse(parse_import_declaration) orelse
-            try self.parse_extern_declaration();
+            self.accept_parse(parse_extern_declaration);
+
+        if (statement == null) {
+            _ = try self.parse_token(tokenizer.TokenType.BREAK);
+            statement = try self.create_node(.{
+                .BREAK_STATEMENT = void{},
+            });
+        }
 
         _ = try self.parse_token(tokenizer.TokenType.SEMICOLON);
 
         return self.create_node(.{
             .STATEMENT = .{
-                .statement = statement,
+                .statement = statement.?,
             },
         });
     }
diff --git a/src/tokenizer.zig b/src/tokenizer.zig
index 53e5c63..ac7fc9f 100644
--- a/src/tokenizer.zig
+++ b/src/tokenizer.zig
@@ -12,6 +12,7 @@ pub const TokenType = union(enum) {
     IF: void,
     WHILE: void,
     RETURN: void,
+    BREAK: void,
     ARROW: void,
 
     // Identifiers
@@ -90,6 +91,7 @@ pub const Tokenizer = struct {
         if (self.accept_string("if")) return self.create_token(.{ .IF = void{} });
         if (self.accept_string("while")) return self.create_token(.{ .WHILE = void{} });
         if (self.accept_string("return")) return self.create_token(.{ .RETURN = void{} });
+        if (self.accept_string("break")) return self.create_token(.{ .BREAK = void{} });
         if (self.accept_string("true")) return self.create_token(.{ .BOOLEAN = true });
         if (self.accept_string("false")) return self.create_token(.{ .BOOLEAN = false });