refactor: using current_chunk()

This commit is contained in:
Patrick MARIE 2024-08-28 09:23:33 +02:00
parent f7c10c13bb
commit 0850198784
3 changed files with 73 additions and 18 deletions

View File

@ -62,6 +62,10 @@ const Parser = struct {
}; };
} }
inline fn current_chunk(self: *Parser) *Chunk {
return self.chunk;
}
fn advance(self: *Parser) void { fn advance(self: *Parser) void {
self.previous = self.current; self.previous = self.current;
@ -117,7 +121,7 @@ const Parser = struct {
} }
fn emit_byte(self: *Parser, byte: u8) ParsingError!void { fn emit_byte(self: *Parser, byte: u8) ParsingError!void {
self.chunk.write(byte, self.previous.?.line) catch |err| { self.current_chunk().write(byte, self.previous.?.line) catch |err| {
switch (err) { switch (err) {
error.OutOfMemory => return ParsingError.OutOfMemory, error.OutOfMemory => return ParsingError.OutOfMemory,
} }
@ -135,7 +139,7 @@ const Parser = struct {
fn end_parser(self: *Parser) !void { fn end_parser(self: *Parser) !void {
if (!self.had_error and self.vm.has_tracing()) { if (!self.had_error and self.vm.has_tracing()) {
self.chunk.dissassemble("code"); self.current_chunk().dissassemble("code");
} }
try self.emit_return(); try self.emit_return();
} }
@ -162,7 +166,7 @@ const Parser = struct {
} }
fn make_constant(self: *Parser, value: Value) !u8 { fn make_constant(self: *Parser, value: Value) !u8 {
const constant = try self.chunk.add_constant(value); const constant = try self.current_chunk().add_constant(value);
if (constant > constants.UINT8_MAX) { if (constant > constants.UINT8_MAX) {
self.error_msg("Too many constants in one chunk."); self.error_msg("Too many constants in one chunk.");
return 0; return 0;
@ -585,11 +589,11 @@ const Parser = struct {
try self.emit_byte(0xff); try self.emit_byte(0xff);
try self.emit_byte(0xff); try self.emit_byte(0xff);
return self.chunk.count - 2; return self.current_chunk().count - 2;
} }
fn patch_jump(self: *Parser, offset: usize) void { fn patch_jump(self: *Parser, offset: usize) void {
const jump = self.chunk.count - offset - 2; const jump = self.current_chunk().count - offset - 2;
if (jump > constants.UINT16_MAX) { if (jump > constants.UINT16_MAX) {
self.error_msg("Too much code to jump over."); self.error_msg("Too much code to jump over.");
@ -598,8 +602,8 @@ const Parser = struct {
const b1 = (jump >> 8) & 0xff; const b1 = (jump >> 8) & 0xff;
const b0 = jump & 0xff; const b0 = jump & 0xff;
self.chunk.code[offset] = @intCast(b1); self.current_chunk().code[offset] = @intCast(b1);
self.chunk.code[offset + 1] = @intCast(b0); self.current_chunk().code[offset + 1] = @intCast(b0);
} }
fn and_(self: *Parser, can_assign: bool) ParsingError!void { fn and_(self: *Parser, can_assign: bool) ParsingError!void {
@ -624,7 +628,7 @@ const Parser = struct {
} }
fn while_statement(self: *Parser) ParsingError!void { fn while_statement(self: *Parser) ParsingError!void {
const loop_start = self.chunk.count; const loop_start = self.current_chunk().count;
self.consume(TokenType.LEFT_PAREN, "Expect '(' after 'while'."); self.consume(TokenType.LEFT_PAREN, "Expect '(' after 'while'.");
try self.expression(); try self.expression();
self.consume(TokenType.RIGHT_PAREN, "Expect ')' after condition."); self.consume(TokenType.RIGHT_PAREN, "Expect ')' after condition.");
@ -640,7 +644,7 @@ const Parser = struct {
fn emit_loop(self: *Parser, loop_start: usize) ParsingError!void { fn emit_loop(self: *Parser, loop_start: usize) ParsingError!void {
try self.emit_byte(@intFromEnum(OpCode.OP_LOOP)); try self.emit_byte(@intFromEnum(OpCode.OP_LOOP));
const offset = self.chunk.count - loop_start + 2; const offset = self.current_chunk().count - loop_start + 2;
if (offset > constants.UINT16_MAX) { if (offset > constants.UINT16_MAX) {
self.error_msg("Loop body too large."); self.error_msg("Loop body too large.");
} }
@ -661,7 +665,7 @@ const Parser = struct {
try self.expression_statement(); try self.expression_statement();
} }
var loop_start = self.chunk.count; var loop_start = self.current_chunk().count;
var exit_jump: ?usize = null; var exit_jump: ?usize = null;
@ -676,7 +680,7 @@ const Parser = struct {
if (!self.match(TokenType.RIGHT_PAREN)) { if (!self.match(TokenType.RIGHT_PAREN)) {
const body_jump = try self.emit_jump(@intFromEnum(OpCode.OP_JUMP)); const body_jump = try self.emit_jump(@intFromEnum(OpCode.OP_JUMP));
const increment_start = self.chunk.count; const increment_start = self.current_chunk().count;
try self.expression(); try self.expression();
try self.emit_byte(@intFromEnum(OpCode.OP_POP)); try self.emit_byte(@intFromEnum(OpCode.OP_POP));
self.consume(TokenType.RIGHT_PAREN, "Expect ')' after for clauses."); self.consume(TokenType.RIGHT_PAREN, "Expect ')' after for clauses.");

View File

@ -2,10 +2,13 @@ const std = @import("std");
const debug = std.debug; const debug = std.debug;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const Chunk = @import("./chunk.zig").Chunk;
const compute_hash = @import("./utils.zig").compute_hash; const compute_hash = @import("./utils.zig").compute_hash;
pub const ObjType = enum { pub const ObjType = enum {
String, String,
Function,
}; };
pub const Obj = struct { pub const Obj = struct {
@ -13,8 +16,8 @@ pub const Obj = struct {
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
pub const String = struct { pub const String = struct {
chars: []const u8,
obj: Obj, obj: Obj,
chars: []const u8,
hash: u32, hash: u32,
pub fn new(allocator: std.mem.Allocator, chars: []const u8) *String { pub fn new(allocator: std.mem.Allocator, chars: []const u8) *String {
@ -39,6 +42,33 @@ pub const Obj = struct {
} }
}; };
pub const Function = struct {
obj: Obj,
arity: usize,
chunk: *Chunk,
name: *Obj.String,
pub fn new(allocator: std.mem.Allocator) *Function {
const obj = Obj{
.kind = ObjType.Function,
.allocator = allocator,
};
const function_obj = allocator.create(Function) catch unreachable;
function_obj.obj = obj;
function_obj.arity = 0;
function_obj.chunk = Chunk.new(allocator);
return function_obj;
}
pub fn destroy(self: *Function) void {
const allocator = self.obj.allocator;
self.chunk.deinit();
allocator.destroy(self);
}
};
pub fn is_type(self: *Obj, kind: ObjType) bool { pub fn is_type(self: *Obj, kind: ObjType) bool {
return self.kind == kind; return self.kind == kind;
} }
@ -47,12 +77,20 @@ pub const Obj = struct {
return self.is_type(ObjType.String); return self.is_type(ObjType.String);
} }
pub fn is_function(self: *Obj) bool {
return self.is_function(ObjType.Function);
}
pub fn print(self: *Obj) void { pub fn print(self: *Obj) void {
switch (self.kind) { switch (self.kind) {
ObjType.String => { ObjType.String => {
const obj = self.as_string(); const obj = self.as_string();
debug.print("{s}", .{obj.chars}); debug.print("{s}", .{obj.chars});
}, },
ObjType.Function => {
const obj = self.as_function();
debug.print("<fn {s}>", .{obj.name.chars});
},
} }
} }
@ -62,6 +100,10 @@ pub const Obj = struct {
const obj: *String = @fieldParentPtr("obj", self); const obj: *String = @fieldParentPtr("obj", self);
obj.destroy(); obj.destroy();
}, },
ObjType.Function => {
const obj: *Function = @fieldParentPtr("obj", self);
obj.destroy();
},
} }
} }
@ -69,4 +111,9 @@ pub const Obj = struct {
std.debug.assert(self.kind == ObjType.String); std.debug.assert(self.kind == ObjType.String);
return @fieldParentPtr("obj", self); return @fieldParentPtr("obj", self);
} }
pub fn as_function(self: *Obj) *Function {
std.debug.assert(self.kind == ObjType.Function);
return @fieldParentPtr("obj", self);
}
}; };

View File

@ -61,6 +61,10 @@ pub const VM = struct {
self.references.deinit(); self.references.deinit();
} }
inline fn current_chunk(self: *VM) *Chunk {
return self.chunk.?;
}
pub fn set_trace(self: *VM, tracing: bool) void { pub fn set_trace(self: *VM, tracing: bool) void {
self.tracing = tracing; self.tracing = tracing;
} }
@ -96,7 +100,7 @@ pub const VM = struct {
} }
debug.print("\n", .{}); debug.print("\n", .{});
} }
_ = self.chunk.?.dissassemble_instruction(self.ip.?); _ = self.current_chunk().dissassemble_instruction(self.ip.?);
} }
const instruction = self.read_byte(); const instruction = self.read_byte();
@ -209,7 +213,7 @@ pub const VM = struct {
// XXX In the book, we're using a ptr to data directly, to avoid dereferencing to a given offset // XXX In the book, we're using a ptr to data directly, to avoid dereferencing to a given offset
// How to do that in Zig? // How to do that in Zig?
pub fn read_byte(self: *VM) u8 { pub fn read_byte(self: *VM) u8 {
const ret = self.chunk.?.code[self.ip.?]; const ret = self.current_chunk().code[self.ip.?];
self.ip.? += 1; self.ip.? += 1;
return ret; return ret;
@ -218,11 +222,11 @@ pub const VM = struct {
pub fn read_short(self: *VM) u16 { pub fn read_short(self: *VM) u16 {
self.ip.? += 2; self.ip.? += 2;
return (@as(u16, self.chunk.?.code[self.ip.? - 2]) << 8) | (@as(u16, self.chunk.?.code[self.ip.? - 1])); return (@as(u16, self.current_chunk().code[self.ip.? - 2]) << 8) | (@as(u16, self.current_chunk().code[self.ip.? - 1]));
} }
pub fn read_constant(self: *VM) Value { pub fn read_constant(self: *VM) Value {
return self.chunk.?.constants.values[read_byte(self)]; return self.current_chunk().constants.values[read_byte(self)];
} }
pub fn push(self: *VM, value: Value) !void { pub fn push(self: *VM, value: Value) !void {
@ -269,7 +273,7 @@ pub const VM = struct {
const b = self.pop().as_cstring(); const b = self.pop().as_cstring();
const a = self.pop().as_cstring(); const a = self.pop().as_cstring();
const concat_str = try std.mem.concat(self.chunk.?.allocator, u8, &.{ a, b }); const concat_str = try std.mem.concat(self.current_chunk().allocator, u8, &.{ a, b });
var string_obj = self.take_string(concat_str); var string_obj = self.take_string(concat_str);
@ -284,7 +288,7 @@ pub const VM = struct {
pub fn runtime_error(self: *VM, err_msg: []const u8) void { pub fn runtime_error(self: *VM, err_msg: []const u8) void {
const instruction = self.ip.?; const instruction = self.ip.?;
const line = self.chunk.?.lines[instruction]; const line = self.current_chunk().lines[instruction];
debug.print("err: {s}\n", .{err_msg}); debug.print("err: {s}\n", .{err_msg});
debug.print("[line {d}] in script\n", .{line}); debug.print("[line {d}] in script\n", .{line});