1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//! Go e2e method-call assertion helpers.
use crate::e2e::escape::go_string_literal;
use heck::ToUpperCamelCase;
/// Metadata about the return type of a Go method call for `method_result` assertions.
pub(super) struct GoMethodCallInfo {
/// The call expression string.
pub(super) call_expr: String,
/// Whether the return type is a pointer (needs `*` dereference for value comparison).
pub(super) is_pointer: bool,
/// Optional Go type cast to apply to numeric literal values in `equals` assertions
/// (e.g., `"uint"` so that `0` becomes `uint(0)` to match `*uint` deref type).
pub(super) value_cast: Option<&'static str>,
}
/// Build a Go call expression for a `method_result` assertion on a sample_language Tree.
///
/// Maps method names to the appropriate Go function calls, matching the Go binding API
/// in `packages/go/binding.go`. Returns a [`GoMethodCallInfo`] describing the call and
/// its return type characteristics.
///
/// Return types by method:
/// - `has_error_nodes`, `contains_node_type` → `*bool` (pointer)
/// - `error_count` → `*uint` (pointer, value_cast = "uint")
/// - `tree_to_sexp` → `*string` (pointer)
/// - `root_node_type` → `string` via `RootNodeInfo(tree).Kind` (value)
/// - `named_children_count` → `uint` via `RootNodeInfo(tree).NamedChildCount` (value, value_cast = "uint")
/// - `find_nodes_by_type` → `*[]NodeInfo` (pointer to slice)
/// - `run_query` → `(*[]QueryMatch, error)` (pointer + error; use `is_error` check type)
pub(super) fn build_go_method_call(
result_var: &str,
method_name: &str,
args: Option<&serde_json::Value>,
import_alias: &str,
) -> GoMethodCallInfo {
match method_name {
"root_node_type" => GoMethodCallInfo {
call_expr: format!("{import_alias}.RootNodeInfo({result_var}).Kind"),
is_pointer: false,
value_cast: None,
},
"named_children_count" => GoMethodCallInfo {
call_expr: format!("{import_alias}.RootNodeInfo({result_var}).NamedChildCount"),
is_pointer: false,
value_cast: Some("uint"),
},
"has_error_nodes" => GoMethodCallInfo {
call_expr: format!("{import_alias}.TreeHasErrorNodes({result_var})"),
is_pointer: true,
value_cast: None,
},
"error_count" | "tree_error_count" => GoMethodCallInfo {
call_expr: format!("{import_alias}.TreeErrorCount({result_var})"),
is_pointer: true,
value_cast: Some("uint"),
},
"tree_to_sexp" => GoMethodCallInfo {
call_expr: format!("{import_alias}.TreeToSexp({result_var})"),
is_pointer: true,
value_cast: None,
},
"contains_node_type" => {
let node_type = args
.and_then(|a| a.get("node_type"))
.and_then(|v| v.as_str())
.unwrap_or("");
GoMethodCallInfo {
call_expr: format!("{import_alias}.TreeContainsNodeType({result_var}, \"{node_type}\")"),
is_pointer: true,
value_cast: None,
}
}
"find_nodes_by_type" => {
let node_type = args
.and_then(|a| a.get("node_type"))
.and_then(|v| v.as_str())
.unwrap_or("");
GoMethodCallInfo {
call_expr: format!("{import_alias}.FindNodesByType({result_var}, \"{node_type}\")"),
is_pointer: true,
value_cast: None,
}
}
"run_query" => {
let query_source = args
.and_then(|a| a.get("query_source"))
.and_then(|v| v.as_str())
.unwrap_or("");
let language = args
.and_then(|a| a.get("language"))
.and_then(|v| v.as_str())
.unwrap_or("");
let query_lit = go_string_literal(query_source);
let lang_lit = go_string_literal(language);
// RunQuery returns (*[]QueryMatch, error) — use is_error check type.
GoMethodCallInfo {
call_expr: format!("{import_alias}.RunQuery({result_var}, {lang_lit}, {query_lit}, []byte(source))"),
is_pointer: false,
value_cast: None,
}
}
other => {
let method_pascal = other.to_upper_camel_case();
GoMethodCallInfo {
call_expr: format!("{result_var}.{method_pascal}()"),
is_pointer: false,
value_cast: None,
}
}
}
}