Skip to content

Commit

Permalink
refactor(semantic): use nominal ids for scopes (#85)
Browse files Browse the repository at this point in the history
  • Loading branch information
DonIsaac authored Nov 17, 2024
1 parent 94da4cc commit 54641e0
Show file tree
Hide file tree
Showing 21 changed files with 263 additions and 257 deletions.
8 changes: 4 additions & 4 deletions src/printer/SemanticPrinter.zig
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fn printSymbol(self: *SemanticPrinter, symbol: *const Semantic.Symbol, symbols:
}

pub fn printScopeTree(self: *SemanticPrinter) !void {
return self.printScope(&self.semantic.scopes.scopes.get(Semantic.ROOT_SCOPE_ID));
return self.printScope(&self.semantic.scopes.getScope(Semantic.ROOT_SCOPE_ID));
}

const StackAllocator = std.heap.StackFallbackAllocator(1024);
Expand Down Expand Up @@ -77,7 +77,7 @@ fn printScope(self: *SemanticPrinter, scope: *const Semantic.Scope) !void {
defer p.pop();
// var bindings = std.StringHashMap(Symbol.Id).init(fixed_alloc.get());
// defer bindings.deinit();
for (scopes.bindings.items[scope.id].items) |id| {
for (scopes.bindings.items[scope.id.int()].items) |id| {
const i = id.int();
var name = bound_names[i];
if (name.len == 0) {
Expand All @@ -87,7 +87,7 @@ fn printScope(self: *SemanticPrinter, scope: *const Semantic.Scope) !void {
}
}

const children = &scopes.children.items[scope.id];
const children = &scopes.children.items[scope.id.int()];
if (children.items.len == 0) {
try p.pPropName("children");
try p.writer.print("[]", .{});
Expand All @@ -99,7 +99,7 @@ fn printScope(self: *SemanticPrinter, scope: *const Semantic.Scope) !void {
try p.pushArray();
defer p.pop();
for (children.items) |child_id| {
const child = &scopes.scopes.get(child_id);
const child = &scopes.getScope(child_id);
try self.printScope(child);
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/semantic/NodeLinks.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
/// - No node is its own parent
/// - No node is the parent of the root node (0 in this case means `null`).
parents: std.ArrayListUnmanaged(NodeIndex) = .{},
scopes: std.ArrayListUnmanaged(ScopeId) = .{},
scopes: std.ArrayListUnmanaged(Scope.Id) = .{},

pub fn init(alloc: Allocator, ast: *const Ast) Allocator.Error!NodeLinks {
var links: NodeLinks = .{};

try links.parents.ensureTotalCapacityPrecise(alloc, ast.nodes.len);
links.parents.appendNTimesAssumeCapacity(NULL_NODE, @intCast(ast.nodes.len));
try links.scopes.ensureTotalCapacityPrecise(alloc, ast.nodes.len);
links.scopes.appendNTimesAssumeCapacity(NULL_NODE, @intCast(ast.nodes.len));
links.scopes.appendNTimesAssumeCapacity(Semantic.ROOT_SCOPE_ID, ast.nodes.len);

return links;
}
Expand All @@ -33,7 +33,7 @@ pub fn deinit(self: *NodeLinks, alloc: Allocator) void {
}
}

pub inline fn setScope(self: *NodeLinks, node_id: NodeIndex, scope_id: ScopeId) void {
pub inline fn setScope(self: *NodeLinks, node_id: NodeIndex, scope_id: Scope.Id) void {
assert(
node_id < self.scopes.items.len,
"Node id out of bounds (id {d} >= {d})",
Expand Down Expand Up @@ -90,7 +90,7 @@ const NodeIndex = Ast.Node.Index;
const Semantic = @import("./Semantic.zig");
const ROOT_NODE_ID = Semantic.ROOT_NODE_ID;
const NULL_NODE = Semantic.NULL_NODE;
const ScopeId = Semantic.Scope.Id;
const Scope = Semantic.Scope;

const std = @import("std");
const Allocator = std.mem.Allocator;
Expand Down
30 changes: 18 additions & 12 deletions src/semantic/Scope.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ flags: Flags,
parent: ?Id,

/// Uniquely identifies a scope within a source file.
pub const Id = u32;
pub const MAX_ID = std.math.maxInt(Id);
pub const Id = NominalId(u32);
pub const MAX_ID = Id.MAX;

const FLAGS_REPR = u16;
/// Scope flags provide hints about what kind of node is creating the
Expand Down Expand Up @@ -63,13 +63,17 @@ pub const ScopeTree = struct {
const ScopeIdList = std.ArrayListUnmanaged(Scope.Id);
const SymbolIdList = std.ArrayListUnmanaged(Symbol.Id);

pub fn getScope(self: *const ScopeTree, id: Scope.Id) Scope {
return self.scopes.get(id.into(usize));
}

/// Create a new scope and insert it into the scope tree.
///
/// ## Errors
/// If allocation fails. Usually due to OOM.
pub fn addScope(self: *ScopeTree, alloc: Allocator, parent: ?Scope.Id, flags: Scope.Flags) !Scope.Id {
assert(self.scopes.len < Scope.MAX_ID);
const id: Scope.Id = @intCast(self.scopes.len);
const id: Scope.Id = Id.from(self.scopes.len);

// initialize the new scope
try self.scopes.append(alloc, Scope{
Expand All @@ -84,8 +88,9 @@ pub const ScopeTree = struct {

// Add it to its parent's list of child scopes
if (parent != null) {
assert(parent.? < self.children.items.len);
var parentChildren: *ScopeIdList = &self.children.items[parent.?];
const p = parent.?.int();
assert(p < self.children.items.len);
var parentChildren: *ScopeIdList = &self.children.items[p];
try parentChildren.append(alloc, id);
}

Expand All @@ -96,7 +101,7 @@ pub const ScopeTree = struct {
}

pub fn addBinding(self: *ScopeTree, alloc: Allocator, scope_id: Scope.Id, symbol_id: Symbol.Id) Allocator.Error!void {
return self.bindings.items[scope_id].append(alloc, symbol_id);
return self.bindings.items[scope_id.int()].append(alloc, symbol_id);
}

pub fn deinit(self: *ScopeTree, alloc: Allocator) void {
Expand Down Expand Up @@ -126,6 +131,7 @@ const Allocator = std.mem.Allocator;
const Ast = std.zig.Ast;
const Type = std.builtin.Type;
const Symbol = @import("Symbol.zig");
const NominalId = @import("id.zig").NominalId;

const string = @import("util").string;
const assert = std.debug.assert;
Expand All @@ -149,22 +155,22 @@ test "ScopeTree.addScope" {
defer tree.deinit(alloc);

const root_id = try tree.addScope(alloc, null, .{ .s_top = true });
const root = tree.scopes.get(root_id);
const root = tree.getScope(root_id);
try expectEqual(1, tree.scopes.len);
try expectEqual(0, root_id);
try expectEqual(0, root.id);
try expectEqual(0, root_id.int());
try expectEqual(0, root.id.int());
try expectEqual(Scope.Flags{ .s_top = true }, root.flags);
try expectEqual(root, tree.scopes.get(0));

const child_id = try tree.addScope(alloc, root.id, .{});
const child = tree.scopes.get(child_id);
try expectEqual(1, child.id);
const child = tree.getScope(child_id);
try expectEqual(1, child.id.int());
try expectEqual(Scope.Flags{}, child.flags);
try expectEqual(root.id, child.parent);
try expectEqual(child, tree.scopes.get(1));

try expectEqual(2, tree.scopes.len);
try expectEqual(2, tree.children.items.len);
try expectEqual(1, tree.children.items[0].items.len);
try expectEqual(1, tree.children.items[0].items[0]);
try expectEqual(1, tree.children.items[0].items[0].int());
}
2 changes: 1 addition & 1 deletion src/semantic/Semantic.zig
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ _arena: ArenaAllocator,
///
/// The root scope is eventually the parent of all other scopes. Its parent is
/// always `null`.
pub const ROOT_SCOPE_ID: Scope.Id = 0;
pub const ROOT_SCOPE_ID: Scope.Id = Scope.Id.from(0);
/// The root node always has an index of 0. Since it is never referenced by other nodes,
/// the Zig team uses it to represent `null` without wasting extra memory.
pub const ROOT_NODE_ID: Ast.Node.Index = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/semantic/SemanticBuilder.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,7 @@ fn printScopeStack(self: *const SemanticBuilder) void {
const scope_flags = scopes.scopes.items(.flags);
for (self._scope_stack.items) |id| {
// const flags = scopes.scopes.items[id].flags;
print(" - {d}: (flags: {any})\n", .{ id, scope_flags[id] });
print(" - {d}: (flags: {any})\n", .{ id, scope_flags[id.into(usize)] });
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/semantic/Symbol.zig
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@ test "SymbolTable.iter()" {
var table = SymbolTable{};
defer table.deinit(a);

_ = try table.addSymbol(a, 1, "a", null, 0, .public, .{});
_ = try table.addSymbol(a, 1, "b", null, 1, .public, .{});
_ = try table.addSymbol(a, 1, "a", null, Scope.Id.new(0), .public, .{});
_ = try table.addSymbol(a, 1, "b", null, Scope.Id.new(1), .public, .{});
try expectEqual(2, table.symbols.len);

var iter = table.iter();
Expand Down
2 changes: 1 addition & 1 deletion src/semantic/id.zig
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub fn NominalId(TRepr: type) type {
pub inline fn from(value: anytype) Id {
const T = @TypeOf(value);
return switch (T) {
Repr => return @enumFromInt(value),
Repr, comptime_int => return @enumFromInt(value),
Id => return value,
Optional => @enumFromInt(@intFromEnum(value)),
// allow other int types
Expand Down
Loading

0 comments on commit 54641e0

Please sign in to comment.