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    "pad_left",
37    "pad_right",
38    "trim_start",
39    "trim_end",
40    "lines",
41    "char_at",
42    "last_index_of",
43    "rfind",
44    "lower",
45    "to_lower",
46    "upper",
47    "to_upper",
48    "len",
49    "iter",
50];
51
52/// `list` receiver methods (`call_list_method_sync` + `call_list_method`),
53/// plus `.iter()`.
54pub const LIST_METHODS: &[&str] = &[
55    "count",
56    "empty",
57    "map",
58    "filter",
59    "find",
60    "flat_map",
61    "sorted_by",
62    "partition",
63    "group_by",
64    "reduce",
65    "any",
66    "all",
67    "every",
68    "all?",
69    "sorted",
70    "reversed",
71    "join",
72    "contains",
73    "includes",
74    "index_of",
75    "enumerate",
76    "zip",
77    "slice",
78    "unique",
79    "take",
80    "skip",
81    "sum",
82    "min",
83    "max",
84    "flatten",
85    "appending",
86    "dropping_last",
87    "none",
88    "none?",
89    "find_index",
90    "first",
91    "last",
92    "chunk",
93    "each_slice",
94    "min_by",
95    "max_by",
96    "compact",
97    "window",
98    "each_cons",
99    "sliding_window",
100    "tally",
101    "to_list",
102    "to_set",
103    "take_while",
104    "drop_while",
105    "count_by",
106    "iter",
107];
108
109/// `set` receiver methods (`call_set_method_sync` + `call_set_method`), plus
110/// `.iter()`.
111pub const SET_METHODS: &[&str] = &[
112    "count",
113    "len",
114    "empty",
115    "contains",
116    "includes",
117    "adding",
118    "removing",
119    "union",
120    "intersect",
121    "intersection",
122    "difference",
123    "symmetric_difference",
124    "is_subset",
125    "is_superset",
126    "is_disjoint",
127    "to_list",
128    "to_set",
129    "map",
130    "filter",
131    "any",
132    "all",
133    "every",
134    "iter",
135];
136
137/// `dict` receiver methods (`call_dict_method_sync` + `call_dict_method`),
138/// plus `.iter()`. Dicts are *not* directly existence-checked (a dict may
139/// store a callable under a key and be invoked as `d.field()`), but their
140/// method names still belong to the recognized-method universe.
141pub const DICT_METHODS: &[&str] = &[
142    "keys",
143    "values",
144    "entries",
145    "count",
146    "has",
147    "merging",
148    "map_values",
149    "rekeyed",
150    "map_keys",
151    "filter",
152    "removing",
153    "get",
154    "to_dict",
155    "to_list",
156    "iter",
157];
158
159/// `range` receiver methods (`call_range_method_sync`), plus `.iter()`.
160pub const RANGE_METHODS: &[&str] = &[
161    "len",
162    "count",
163    "empty",
164    "contains",
165    "includes",
166    "first",
167    "last",
168    "to_string",
169    "iter",
170];
171
172/// `Iter<T>` combinators and sinks (`call_iter_method` + the lazy-iter arms
173/// in `infer_type`). Part of the recognized-method universe.
174pub const ITER_METHODS: &[&str] = &[
175    "iter",
176    "map",
177    "flat_map",
178    "filter",
179    "take",
180    "skip",
181    "take_while",
182    "skip_while",
183    "zip",
184    "enumerate",
185    "chain",
186    "chunks",
187    "windows",
188    "to_list",
189    "to_set",
190    "to_dict",
191    "count",
192    "sum",
193    "min",
194    "max",
195    "first",
196    "last",
197    "find",
198    "any",
199    "all",
200    "for_each",
201    "reduce",
202];
203
204/// Generator / stream drive methods (`call_generator_method`).
205pub const GENERATOR_METHODS: &[&str] = &["done", "next", "value"];
206
207/// True when `method` names a method on *any* builtin receiver. Used for the
208/// permissive tier (`int` / `float` / `bool`), whose VM dispatch either
209/// returns `nil` for every name (numbers) or has no methods at all (bool):
210/// there is no closed per-type set to check against, so we only reject names
211/// that are unknown everywhere — enough to catch typos like `frobnicate`
212/// without ever flagging a real method name.
213pub(super) fn is_any_known_builtin_method(method: &str) -> bool {
214    STRING_METHODS.contains(&method)
215        || LIST_METHODS.contains(&method)
216        || SET_METHODS.contains(&method)
217        || DICT_METHODS.contains(&method)
218        || RANGE_METHODS.contains(&method)
219        || ITER_METHODS.contains(&method)
220        || GENERATOR_METHODS.contains(&method)
221}