chunk: split writing side-effects into own function
split writeConstant() into that and writeConstantRaw() for the places where we don't want OP_CONSTANT written as well. this caused a bug where doing `"some const string" + x` would cause an unecessary OP_CONSTANT to be added for the x variable and would cause the wrong result to be given. - main: reset stack on repl tick (?)
This commit is contained in:
parent
922f3c530c
commit
8bc220d2f8
4 changed files with 42 additions and 9 deletions
|
@ -134,7 +134,7 @@ pub const Chunk = struct {
|
||||||
return self.constants.count - 1;
|
return self.constants.count - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeConstant(
|
pub fn writeConstantRaw(
|
||||||
self: *Chunk,
|
self: *Chunk,
|
||||||
val: value.Value,
|
val: value.Value,
|
||||||
line: usize,
|
line: usize,
|
||||||
|
@ -143,10 +143,7 @@ pub const Chunk = struct {
|
||||||
var constant_idx = self.constants.count - 1;
|
var constant_idx = self.constants.count - 1;
|
||||||
|
|
||||||
if (constant_idx < 256) {
|
if (constant_idx < 256) {
|
||||||
try self.write(OpCode.Constant, line);
|
|
||||||
|
|
||||||
var idx_small = @intCast(u8, constant_idx);
|
var idx_small = @intCast(u8, constant_idx);
|
||||||
try self.write(idx_small, line);
|
|
||||||
return ConstantIndex{ .Small = idx_small };
|
return ConstantIndex{ .Small = idx_small };
|
||||||
} else {
|
} else {
|
||||||
var idx_u24: u24 = @intCast(u24, constant_idx);
|
var idx_u24: u24 = @intCast(u24, constant_idx);
|
||||||
|
@ -157,14 +154,35 @@ pub const Chunk = struct {
|
||||||
const v2: u8 = @intCast(u8, (idx_u24 >> 8) & mask);
|
const v2: u8 = @intCast(u8, (idx_u24 >> 8) & mask);
|
||||||
const v3: u8 = @intCast(u8, (idx_u24 >> 16) & mask);
|
const v3: u8 = @intCast(u8, (idx_u24 >> 16) & mask);
|
||||||
|
|
||||||
try self.write(OpCode.ConstantLong, line);
|
|
||||||
try self.write(v3, line);
|
|
||||||
try self.write(v2, line);
|
|
||||||
try self.write(v1, line);
|
|
||||||
return ConstantIndex{ .Long = []u8{ v3, v2, v1 } };
|
return ConstantIndex{ .Long = []u8{ v3, v2, v1 } };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn writeConstant(
|
||||||
|
self: *Chunk,
|
||||||
|
val: value.Value,
|
||||||
|
line: usize,
|
||||||
|
) !ConstantIndex {
|
||||||
|
var idx = try self.writeConstantRaw(val, line);
|
||||||
|
|
||||||
|
switch (idx) {
|
||||||
|
.Small => |idx_small| blk: {
|
||||||
|
try self.write(OpCode.Constant, line);
|
||||||
|
try self.write(idx_small, line);
|
||||||
|
break :blk;
|
||||||
|
},
|
||||||
|
.Long => |long_u8| blk: {
|
||||||
|
try self.write(OpCode.ConstantLong, line);
|
||||||
|
try self.write(long_u8[0], line);
|
||||||
|
try self.write(long_u8[1], line);
|
||||||
|
try self.write(long_u8[2], line);
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn disassembleInstruction(
|
pub fn disassembleInstruction(
|
||||||
self: *Chunk,
|
self: *Chunk,
|
||||||
stdout: var,
|
stdout: var,
|
||||||
|
|
|
@ -253,7 +253,13 @@ pub const Compiler = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn namedVariable(self: *Compiler, tok: *Token) !void {
|
fn namedVariable(self: *Compiler, tok: *Token) !void {
|
||||||
var idx = try self.identifierConstant(tok);
|
// writeConstant always writes OP_CODE which may be not
|
||||||
|
// what we want, so.
|
||||||
|
var idx = try self.currentChunk().writeConstantRaw(values.ObjVal(try objects.copyString(
|
||||||
|
self.vmach,
|
||||||
|
tok.lexeme,
|
||||||
|
)), tok.line);
|
||||||
|
|
||||||
try self.emitConstWithIndex(
|
try self.emitConstWithIndex(
|
||||||
chunks.OpCode.GetGlobal,
|
chunks.OpCode.GetGlobal,
|
||||||
chunks.OpCode.GetGlobalLong,
|
chunks.OpCode.GetGlobalLong,
|
||||||
|
|
|
@ -85,6 +85,8 @@ fn runPrompt(allocator: *Allocator) !void {
|
||||||
else => return err,
|
else => return err,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
vmach.resetStack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -237,6 +237,13 @@ pub const VM = struct {
|
||||||
fn doGetGlobal(self: *VM, name: []u8) !void {
|
fn doGetGlobal(self: *VM, name: []u8) !void {
|
||||||
var kv_opt = self.globals.get(name);
|
var kv_opt = self.globals.get(name);
|
||||||
|
|
||||||
|
// take out the OP_CONST loaded before, if any
|
||||||
|
// note this is a complete hack.
|
||||||
|
//var val = self.peek(0);
|
||||||
|
//if (val.vtype == .Object and val.as.Object.otype == .String and std.mem.compare(u8, val.as.Object.value.String, name) == .Equal) {
|
||||||
|
// _ = self.pop();
|
||||||
|
//}
|
||||||
|
|
||||||
if (kv_opt) |kv| {
|
if (kv_opt) |kv| {
|
||||||
try self.push(kv.value);
|
try self.push(kv.value);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue