Merge branch 'flow/sx-plan-arch/A8.1' into arch-refactor

This commit is contained in:
agra
2026-06-03 13:05:02 +03:00
3 changed files with 12 additions and 49 deletions

View File

@@ -2,7 +2,6 @@ const std = @import("std");
const ast = @import("ast.zig");
const parser = @import("parser.zig");
const imports = @import("imports.zig");
const sema = @import("sema.zig");
const errors = @import("errors.zig");
const c_import = @import("c_import.zig");
const ir = @import("ir/ir.zig");
@@ -27,7 +26,6 @@ pub const Compilation = struct {
import_sources: std.StringHashMap([:0]const u8),
module_scopes: std.StringHashMap(std.StringHashMap(void)),
import_graph: std.StringHashMap(std.StringHashMap(void)),
sema_result: ?sema.SemaResult = null,
ir_emitter: ?ir.LLVMEmitter = null,
/// Lowered IR module, kept alive past `generateCode` so post-link
/// callbacks can re-enter the interpreter to invoke sx functions
@@ -128,18 +126,6 @@ pub const Compilation = struct {
self.resolved_root = new_root;
}
pub fn analyze(self: *Compilation) !void {
const root = self.resolved_root orelse self.root orelse return error.CompileError;
var analyzer = sema.Analyzer.init(self.allocator);
self.sema_result = analyzer.analyze(root) catch return error.CompileError;
// Merge sema diagnostics into our list
if (self.sema_result) |sr| {
for (sr.diagnostics) |d| {
self.diagnostics.add(d.level, d.message, d.span);
}
}
}
/// Generate code via the IR pipeline: lower AST → IR → LLVM.
pub fn generateCode(self: *Compilation) !void {
// Heap-allocate the IR module so its address is stable during emit

View File

@@ -23,7 +23,9 @@ pub const Document = struct {
version: i64,
/// AST root for this file only (not merged).
root: ?*sx.ast.Node,
/// Sema results for this file (references are relative to this source).
/// Editor index for this file — symbols/references/types for navigation,
/// completion, and hover (references are relative to this source). Not a
/// diagnostic source; see `sema.zig` module doc.
sema: ?sx.sema.SemaResult,
/// Last successful sema (preserved across parse failures for completions).
last_good_sema: ?sx.sema.SemaResult = null,

View File

@@ -158,7 +158,7 @@ pub const Server = struct {
const text = jsonStr(jsonGet(td, "text") orelse return) orelse return;
const version = jsonInt(jsonGet(td, "version") orelse return) orelse return;
try self.analyzeAndPublish(uri, text, version);
try self.refreshEditorIndex(uri, text, version);
self.runProjectCheck();
}
@@ -173,7 +173,7 @@ pub const Server = struct {
const last = changes_arr[changes_arr.len - 1];
const text = jsonStr(jsonGet(last, "text") orelse return) orelse return;
try self.analyzeAndPublish(uri, text, version);
try self.refreshEditorIndex(uri, text, version);
}
fn handleDidClose(_: *Server, params: std.json.Value) void {
@@ -1919,41 +1919,16 @@ pub const Server = struct {
// ---- Core analysis pipeline ----
fn analyzeAndPublish(self: *Server, uri: []const u8, text: []const u8, version: i64) !void {
/// Refresh the editor index for a document (symbols/references/types that
/// power navigation, completion, hover, and token classification). Publishes
/// no diagnostics — authoritative diagnostics come only from the canonical
/// compiler pipeline in `runProjectCheck`.
fn refreshEditorIndex(self: *Server, uri: []const u8, text: []const u8, version: i64) !void {
const file_path = uriToFilePath(uri) orelse "";
const source = try self.allocator.dupeZ(u8, text);
const doc = try self.documents.openOrUpdate(file_path, source, version);
self.documents.analyzeDocument(doc) catch {};
// Publish diagnostics from sema
if (doc.sema) |sema| {
try self.sendDiagnostics(uri, semaToLspDiags(self.allocator, doc.source, sema.diagnostics));
} else {
try self.sendDiagnostics(uri, &.{});
}
}
fn semaToLspDiags(allocator: std.mem.Allocator, source: [:0]const u8, diags: []const sx.errors.Diagnostic) []const lsp.Diagnostic {
var result = std.ArrayList(lsp.Diagnostic).empty;
for (diags) |d| {
const range = if (d.span) |span| spanToRange(source, span) else lsp.Range{
.start = .{ .line = 0, .character = 0 },
.end = .{ .line = 0, .character = 1 },
};
const severity: u32 = switch (d.level) {
.err => 1,
.warn => 2,
.note => 3,
.help => 4,
};
result.append(allocator, .{
.range = range,
.severity = severity,
.message = d.message,
}) catch continue;
}
return result.items;
}
fn sendDiagnostics(self: *Server, uri: []const u8, diagnostics: []const lsp.Diagnostic) !void {
@@ -2012,8 +1987,8 @@ pub const Server = struct {
}
/// Drive the whole-program check from the workspace entry point and publish
/// the real compiler's diagnostics per file (runs on save; the sema layer
/// keeps live per-keystroke feedback).
/// the real compiler's diagnostics per file. Runs on open and save; this is
/// the sole source of LSP diagnostics (the editor index publishes none).
fn runProjectCheck(self: *Server) void {
if (self.root_path.len == 0) return;
const entry_path = std.fmt.allocPrint(self.allocator, "{s}/main.sx", .{self.root_path}) catch return;