feat(extract): VB6 class modules as Class + Methods (stacked on grammar PR) - #2087
feat(extract): VB6 class modules as Class + Methods (stacked on grammar PR)#2087Tokarzewski wants to merge 3 commits into
Conversation
|
Thanks for opening this — it has been seen, and it is queued. This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence. Current review status: working through a backlog. What that means for this PR, concretely:
Things that will genuinely speed it up whenever review does happen:
If this fixes a bug, a reproduction we can run is worth more than a description of the symptom. Thanks for contributing, and sorry in advance for the wait. |
Vendors tree-sitter-vba @ 63b2f8d0d65c (v0.13.0, MIT, ABI 15, lexer-only, no external scanner) as CBM_LANG_VB6 and wires it end to end: - discover: .bas/.ctl/.dsr/.pag map directly; .cls (Apex/ObjectScript) and .frm (FORM) keep their table owners and the DeusData#2074 content sniffers now route VB6 modules to CBM_LANG_VB6 instead of CBM_LANG_COUNT. - lang_specs: Sub/Function/Property Get|Let|Set/Declare/Event as callables; Type -> Class with typed Fields (As clause unwrapped); Enum -> Enum with members; module-level Dim/Const -> one Variable per declarator; call_statement/call_expression/raise_event_statement callees; Implements as import; VB6 keyword set; source_file module parents. - release surfaces: MANIFEST (163 grammars, 75x ABI-15, vba row + note on the locally generated parser.c), THIRD_PARTY, vendored checksums, new-languages.json, and the 162 -> 163 language-count claims on all seven contract surfaces. - tests: extension/sniff mapping, grammar regression + label golden, calls contract, extraction block, and the four repro registries (capability ledger, call-node manifest, invariant breadth, argument matrix B). Class-module synthesis (.cls/.frm as a Class with Methods) is a separate follow-up change. Refs DeusData#721. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Tokarzewski <bartlomiej.tokarzewski@gmail.com>
A VB6 .cls/.frm/.ctl/.dsr/.pag file is one COM class, but tree-sitter-vba has no class node, so the file's procedures surfaced as free Functions and the calls inside them were attributed to the Module. - helpers.c: cbm_vb6_is_class_module_path / cbm_vb6_file_class_name / cbm_vb6_file_class_qn resolve the class from `Attribute VB_Name` (file stem fallback). One helper feeds both extractors so the QNs cannot drift; it returns NULL for .bas standard modules and for every other language. - extract_defs.c: cbm_extract_definitions synthesises the Class def (bases from the designer `Begin VB.Form` type and every `Implements`) and runs the def walk with enclosing_class_qn set to it; extract_func_def promotes the file's procedures to Methods (QN class.name, parent_class set so DEFINES_METHOD links). - extract_unified.c: the scope-frame walker's baseline enclosing_class_qn starts as the file-class QN instead of NULL. push_scope saves and pop_expired_scopes restores that baseline exactly like any other frame value, so compute_func_qn yields class.name for every procedure and each in-body call sources to the Method, never the Module. No extra WalkState field is needed. Stacks on the VB6 grammar commit that introduces CBM_LANG_VB6. Refs DeusData#721. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Tokarzewski <bartlomiej.tokarzewski@gmail.com>
- grammar_regression: Widget.cls yields exactly one Class (base IShape), two Methods whose parent_class is the class QN, and no Function; the call inside Go carries enclosing_func_qn class.Go. ModA.bas yields no Class and no Method. - lang_contract: a Widget.cls CALL_CASES row, plus a dedicated contract that indexes the file through the production pipeline and checks the CALLS edge into Helper is sourced by the Method Go and by nothing else (a Module-sourced edge would surface the module's name as the caller). - extraction: vb6_implements_is_an_import (from the grammar commit) now expects Go in Widget.cls to be a Method, not a Function -- the class synthesis this series adds makes every .cls procedure a Method. Refs DeusData#721. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Tokarzewski <bartlomiej.tokarzewski@gmail.com>
45b28f0 to
9a7445e
Compare
|
This looks pre-existing and unrelated to this PR: the fixture tests the CI harness's own process-timeout/kill logic under synthetic subprocess trees, not extraction/parsing, and the failure text describes the test's own race precondition not being hit on this run rather than an assertion mismatch. I don't have rights to re-run the job on this repo. Happy to investigate further if it recurs or if you'd like a second opinion. |
What does this PR do?
Draft, stacked on #2086. Only the top two commits are this change; until that PR merges the diff here also shows its grammar commit. Rebased onto
main, this is an 8-file change (+379/−3). Opened as a draft so the design can be reviewed alongside the grammar — happy to fold it into the grammar PR, keep it separate, or drop it, whichever you prefer.Refs #721.
Why: a VB6
.cls/.frm/.ctl/.dsr/.pagfile is exactly one COM class, but the grammar has no class node. With the grammar PR alone every procedure in a class module is a freeFunction, and a VB6 project has noClassnodes, noDEFINES_METHODedges and noImplements/form inheritance in the graph.What it does:
Classper class-module file, named fromAttribute VB_Name = "…"(the IDE-written identity; falls back to the file stem), with base classes from the designer block type (Begin VB.Form Form1→VB.Form; GUID-typed blocks skipped) and everyImplements.Methods (class.Name,parent_classset →DEFINES_METHOD), and nestedType/Enumdeclarations nest under the class..basstandard modules are untouched (stillFunctions).enclosing_class_qnon every push and restores it on pop, so the seeding is one line incbm_extract_unified()— the baseline becomes the file-class QN for VB6 class modules and staysNULLfor everything else.compute_func_qnthen produces exactly the Method QN the def side mints; both sides derive the class QN from a single helper (cbm_vb6_file_class_qn), so they cannot drift. No new state field.Tests: regression —
Widget.clsyields 1Class(baseIShape), 2Methods, 0Functions, every Method'sparent_classis the class QN, and the call toHelperis attributed toclass.Go; a.basmodule yields no Class/Method. Contract — a.clsCALL_CASESrow pluscontract_vb6_class_module_calls_source_from_method, which indexes the fixture through the production pipeline and requires the only caller ofHelperto be the MethodGo(never the Module). Amends one assertion in the grammar PR'svb6_implements_is_an_import(Gois now aMethod).Open design points for you:
Property Get/Let/Settriplets share one QN (class.Name) and collapse to oneMethodnode — consistent on the def and call side, and the same collapse the grammar PR has for.bas. A.get/.let/.setsuffix would need matching changes on both sides.Declare … LibandEventdeclarations inside a.clsbecome Methods of that class (they are module members).Dim/Constin a.clsremain module-levelVariables rather than classFields — a possible follow-up.Checklist
git commit -s)language extraction grammar_regression grammar_labels lang_contract→ 628 passed, 0 failed;grammar_label_goldensunchanged;[CALLS-BREADTH] 56 langs: 0 FAILURES; language-count contract unchanged (this PR adds no grammar). CI's sanitised runs are authoritative.clang-format-20 --dry-run --Werrorclean onhelpers.c/.h,extract_defs.c,extract_unified.c/.h; cppcheck not run locally — relying on CI