You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Brings the tree-sitter walker to full parity with the Phase-1 regex
scanner on the three remaining ported kinds (raw-js,
untyped-exception, mutable-global), adds the two anti-patterns that
were explicitly deferred from Phase 1 because they need real AST
(inline-callback-record, oversized-function), and flips
--engine=walker to the default in main.ml.
Scope (per PR #322's "What is NOT in this PR" / Phase 2c plan):
- raw-js: any extension_expression node (covers %raw / %bs.raw).
- untyped-exception: try_expression, call_expression with function
text "raise", and member_expression / value_identifier_path whose
text starts with "Js.Exn" or ends with "Promise.catch".
- mutable-global: top-level let_declaration whose let_binding body
is a call to ref(), plus top-level mutation_expression (:=). The
"at module top level" predicate now walks the ancestor chain
outward, refusing if a function or let_binding body intervenes
before source_file / module_declaration.
- inline-callback-record: record literal or call_expression with
≥3 inline function values (directly, or wrapped in
labeled_argument / record_field). Threshold matches LESSONS.md.
- oversized-function: function node whose stop.row - start.row +1
exceeds 50 source rows.
Findings deduped by (kind, line) to match the regex scanner's
"one match per regex per line" contract. CLI default flips to
--engine=walker; the walker auto-falls-back to the scanner if the
vendored grammar is missing or tree-sitter parse fails (unchanged
fallback path from #322).
Tests
- test_walker.ml now exercises every kind on the existing
fixtures/sample.res (raw-js line 11, mutable-global lines 14+15,
untyped-exception lines 19/22/28). All gated on tree-sitter +
vendored grammar being present, same skip discipline as Phase 2b.
- New fixtures/phase2c.res exercises the two walker-only kinds:
a 4-field handlers record + a Widget.make call with 3 labelled-
argument lambdas (inline-callback-record), plus a let-bound
function spanning 60 source rows (oversized-function).
Docs
- tools/res-to-affine/README.md updated: walker is the default,
coverage matrix shows ✓ for all six kinds, what-gets-flagged
table replaces the old Phase-1/Phase-2 split.
- walker.mli docstring updated for Phase 2c scope.
- scanner.mli kind type extended with Inline_callback_record and
Oversized_function; scanner.ml gives them labels + guidance.
The scanner.ml scan pipeline is unchanged (these two kinds are
walker-only by construction).
Test plan
- [ ] CI build green (dune build + dune runtest).
- [ ] CI migration-assistant job green.
- [ ] Local: just install-grammar && dune runtest
tools/res-to-affine/ reports all walker tests OK.
Local-build caveat: container has no OCaml toolchain (per
CLAUDE.md §Agent operations notes); dune build / dune runtest
were not run locally. CI is the source of truth.
Refs #57
The output is **not compilable**. It is a starting point for the human:
@@ -36,8 +36,8 @@ needs re-decomposing.
36
36
37
37
|`--engine`| Implementation | When to use |
38
38
|---|---|---|
39
-
|`scanner` (default) |Line-anchored regex over the raw source (`scanner.ml`). | Default — no prerequisites, ships with the binary. |
40
-
|`walker`|Shells out to the vendored `tree-sitter` CLI, walks the AST (`walker.ml`). |When the regex's false-positive surface matters — eliminates the `let _ = chained.call()` class of misfire that the column-0 anchor in #319 had to band-aid. |
39
+
|`walker` (default) |Shells out to the vendored `tree-sitter` CLI, walks the AST (`walker.ml`). | Default since Phase 2c — covers all six anti-patterns including the two that the scanner cannot see (inline callback records, oversized functions) and eliminates the `let _ = chained.call()` / line-anchored false-positive classes. |
40
+
|`scanner`|Line-anchored regex over the raw source (`scanner.ml`). |Fallback when the vendored grammar is unavailable (no `tree-sitter` CLI, missing `tools/vendor/tree-sitter-rescript/`). Detects four of the six anti-patterns only. |
41
41
42
42
The walker requires the vendored `tree-sitter-rescript` grammar to be
43
43
built first:
@@ -50,42 +50,37 @@ just install-grammar
50
50
If the grammar isn't built or the `tree-sitter` CLI isn't on PATH, the
51
51
walker auto-falls-back to the scanner and prints the reason to stderr.
|`mutable-global`| Top-level `let x = ref(...)` (call-of-`ref` body) OR top-level `mutation_expression` (`x := y`) | Affine record threaded through |
64
+
|`inline-callback-record`| ≥ 3 inline `function` values in one `record` literal OR one call's `arguments` list (via `labeled_argument` or direct) | Row-polymorphic handler record (LESSONS.md §callback-record) |
65
+
|`oversized-function`|`function` node whose row span exceeds 50 source lines | Re-decompose before porting; do not transliterate |
0 commit comments