Skip to content

Commit ae2cfb8

Browse files
committed
chore(fsharp): align npm grammar with cargo at v0.3.0
The WASM engine pulled tree-sitter-fsharp 0.1.0 from npm while the native engine used 0.3.0 from crates.io. The two versions diverged in how they parse type signatures in .fsi files: 0.1.0 emits `function_type` nodes for `a -> b` types, while 0.3.0 wraps every signature in `curried_spec` with `arguments_spec` children for function shapes. The F# extractor was forced to detect both shapes simultaneously, which is fragile — future grammar churn could silently desync further. * package.json now installs tree-sitter-fsharp from the ionide v0.3.0 GitHub tarball (npm has no 0.3.0 release; ionide is the upstream the cargo crate also tracks). Lockfile pins via SRI hash. * Both extractors now check only `curried_spec` → `arguments_spec`, removing the dead `function_type` branch from each. docs check acknowledged: README's F# row already covers .fs/.fsx/.fsi and the user-facing language count is unchanged; the grammar version is an internal implementation detail. Closes #1161
1 parent ce7297b commit ae2cfb8

4 files changed

Lines changed: 25 additions & 55 deletions

File tree

crates/codegraph-core/src/extractors/fsharp.rs

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -355,31 +355,15 @@ fn extract_value_name(decl_left: &Node, source: &[u8]) -> Option<String> {
355355
}
356356

357357
fn has_function_type(node: &Node) -> bool {
358-
// The two grammar versions use different node shapes for type signatures:
359-
//
360-
// • WASM (tree-sitter-fsharp npm 0.1.0): `function_type` is the explicit
361-
// function-type kind, only present for `a -> b` types.
362-
// • Native (tree-sitter-fsharp 0.3.0): every type signature is wrapped
363-
// in `curried_spec`. For a function it contains `arguments_spec`
364-
// children; for a plain value (e.g. `val pi : float`) it wraps a
365-
// single `simple_type`.
366-
//
367-
// Treat both engines consistently by classifying as a function whenever
368-
// a function_type node appears OR a curried_spec contains `arguments_spec`.
369-
for i in 0..node.child_count() {
370-
let Some(child) = node.child(i) else { continue };
371-
match child.kind() {
372-
"function_type" => return true,
373-
"curried_spec" => {
374-
for j in 0..child.child_count() {
375-
if let Some(g) = child.child(j) {
376-
if g.kind() == "arguments_spec" {
377-
return true;
378-
}
379-
}
380-
}
358+
// The grammar wraps every type signature in `curried_spec`. A function type
359+
// (e.g. `val add : int -> int -> int`) contains one or more `arguments_spec`
360+
// children; a plain value (e.g. `val pi : float`) wraps a single `simple_type`.
361+
let Some(curried) = find_child(node, "curried_spec") else { return false };
362+
for i in 0..curried.child_count() {
363+
if let Some(child) = curried.child(i) {
364+
if child.kind() == "arguments_spec" {
365+
return true;
381366
}
382-
_ => {}
383367
}
384368
}
385369
false

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@
162162
"tree-sitter-dart": "^1.0.0",
163163
"tree-sitter-elixir": "^0.3.5",
164164
"tree-sitter-erlang": "github:WhatsApp/tree-sitter-erlang#semver:*",
165-
"tree-sitter-fsharp": "^0.1.0",
165+
"tree-sitter-fsharp": "https://github.com/ionide/tree-sitter-fsharp/archive/refs/tags/0.3.0.tar.gz",
166166
"tree-sitter-gleam": "github:gleam-lang/tree-sitter-gleam",
167167
"tree-sitter-go": "^0.25.0",
168168
"tree-sitter-groovy": "^0.1.2",

src/extractors/fsharp.ts

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -280,31 +280,17 @@ function handleValueDefinition(
280280
findChild(pattern, 'identifier');
281281
if (!ident) return;
282282

283-
// The two grammar versions use different shapes for type signatures:
284-
// • WASM (npm tree-sitter-fsharp 0.1.0): `function_type` is the explicit
285-
// function-type kind, only present for `a -> b` types.
286-
// • Native (cargo tree-sitter-fsharp 0.3.0): every type signature is
287-
// wrapped in `curried_spec`. For a function it contains `arguments_spec`
288-
// children; for a plain value (e.g. `val pi : float`) it wraps a single
289-
// `simple_type`.
290-
// Treat both engines consistently by classifying as a function whenever
291-
// function_type appears OR a curried_spec contains an arguments_spec child.
283+
// The grammar wraps every type signature in `curried_spec`. A function type
284+
// (e.g. `val add : int -> int -> int`) contains one or more `arguments_spec`
285+
// children; a plain value (e.g. `val pi : float`) wraps a single `simple_type`.
286+
const curriedSpec = findChild(node, 'curried_spec');
292287
let hasFunctionType = false;
293-
for (let i = 0; i < node.childCount; i++) {
294-
const c = node.child(i);
295-
if (!c) continue;
296-
if (c.type === 'function_type') {
297-
hasFunctionType = true;
298-
break;
299-
}
300-
if (c.type === 'curried_spec') {
301-
for (let j = 0; j < c.childCount; j++) {
302-
if (c.child(j)?.type === 'arguments_spec') {
303-
hasFunctionType = true;
304-
break;
305-
}
288+
if (curriedSpec) {
289+
for (let i = 0; i < curriedSpec.childCount; i++) {
290+
if (curriedSpec.child(i)?.type === 'arguments_spec') {
291+
hasFunctionType = true;
292+
break;
306293
}
307-
if (hasFunctionType) break;
308294
}
309295
}
310296

0 commit comments

Comments
 (0)