...
This commit is contained in:
92
src/sema.zig
92
src/sema.zig
@@ -148,7 +148,7 @@ pub const Analyzer = struct {
|
||||
});
|
||||
},
|
||||
.const_decl => |cd| {
|
||||
const ty = resolveTypeAnnotation(cd.type_annotation) orelse inferValueType(cd.value);
|
||||
const ty = self.resolveTypeAnnotation(cd.type_annotation) orelse inferValueType(cd.value);
|
||||
const kind = classifyConstDecl(cd);
|
||||
try self.addSymbol(cd.name, kind, ty, node.span);
|
||||
// Populate type_aliases registry
|
||||
@@ -175,7 +175,7 @@ pub const Analyzer = struct {
|
||||
}
|
||||
},
|
||||
.var_decl => |vd| {
|
||||
const ty = resolveTypeAnnotation(vd.type_annotation);
|
||||
const ty = self.resolveTypeAnnotation(vd.type_annotation);
|
||||
try self.addSymbol(vd.name, .variable, ty, node.span);
|
||||
},
|
||||
.enum_decl => |ed| {
|
||||
@@ -581,7 +581,7 @@ pub const Analyzer = struct {
|
||||
.const_decl => |cd| {
|
||||
// Analyze value first (so it can't reference itself)
|
||||
try self.analyzeNode(cd.value);
|
||||
const ty = resolveTypeAnnotation(cd.type_annotation) orelse inferValueType(cd.value);
|
||||
const ty = self.resolveTypeAnnotation(cd.type_annotation) orelse inferValueType(cd.value);
|
||||
const kind = classifyConstDecl(cd);
|
||||
try self.addSymbol(cd.name, kind, ty, node.span);
|
||||
},
|
||||
@@ -589,7 +589,7 @@ pub const Analyzer = struct {
|
||||
if (vd.value) |val| {
|
||||
try self.analyzeNode(val);
|
||||
}
|
||||
const ty = resolveTypeAnnotation(vd.type_annotation) orelse
|
||||
const ty = self.resolveTypeAnnotation(vd.type_annotation) orelse
|
||||
if (vd.value) |val| self.inferExprType(val) else null;
|
||||
try self.addSymbol(vd.name, .variable, ty, node.span);
|
||||
},
|
||||
@@ -637,7 +637,12 @@ pub const Analyzer = struct {
|
||||
.match_expr => |me| {
|
||||
try self.analyzeNode(me.subject);
|
||||
for (me.arms) |arm| {
|
||||
try self.pushScope();
|
||||
if (arm.capture) |cap_name| {
|
||||
try self.addSymbol(cap_name, .variable, null, arm.body.span);
|
||||
}
|
||||
try self.analyzeNode(arm.body);
|
||||
self.popScope();
|
||||
}
|
||||
},
|
||||
.while_expr => |we| {
|
||||
@@ -773,9 +778,19 @@ pub const Analyzer = struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn resolveTypeAnnotation(type_node: ?*Node) ?Type {
|
||||
fn resolveTypeAnnotation(self: *Analyzer, type_node: ?*Node) ?Type {
|
||||
if (type_node) |tn| {
|
||||
return Type.fromTypeExpr(tn);
|
||||
if (Type.fromTypeExpr(tn)) |t| return t;
|
||||
// Check registered types (structs, enums, tagged enums)
|
||||
if (tn.data == .type_expr) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -986,6 +1001,71 @@ pub fn findNodeAtOffset(node: *Node, offset: u32) ?*Node {
|
||||
return node;
|
||||
}
|
||||
|
||||
/// Find the nearest match_expr ancestor that contains the given offset.
|
||||
/// Returns the match subject node if found, null otherwise.
|
||||
pub fn findEnclosingMatchSubject(node: *Node, offset: u32) ?*Node {
|
||||
if (offset < node.span.start or offset >= node.span.end) return null;
|
||||
|
||||
switch (node.data) {
|
||||
.match_expr => |me| {
|
||||
// First recurse into arm bodies — there might be a nested match
|
||||
for (me.arms) |arm| {
|
||||
if (findEnclosingMatchSubject(arm.body, offset)) |inner| return inner;
|
||||
}
|
||||
// If offset is inside this match_expr (but not in the subject itself),
|
||||
// it's in an arm pattern, between arms, or in a partially-typed arm
|
||||
if (me.subject.span.start <= offset and offset < me.subject.span.end) {
|
||||
// Cursor is on the subject itself, not in an arm
|
||||
} else {
|
||||
return me.subject;
|
||||
}
|
||||
},
|
||||
.root => |r| {
|
||||
for (r.decls) |decl| {
|
||||
if (findEnclosingMatchSubject(decl, offset)) |found| return found;
|
||||
}
|
||||
},
|
||||
.fn_decl => |fd| {
|
||||
if (findEnclosingMatchSubject(fd.body, offset)) |found| return found;
|
||||
},
|
||||
.block => |blk| {
|
||||
for (blk.stmts) |stmt| {
|
||||
if (findEnclosingMatchSubject(stmt, offset)) |found| return found;
|
||||
}
|
||||
},
|
||||
.if_expr => |ie| {
|
||||
if (findEnclosingMatchSubject(ie.then_branch, offset)) |found| return found;
|
||||
if (ie.else_branch) |eb| {
|
||||
if (findEnclosingMatchSubject(eb, offset)) |found| return found;
|
||||
}
|
||||
},
|
||||
.while_expr => |we| {
|
||||
if (findEnclosingMatchSubject(we.body, offset)) |found| return found;
|
||||
},
|
||||
.for_expr => |fe| {
|
||||
if (findEnclosingMatchSubject(fe.body, offset)) |found| return found;
|
||||
},
|
||||
.const_decl => |cd| {
|
||||
if (findEnclosingMatchSubject(cd.value, offset)) |found| return found;
|
||||
},
|
||||
.var_decl => |vd| {
|
||||
if (vd.value) |val| {
|
||||
if (findEnclosingMatchSubject(val, offset)) |found| return found;
|
||||
}
|
||||
},
|
||||
.lambda => |lam| {
|
||||
if (findEnclosingMatchSubject(lam.body, offset)) |found| return found;
|
||||
},
|
||||
.namespace_decl => |ns| {
|
||||
for (ns.decls) |decl| {
|
||||
if (findEnclosingMatchSubject(decl, offset)) |found| return found;
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
test "sema: collect top-level declarations" {
|
||||
const parser_mod = @import("parser.zig");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user