This commit is contained in:
agra
2026-02-20 18:22:42 +02:00
parent 6f927361aa
commit 2f95810f9d
10 changed files with 510 additions and 77 deletions

View File

@@ -28,6 +28,8 @@ pub const Document = struct {
last_good_sema: ?sx.sema.SemaResult = null,
/// Import declarations parsed from this file.
imports: []const Import,
/// True while this document is being analyzed (circular import guard).
is_analyzing: bool = false,
pub fn topLevelSymbols(self: *const Document) []const sx.sema.Symbol {
const sr = self.sema orelse return &.{};
@@ -115,6 +117,10 @@ pub const DocumentStore = struct {
/// Analyze a document: parse, resolve imports, run sema with imported symbols pre-registered.
pub fn analyzeDocument(self: *DocumentStore, doc: *Document) !void {
if (doc.is_analyzing) return; // circular import guard
doc.is_analyzing = true;
defer doc.is_analyzing = false;
// Parse if needed
if (doc.root == null) {
var p = sx.parser.Parser.init(self.allocator, doc.source);
@@ -144,10 +150,6 @@ pub const DocumentStore = struct {
// Recursively analyze imported documents and pre-register their symbols
var analyzer = sx.sema.Analyzer.init(self.allocator);
// Track in-progress documents to detect cycles
var cycle_guard = std.StringHashMap(void).init(self.allocator);
try cycle_guard.put(doc.path, {});
for (doc.imports) |imp| {
// Try as file first; if that fails, try as directory import
const imp_doc = self.getOrLoad(imp.path) catch {
@@ -155,11 +157,8 @@ pub const DocumentStore = struct {
const dir_files = self.listDirectoryFiles(imp.path) orelse continue;
for (dir_files) |file_path| {
const file_doc = self.getOrLoad(file_path) catch continue;
if (cycle_guard.contains(file_path)) continue;
if (file_doc.sema == null) {
try cycle_guard.put(file_path, {});
self.analyzeDocument(file_doc) catch {};
_ = cycle_guard.remove(file_path);
}
const file_sema = file_doc.sema orelse continue;
if (imp.ns) |ns_name| {
@@ -219,14 +218,9 @@ pub const DocumentStore = struct {
continue;
};
// Cycle detection
if (cycle_guard.contains(imp.path)) continue;
// Ensure imported doc is analyzed
if (imp_doc.sema == null) {
try cycle_guard.put(imp.path, {});
self.analyzeDocument(imp_doc) catch {};
_ = cycle_guard.remove(imp.path);
}
const imp_sema = imp_doc.sema orelse continue;