diff options
| author | Baitinq <[email protected]> | 2025-05-12 23:45:57 +0200 |
|---|---|---|
| committer | Baitinq <[email protected]> | 2025-05-12 23:45:57 +0200 |
| commit | a1a1564a44a56fa9308c440e2e72f62af689e2d2 (patch) | |
| tree | a228a968c7fc21a8398e8f7ead0596eb423f999d | |
| parent | boostrap: tokenizer: clean (diff) | |
| download | pry-lang-a1a1564a44a56fa9308c440e2e72f62af689e2d2.tar.gz pry-lang-a1a1564a44a56fa9308c440e2e72f62af689e2d2.tar.bz2 pry-lang-a1a1564a44a56fa9308c440e2e72f62af689e2d2.zip | |
Feature: Add support for break statement
| -rw-r--r-- | grammar.ebnf | 2 | ||||
| -rw-r--r-- | src/codegen.zig | 16 | ||||
| -rw-r--r-- | src/parser.zig | 16 | ||||
| -rw-r--r-- | src/tokenizer.zig | 2 |
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 }); |