#ifndef CBM_LSP_GO_LSP_H #define CBM_LSP_GO_LSP_H #include "type_rep.h" #include "scope.h" #include "type_registry.h" #include "../cbm.h" // GoLSPContext holds state for Go expression type evaluation within a file. typedef struct { CBMArena* arena; const char* source; int source_len; const CBMTypeRegistry* registry; CBMScope* current_scope; // Import map: local_name -> package QN (arena-allocated) const char** import_local_names; // NULL-terminated const char** import_package_qns; // NULL-terminated int import_count; // Current function context const char* enclosing_func_qn; const char* package_qn; // module QN for this file // Output: resolved calls accumulate here CBMResolvedCallArray* resolved_calls; // AST-walk recursion depth for resolve_calls_in_node (guards stack overflow // on deeply-nested/cyclic files; see cbm_lsp_max_walk_depth). Zero via memset. int walk_depth; // Debug mode (CBM_LSP_DEBUG env) bool debug; } GoLSPContext; // Initialize a GoLSPContext for processing one file. void go_lsp_init(GoLSPContext* ctx, CBMArena* arena, const char* source, int source_len, const CBMTypeRegistry* registry, const char* package_qn, CBMResolvedCallArray* out); // Add an import mapping. void go_lsp_add_import(GoLSPContext* ctx, const char* local_name, const char* package_qn); // Process all functions in a file's AST, evaluating types and resolving calls. // root is the tree-sitter root node of the file. void go_lsp_process_file(GoLSPContext* ctx, TSNode root); // Evaluate the type of a Go expression node. const CBMType* go_eval_expr_type(GoLSPContext* ctx, TSNode node); // Parse a Go type AST node into a CBMType. const CBMType* go_parse_type_node(GoLSPContext* ctx, TSNode node); // Process a Go statement, binding variables into the current scope. void go_process_statement(GoLSPContext* ctx, TSNode node); // Evaluate a builtin call (make, new, append, len, cap, delete). const CBMType* go_eval_builtin_call(GoLSPContext* ctx, const char* name, TSNode args); // Look up a field or method on a type, traversing embedded types. const CBMRegisteredFunc* go_lookup_field_or_method(GoLSPContext* ctx, const char* type_qn, const char* member_name); // Entry point: build registry from file's own defs + run LSP resolution. // Called from cbm_extract_file() after definitions and imports are extracted. void cbm_run_go_lsp(CBMArena* arena, CBMFileResult* result, const char* source, int source_len, TSNode root); // Register Go stdlib types and functions into a registry. // Auto-generated by scripts/gen-go-stdlib.go. void cbm_go_stdlib_register(CBMTypeRegistry* reg, CBMArena* arena); // --- Cross-file LSP resolution --- // Simplified definition for cross-file type/function registration. // String fields are borrowed (caller owns memory until cbm_run_go_lsp_cross returns). typedef struct { const char* qualified_name; const char* short_name; const char* label; // "Function", "Method", "Type", "Interface" const char* receiver_type; // for methods: receiver type QN (NULL for functions) const char* def_module_qn; // module QN where this def lives (for type text qualification) const char* return_types; // "|"-separated return type texts, e.g. "*File|error" const char* embedded_types; // "|"-separated embedded type QNs (for struct embedding) const char* field_defs; // "|"-separated "name:type" pairs (for struct fields, e.g. "Binder:Binder|Name:string") const char* method_names_str; // "|"-separated method names for interfaces (e.g. "Get|Put|Delete") bool is_interface; CBMLanguage lang; // language of the file that defined this — used by Tier 2 per-language registry build to filter all_defs const char* namespace_name; // declared namespace/package for source-root-independent JVM filtering } CBMLSPDef; // Parse source, build registry from defs + stdlib, run LSP. // Re-parses source with tree-sitter internally. // defs includes both file-local and cross-file definitions. // import_names/import_qns are parallel arrays of length import_count. // Results written to out (arena-allocated). void cbm_run_go_lsp_cross( CBMArena* arena, const char* source, int source_len, const char* module_qn, CBMLSPDef* defs, int def_count, const char** import_names, const char** import_qns, int import_count, TSTree* cached_tree, // NULL = parse internally CBMResolvedCallArray* out); /* Tier 2 (gopls package-summary pattern): * Build a project-wide, finalized CBMTypeRegistry from all Go defs ONCE. * Run cross-file LSP per file using that shared registry — no per-file * registry build, O(1) lookups, no Phase 1b/1c mutations. Reg is borrowed * from arena (arena owns the storage); reg pointer is valid for arena * lifetime. */ CBMTypeRegistry* cbm_go_build_cross_registry( CBMArena* arena, CBMLSPDef* defs, int def_count); void cbm_run_go_lsp_cross_with_registry( CBMArena* arena, const char* source, int source_len, const char* module_qn, CBMTypeRegistry* reg, // pre-built, finalized, READ-ONLY const char** import_names, const char** import_qns, int import_count, TSTree* cached_tree, // NULL = parse internally CBMResolvedCallArray* out); /* Tier 3: AST-walk-free fast resolver. Iterates result->calls and * resolves fully-qualified calls (pkg.Func) directly from the * pre-built registry — no tree-sitter parse, no AST walk. Returns * the count of calls that STILL need the slow path (methods on * locals + qualified calls we couldn't resolve). When the return * value is 0, the caller can skip the cbm_run_go_lsp_cross_with_ * registry parse+walk entirely. Resolved entries are appended to * result->resolved_calls in result->arena. */ int cbm_go_fast_resolve_qualified_calls( CBMFileResult* result, CBMTypeRegistry* reg, const char** import_names, const char** import_qns, int import_count); // --- Batch cross-file LSP --- // Per-file input for batch Go LSP processing. typedef struct { const char* source; int source_len; const char* module_qn; TSTree* cached_tree; // from TSTree caching (NULL = parse internally) CBMLSPDef* defs; // combined file-local + cross-file defs int def_count; const char** import_names; // parallel arrays, import_count long const char** import_qns; int import_count; } CBMBatchGoLSPFile; // Process multiple Go files' cross-file LSP in one CGo call. // out must point to file_count pre-zeroed CBMResolvedCallArray structs. // Uses per-file arenas internally; results are copied to the output arena. void cbm_batch_go_lsp_cross( CBMArena* arena, CBMBatchGoLSPFile* files, int file_count, CBMResolvedCallArray* out); #endif // CBM_LSP_GO_LSP_H