DzLox

:)
git clone https://git.sr.ht/~ashymad/DzLox
Log | Files | Refs | Submodules | LICENSE

commit 28bc47f83eb783d32b2bf6188cecf3df9e8d27e2
parent 372a5c516991a81012d7b7031dc39f4b88b81db1
Author: Ashymad <szymon.mikulicz@posteo.net>
Date:   Thu, 29 Feb 2024 22:41:37 +0100

Make TrieTable comptime

Diffstat:
Mzlox/src/compiler.zig | 5++---
Mzlox/src/main.zig | 6+++---
Mzlox/src/scanner.zig | 47++++++++++++++++++++++-------------------------
Mzlox/src/test.zig | 8+-------
Mzlox/src/trie.zig | 56+++++++++++++++++++++++++++++++++-----------------------
Mzlox/src/vm.zig | 4++--
6 files changed, 63 insertions(+), 63 deletions(-)

diff --git a/zlox/src/compiler.zig b/zlox/src/compiler.zig @@ -3,9 +3,8 @@ const scanner = @import("scanner.zig"); pub const CompilerError = scanner.ScannerError; -pub fn compile(source: []const u8, allocator: std.mem.Allocator) !void { - var Scanner = try scanner.Scanner.init(source, allocator); - defer Scanner.deinit(); +pub fn compile(source: []const u8) !void { + var Scanner = try scanner.Scanner.init(source); var line: i32 = -1; diff --git a/zlox/src/main.zig b/zlox/src/main.zig @@ -15,7 +15,7 @@ pub fn main() anyerror!u8 { defer std.process.argsFree(allocator, args); if (args.len == 1) { - try repl(allocator); + try repl(); } else if (args.len == 2) { try runFile(allocator, args[1]); } else { @@ -34,7 +34,7 @@ pub fn runFile(allocator: std.mem.Allocator, path: []const u8) anyerror!void { defer allocator.free(text); } -pub fn repl(allocator: std.mem.Allocator) anyerror!void { +pub fn repl() anyerror!void { var VM = vm.VM.init(); defer VM.deinit(); @@ -42,7 +42,7 @@ pub fn repl(allocator: std.mem.Allocator) anyerror!void { while (Linenoise.linenoise("lox> ")) |line| { defer Linenoise.linenoiseFree(line); - try VM.interpret(std.mem.span(line), allocator); + try VM.interpret(std.mem.span(line)); _ = Linenoise.linenoiseHistoryAdd(line); } } diff --git a/zlox/src/scanner.zig b/zlox/src/scanner.zig @@ -56,29 +56,27 @@ pub const Token = struct { }; pub const Scanner = struct { - pub fn init(source: []const u8, allocator: std.mem.Allocator) !@This() { - var this = @This(){ .start = source.ptr, .current = source.ptr, .end = source.ptr + source.len, .line = 0, .identifiers = try trie.TrieTable(TokenType).init(allocator) }; - try this.identifiers.put("and", TokenType.AND); - try this.identifiers.put("class", TokenType.CLASS); - try this.identifiers.put("else", TokenType.ELSE); - try this.identifiers.put("false", TokenType.FALSE); - try this.identifiers.put("for", TokenType.FOR); - try this.identifiers.put("fun", TokenType.FUN); - try this.identifiers.put("if", TokenType.IF); - try this.identifiers.put("nil", TokenType.NIL); - try this.identifiers.put("or", TokenType.OR); - try this.identifiers.put("print", TokenType.PRINT); - try this.identifiers.put("return", TokenType.RETURN); - try this.identifiers.put("super", TokenType.SUPER); - try this.identifiers.put("this", TokenType.THIS); - try this.identifiers.put("true", TokenType.TRUE); - try this.identifiers.put("var", TokenType.VAR); - try this.identifiers.put("while", TokenType.WHILE); - return this; - } - - pub fn deinit(self: *@This()) void { - self.identifiers.deinit(); + const identifiers = trie.TrieTable(TokenType, .{ + .{ "and", TokenType.AND }, + .{ "class", TokenType.CLASS }, + .{ "else", TokenType.ELSE }, + .{ "false", TokenType.FALSE }, + .{ "for", TokenType.FOR }, + .{ "fun", TokenType.FUN }, + .{ "if", TokenType.IF }, + .{ "nil", TokenType.NIL }, + .{ "or", TokenType.OR }, + .{ "print", TokenType.PRINT }, + .{ "return", TokenType.RETURN }, + .{ "super", TokenType.SUPER }, + .{ "this", TokenType.THIS }, + .{ "true", TokenType.TRUE }, + .{ "var", TokenType.VAR }, + .{ "while", TokenType.WHILE }, + }); + + pub fn init(source: []const u8) !@This() { + return @This(){ .start = source.ptr, .current = source.ptr, .end = source.ptr + source.len, .line = 0 }; } pub fn scanToken(self: *@This()) ScannerError!Token { @@ -161,7 +159,7 @@ pub const Scanner = struct { } fn identifierType(self: *const @This()) TokenType { - if (self.identifiers.get(self.start[0..(@intFromPtr(self.current) - @intFromPtr(self.start))])) |tok| { + if (identifiers.get(self.start[0..(@intFromPtr(self.current) - @intFromPtr(self.start))])) |tok| { return tok; } else { return TokenType.IDENTIFIER; @@ -204,7 +202,6 @@ pub const Scanner = struct { return Token{ .type = tokentype, .lexeme = self.start[0..(@intFromPtr(self.current) - @intFromPtr(self.start))], .line = self.line }; } - identifiers: trie.TrieTable(TokenType), start: [*]const u8, current: [*]const u8, end: [*]const u8, diff --git a/zlox/src/test.zig b/zlox/src/test.zig @@ -35,13 +35,7 @@ test "testChunk" { } test "testTrie" { - var allocator = std.heap.GeneralPurposeAllocator(.{}){}; - defer std.debug.assert(allocator.deinit() == std.heap.Check.ok); - - var tr = try Trie(u8).init(allocator.allocator()); - defer tr.deinit(); - - try tr.put("test", 16); + const tr = Trie(u8, .{.{ "test", 16 }}); try std.testing.expectEqual(tr.get("test").?, 16); try std.testing.expectEqual(tr.get("tes"), null); diff --git a/zlox/src/trie.zig b/zlox/src/trie.zig @@ -1,36 +1,50 @@ const std = @import("std"); -pub fn TrieTable(comptime T: type) type { - return struct { +pub fn TrieTable(comptime T: type, comptime list: anytype) type { + const TrieLeaf = struct { value: ?T, data: [26]?*@This(), - allocator: ?std.heap.ArenaAllocator, + }; - pub fn init(allocator: std.mem.Allocator) !@This() { - return @This(){ .value = null, .data = [_]?*@This(){null} ** 26, .allocator = std.heap.ArenaAllocator.init(allocator) }; + const max_len = comptime blk: { + var ret = 0; + for (list) |el| { + ret += el.@"0".len; } + break :blk ret; + }; - pub fn put(self: *@This(), word: []const u8, value: T) !void { - var this = self; - const allo = self.allocator.?.allocator(); - for (word) |ch| { + const precomputed = comptime blk: { + var allocated = [_]TrieLeaf{TrieLeaf{ .value = null, .data = [_]?*TrieLeaf{null} ** 26 }} ** max_len; + var allocated_i = 0; + var tip = TrieLeaf{ .value = null, .data = [_]?*TrieLeaf{null} ** 26 }; + + for (list) |el| { + var leaf = &tip; + for (el.@"0") |ch| { const idx = ch - 'a'; - if (this.data[idx]) |val| { - this = val; + if (leaf.data[idx]) |val| { + leaf = val; } else { - var new = try allo.create(@This()); + var new = &allocated[allocated_i]; + allocated_i += 1; new.value = null; - new.data = [_]?*@This(){null} ** 26; - new.allocator = null; - this.data[idx] = new; - this = new; + new.data = [_]?*TrieLeaf{null} ** 26; + leaf.data[idx] = new; + leaf = new; } } - this.value = value; + leaf.value = el.@"1"; } + break :blk .{ .allocated = allocated, .tip = tip }; + }; + + return struct { + const allocated = precomputed.allocated; + const tip = precomputed.tip; - pub fn get(self: *const @This(), word: []const u8) ?T { - var this = self; + pub fn get(word: []const u8) ?T { + var this = &tip; for (word) |ch| { if (ch < 'a' or ch > 'z') return null; const idx = ch - 'a'; @@ -42,9 +56,5 @@ pub fn TrieTable(comptime T: type) type { } return this.value; } - - pub fn deinit(self: *@This()) void { - self.allocator.?.deinit(); - } }; } diff --git a/zlox/src/vm.zig b/zlox/src/vm.zig @@ -35,8 +35,8 @@ pub const VM = struct { try self.run(true); } - pub fn interpret(self: *@This(), source: []const u8, allocator: std.mem.Allocator) !void { - try compiler.compile(source, allocator); + pub fn interpret(self: *@This(), source: []const u8) !void { + try compiler.compile(source); self.resetStack(); }