Skip to main content

doge_compiler/
stdlib.rs

1//! The compiler-side view of the standard library: the modules a `so` import can
2//! name, their members, and the `doge-runtime` function each member call wires to.
3//! Mirrors the runtime `stdlib` (like [`crate::builtins`] mirrors the builtin
4//! functions) — a member here must have a matching `{module}_{member}` function
5//! there.
6
7/// One callable member of a module: its arity, the runtime function a call emits,
8/// and the call-shape hint shown in arity diagnostics.
9pub struct ModuleFn {
10    pub name: &'static str,
11    pub arity: usize,
12    pub runtime_fn: &'static str,
13    pub hint: &'static str,
14}
15
16/// One importable module: its name, its function members, and its constant
17/// members (each a name paired with the Rust expression codegen emits inline).
18pub struct Module {
19    pub name: &'static str,
20    pub funcs: &'static [ModuleFn],
21    pub consts: &'static [(&'static str, &'static str)],
22}
23
24impl Module {
25    /// The function member `name`, if this module has one.
26    pub fn func(&self, name: &str) -> Option<&'static ModuleFn> {
27        self.funcs.iter().find(|f| f.name == name)
28    }
29
30    /// The Rust expression for the constant member `name`, if this module has one.
31    pub fn const_expr(&self, name: &str) -> Option<&'static str> {
32        self.consts
33            .iter()
34            .find(|(n, _)| *n == name)
35            .map(|(_, expr)| *expr)
36    }
37
38    /// Every member name, comma-joined, for the "unknown member" hint.
39    pub fn members(&self) -> String {
40        let mut names: Vec<&str> = self.funcs.iter().map(|f| f.name).collect();
41        names.extend(self.consts.iter().map(|(n, _)| *n));
42        names.join(", ")
43    }
44
45    /// The first member name, for hints that show one example call/value.
46    pub fn first_member(&self) -> &'static str {
47        self.funcs
48            .first()
49            .map(|f| f.name)
50            .or_else(|| self.consts.first().map(|(n, _)| *n))
51            .unwrap_or("")
52    }
53}
54
55/// The runtime function `pack.zoom` maps to. Both engines special-case it: the
56/// compiler hands it the pup trampoline plus a globals snapshot, and the
57/// interpreter routes it to its own thread-spawning path instead of the generic
58/// native dispatch. Kept in step with the `pack` module's `zoom` entry below.
59pub const PACK_ZOOM_RUNTIME_FN: &str = "pack_zoom";
60
61/// The module named `name`, if it exists.
62pub fn module(name: &str) -> Option<&'static Module> {
63    MODULES.iter().find(|m| m.name == name)
64}
65
66/// The comma-joined list of module names, for the "no such module" hint.
67pub(crate) fn module_names() -> String {
68    MODULES
69        .iter()
70        .map(|m| m.name)
71        .collect::<Vec<_>>()
72        .join(", ")
73}
74
75pub const MODULES: &[Module] = &[
76    Module {
77        name: "nerd",
78        funcs: &[
79            ModuleFn {
80                name: "abs",
81                arity: 1,
82                runtime_fn: "nerd_abs",
83                hint: "nerd.abs(x)",
84            },
85            ModuleFn {
86                name: "sqrt",
87                arity: 1,
88                runtime_fn: "nerd_sqrt",
89                hint: "nerd.sqrt(x)",
90            },
91            ModuleFn {
92                name: "floor",
93                arity: 1,
94                runtime_fn: "nerd_floor",
95                hint: "nerd.floor(x)",
96            },
97            ModuleFn {
98                name: "ceil",
99                arity: 1,
100                runtime_fn: "nerd_ceil",
101                hint: "nerd.ceil(x)",
102            },
103            ModuleFn {
104                name: "round",
105                arity: 1,
106                runtime_fn: "nerd_round",
107                hint: "nerd.round(x)",
108            },
109            ModuleFn {
110                name: "min",
111                arity: 2,
112                runtime_fn: "nerd_min",
113                hint: "nerd.min(a, b)",
114            },
115            ModuleFn {
116                name: "max",
117                arity: 2,
118                runtime_fn: "nerd_max",
119                hint: "nerd.max(a, b)",
120            },
121            ModuleFn {
122                name: "pow",
123                arity: 2,
124                runtime_fn: "nerd_pow",
125                hint: "nerd.pow(base, exponent)",
126            },
127        ],
128        consts: &[
129            ("pi", "Value::Float(std::f64::consts::PI)"),
130            ("e", "Value::Float(std::f64::consts::E)"),
131        ],
132    },
133    Module {
134        name: "strings",
135        funcs: &[
136            ModuleFn {
137                name: "beeg",
138                arity: 1,
139                runtime_fn: "strings_beeg",
140                hint: "strings.beeg(s)",
141            },
142            ModuleFn {
143                name: "smoll",
144                arity: 1,
145                runtime_fn: "strings_smoll",
146                hint: "strings.smoll(s)",
147            },
148            ModuleFn {
149                name: "trim",
150                arity: 1,
151                runtime_fn: "strings_trim",
152                hint: "strings.trim(s)",
153            },
154            ModuleFn {
155                name: "split",
156                arity: 2,
157                runtime_fn: "strings_split",
158                hint: "strings.split(s, sep)",
159            },
160            ModuleFn {
161                name: "join",
162                arity: 2,
163                runtime_fn: "strings_join",
164                hint: "strings.join(parts, sep)",
165            },
166            ModuleFn {
167                name: "contains",
168                arity: 2,
169                runtime_fn: "strings_contains",
170                hint: "strings.contains(s, needle)",
171            },
172            ModuleFn {
173                name: "replace",
174                arity: 3,
175                runtime_fn: "strings_replace",
176                hint: "strings.replace(s, from, to)",
177            },
178        ],
179        consts: &[],
180    },
181    Module {
182        name: "fetch",
183        funcs: &[
184            ModuleFn {
185                name: "read",
186                arity: 1,
187                runtime_fn: "fetch_read",
188                hint: "fetch.read(path)",
189            },
190            ModuleFn {
191                name: "write",
192                arity: 2,
193                runtime_fn: "fetch_write",
194                hint: "fetch.write(path, text)",
195            },
196            ModuleFn {
197                name: "append",
198                arity: 2,
199                runtime_fn: "fetch_append",
200                hint: "fetch.append(path, text)",
201            },
202            ModuleFn {
203                name: "exists",
204                arity: 1,
205                runtime_fn: "fetch_exists",
206                hint: "fetch.exists(path)",
207            },
208            ModuleFn {
209                name: "delete",
210                arity: 1,
211                runtime_fn: "fetch_delete",
212                hint: "fetch.delete(path)",
213            },
214        ],
215        consts: &[],
216    },
217    Module {
218        name: "env",
219        funcs: &[
220            ModuleFn {
221                name: "args",
222                arity: 0,
223                runtime_fn: "env_args",
224                hint: "env.args()",
225            },
226            ModuleFn {
227                name: "get",
228                arity: 1,
229                runtime_fn: "env_get",
230                hint: "env.get(name)",
231            },
232        ],
233        consts: &[],
234    },
235    Module {
236        name: "howl",
237        funcs: &[
238            ModuleFn {
239                name: "listen",
240                arity: 2,
241                runtime_fn: "howl_listen",
242                hint: "howl.listen(host, port)",
243            },
244            ModuleFn {
245                name: "connect",
246                arity: 2,
247                runtime_fn: "howl_connect",
248                hint: "howl.connect(host, port)",
249            },
250            ModuleFn {
251                name: "accept",
252                arity: 1,
253                runtime_fn: "howl_accept",
254                hint: "howl.accept(listener)",
255            },
256            ModuleFn {
257                name: "port",
258                arity: 1,
259                runtime_fn: "howl_port",
260                hint: "howl.port(sock)",
261            },
262            ModuleFn {
263                name: "send",
264                arity: 2,
265                runtime_fn: "howl_send",
266                hint: "howl.send(conn, text)",
267            },
268            ModuleFn {
269                name: "recv",
270                arity: 2,
271                runtime_fn: "howl_recv",
272                hint: "howl.recv(conn, max_bytes)",
273            },
274            ModuleFn {
275                name: "recv_line",
276                arity: 1,
277                runtime_fn: "howl_recv_line",
278                hint: "howl.recv_line(conn)",
279            },
280            ModuleFn {
281                name: "close",
282                arity: 1,
283                runtime_fn: "howl_close",
284                hint: "howl.close(sock)",
285            },
286            ModuleFn {
287                name: "get",
288                arity: 1,
289                runtime_fn: "howl_get",
290                hint: "howl.get(url)",
291            },
292            ModuleFn {
293                name: "post",
294                arity: 2,
295                runtime_fn: "howl_post",
296                hint: "howl.post(url, body)",
297            },
298        ],
299        consts: &[],
300    },
301    Module {
302        name: "json",
303        funcs: &[
304            ModuleFn {
305                name: "parse",
306                arity: 1,
307                runtime_fn: "json_parse",
308                hint: "json.parse(text)",
309            },
310            ModuleFn {
311                name: "emit",
312                arity: 1,
313                runtime_fn: "json_emit",
314                hint: "json.emit(value)",
315            },
316        ],
317        consts: &[],
318    },
319    Module {
320        name: "dson",
321        funcs: &[
322            ModuleFn {
323                name: "parse",
324                arity: 1,
325                runtime_fn: "dson_parse",
326                hint: "dson.parse(text)",
327            },
328            ModuleFn {
329                name: "emit",
330                arity: 1,
331                runtime_fn: "dson_emit",
332                hint: "dson.emit(value)",
333            },
334        ],
335        consts: &[],
336    },
337    Module {
338        name: "nap",
339        funcs: &[
340            ModuleFn {
341                name: "now",
342                arity: 0,
343                runtime_fn: "nap_now",
344                hint: "nap.now()",
345            },
346            ModuleFn {
347                name: "mono",
348                arity: 0,
349                runtime_fn: "nap_mono",
350                hint: "nap.mono()",
351            },
352            ModuleFn {
353                name: "rest",
354                arity: 1,
355                runtime_fn: "nap_rest",
356                hint: "nap.rest(seconds)",
357            },
358            ModuleFn {
359                name: "stamp",
360                arity: 1,
361                runtime_fn: "nap_stamp",
362                hint: "nap.stamp(secs)",
363            },
364            ModuleFn {
365                name: "parse",
366                arity: 1,
367                runtime_fn: "nap_parse",
368                hint: "nap.parse(text)",
369            },
370        ],
371        consts: &[],
372    },
373    Module {
374        name: "pack",
375        funcs: &[
376            // `zoom` is special in codegen: it also receives the generated pup
377            // trampoline and a snapshot of the globals (see `PACK_ZOOM_RUNTIME_FN`),
378            // so its two members here are the two the user actually writes.
379            ModuleFn {
380                name: "zoom",
381                arity: 2,
382                runtime_fn: PACK_ZOOM_RUNTIME_FN,
383                hint: "pack.zoom(f, [args])",
384            },
385            ModuleFn {
386                name: "fetch",
387                arity: 1,
388                runtime_fn: "pack_fetch",
389                hint: "pack.fetch(pup)",
390            },
391            ModuleFn {
392                name: "bowl",
393                arity: 0,
394                runtime_fn: "pack_bowl",
395                hint: "pack.bowl()",
396            },
397            ModuleFn {
398                name: "drop",
399                arity: 2,
400                runtime_fn: "pack_drop",
401                hint: "pack.drop(bowl, value)",
402            },
403            ModuleFn {
404                name: "sniff",
405                arity: 1,
406                runtime_fn: "pack_sniff",
407                hint: "pack.sniff(bowl)",
408            },
409        ],
410        consts: &[],
411    },
412    Module {
413        name: "roll",
414        funcs: &[
415            ModuleFn {
416                name: "seed",
417                arity: 1,
418                runtime_fn: "roll_seed",
419                hint: "roll.seed(n)",
420            },
421            ModuleFn {
422                name: "int",
423                arity: 2,
424                runtime_fn: "roll_int",
425                hint: "roll.int(low, high)",
426            },
427            ModuleFn {
428                name: "float",
429                arity: 0,
430                runtime_fn: "roll_float",
431                hint: "roll.float()",
432            },
433            ModuleFn {
434                name: "choice",
435                arity: 1,
436                runtime_fn: "roll_choice",
437                hint: "roll.choice(list)",
438            },
439            ModuleFn {
440                name: "shuffle",
441                arity: 1,
442                runtime_fn: "roll_shuffle",
443                hint: "roll.shuffle(list)",
444            },
445            ModuleFn {
446                name: "sample",
447                arity: 2,
448                runtime_fn: "roll_sample",
449                hint: "roll.sample(list, k)",
450            },
451        ],
452        consts: &[],
453    },
454];