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 module named `name`, if it exists.
56pub fn module(name: &str) -> Option<&'static Module> {
57    MODULES.iter().find(|m| m.name == name)
58}
59
60/// The comma-joined list of module names, for the "no such module" hint.
61pub(crate) fn module_names() -> String {
62    MODULES
63        .iter()
64        .map(|m| m.name)
65        .collect::<Vec<_>>()
66        .join(", ")
67}
68
69pub const MODULES: &[Module] = &[
70    Module {
71        name: "nerd",
72        funcs: &[
73            ModuleFn {
74                name: "abs",
75                arity: 1,
76                runtime_fn: "nerd_abs",
77                hint: "nerd.abs(x)",
78            },
79            ModuleFn {
80                name: "sqrt",
81                arity: 1,
82                runtime_fn: "nerd_sqrt",
83                hint: "nerd.sqrt(x)",
84            },
85            ModuleFn {
86                name: "floor",
87                arity: 1,
88                runtime_fn: "nerd_floor",
89                hint: "nerd.floor(x)",
90            },
91            ModuleFn {
92                name: "ceil",
93                arity: 1,
94                runtime_fn: "nerd_ceil",
95                hint: "nerd.ceil(x)",
96            },
97            ModuleFn {
98                name: "round",
99                arity: 1,
100                runtime_fn: "nerd_round",
101                hint: "nerd.round(x)",
102            },
103            ModuleFn {
104                name: "min",
105                arity: 2,
106                runtime_fn: "nerd_min",
107                hint: "nerd.min(a, b)",
108            },
109            ModuleFn {
110                name: "max",
111                arity: 2,
112                runtime_fn: "nerd_max",
113                hint: "nerd.max(a, b)",
114            },
115            ModuleFn {
116                name: "pow",
117                arity: 2,
118                runtime_fn: "nerd_pow",
119                hint: "nerd.pow(base, exponent)",
120            },
121        ],
122        consts: &[
123            ("pi", "Value::Float(std::f64::consts::PI)"),
124            ("e", "Value::Float(std::f64::consts::E)"),
125        ],
126    },
127    Module {
128        name: "strings",
129        funcs: &[
130            ModuleFn {
131                name: "beeg",
132                arity: 1,
133                runtime_fn: "strings_beeg",
134                hint: "strings.beeg(s)",
135            },
136            ModuleFn {
137                name: "smoll",
138                arity: 1,
139                runtime_fn: "strings_smoll",
140                hint: "strings.smoll(s)",
141            },
142            ModuleFn {
143                name: "trim",
144                arity: 1,
145                runtime_fn: "strings_trim",
146                hint: "strings.trim(s)",
147            },
148            ModuleFn {
149                name: "split",
150                arity: 2,
151                runtime_fn: "strings_split",
152                hint: "strings.split(s, sep)",
153            },
154            ModuleFn {
155                name: "join",
156                arity: 2,
157                runtime_fn: "strings_join",
158                hint: "strings.join(parts, sep)",
159            },
160            ModuleFn {
161                name: "contains",
162                arity: 2,
163                runtime_fn: "strings_contains",
164                hint: "strings.contains(s, needle)",
165            },
166            ModuleFn {
167                name: "replace",
168                arity: 3,
169                runtime_fn: "strings_replace",
170                hint: "strings.replace(s, from, to)",
171            },
172        ],
173        consts: &[],
174    },
175    Module {
176        name: "fetch",
177        funcs: &[
178            ModuleFn {
179                name: "read",
180                arity: 1,
181                runtime_fn: "fetch_read",
182                hint: "fetch.read(path)",
183            },
184            ModuleFn {
185                name: "write",
186                arity: 2,
187                runtime_fn: "fetch_write",
188                hint: "fetch.write(path, text)",
189            },
190            ModuleFn {
191                name: "append",
192                arity: 2,
193                runtime_fn: "fetch_append",
194                hint: "fetch.append(path, text)",
195            },
196            ModuleFn {
197                name: "exists",
198                arity: 1,
199                runtime_fn: "fetch_exists",
200                hint: "fetch.exists(path)",
201            },
202            ModuleFn {
203                name: "delete",
204                arity: 1,
205                runtime_fn: "fetch_delete",
206                hint: "fetch.delete(path)",
207            },
208        ],
209        consts: &[],
210    },
211    Module {
212        name: "env",
213        funcs: &[
214            ModuleFn {
215                name: "args",
216                arity: 0,
217                runtime_fn: "env_args",
218                hint: "env.args()",
219            },
220            ModuleFn {
221                name: "get",
222                arity: 1,
223                runtime_fn: "env_get",
224                hint: "env.get(name)",
225            },
226        ],
227        consts: &[],
228    },
229];