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: "hunt",
183        funcs: &[
184            ModuleFn {
185                name: "test",
186                arity: 2,
187                runtime_fn: "hunt_test",
188                hint: "hunt.test(pat, text)",
189            },
190            ModuleFn {
191                name: "find",
192                arity: 2,
193                runtime_fn: "hunt_find",
194                hint: "hunt.find(pat, text)",
195            },
196            ModuleFn {
197                name: "find_all",
198                arity: 2,
199                runtime_fn: "hunt_find_all",
200                hint: "hunt.find_all(pat, text)",
201            },
202            ModuleFn {
203                name: "groups",
204                arity: 2,
205                runtime_fn: "hunt_groups",
206                hint: "hunt.groups(pat, text)",
207            },
208            ModuleFn {
209                name: "replace",
210                arity: 3,
211                runtime_fn: "hunt_replace",
212                hint: "hunt.replace(pat, text, repl)",
213            },
214        ],
215        consts: &[],
216    },
217    Module {
218        name: "fetch",
219        funcs: &[
220            ModuleFn {
221                name: "read",
222                arity: 1,
223                runtime_fn: "fetch_read",
224                hint: "fetch.read(path)",
225            },
226            ModuleFn {
227                name: "write",
228                arity: 2,
229                runtime_fn: "fetch_write",
230                hint: "fetch.write(path, text)",
231            },
232            ModuleFn {
233                name: "append",
234                arity: 2,
235                runtime_fn: "fetch_append",
236                hint: "fetch.append(path, text)",
237            },
238            ModuleFn {
239                name: "read_bytes",
240                arity: 1,
241                runtime_fn: "fetch_read_bytes",
242                hint: "fetch.read_bytes(path)",
243            },
244            ModuleFn {
245                name: "write_bytes",
246                arity: 2,
247                runtime_fn: "fetch_write_bytes",
248                hint: "fetch.write_bytes(path, bytes)",
249            },
250            ModuleFn {
251                name: "exists",
252                arity: 1,
253                runtime_fn: "fetch_exists",
254                hint: "fetch.exists(path)",
255            },
256            ModuleFn {
257                name: "delete",
258                arity: 1,
259                runtime_fn: "fetch_delete",
260                hint: "fetch.delete(path)",
261            },
262            ModuleFn {
263                name: "list",
264                arity: 1,
265                runtime_fn: "fetch_list",
266                hint: "fetch.list(path)",
267            },
268            ModuleFn {
269                name: "make_dir",
270                arity: 1,
271                runtime_fn: "fetch_make_dir",
272                hint: "fetch.make_dir(path)",
273            },
274            ModuleFn {
275                name: "remove_dir",
276                arity: 1,
277                runtime_fn: "fetch_remove_dir",
278                hint: "fetch.remove_dir(path)",
279            },
280            ModuleFn {
281                name: "rename",
282                arity: 2,
283                runtime_fn: "fetch_rename",
284                hint: "fetch.rename(from, to)",
285            },
286            ModuleFn {
287                name: "copy",
288                arity: 2,
289                runtime_fn: "fetch_copy",
290                hint: "fetch.copy(from, to)",
291            },
292            ModuleFn {
293                name: "stat",
294                arity: 1,
295                runtime_fn: "fetch_stat",
296                hint: "fetch.stat(path)",
297            },
298            ModuleFn {
299                name: "join",
300                arity: 2,
301                runtime_fn: "fetch_join",
302                hint: "fetch.join(a, b)",
303            },
304            ModuleFn {
305                name: "basename",
306                arity: 1,
307                runtime_fn: "fetch_basename",
308                hint: "fetch.basename(path)",
309            },
310            ModuleFn {
311                name: "ext",
312                arity: 1,
313                runtime_fn: "fetch_ext",
314                hint: "fetch.ext(path)",
315            },
316        ],
317        consts: &[],
318    },
319    Module {
320        name: "env",
321        funcs: &[
322            ModuleFn {
323                name: "args",
324                arity: 0,
325                runtime_fn: "env_args",
326                hint: "env.args()",
327            },
328            ModuleFn {
329                name: "get",
330                arity: 1,
331                runtime_fn: "env_get",
332                hint: "env.get(name)",
333            },
334        ],
335        consts: &[],
336    },
337    Module {
338        name: "howl",
339        funcs: &[
340            ModuleFn {
341                name: "listen",
342                arity: 2,
343                runtime_fn: "howl_listen",
344                hint: "howl.listen(host, port)",
345            },
346            ModuleFn {
347                name: "connect",
348                arity: 2,
349                runtime_fn: "howl_connect",
350                hint: "howl.connect(host, port)",
351            },
352            ModuleFn {
353                name: "accept",
354                arity: 1,
355                runtime_fn: "howl_accept",
356                hint: "howl.accept(listener)",
357            },
358            ModuleFn {
359                name: "port",
360                arity: 1,
361                runtime_fn: "howl_port",
362                hint: "howl.port(sock)",
363            },
364            ModuleFn {
365                name: "send",
366                arity: 2,
367                runtime_fn: "howl_send",
368                hint: "howl.send(conn, text)",
369            },
370            ModuleFn {
371                name: "recv",
372                arity: 2,
373                runtime_fn: "howl_recv",
374                hint: "howl.recv(conn, max_bytes)",
375            },
376            ModuleFn {
377                name: "recv_line",
378                arity: 1,
379                runtime_fn: "howl_recv_line",
380                hint: "howl.recv_line(conn)",
381            },
382            ModuleFn {
383                name: "close",
384                arity: 1,
385                runtime_fn: "howl_close",
386                hint: "howl.close(sock)",
387            },
388            ModuleFn {
389                name: "get",
390                arity: 1,
391                runtime_fn: "howl_get",
392                hint: "howl.get(url)",
393            },
394            ModuleFn {
395                name: "post",
396                arity: 2,
397                runtime_fn: "howl_post",
398                hint: "howl.post(url, body)",
399            },
400        ],
401        consts: &[],
402    },
403    Module {
404        name: "json",
405        funcs: &[
406            ModuleFn {
407                name: "parse",
408                arity: 1,
409                runtime_fn: "json_parse",
410                hint: "json.parse(text)",
411            },
412            ModuleFn {
413                name: "emit",
414                arity: 1,
415                runtime_fn: "json_emit",
416                hint: "json.emit(value)",
417            },
418        ],
419        consts: &[],
420    },
421    Module {
422        name: "dson",
423        funcs: &[
424            ModuleFn {
425                name: "parse",
426                arity: 1,
427                runtime_fn: "dson_parse",
428                hint: "dson.parse(text)",
429            },
430            ModuleFn {
431                name: "emit",
432                arity: 1,
433                runtime_fn: "dson_emit",
434                hint: "dson.emit(value)",
435            },
436        ],
437        consts: &[],
438    },
439    Module {
440        name: "nap",
441        funcs: &[
442            ModuleFn {
443                name: "now",
444                arity: 0,
445                runtime_fn: "nap_now",
446                hint: "nap.now()",
447            },
448            ModuleFn {
449                name: "mono",
450                arity: 0,
451                runtime_fn: "nap_mono",
452                hint: "nap.mono()",
453            },
454            ModuleFn {
455                name: "rest",
456                arity: 1,
457                runtime_fn: "nap_rest",
458                hint: "nap.rest(seconds)",
459            },
460            ModuleFn {
461                name: "stamp",
462                arity: 1,
463                runtime_fn: "nap_stamp",
464                hint: "nap.stamp(secs)",
465            },
466            ModuleFn {
467                name: "parse",
468                arity: 1,
469                runtime_fn: "nap_parse",
470                hint: "nap.parse(text)",
471            },
472        ],
473        consts: &[],
474    },
475    Module {
476        name: "pack",
477        funcs: &[
478            // `zoom` is special in codegen: it also receives the generated pup
479            // trampoline and a snapshot of the globals (see `PACK_ZOOM_RUNTIME_FN`),
480            // so its two members here are the two the user actually writes.
481            ModuleFn {
482                name: "zoom",
483                arity: 2,
484                runtime_fn: PACK_ZOOM_RUNTIME_FN,
485                hint: "pack.zoom(f, [args])",
486            },
487            ModuleFn {
488                name: "fetch",
489                arity: 1,
490                runtime_fn: "pack_fetch",
491                hint: "pack.fetch(pup)",
492            },
493            ModuleFn {
494                name: "bowl",
495                arity: 0,
496                runtime_fn: "pack_bowl",
497                hint: "pack.bowl()",
498            },
499            ModuleFn {
500                name: "drop",
501                arity: 2,
502                runtime_fn: "pack_drop",
503                hint: "pack.drop(bowl, value)",
504            },
505            ModuleFn {
506                name: "sniff",
507                arity: 1,
508                runtime_fn: "pack_sniff",
509                hint: "pack.sniff(bowl)",
510            },
511        ],
512        consts: &[],
513    },
514    Module {
515        name: "chase",
516        funcs: &[ModuleFn {
517            name: "run",
518            arity: 3,
519            runtime_fn: "chase_run",
520            hint: "chase.run(cmd, args, stdin)",
521        }],
522        consts: &[],
523    },
524    Module {
525        name: "roll",
526        funcs: &[
527            ModuleFn {
528                name: "seed",
529                arity: 1,
530                runtime_fn: "roll_seed",
531                hint: "roll.seed(n)",
532            },
533            ModuleFn {
534                name: "int",
535                arity: 2,
536                runtime_fn: "roll_int",
537                hint: "roll.int(low, high)",
538            },
539            ModuleFn {
540                name: "float",
541                arity: 0,
542                runtime_fn: "roll_float",
543                hint: "roll.float()",
544            },
545            ModuleFn {
546                name: "choice",
547                arity: 1,
548                runtime_fn: "roll_choice",
549                hint: "roll.choice(list)",
550            },
551            ModuleFn {
552                name: "shuffle",
553                arity: 1,
554                runtime_fn: "roll_shuffle",
555                hint: "roll.shuffle(list)",
556            },
557            ModuleFn {
558                name: "sample",
559                arity: 2,
560                runtime_fn: "roll_sample",
561                hint: "roll.sample(list, k)",
562            },
563        ],
564        consts: &[],
565    },
566];