Skip to main content

harn_parser/typechecker/
method_registry.rs

1//! Canonical builtin-method name tables.
2//!
3//! These lists mirror the method-dispatch match arms in the VM
4//! (`crates/harn-vm/src/vm/methods/*.rs`). They are the single source of
5//! truth the typechecker uses to decide whether a `receiver.method()` call
6//! names a method that actually exists on a *concrete* builtin receiver, so
7//! that `"x".frobnicate()` / `(3.14).frobnicate()` fail `harn check` instead
8//! of crashing (strings/lists/sets) or silently returning `nil` (numbers) at
9//! runtime.
10//!
11//! Drift guard: a test in `harn-vm` (`method_registry_matches_vm`) asserts
12//! every name here is accepted by the corresponding VM dispatch, so a stale
13//! entry can never produce a false "unknown method". When you add a method to
14//! a VM dispatch, add its name to the matching list below.
15
16/// `string` receiver methods (`call_string_method`), plus the universal
17/// `.iter()` bridge that `call_method_sync` handles for every iterable.
18pub const STRING_METHODS: &[&str] = &[
19    "count",
20    "empty",
21    "contains",
22    "includes",
23    "replace",
24    "split",
25    "trim",
26    "starts_with",
27    "ends_with",
28    "lowercase",
29    "uppercase",
30    "substring",
31    "slice",
32    "index_of",
33    "chars",
34    "repeat",
35    "reversed",
36    "reverse",
37    "pad_left",
38    "pad_right",
39    "trim_start",
40    "trim_end",
41    "lines",
42    "char_at",
43    "last_index_of",
44    "rfind",
45    "lower",
46    "to_lower",
47    "upper",
48    "to_upper",
49    "len",
50    "iter",
51];
52
53/// `list` receiver methods (`call_list_method_sync` + `call_list_method`),
54/// plus `.iter()`.
55pub const LIST_METHODS: &[&str] = &[
56    "count",
57    "empty",
58    "map",
59    "filter",
60    "find",
61    "flat_map",
62    "sorted_by",
63    "sort_by",
64    "partition",
65    "group_by",
66    "reduce",
67    "any",
68    "all",
69    "every",
70    "all?",
71    "sorted",
72    "sort",
73    "reversed",
74    "reverse",
75    "join",
76    "contains",
77    "includes",
78    "index_of",
79    "enumerate",
80    "zip",
81    "slice",
82    "unique",
83    "take",
84    "skip",
85    "sum",
86    "min",
87    "max",
88    "flatten",
89    "appending",
90    "push",
91    "dropping_last",
92    "pop",
93    "none",
94    "none?",
95    "find_index",
96    "first",
97    "last",
98    "chunk",
99    "each_slice",
100    "min_by",
101    "max_by",
102    "compact",
103    "window",
104    "each_cons",
105    "sliding_window",
106    "tally",
107    "to_list",
108    "to_set",
109    "take_while",
110    "drop_while",
111    "count_by",
112    "iter",
113];
114
115/// `set` receiver methods (`call_set_method_sync` + `call_set_method`), plus
116/// `.iter()`.
117pub const SET_METHODS: &[&str] = &[
118    "count",
119    "len",
120    "empty",
121    "contains",
122    "includes",
123    "adding",
124    "add",
125    "removing",
126    "remove",
127    "delete",
128    "union",
129    "intersect",
130    "intersection",
131    "difference",
132    "symmetric_difference",
133    "is_subset",
134    "is_superset",
135    "is_disjoint",
136    "to_list",
137    "to_set",
138    "map",
139    "filter",
140    "any",
141    "all",
142    "every",
143    "iter",
144];
145
146/// `dict` receiver methods (`call_dict_method_sync` + `call_dict_method`),
147/// plus `.iter()`. Dicts are *not* directly existence-checked (a dict may
148/// store a callable under a key and be invoked as `d.field()`), but their
149/// method names still belong to the recognized-method universe.
150pub const DICT_METHODS: &[&str] = &[
151    "keys",
152    "values",
153    "entries",
154    "count",
155    "has",
156    "merging",
157    "merge",
158    "map_values",
159    "rekeyed",
160    "rekey",
161    "map_keys",
162    "filter",
163    "removing",
164    "remove",
165    "get",
166    "to_dict",
167    "to_list",
168    "iter",
169];
170
171/// `range` receiver methods (`call_range_method_sync`), plus `.iter()`.
172pub const RANGE_METHODS: &[&str] = &[
173    "len",
174    "count",
175    "empty",
176    "contains",
177    "includes",
178    "first",
179    "last",
180    "to_string",
181    "iter",
182];
183
184/// `Iter<T>` combinators and sinks (`call_iter_method` + the lazy-iter arms
185/// in `infer_type`). Part of the recognized-method universe.
186pub const ITER_METHODS: &[&str] = &[
187    "iter",
188    "map",
189    "flat_map",
190    "filter",
191    "take",
192    "skip",
193    "take_while",
194    "skip_while",
195    "zip",
196    "enumerate",
197    "chain",
198    "chunks",
199    "windows",
200    "to_list",
201    "to_set",
202    "to_dict",
203    "count",
204    "sum",
205    "min",
206    "max",
207    "first",
208    "last",
209    "find",
210    "any",
211    "all",
212    "for_each",
213    "reduce",
214];
215
216/// Generator / stream drive methods (`call_generator_method`).
217pub const GENERATOR_METHODS: &[&str] = &["done", "next", "value"];
218
219/// True when `method` names a method on *any* builtin receiver. Used for the
220/// permissive tier (`int` / `float` / `bool`), whose VM dispatch either
221/// returns `nil` for every name (numbers) or has no methods at all (bool):
222/// there is no closed per-type set to check against, so we only reject names
223/// that are unknown everywhere — enough to catch typos like `frobnicate`
224/// without ever flagging a real method name.
225pub(super) fn is_any_known_builtin_method(method: &str) -> bool {
226    STRING_METHODS.contains(&method)
227        || LIST_METHODS.contains(&method)
228        || SET_METHODS.contains(&method)
229        || DICT_METHODS.contains(&method)
230        || RANGE_METHODS.contains(&method)
231        || ITER_METHODS.contains(&method)
232        || GENERATOR_METHODS.contains(&method)
233}