while statements (ch23)
This commit is contained in:
parent
9de028d09c
commit
d67c99ffe5
6
samples/ch23_while.lox
Normal file
6
samples/ch23_while.lox
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
var i = 0;
|
||||||
|
|
||||||
|
while(i < 10) {
|
||||||
|
print i;
|
||||||
|
i = i + 1;
|
||||||
|
}
|
@ -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;
|
||||||
|
@ -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 {
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user