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. `arity` is the required
9/// positional-argument count; `optional == true` allows exactly one extra trailing
10/// argument, so the accepted range is `arity..=arity + 1` (an omitted trailing
11/// argument reaches the runtime function as `Value::None`).
12pub struct ModuleFn {
13    pub name: &'static str,
14    pub arity: usize,
15    pub optional: bool,
16    pub runtime_fn: &'static str,
17    pub hint: &'static str,
18}
19
20impl ModuleFn {
21    /// The largest argument count this member accepts.
22    pub fn max_arity(&self) -> usize {
23        self.arity + self.optional as usize
24    }
25}
26
27/// One importable module: its name, its function members, and its constant
28/// members (each a name paired with the Rust expression codegen emits inline).
29pub struct Module {
30    pub name: &'static str,
31    pub funcs: &'static [ModuleFn],
32    pub consts: &'static [(&'static str, &'static str)],
33}
34
35impl Module {
36    /// The function member `name`, if this module has one.
37    pub fn func(&self, name: &str) -> Option<&'static ModuleFn> {
38        self.funcs.iter().find(|f| f.name == name)
39    }
40
41    /// The Rust expression for the constant member `name`, if this module has one.
42    pub fn const_expr(&self, name: &str) -> Option<&'static str> {
43        self.consts
44            .iter()
45            .find(|(n, _)| *n == name)
46            .map(|(_, expr)| *expr)
47    }
48
49    /// Every member name, comma-joined, for the "unknown member" hint.
50    pub fn members(&self) -> String {
51        let mut names: Vec<&str> = self.funcs.iter().map(|f| f.name).collect();
52        names.extend(self.consts.iter().map(|(n, _)| *n));
53        names.join(", ")
54    }
55
56    /// The first member name, for hints that show one example call/value.
57    pub fn first_member(&self) -> &'static str {
58        self.funcs
59            .first()
60            .map(|f| f.name)
61            .or_else(|| self.consts.first().map(|(n, _)| *n))
62            .unwrap_or("")
63    }
64}
65
66/// The runtime function `pack.zoom` maps to. Both engines special-case it: the
67/// compiler hands it the pup trampoline plus a globals snapshot, and the
68/// interpreter routes it to its own thread-spawning path instead of the generic
69/// native dispatch. Kept in step with the `pack` module's `zoom` entry below.
70pub const PACK_ZOOM_RUNTIME_FN: &str = "pack_zoom";
71
72/// The module named `name`, if it exists.
73pub fn module(name: &str) -> Option<&'static Module> {
74    MODULES.iter().find(|m| m.name == name)
75}
76
77/// The comma-joined list of module names, for the "no such module" hint.
78pub(crate) fn module_names() -> String {
79    MODULES
80        .iter()
81        .map(|m| m.name)
82        .collect::<Vec<_>>()
83        .join(", ")
84}
85
86pub const MODULES: &[Module] = &[
87    Module {
88        name: "nerd",
89        funcs: &[
90            ModuleFn {
91                name: "abs",
92                arity: 1,
93                optional: false,
94                runtime_fn: "nerd_abs",
95                hint: "nerd.abs(x)",
96            },
97            ModuleFn {
98                name: "sqrt",
99                arity: 1,
100                optional: false,
101                runtime_fn: "nerd_sqrt",
102                hint: "nerd.sqrt(x)",
103            },
104            ModuleFn {
105                name: "floor",
106                arity: 1,
107                optional: false,
108                runtime_fn: "nerd_floor",
109                hint: "nerd.floor(x)",
110            },
111            ModuleFn {
112                name: "ceil",
113                arity: 1,
114                optional: false,
115                runtime_fn: "nerd_ceil",
116                hint: "nerd.ceil(x)",
117            },
118            ModuleFn {
119                name: "round",
120                arity: 1,
121                optional: false,
122                runtime_fn: "nerd_round",
123                hint: "nerd.round(x)",
124            },
125            ModuleFn {
126                name: "min",
127                arity: 2,
128                optional: false,
129                runtime_fn: "nerd_min",
130                hint: "nerd.min(a, b)",
131            },
132            ModuleFn {
133                name: "max",
134                arity: 2,
135                optional: false,
136                runtime_fn: "nerd_max",
137                hint: "nerd.max(a, b)",
138            },
139            ModuleFn {
140                name: "pow",
141                arity: 2,
142                optional: false,
143                runtime_fn: "nerd_pow",
144                hint: "nerd.pow(base, exponent)",
145            },
146        ],
147        consts: &[
148            ("pi", "Value::Float(std::f64::consts::PI)"),
149            ("e", "Value::Float(std::f64::consts::E)"),
150        ],
151    },
152    Module {
153        name: "strings",
154        funcs: &[
155            ModuleFn {
156                name: "beeg",
157                arity: 1,
158                optional: false,
159                runtime_fn: "strings_beeg",
160                hint: "strings.beeg(s)",
161            },
162            ModuleFn {
163                name: "smoll",
164                arity: 1,
165                optional: false,
166                runtime_fn: "strings_smoll",
167                hint: "strings.smoll(s)",
168            },
169            ModuleFn {
170                name: "trim",
171                arity: 1,
172                optional: false,
173                runtime_fn: "strings_trim",
174                hint: "strings.trim(s)",
175            },
176            ModuleFn {
177                name: "split",
178                arity: 2,
179                optional: false,
180                runtime_fn: "strings_split",
181                hint: "strings.split(s, sep)",
182            },
183            ModuleFn {
184                name: "join",
185                arity: 2,
186                optional: false,
187                runtime_fn: "strings_join",
188                hint: "strings.join(parts, sep)",
189            },
190            ModuleFn {
191                name: "contains",
192                arity: 2,
193                optional: false,
194                runtime_fn: "strings_contains",
195                hint: "strings.contains(s, needle)",
196            },
197            ModuleFn {
198                name: "replace",
199                arity: 3,
200                optional: false,
201                runtime_fn: "strings_replace",
202                hint: "strings.replace(s, from, to)",
203            },
204        ],
205        consts: &[],
206    },
207    Module {
208        name: "hunt",
209        funcs: &[
210            ModuleFn {
211                name: "test",
212                arity: 2,
213                optional: false,
214                runtime_fn: "hunt_test",
215                hint: "hunt.test(pat, text)",
216            },
217            ModuleFn {
218                name: "find",
219                arity: 2,
220                optional: false,
221                runtime_fn: "hunt_find",
222                hint: "hunt.find(pat, text)",
223            },
224            ModuleFn {
225                name: "find_all",
226                arity: 2,
227                optional: false,
228                runtime_fn: "hunt_find_all",
229                hint: "hunt.find_all(pat, text)",
230            },
231            ModuleFn {
232                name: "groups",
233                arity: 2,
234                optional: false,
235                runtime_fn: "hunt_groups",
236                hint: "hunt.groups(pat, text)",
237            },
238            ModuleFn {
239                name: "replace",
240                arity: 3,
241                optional: false,
242                runtime_fn: "hunt_replace",
243                hint: "hunt.replace(pat, text, repl)",
244            },
245        ],
246        consts: &[],
247    },
248    Module {
249        name: "fetch",
250        funcs: &[
251            ModuleFn {
252                name: "read",
253                arity: 1,
254                optional: false,
255                runtime_fn: "fetch_read",
256                hint: "fetch.read(path)",
257            },
258            ModuleFn {
259                name: "write",
260                arity: 2,
261                optional: false,
262                runtime_fn: "fetch_write",
263                hint: "fetch.write(path, text)",
264            },
265            ModuleFn {
266                name: "append",
267                arity: 2,
268                optional: false,
269                runtime_fn: "fetch_append",
270                hint: "fetch.append(path, text)",
271            },
272            ModuleFn {
273                name: "read_bytes",
274                arity: 1,
275                optional: false,
276                runtime_fn: "fetch_read_bytes",
277                hint: "fetch.read_bytes(path)",
278            },
279            ModuleFn {
280                name: "write_bytes",
281                arity: 2,
282                optional: false,
283                runtime_fn: "fetch_write_bytes",
284                hint: "fetch.write_bytes(path, bytes)",
285            },
286            ModuleFn {
287                name: "exists",
288                arity: 1,
289                optional: false,
290                runtime_fn: "fetch_exists",
291                hint: "fetch.exists(path)",
292            },
293            ModuleFn {
294                name: "delete",
295                arity: 1,
296                optional: false,
297                runtime_fn: "fetch_delete",
298                hint: "fetch.delete(path)",
299            },
300            ModuleFn {
301                name: "list",
302                arity: 1,
303                optional: false,
304                runtime_fn: "fetch_list",
305                hint: "fetch.list(path)",
306            },
307            ModuleFn {
308                name: "make_dir",
309                arity: 1,
310                optional: false,
311                runtime_fn: "fetch_make_dir",
312                hint: "fetch.make_dir(path)",
313            },
314            ModuleFn {
315                name: "remove_dir",
316                arity: 1,
317                optional: false,
318                runtime_fn: "fetch_remove_dir",
319                hint: "fetch.remove_dir(path)",
320            },
321            ModuleFn {
322                name: "rename",
323                arity: 2,
324                optional: false,
325                runtime_fn: "fetch_rename",
326                hint: "fetch.rename(from, to)",
327            },
328            ModuleFn {
329                name: "copy",
330                arity: 2,
331                optional: false,
332                runtime_fn: "fetch_copy",
333                hint: "fetch.copy(from, to)",
334            },
335            ModuleFn {
336                name: "stat",
337                arity: 1,
338                optional: false,
339                runtime_fn: "fetch_stat",
340                hint: "fetch.stat(path)",
341            },
342            ModuleFn {
343                name: "join",
344                arity: 2,
345                optional: false,
346                runtime_fn: "fetch_join",
347                hint: "fetch.join(a, b)",
348            },
349            ModuleFn {
350                name: "basename",
351                arity: 1,
352                optional: false,
353                runtime_fn: "fetch_basename",
354                hint: "fetch.basename(path)",
355            },
356            ModuleFn {
357                name: "ext",
358                arity: 1,
359                optional: false,
360                runtime_fn: "fetch_ext",
361                hint: "fetch.ext(path)",
362            },
363        ],
364        consts: &[],
365    },
366    Module {
367        name: "env",
368        funcs: &[
369            ModuleFn {
370                name: "args",
371                arity: 0,
372                optional: false,
373                runtime_fn: "env_args",
374                hint: "env.args()",
375            },
376            ModuleFn {
377                name: "get",
378                arity: 1,
379                optional: false,
380                runtime_fn: "env_get",
381                hint: "env.get(name)",
382            },
383        ],
384        consts: &[],
385    },
386    Module {
387        name: "howl",
388        funcs: &[
389            ModuleFn {
390                name: "listen",
391                arity: 2,
392                optional: false,
393                runtime_fn: "howl_listen",
394                hint: "howl.listen(host, port)",
395            },
396            ModuleFn {
397                name: "connect",
398                arity: 2,
399                optional: false,
400                runtime_fn: "howl_connect",
401                hint: "howl.connect(host, port)",
402            },
403            ModuleFn {
404                name: "accept",
405                arity: 1,
406                optional: false,
407                runtime_fn: "howl_accept",
408                hint: "howl.accept(listener)",
409            },
410            ModuleFn {
411                name: "port",
412                arity: 1,
413                optional: false,
414                runtime_fn: "howl_port",
415                hint: "howl.port(sock)",
416            },
417            ModuleFn {
418                name: "send",
419                arity: 2,
420                optional: false,
421                runtime_fn: "howl_send",
422                hint: "howl.send(conn, text)",
423            },
424            ModuleFn {
425                name: "send_bytes",
426                arity: 2,
427                optional: false,
428                runtime_fn: "howl_send_bytes",
429                hint: "howl.send_bytes(conn, bytes)",
430            },
431            ModuleFn {
432                name: "recv",
433                arity: 2,
434                optional: false,
435                runtime_fn: "howl_recv",
436                hint: "howl.recv(conn, max_bytes)",
437            },
438            ModuleFn {
439                name: "recv_bytes",
440                arity: 2,
441                optional: false,
442                runtime_fn: "howl_recv_bytes",
443                hint: "howl.recv_bytes(conn, max_bytes)",
444            },
445            ModuleFn {
446                name: "recv_line",
447                arity: 1,
448                optional: false,
449                runtime_fn: "howl_recv_line",
450                hint: "howl.recv_line(conn)",
451            },
452            ModuleFn {
453                name: "close",
454                arity: 1,
455                optional: false,
456                runtime_fn: "howl_close",
457                hint: "howl.close(sock)",
458            },
459            ModuleFn {
460                name: "get",
461                arity: 1,
462                optional: false,
463                runtime_fn: "howl_get",
464                hint: "howl.get(url)",
465            },
466            ModuleFn {
467                name: "post",
468                arity: 2,
469                optional: false,
470                runtime_fn: "howl_post",
471                hint: "howl.post(url, body)",
472            },
473            ModuleFn {
474                name: "request",
475                arity: 2,
476                optional: true,
477                runtime_fn: "howl_request",
478                hint: "howl.request(method, url) or howl.request(method, url, opts)",
479            },
480        ],
481        consts: &[],
482    },
483    Module {
484        name: "json",
485        funcs: &[
486            ModuleFn {
487                name: "parse",
488                arity: 1,
489                optional: false,
490                runtime_fn: "json_parse",
491                hint: "json.parse(text)",
492            },
493            ModuleFn {
494                name: "emit",
495                arity: 1,
496                optional: false,
497                runtime_fn: "json_emit",
498                hint: "json.emit(value)",
499            },
500        ],
501        consts: &[],
502    },
503    Module {
504        name: "dson",
505        funcs: &[
506            ModuleFn {
507                name: "parse",
508                arity: 1,
509                optional: false,
510                runtime_fn: "dson_parse",
511                hint: "dson.parse(text)",
512            },
513            ModuleFn {
514                name: "emit",
515                arity: 1,
516                optional: false,
517                runtime_fn: "dson_emit",
518                hint: "dson.emit(value)",
519            },
520        ],
521        consts: &[],
522    },
523    Module {
524        name: "nap",
525        funcs: &[
526            ModuleFn {
527                name: "now",
528                arity: 0,
529                optional: false,
530                runtime_fn: "nap_now",
531                hint: "nap.now()",
532            },
533            ModuleFn {
534                name: "mono",
535                arity: 0,
536                optional: false,
537                runtime_fn: "nap_mono",
538                hint: "nap.mono()",
539            },
540            ModuleFn {
541                name: "rest",
542                arity: 1,
543                optional: false,
544                runtime_fn: "nap_rest",
545                hint: "nap.rest(seconds)",
546            },
547            ModuleFn {
548                name: "stamp",
549                arity: 1,
550                optional: false,
551                runtime_fn: "nap_stamp",
552                hint: "nap.stamp(secs)",
553            },
554            ModuleFn {
555                name: "parse",
556                arity: 1,
557                optional: false,
558                runtime_fn: "nap_parse",
559                hint: "nap.parse(text)",
560            },
561        ],
562        consts: &[],
563    },
564    Module {
565        name: "pack",
566        funcs: &[
567            // `zoom` is special in codegen: it also receives the generated pup
568            // trampoline and a snapshot of the globals (see `PACK_ZOOM_RUNTIME_FN`),
569            // so its two members here are the two the user actually writes.
570            ModuleFn {
571                name: "zoom",
572                arity: 2,
573                optional: false,
574                runtime_fn: PACK_ZOOM_RUNTIME_FN,
575                hint: "pack.zoom(f, [args])",
576            },
577            ModuleFn {
578                name: "fetch",
579                arity: 1,
580                optional: false,
581                runtime_fn: "pack_fetch",
582                hint: "pack.fetch(pup)",
583            },
584            ModuleFn {
585                name: "bowl",
586                arity: 0,
587                optional: false,
588                runtime_fn: "pack_bowl",
589                hint: "pack.bowl()",
590            },
591            ModuleFn {
592                name: "drop",
593                arity: 2,
594                optional: false,
595                runtime_fn: "pack_drop",
596                hint: "pack.drop(bowl, value)",
597            },
598            ModuleFn {
599                name: "sniff",
600                arity: 1,
601                optional: false,
602                runtime_fn: "pack_sniff",
603                hint: "pack.sniff(bowl)",
604            },
605        ],
606        consts: &[],
607    },
608    Module {
609        name: "chase",
610        funcs: &[ModuleFn {
611            name: "run",
612            arity: 3,
613            optional: false,
614            runtime_fn: "chase_run",
615            hint: "chase.run(cmd, args, stdin)",
616        }],
617        consts: &[],
618    },
619    Module {
620        name: "roll",
621        funcs: &[
622            ModuleFn {
623                name: "seed",
624                arity: 1,
625                optional: false,
626                runtime_fn: "roll_seed",
627                hint: "roll.seed(n)",
628            },
629            ModuleFn {
630                name: "int",
631                arity: 2,
632                optional: false,
633                runtime_fn: "roll_int",
634                hint: "roll.int(low, high)",
635            },
636            ModuleFn {
637                name: "float",
638                arity: 0,
639                optional: false,
640                runtime_fn: "roll_float",
641                hint: "roll.float()",
642            },
643            ModuleFn {
644                name: "choice",
645                arity: 1,
646                optional: false,
647                runtime_fn: "roll_choice",
648                hint: "roll.choice(list)",
649            },
650            ModuleFn {
651                name: "shuffle",
652                arity: 1,
653                optional: false,
654                runtime_fn: "roll_shuffle",
655                hint: "roll.shuffle(list)",
656            },
657            ModuleFn {
658                name: "sample",
659                arity: 2,
660                optional: false,
661                runtime_fn: "roll_sample",
662                hint: "roll.sample(list, k)",
663            },
664        ],
665        consts: &[],
666    },
667    Module {
668        name: "crypto",
669        funcs: &[
670            ModuleFn {
671                name: "sha256",
672                arity: 1,
673                optional: false,
674                runtime_fn: "crypto_sha256",
675                hint: "crypto.sha256(data)",
676            },
677            ModuleFn {
678                name: "hmac_sha256",
679                arity: 2,
680                optional: false,
681                runtime_fn: "crypto_hmac_sha256",
682                hint: "crypto.hmac_sha256(key, data)",
683            },
684            ModuleFn {
685                name: "token",
686                arity: 1,
687                optional: false,
688                runtime_fn: "crypto_token",
689                hint: "crypto.token(n)",
690            },
691            ModuleFn {
692                name: "same",
693                arity: 2,
694                optional: false,
695                runtime_fn: "crypto_same",
696                hint: "crypto.same(a, b)",
697            },
698        ],
699        consts: &[],
700    },
701];