...
This commit is contained in:
97
src/sema.zig
97
src/sema.zig
@@ -68,6 +68,8 @@ pub const Analyzer = struct {
|
||||
scope_depth: u32,
|
||||
/// Stack of symbol counts at each scope entry, for popScope cleanup.
|
||||
scope_starts: std.ArrayList(u32),
|
||||
/// Hash index: name → list of indices into symbols array for O(1) lookup
|
||||
symbol_index: std.StringHashMap(std.ArrayList(u32)),
|
||||
// Type registries
|
||||
fn_signatures: std.StringHashMap(FnSignature),
|
||||
struct_types: std.StringHashMap(StructTypeInfo),
|
||||
@@ -83,6 +85,7 @@ pub const Analyzer = struct {
|
||||
.diagnostics = std.ArrayList(Diagnostic).empty,
|
||||
.scope_depth = 0,
|
||||
.scope_starts = std.ArrayList(u32).empty,
|
||||
.symbol_index = std.StringHashMap(std.ArrayList(u32)).init(allocator),
|
||||
.fn_signatures = std.StringHashMap(FnSignature).init(allocator),
|
||||
.struct_types = std.StringHashMap(StructTypeInfo).init(allocator),
|
||||
.enum_types = std.StringHashMap([]const []const u8).init(allocator),
|
||||
@@ -315,13 +318,15 @@ pub const Analyzer = struct {
|
||||
},
|
||||
.chained_comparison => .boolean,
|
||||
.identifier => |ident| {
|
||||
// Search symbols backwards for matching name at or above current scope
|
||||
var i = self.symbols.items.len;
|
||||
while (i > 0) {
|
||||
i -= 1;
|
||||
const sym = self.symbols.items[i];
|
||||
if (sym.scope_depth <= self.scope_depth and std.mem.eql(u8, sym.name, ident.name)) {
|
||||
return sym.ty orelse Type.s(64);
|
||||
// Use symbol index for O(1) name lookup
|
||||
if (self.symbol_index.get(ident.name)) |indices| {
|
||||
var j = indices.items.len;
|
||||
while (j > 0) {
|
||||
j -= 1;
|
||||
const sym = self.symbols.items[indices.items[j]];
|
||||
if (sym.scope_depth <= self.scope_depth) {
|
||||
return sym.ty orelse Type.s(64);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Type.s(64);
|
||||
@@ -508,19 +513,24 @@ pub const Analyzer = struct {
|
||||
}
|
||||
|
||||
fn addSymbol(self: *Analyzer, name: []const u8, kind: SymbolKind, ty: ?Type, span: Span) !void {
|
||||
// Check for duplicate only within the current scope window.
|
||||
const scope_start: usize = if (self.scope_starts.items.len > 0)
|
||||
self.scope_starts.items[self.scope_starts.items.len - 1]
|
||||
else
|
||||
0;
|
||||
for (self.symbols.items[scope_start..]) |sym| {
|
||||
if (sym.scope_depth == self.scope_depth and std.mem.eql(u8, sym.name, name)) {
|
||||
try self.diagnostics.append(self.allocator, .{
|
||||
.level = .warn,
|
||||
.span = span,
|
||||
.message = "duplicate declaration",
|
||||
});
|
||||
break;
|
||||
// Check for duplicate using the symbol index
|
||||
if (self.symbol_index.get(name)) |indices| {
|
||||
const scope_start: u32 = if (self.scope_starts.items.len > 0)
|
||||
self.scope_starts.items[self.scope_starts.items.len - 1]
|
||||
else
|
||||
0;
|
||||
for (indices.items) |idx| {
|
||||
if (idx >= scope_start) {
|
||||
const sym = self.symbols.items[idx];
|
||||
if (sym.scope_depth == self.scope_depth) {
|
||||
try self.diagnostics.append(self.allocator, .{
|
||||
.level = .warn,
|
||||
.span = span,
|
||||
.message = "duplicate declaration",
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,26 +541,42 @@ pub const Analyzer = struct {
|
||||
.def_span = span,
|
||||
.scope_depth = self.scope_depth,
|
||||
});
|
||||
// Update symbol index
|
||||
const idx: u32 = @intCast(self.symbols.items.len - 1);
|
||||
const gop = try self.symbol_index.getOrPut(name);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = std.ArrayList(u32).empty;
|
||||
}
|
||||
try gop.value_ptr.append(self.allocator, idx);
|
||||
}
|
||||
|
||||
/// Pre-register an imported symbol so references in this file can resolve to it.
|
||||
pub fn preRegisterSymbol(self: *Analyzer, sym: Symbol) !void {
|
||||
try self.symbols.append(self.allocator, sym);
|
||||
// Update symbol index
|
||||
const idx: u32 = @intCast(self.symbols.items.len - 1);
|
||||
const gop = try self.symbol_index.getOrPut(sym.name);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = std.ArrayList(u32).empty;
|
||||
}
|
||||
try gop.value_ptr.append(self.allocator, idx);
|
||||
}
|
||||
|
||||
fn resolveIdentifier(self: *Analyzer, name: []const u8, span: Span) !void {
|
||||
// Search backwards to find the most recent declaration with this name
|
||||
// that is at or above the current scope depth.
|
||||
var i = self.symbols.items.len;
|
||||
while (i > 0) {
|
||||
i -= 1;
|
||||
const sym = self.symbols.items[i];
|
||||
if (sym.scope_depth <= self.scope_depth and std.mem.eql(u8, sym.name, name)) {
|
||||
try self.references.append(self.allocator, .{
|
||||
.span = span,
|
||||
.symbol_index = @intCast(i),
|
||||
});
|
||||
return;
|
||||
// Use symbol index for O(1) name lookup, then walk backwards through indices
|
||||
if (self.symbol_index.get(name)) |indices| {
|
||||
var j = indices.items.len;
|
||||
while (j > 0) {
|
||||
j -= 1;
|
||||
const idx = indices.items[j];
|
||||
const sym = self.symbols.items[idx];
|
||||
if (sym.scope_depth <= self.scope_depth) {
|
||||
try self.references.append(self.allocator, .{
|
||||
.span = span,
|
||||
.symbol_index = idx,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -787,9 +813,10 @@ pub const Analyzer = struct {
|
||||
const name = tn.data.type_expr.name;
|
||||
// Check type aliases first
|
||||
const resolved = self.type_aliases.get(name) orelse name;
|
||||
for (self.symbols.items) |sym| {
|
||||
if (!std.mem.eql(u8, sym.name, resolved)) continue;
|
||||
if (sym.ty) |ty| return ty;
|
||||
if (self.symbol_index.get(resolved)) |indices| {
|
||||
for (indices.items) |idx| {
|
||||
if (self.symbols.items[idx].ty) |ty| return ty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user