while statements (ch23)

This commit is contained in:
Patrick MARIE 2024-08-27 14:15:29 +02:00
parent 9de028d09c
commit d67c99ffe5
5 changed files with 40 additions and 0 deletions

6
samples/ch23_while.lox Normal file
View File

@ -0,0 +1,6 @@
var i = 0;
while(i < 10) {
print i;
i = i + 1;
}

View File

@ -101,6 +101,7 @@ pub const Chunk = struct {
@intFromEnum(OpCode.OP_SET_LOCAL) => return utils.byte_instruction("OP_SET_LOCAL", self, offset), @intFromEnum(OpCode.OP_SET_LOCAL) => return utils.byte_instruction("OP_SET_LOCAL", self, offset),
@intFromEnum(OpCode.OP_JUMP) => return utils.jump_instruction("OP_JUMP", 1, self, offset), @intFromEnum(OpCode.OP_JUMP) => return utils.jump_instruction("OP_JUMP", 1, self, offset),
@intFromEnum(OpCode.OP_JUMP_IF_FALSE) => return utils.jump_instruction("OP_JUMP_IF_FALSE", 1, self, offset), @intFromEnum(OpCode.OP_JUMP_IF_FALSE) => return utils.jump_instruction("OP_JUMP_IF_FALSE", 1, self, offset),
@intFromEnum(OpCode.OP_LOOP) => return utils.jump_instruction("OP_LOOP", -1, self, offset),
else => { else => {
debug.print("unknown opcode {d}\n", .{instruction}); debug.print("unknown opcode {d}\n", .{instruction});
return offset + 1; return offset + 1;

View File

@ -362,6 +362,8 @@ const Parser = struct {
try self.print_statement(); try self.print_statement();
} else if (self.match(TokenType.IF)) { } else if (self.match(TokenType.IF)) {
try self.if_statement(); try self.if_statement();
} else if (self.match(TokenType.WHILE)) {
try self.while_statement();
} else if (self.match(TokenType.LEFT_BRACE)) { } else if (self.match(TokenType.LEFT_BRACE)) {
self.begin_scope(); self.begin_scope();
try self.block(); try self.block();
@ -616,6 +618,32 @@ const Parser = struct {
try self.parse_precedence(Precedence.Or); try self.parse_precedence(Precedence.Or);
self.patch_jump(end_jump); self.patch_jump(end_jump);
} }
fn while_statement(self: *Parser) ParsingError!void {
const loop_start = self.chunk.count;
self.consume(TokenType.LEFT_PAREN, "Expect '(' after 'while'.");
try self.expression();
self.consume(TokenType.RIGHT_PAREN, "Expect ')' after condition.");
const exit_jump = try self.emit_jump(@intFromEnum(OpCode.OP_JUMP_IF_FALSE));
try self.emit_byte(@intFromEnum(OpCode.OP_POP));
try self.statement();
try self.emit_loop(loop_start);
self.patch_jump(exit_jump);
try self.emit_byte(@intFromEnum(OpCode.OP_POP));
}
fn emit_loop(self: *Parser, loop_start: usize) ParsingError!void {
try self.emit_byte(@intFromEnum(OpCode.OP_LOOP));
const offset = self.chunk.count - loop_start + 2;
if (offset > 65536) {
self.error_msg("Loop body too large.");
}
try self.emit_byte(@intCast((offset >> 8) & 0xff));
try self.emit_byte(@intCast(offset & 0xff));
}
}; };
const Compiler = struct { const Compiler = struct {

View File

@ -21,5 +21,6 @@ pub const OpCode = enum(u8) {
OP_PRINT, OP_PRINT,
OP_JUMP, OP_JUMP,
OP_JUMP_IF_FALSE, OP_JUMP_IF_FALSE,
OP_LOOP,
OP_RETURN, OP_RETURN,
}; };

View File

@ -192,6 +192,10 @@ pub const VM = struct {
self.ip.? += offset; self.ip.? += offset;
} }
}, },
@intFromEnum(OpCode.OP_LOOP) => {
const offset = self.read_short();
self.ip.? -= offset;
},
else => { else => {
debug.print("Invalid instruction: {d}\n", .{instruction}); debug.print("Invalid instruction: {d}\n", .{instruction});
return InterpretResult.RUNTIME_ERROR; return InterpretResult.RUNTIME_ERROR;