Skip to main content

pepl_compiler/
stdlib.rs

1//! Standard library function signature registry.
2//!
3//! Registers all 100 Phase 0 stdlib function signatures + 2 constants so the type checker
4//! can validate qualified calls like `math.abs(x)`.
5
6use std::collections::HashMap;
7
8use crate::ty::{FnSig, Type};
9
10/// Registry mapping `(module, function)` → function signature.
11#[derive(Debug)]
12pub struct StdlibRegistry {
13    modules: HashMap<String, HashMap<String, FnSig>>,
14    /// Module-level constants: `(module, name)` → Type.
15    constants: HashMap<String, HashMap<String, Type>>,
16}
17
18impl StdlibRegistry {
19    /// Create a new registry with all 100 Phase 0 stdlib functions + 2 constants.
20    pub fn new() -> Self {
21        let mut reg = Self {
22            modules: HashMap::new(),
23            constants: HashMap::new(),
24        };
25        reg.register_core();
26        reg.register_math();
27        reg.register_string();
28        reg.register_list();
29        reg.register_record();
30        reg.register_time();
31        reg.register_convert();
32        reg.register_json();
33        reg.register_timer();
34        reg.register_http();
35        reg.register_storage();
36        reg.register_location();
37        reg.register_notifications();
38        reg
39    }
40
41    /// Look up a function signature by module and function name.
42    pub fn get(&self, module: &str, function: &str) -> Option<&FnSig> {
43        self.modules.get(module)?.get(function)
44    }
45
46    /// Check if a module exists.
47    pub fn has_module(&self, module: &str) -> bool {
48        self.modules.contains_key(module) || self.constants.contains_key(module)
49    }
50
51    /// Look up a constant by module and name.
52    pub fn get_constant(&self, module: &str, name: &str) -> Option<&Type> {
53        self.constants.get(module)?.get(name)
54    }
55
56    /// Iterate over all registered modules and their functions.
57    pub fn modules(&self) -> &HashMap<String, HashMap<String, FnSig>> {
58        &self.modules
59    }
60
61    /// Iterate over all registered constants.
62    pub fn all_constants(&self) -> &HashMap<String, HashMap<String, Type>> {
63        &self.constants
64    }
65
66    // ──────────────────────────────────────────────────────────────────────
67    // Registration helpers
68    // ──────────────────────────────────────────────────────────────────────
69
70    fn add(&mut self, module: &str, name: &str, sig: FnSig) {
71        self.modules
72            .entry(module.to_string())
73            .or_default()
74            .insert(name.to_string(), sig);
75    }
76
77    fn add_const(&mut self, module: &str, name: &str, ty: Type) {
78        self.constants
79            .entry(module.to_string())
80            .or_default()
81            .insert(name.to_string(), ty);
82    }
83
84    fn sig(params: Vec<(&str, Type)>, ret: Type) -> FnSig {
85        FnSig {
86            params: params
87                .into_iter()
88                .map(|(n, t)| (n.to_string(), t))
89                .collect(),
90            ret,
91            variadic: false,
92        }
93    }
94
95    fn variadic_sig(params: Vec<(&str, Type)>, ret: Type) -> FnSig {
96        FnSig {
97            params: params
98                .into_iter()
99                .map(|(n, t)| (n.to_string(), t))
100                .collect(),
101            ret,
102            variadic: true,
103        }
104    }
105
106    // ══════════════════════════════════════════════════════════════════════
107    // Module registration (100 functions + 2 constants)
108    // ══════════════════════════════════════════════════════════════════════
109
110    /// core: 4 functions
111    fn register_core(&mut self) {
112        use Type::*;
113        self.add("core", "log", Self::sig(vec![("value", Any)], Nil));
114        self.add(
115            "core",
116            "assert",
117            Self::sig(vec![("condition", Bool), ("message", String)], Nil),
118        );
119        self.add("core", "type_of", Self::sig(vec![("value", Any)], String));
120        self.add(
121            "core",
122            "capability",
123            Self::sig(vec![("name", String)], Bool),
124        );
125    }
126
127    /// math: 10 functions + 2 constants (PI, E)
128    fn register_math(&mut self) {
129        use Type::*;
130        self.add("math", "abs", Self::sig(vec![("x", Number)], Number));
131        self.add(
132            "math",
133            "min",
134            Self::sig(vec![("a", Number), ("b", Number)], Number),
135        );
136        self.add(
137            "math",
138            "max",
139            Self::sig(vec![("a", Number), ("b", Number)], Number),
140        );
141        self.add("math", "floor", Self::sig(vec![("x", Number)], Number));
142        self.add("math", "ceil", Self::sig(vec![("x", Number)], Number));
143        self.add("math", "round", Self::sig(vec![("x", Number)], Number));
144        self.add(
145            "math",
146            "round_to",
147            Self::sig(vec![("x", Number), ("decimals", Number)], Number),
148        );
149        self.add(
150            "math",
151            "pow",
152            Self::sig(vec![("base", Number), ("exp", Number)], Number),
153        );
154        self.add(
155            "math",
156            "clamp",
157            Self::sig(vec![("x", Number), ("min", Number), ("max", Number)], Number),
158        );
159        self.add("math", "sqrt", Self::sig(vec![("x", Number)], Number));
160
161        // Constants
162        self.add_const("math", "PI", Number);
163        self.add_const("math", "E", Number);
164    }
165
166    /// string: 20 functions
167    fn register_string(&mut self) {
168        use Type::*;
169        self.add(
170            "string",
171            "length",
172            Self::sig(vec![("s", String)], Number),
173        );
174        self.add(
175            "string",
176            "concat",
177            Self::sig(vec![("a", String), ("b", String)], String),
178        );
179        self.add(
180            "string",
181            "contains",
182            Self::sig(vec![("s", String), ("substr", String)], Bool),
183        );
184        self.add(
185            "string",
186            "slice",
187            Self::sig(
188                vec![("s", String), ("start", Number), ("end", Number)],
189                String,
190            ),
191        );
192        self.add("string", "trim", Self::sig(vec![("s", String)], String));
193        self.add(
194            "string",
195            "split",
196            Self::sig(
197                vec![("s", String), ("delimiter", String)],
198                List(Box::new(String)),
199            ),
200        );
201        self.add(
202            "string",
203            "to_upper",
204            Self::sig(vec![("s", String)], String),
205        );
206        self.add(
207            "string",
208            "to_lower",
209            Self::sig(vec![("s", String)], String),
210        );
211        self.add(
212            "string",
213            "starts_with",
214            Self::sig(vec![("s", String), ("prefix", String)], Bool),
215        );
216        self.add(
217            "string",
218            "ends_with",
219            Self::sig(vec![("s", String), ("suffix", String)], Bool),
220        );
221        self.add(
222            "string",
223            "replace",
224            Self::sig(
225                vec![("s", String), ("from", String), ("to", String)],
226                String,
227            ),
228        );
229        self.add(
230            "string",
231            "replace_all",
232            Self::sig(
233                vec![("s", String), ("from", String), ("to", String)],
234                String,
235            ),
236        );
237        self.add(
238            "string",
239            "pad_start",
240            Self::sig(
241                vec![("s", String), ("length", Number), ("pad", String)],
242                String,
243            ),
244        );
245        self.add(
246            "string",
247            "pad_end",
248            Self::sig(
249                vec![("s", String), ("length", Number), ("pad", String)],
250                String,
251            ),
252        );
253        self.add(
254            "string",
255            "repeat",
256            Self::sig(vec![("s", String), ("count", Number)], String),
257        );
258        self.add(
259            "string",
260            "join",
261            Self::sig(
262                vec![("items", List(Box::new(String))), ("separator", String)],
263                String,
264            ),
265        );
266        self.add(
267            "string",
268            "format",
269            Self::sig(
270                vec![("template", String), ("values", Record(vec![]))],
271                String,
272            ),
273        );
274        self.add("string", "from", Self::sig(vec![("value", Any)], String));
275        self.add(
276            "string",
277            "is_empty",
278            Self::sig(vec![("s", String)], Bool),
279        );
280        self.add(
281            "string",
282            "index_of",
283            Self::sig(vec![("s", String), ("substr", String)], Number),
284        );
285    }
286
287    /// list: 34 functions
288    fn register_list(&mut self) {
289        use Type::*;
290        let t = || Any; // Generic T placeholder
291        let list_t = || List(Box::new(Any));
292
293        // Construction
294        self.add("list", "empty", Self::sig(vec![], list_t()));
295        self.add("list", "of", Self::variadic_sig(vec![("items", t())], list_t()));
296        self.add(
297            "list",
298            "repeat",
299            Self::sig(vec![("value", t()), ("count", Number)], list_t()),
300        );
301        self.add(
302            "list",
303            "range",
304            Self::sig(vec![("start", Number), ("end", Number)], List(Box::new(Number))),
305        );
306
307        // Access
308        self.add(
309            "list",
310            "length",
311            Self::sig(vec![("items", list_t())], Number),
312        );
313        self.add(
314            "list",
315            "get",
316            Self::sig(vec![("items", list_t()), ("index", Number)], t()),
317        );
318        self.add(
319            "list",
320            "first",
321            Self::sig(vec![("items", list_t())], t()),
322        );
323        self.add(
324            "list",
325            "last",
326            Self::sig(vec![("items", list_t())], t()),
327        );
328        self.add(
329            "list",
330            "index_of",
331            Self::sig(vec![("items", list_t()), ("value", t())], Number),
332        );
333
334        // Modification (immutable — returns new list)
335        self.add(
336            "list",
337            "append",
338            Self::sig(vec![("items", list_t()), ("value", t())], list_t()),
339        );
340        self.add(
341            "list",
342            "prepend",
343            Self::sig(vec![("items", list_t()), ("value", t())], list_t()),
344        );
345        self.add(
346            "list",
347            "insert",
348            Self::sig(
349                vec![("items", list_t()), ("index", Number), ("value", t())],
350                list_t(),
351            ),
352        );
353        self.add(
354            "list",
355            "remove",
356            Self::sig(vec![("items", list_t()), ("index", Number)], list_t()),
357        );
358        self.add(
359            "list",
360            "update",
361            Self::sig(
362                vec![("items", list_t()), ("index", Number), ("value", t())],
363                list_t(),
364            ),
365        );
366        // list.set is a spec alias for list.update
367        self.add(
368            "list",
369            "set",
370            Self::sig(
371                vec![("items", list_t()), ("index", Number), ("value", t())],
372                list_t(),
373            ),
374        );
375        self.add(
376            "list",
377            "slice",
378            Self::sig(
379                vec![("items", list_t()), ("start", Number), ("end", Number)],
380                list_t(),
381            ),
382        );
383        self.add(
384            "list",
385            "concat",
386            Self::sig(vec![("a", list_t()), ("b", list_t())], list_t()),
387        );
388        self.add(
389            "list",
390            "reverse",
391            Self::sig(vec![("items", list_t())], list_t()),
392        );
393        self.add(
394            "list",
395            "flatten",
396            Self::sig(vec![("items", list_t())], list_t()),
397        );
398        self.add(
399            "list",
400            "unique",
401            Self::sig(vec![("items", list_t())], list_t()),
402        );
403
404        // Higher-order
405        self.add(
406            "list",
407            "map",
408            Self::sig(
409                vec![
410                    ("items", list_t()),
411                    ("f", Function(vec![t()], Box::new(t()))),
412                ],
413                list_t(),
414            ),
415        );
416        self.add(
417            "list",
418            "filter",
419            Self::sig(
420                vec![
421                    ("items", list_t()),
422                    ("predicate", Function(vec![t()], Box::new(Bool))),
423                ],
424                list_t(),
425            ),
426        );
427        self.add(
428            "list",
429            "reduce",
430            Self::sig(
431                vec![
432                    ("items", list_t()),
433                    ("initial", t()),
434                    ("f", Function(vec![t(), t()], Box::new(t()))),
435                ],
436                t(),
437            ),
438        );
439        self.add(
440            "list",
441            "find",
442            Self::sig(
443                vec![
444                    ("items", list_t()),
445                    ("predicate", Function(vec![t()], Box::new(Bool))),
446                ],
447                Nullable(Box::new(t())),
448            ),
449        );
450        self.add(
451            "list",
452            "find_index",
453            Self::sig(
454                vec![
455                    ("items", list_t()),
456                    ("predicate", Function(vec![t()], Box::new(Bool))),
457                ],
458                Number,
459            ),
460        );
461        self.add(
462            "list",
463            "every",
464            Self::sig(
465                vec![
466                    ("items", list_t()),
467                    ("predicate", Function(vec![t()], Box::new(Bool))),
468                ],
469                Bool,
470            ),
471        );
472        // list.any (spec name) + list.some (backward-compat alias)
473        self.add(
474            "list",
475            "any",
476            Self::sig(
477                vec![
478                    ("items", list_t()),
479                    ("predicate", Function(vec![t()], Box::new(Bool))),
480                ],
481                Bool,
482            ),
483        );
484        self.add(
485            "list",
486            "some",
487            Self::sig(
488                vec![
489                    ("items", list_t()),
490                    ("predicate", Function(vec![t()], Box::new(Bool))),
491                ],
492                Bool,
493            ),
494        );
495        self.add(
496            "list",
497            "sort",
498            Self::sig(
499                vec![
500                    ("items", list_t()),
501                    ("compare", Function(vec![t(), t()], Box::new(Number))),
502                ],
503                list_t(),
504            ),
505        );
506        self.add(
507            "list",
508            "contains",
509            Self::sig(vec![("items", list_t()), ("value", t())], Bool),
510        );
511        self.add(
512            "list",
513            "count",
514            Self::sig(
515                vec![
516                    ("items", list_t()),
517                    ("predicate", Function(vec![t()], Box::new(Bool))),
518                ],
519                Number,
520            ),
521        );
522        self.add(
523            "list",
524            "zip",
525            Self::sig(vec![("a", list_t()), ("b", list_t())], list_t()),
526        );
527        self.add(
528            "list",
529            "take",
530            Self::sig(vec![("items", list_t()), ("n", Number)], list_t()),
531        );
532        self.add(
533            "list",
534            "drop",
535            Self::sig(vec![("items", list_t()), ("n", Number)], list_t()),
536        );
537    }
538
539    /// record: 5 functions
540    fn register_record(&mut self) {
541        use Type::*;
542        self.add(
543            "record",
544            "get",
545            Self::sig(vec![("rec", Record(vec![])), ("key", String)], Any),
546        );
547        self.add(
548            "record",
549            "set",
550            Self::sig(
551                vec![("rec", Record(vec![])), ("key", String), ("value", Any)],
552                Record(vec![]),
553            ),
554        );
555        self.add(
556            "record",
557            "has",
558            Self::sig(vec![("rec", Record(vec![])), ("key", String)], Bool),
559        );
560        self.add(
561            "record",
562            "keys",
563            Self::sig(
564                vec![("rec", Record(vec![]))],
565                List(Box::new(String)),
566            ),
567        );
568        self.add(
569            "record",
570            "values",
571            Self::sig(vec![("rec", Record(vec![]))], List(Box::new(Any))),
572        );
573    }
574
575    /// time: 5 functions
576    fn register_time(&mut self) {
577        use Type::*;
578        self.add("time", "now", Self::sig(vec![], Number));
579        self.add(
580            "time",
581            "format",
582            Self::sig(vec![("timestamp", Number), ("pattern", String)], String),
583        );
584        self.add(
585            "time",
586            "diff",
587            Self::sig(vec![("a", Number), ("b", Number)], Number),
588        );
589        self.add(
590            "time",
591            "day_of_week",
592            Self::sig(vec![("timestamp", Number)], Number),
593        );
594        self.add(
595            "time",
596            "start_of_day",
597            Self::sig(vec![("timestamp", Number)], Number),
598        );
599    }
600
601    /// convert: 5 functions
602    fn register_convert(&mut self) {
603        use Type::*;
604        self.add(
605            "convert",
606            "to_string",
607            Self::sig(vec![("value", Any)], String),
608        );
609        self.add(
610            "convert",
611            "to_number",
612            Self::sig(
613                vec![("value", Any)],
614                Result(Box::new(Number), Box::new(String)),
615            ),
616        );
617        self.add(
618            "convert",
619            "parse_int",
620            Self::sig(
621                vec![("s", String)],
622                Result(Box::new(Number), Box::new(String)),
623            ),
624        );
625        self.add(
626            "convert",
627            "parse_float",
628            Self::sig(
629                vec![("s", String)],
630                Result(Box::new(Number), Box::new(String)),
631            ),
632        );
633        self.add(
634            "convert",
635            "to_bool",
636            Self::sig(vec![("value", Any)], Bool),
637        );
638    }
639
640    /// json: 2 functions
641    fn register_json(&mut self) {
642        use Type::*;
643        self.add(
644            "json",
645            "parse",
646            Self::sig(
647                vec![("s", String)],
648                Result(Box::new(Any), Box::new(String)),
649            ),
650        );
651        self.add(
652            "json",
653            "stringify",
654            Self::sig(vec![("value", Any)], String),
655        );
656    }
657
658    /// timer: 4 functions (capability: timer)
659    fn register_timer(&mut self) {
660        use Type::*;
661        self.add(
662            "timer",
663            "start",
664            Self::sig(vec![("id", String), ("interval_ms", Number)], String),
665        );
666        self.add(
667            "timer",
668            "start_once",
669            Self::sig(vec![("id", String), ("delay_ms", Number)], String),
670        );
671        self.add(
672            "timer",
673            "stop",
674            Self::sig(vec![("id", String)], Nil),
675        );
676        self.add("timer", "stop_all", Self::sig(vec![], Nil));
677    }
678
679    /// http: 5 functions (capability: http)
680    fn register_http(&mut self) {
681        use Type::*;
682        let result_ty = |ok: Type| Result(Box::new(ok), Box::new(String));
683        self.add("http", "get", Self::sig(vec![("url", String)], result_ty(String)));
684        self.add(
685            "http",
686            "post",
687            Self::sig(vec![("url", String), ("body", String)], result_ty(String)),
688        );
689        self.add(
690            "http",
691            "put",
692            Self::sig(vec![("url", String), ("body", String)], result_ty(String)),
693        );
694        self.add(
695            "http",
696            "patch",
697            Self::sig(vec![("url", String), ("body", String)], result_ty(String)),
698        );
699        self.add("http", "delete", Self::sig(vec![("url", String)], result_ty(String)));
700    }
701
702    /// storage: 4 functions (capability: storage)
703    fn register_storage(&mut self) {
704        use Type::*;
705        self.add("storage", "get", Self::sig(vec![("key", String)], Nullable(Box::new(String))));
706        self.add("storage", "set", Self::sig(vec![("key", String), ("value", String)], Nil));
707        // storage.remove removed — spec only defines storage.delete (F1a)
708        self.add("storage", "delete", Self::sig(vec![("key", String)], Nil));
709        self.add(
710            "storage",
711            "keys",
712            Self::sig(vec![], List(Box::new(String))),
713        );
714    }
715
716    /// location: 1 function (capability: location)
717    fn register_location(&mut self) {
718        use Type::*;
719        self.add(
720            "location",
721            "current",
722            Self::sig(
723                vec![],
724                Record(vec![
725                    crate::ty::RecordField { name: "lat".into(), ty: Number, optional: false },
726                    crate::ty::RecordField { name: "lon".into(), ty: Number, optional: false },
727                ]),
728            ),
729        );
730    }
731
732    /// notifications: 1 function (capability: notifications)
733    fn register_notifications(&mut self) {
734        use Type::*;
735        self.add(
736            "notifications",
737            "send",
738            Self::sig(vec![("title", String), ("body", String)], Nil),
739        );
740    }
741}
742
743impl Default for StdlibRegistry {
744    fn default() -> Self {
745        Self::new()
746    }
747}
748
749/// Modules that require capabilities to use.
750pub fn capability_modules() -> HashMap<&'static str, &'static str> {
751    let mut m = HashMap::new();
752    m.insert("http", "http");
753    m.insert("storage", "storage");
754    m.insert("location", "location");
755    m.insert("notifications", "notifications");
756    m.insert("timer", "timer");
757    m
758}