Skip to content

Commit

Permalink
Create a string interner datastructure.
Browse files Browse the repository at this point in the history
  • Loading branch information
wmedrano committed Sep 1, 2024
1 parent 69d5174 commit b1a32d3
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 21 deletions.
4 changes: 2 additions & 2 deletions src/Compiler.zig
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub fn initFunction(allocator: std.mem.Allocator, env: *Env, module: *Module, ar
var module_defined_vals = std.StringHashMap(Symbol).init(allocator);
var module_definitions = module.values.keyIterator();
while (module_definitions.next()) |sym| {
if (env.memory_manager.symbol_to_name.get(sym.*)) |sym_name|
if (env.memory_manager.symbols.getName(sym.*)) |sym_name|
try module_defined_vals.put(sym_name, sym.*);
}
const scopes = try ScopeManager.initWithArgs(allocator, args);
Expand All @@ -52,7 +52,7 @@ pub fn initModule(allocator: std.mem.Allocator, env: *Env, module: *Module) !Com
var module_defined_vals = std.StringHashMap(Symbol).init(allocator);
var module_definitions = module.values.keyIterator();
while (module_definitions.next()) |sym| {
if (env.memory_manager.symbol_to_name.get(sym.*)) |sym_name|
if (env.memory_manager.symbols.getName(sym.*)) |sym_name|
try module_defined_vals.put(sym_name, sym.*);
}
return .{
Expand Down
22 changes: 6 additions & 16 deletions src/MemoryManager.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const Val = @import("val.zig").Val;
const Symbol = Val.Symbol;
const ByteCode = @import("ByteCode.zig");
const Module = @import("Module.zig");
const StringInterner = @import("datastructures/string_interner.zig").StringInterner;

const std = @import("std");

Expand All @@ -12,10 +13,9 @@ allocator: std.mem.Allocator,
/// cleaned up for garbage collection.
reachable_color: Color = Color.red,

/// A map from name to its symbol.
name_to_symbol: std.StringHashMapUnmanaged(Symbol) = .{},
/// A map from symbol to its name.
symbol_to_name: std.AutoHashMapUnmanaged(Symbol, []const u8) = .{},
/// Contains all the symbols.
symbols: StringInterner(Symbol) = .{},

/// A map from an owned string to its reachable color.
strings: std.StringHashMapUnmanaged(Color) = .{},
/// A map from a struct pointer to its Color.
Expand Down Expand Up @@ -62,11 +62,7 @@ pub fn deinit(self: *MemoryManager) void {
self.sweep() catch {};
self.sweep() catch {};

var symbols_iter = self.name_to_symbol.keyIterator();
while (symbols_iter.next()) |s| self.allocator.free(s.*);
self.name_to_symbol.deinit(self.allocator);
self.symbol_to_name.deinit(self.allocator);

self.symbols.deinit(self.allocator);
self.strings.deinit(self.allocator);
self.structs.deinit(self.allocator);
self.lists.deinit(self.allocator);
Expand Down Expand Up @@ -100,13 +96,7 @@ pub fn allocateStringVal(self: *MemoryManager, str: []const u8) !Val {

/// Create a new symbol and return its id. If the symbol already exists, its id is returned.
pub fn allocateSymbol(self: *MemoryManager, name: []const u8) !Symbol {
if (self.nameToSymbol(name)) |sym| return sym;
const new_name = try self.allocator.dupe(u8, name);
const sym = Symbol{ .id = @intCast(self.name_to_symbol.count()) };
try self.name_to_symbol.put(self.allocator, new_name, sym);
errdefer _ = self.name_to_symbol.remove(new_name);
try self.symbol_to_name.put(self.allocator, sym, new_name);
return sym;
return try self.symbols.getOrMakeId(self.allocator, name);
}

/// Get the symbol from a name or `null` if it has not been allocated.
Expand Down
4 changes: 2 additions & 2 deletions src/Vm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ pub fn toZig(self: *Vm, T: type, alloc: std.mem.Allocator, val: Val) !T {
var fizz_field_name: [field.name.len]u8 = undefined;
@memcpy(&fizz_field_name, field.name);
makeKebabCase(&fizz_field_name);
if (self.env.memory_manager.name_to_symbol.get(&fizz_field_name)) |sym| {
if (self.env.memory_manager.symbols.getId(&fizz_field_name)) |sym| {
const field_val = map.get(sym) orelse
return Error.TypeError;
const field_zig_val = try self.toZig(field.type, alloc, field_val);
Expand Down Expand Up @@ -534,7 +534,7 @@ fn executeImportModule(self: *Vm, module: *Module, module_path: []const u8) Erro

fn errSymbolNotFound(self: *Vm, module: *const Module, sym: Symbol) Error {
@setCold(true);
const name = self.env.memory_manager.symbol_to_name.get(sym) orelse "*unknown-symbol*";
const name = self.env.memory_manager.symbols.getName(sym) orelse "*unknown-symbol*";
const msg = try std.fmt.allocPrint(
self.env.errors.allocator(),
"Symbol {s} (id={d}) not found in module {s}",
Expand Down
38 changes: 38 additions & 0 deletions src/datastructures/string_interner.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const std = @import("std");

/// Create a new string interner. `Id` must be a struct that contains a single number field named
/// `id`.
pub fn StringInterner(Id: type) type {
return struct {
const Self = @This();

string_to_id: std.StringHashMapUnmanaged(Id) = .{},
id_to_string: std.AutoHashMapUnmanaged(Id, []const u8) = .{},

pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
var string_iter = self.string_to_id.keyIterator();
while (string_iter.next()) |s| allocator.free(s.*);
self.string_to_id.deinit(allocator);
self.id_to_string.deinit(allocator);
}

pub fn getName(self: *const Self, id: Id) ?[]const u8 {
return self.id_to_string.get(id);
}

pub fn getId(self: *const Self, name: []const u8) ?Id {
return self.string_to_id.get(name);
}

pub fn getOrMakeId(self: *Self, allocator: std.mem.Allocator, name: []const u8) !Id {
if (self.getId(name)) |id| return id;
const new_name = try allocator.dupe(u8, name);
errdefer allocator.free(new_name);
const id = .{ .id = self.string_to_id.count() };
try self.id_to_string.put(allocator, id, new_name);
errdefer _ = self.id_to_string.remove(id);
try self.string_to_id.put(allocator, new_name, id);
return id;
}
};
}
2 changes: 1 addition & 1 deletion src/val.zig
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub const Val = union(enum) {
},
.symbol => |sym| {
if (self.memory_manager) |mm| {
if (mm.symbol_to_name.get(sym)) |s| {
if (mm.symbols.getName(sym)) |s| {
try std.fmt.format(writer, "'{s}", .{s});
return;
}
Expand Down

0 comments on commit b1a32d3

Please sign in to comment.