diff options
author | Mathias Magnusson <mathias@magnusson.space> | 2025-06-07 00:57:47 +0200 |
---|---|---|
committer | Mathias Magnusson <mathias@magnusson.space> | 2025-06-07 00:57:47 +0200 |
commit | 47a9c0403576064ece3eb1b1b633b5e3a94cabc4 (patch) | |
tree | a4073ae33c109f7f03fe6135e6b18c3f1c2f9e0d | |
parent | 1ed87d6c58cab383f18590093f651ef35c4fa671 (diff) | |
download | huginn-47a9c0403576064ece3eb1b1b633b5e3a94cabc4.tar.gz |
add while loops
-rw-r--r-- | src/Lexer.zig | 3 | ||||
-rw-r--r-- | src/compile.zig | 28 | ||||
-rw-r--r-- | src/main.zig | 5 | ||||
-rw-r--r-- | src/parse.zig | 22 |
4 files changed, 57 insertions, 1 deletions
diff --git a/src/Lexer.zig b/src/Lexer.zig index f59737e..c938116 100644 --- a/src/Lexer.zig +++ b/src/Lexer.zig @@ -21,6 +21,7 @@ pub const Token = struct { let, @"if", @"else", + @"while", }; }; @@ -122,7 +123,7 @@ fn identifierOrKeyword(self: *Self) Token { } const value = self.source[self.start..self.pos]; return self.create(switch (std.meta.stringToEnum(Token.Type, value) orelse .invalid) { - .let, .@"if", .@"else" => |t| t, + .let, .@"if", .@"else", .@"while" => |t| t, else => .identifier, }); } diff --git a/src/compile.zig b/src/compile.zig index c0ba77d..4d39293 100644 --- a/src/compile.zig +++ b/src/compile.zig @@ -336,6 +336,34 @@ const CompileContext = struct { const val = try self.compileExpr(assign_var.value); try self.assignLocalVar(local, val); }, + .@"while" => |@"while"| { + const curr = self.current_block; + const cond_block = try self.switchToNewBlock(); + self.current_block = curr; + try self.addInstr(.{ + .loc = stmt.loc, + .type = .{ .jump = .{ .to = cond_block } }, + }); + const do = try self.switchToNewBlock(); + const after = try self.switchToNewBlock(); + self.current_block = cond_block; + const cond = try self.compileExpr(@"while".cond); + try self.addInstr(.{ + .loc = stmt.loc, + .type = .{ .branch = .{ + .cond = cond, + .true = .{ .to = do }, + .false = .{ .to = after }, + } }, + }); + self.current_block = do; + try self.compileBlock(@"while".do); + try self.addInstr(.{ + .loc = stmt.loc, + .type = .{ .jump = .{ .to = cond_block } }, + }); + self.current_block = after; + }, } } diff --git a/src/main.zig b/src/main.zig index 314459b..becbf97 100644 --- a/src/main.zig +++ b/src/main.zig @@ -37,6 +37,11 @@ pub fn main() !void { const source = \\{ \\ let x = 10 + \\ let y = 5 + \\ while y { + \\ x = x + x + \\ y = y - 1 + \\ } \\ if x { \\ # let x = read_int(0) \\ # print(18446744073709551615) diff --git a/src/parse.zig b/src/parse.zig index 8347687..e675fbe 100644 --- a/src/parse.zig +++ b/src/parse.zig @@ -45,12 +45,18 @@ pub const Stmt = struct { expr: *const Expr, assign_var: AssignVar, block: Block, + @"while": While, pub const AssignVar = struct { ident: Lexer.Location, is_decl: bool, value: *const Expr, }; + + pub const While = struct { + cond: *const Expr, + do: Block, + }; }; fn format(self: Stmt, writer: anytype, source: []const u8, indent: usize) !void { @@ -63,6 +69,10 @@ pub const Stmt = struct { assign_var.ident.getIdent(source), fmt(assign_var.value, source, indent), }), + .@"while" => |@"while"| try writer.print("while {} {}", .{ + fmt(@"while".cond, source, indent), + fmt(@"while".do, source, indent), + }), }; } }; @@ -165,6 +175,18 @@ pub fn statement(allocator: Allocator, lexer: *Lexer) ParseError!Stmt { .type = .{ .block = b }, }; }, + .@"while" => { + const @"while" = lexer.next(); + const cond = try expression(allocator, lexer); + const do = try block(allocator, lexer); + return .{ + .loc = @"while".loc.combine(do.loc), + .type = .{ .@"while" = .{ + .cond = cond, + .do = do, + } }, + }; + }, else => { const lhs = try expression(allocator, lexer); if (lexer.peek().type == .equal) { |