aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Lexer.zig3
-rw-r--r--src/compile.zig28
-rw-r--r--src/main.zig5
-rw-r--r--src/parse.zig22
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) {