This commit is contained in:
agra
2026-02-15 17:26:15 +02:00
parent 2727b5509e
commit a3be9cce7c
4 changed files with 356 additions and 260 deletions

View File

@@ -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;
}
}
}
}