feat(perl-lsp): implement core semantic resolution (package/sub/method/ISA/bless/exports)

Replace the plan-01 no-op walk in perl_lsp.c with the full Perl resolver,
mirroring php_lsp.c's architecture. Touches ONLY perl_lsp.c.

- Two-pass perl_lsp_process_file: PASS 1 collects package_statement context
  (packages may switch mid-file), @ISA / use parent / use base inheritance,
  and Exporter `use Foo qw(...)` import maps; PASS 2 walks
  subroutine_declaration_statement bodies.
- process_subroutine: pushes a scope, sets enclosing_func_qn (module_qn.sub --
  the structural QN scheme, verified via helpers.c cbm_enclosing_func_qn), and
  binds the $self/$class invocant (my $X = shift idiom) to the package type.
- perl_eval_expr_type: sigil-aware scalar scope lookup, method/function call
  dispatch, bless($r,'Class') literal (0.95) + ref($class)||$class inferred
  (0.75), assignment RHS propagation, ClassName->new => ClassName; recursion-
  guarded via eval_depth (cap 8, mirrors php).
- perl_find_isa via @ISA assignment, use parent, use base; perl_lookup_method
  walks the @ISA chain (embedded_types) bounded by CBM_LSP_MAX_LOOKUP_DEPTH.
- Call/method dispatch + emit: Package::sub() static, bare/imported func(),
  and typed-receiver $obj->m / Class->m / $self->m emit CBMResolvedCall.
  Unresolvable receivers emit NO edge (zero-edge guarantee); symbol-table
  aliasing ignored.

Tree-sitter-perl node/field names verified against the vendored compiled
grammar (parser.c ts_symbol_names/ts_field_names): method_call_expression uses
fields invocant+method; package_statement uses name; use_statement uses module;
variable_declaration target is field `variable` (singular). Documented in a
file-header comment.

Build green (scripts/build.sh); scripts/test.sh 3553 passed / 1 pre-existing
unrelated failure (search_code_multi_word). clang-format clean.

Signed-off-by: Shane McCarron <shane.mccarron@corvexconnect.com>
This commit is contained in:
Shane McCarron committed 2026-07-09 14:09:39 -05:00
1 parent 69c8155335
commit f0aa57c1c6
1 file changed
+1169 -49
File diff suppressed because it is too large. Load diff