lust/builtins/
mod.rs

1use crate::ast::{Span, Type, TypeKind};
2use crate::lazy::StaticOnceCell;
3use crate::FunctionSignature;
4use alloc::{boxed::Box, collections::BTreeMap, string::ToString, vec, vec::Vec};
5use hashbrown::HashMap;
6
7#[derive(Debug, Clone)]
8pub struct BuiltinSignature {
9    pub params: Vec<TypeExpr>,
10    pub return_type: TypeExpr,
11}
12
13#[derive(Debug, Clone)]
14pub struct BuiltinFunction {
15    pub name: &'static str,
16    pub description: &'static str,
17    pub signature: BuiltinSignature,
18    pub param_names: &'static [&'static str],
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22pub enum MethodSemantics {
23    Simple,
24    ArrayMap,
25    ArrayFilter,
26    ArrayReduce,
27}
28
29#[derive(Debug, Clone)]
30pub struct BuiltinMethod {
31    pub receiver: TypeExpr,
32    pub name: &'static str,
33    pub description: &'static str,
34    pub signature: BuiltinSignature,
35    pub param_names: &'static [&'static str],
36    pub semantics: MethodSemantics,
37}
38
39#[derive(Debug, Clone)]
40pub enum TypeExpr {
41    Int,
42    Float,
43    Bool,
44    String,
45    Unit,
46    Unknown,
47    Named(&'static str),
48    Array(Box<TypeExpr>),
49    Map(Box<TypeExpr>, Box<TypeExpr>),
50    Result(Box<TypeExpr>, Box<TypeExpr>),
51    Option(Box<TypeExpr>),
52    Table,
53    Generic(&'static str),
54    SelfType,
55    Function {
56        params: Vec<TypeExpr>,
57        return_type: Box<TypeExpr>,
58    },
59}
60
61impl BuiltinFunction {
62    pub fn to_signature(&self, span: Span) -> FunctionSignature {
63        FunctionSignature {
64            params: self
65                .signature
66                .params
67                .iter()
68                .map(|expr| expr.instantiate(&HashMap::new(), Some(span)))
69                .collect(),
70            return_type: self
71                .signature
72                .return_type
73                .instantiate(&HashMap::new(), Some(span)),
74            is_method: false,
75        }
76    }
77
78    pub fn parameters(&self) -> Vec<(&'static str, &TypeExpr)> {
79        self.signature
80            .params
81            .iter()
82            .enumerate()
83            .map(|(idx, ty)| {
84                let name = self.param_names.get(idx).copied().unwrap_or("");
85                (name, ty)
86            })
87            .collect()
88    }
89
90    pub fn return_type(&self) -> &TypeExpr {
91        &self.signature.return_type
92    }
93}
94
95impl BuiltinMethod {
96    pub fn parameters(&self) -> Vec<(&'static str, &TypeExpr)> {
97        self.signature
98            .params
99            .iter()
100            .enumerate()
101            .map(|(idx, ty)| {
102                let name = self.param_names.get(idx).copied().unwrap_or("");
103                (name, ty)
104            })
105            .collect()
106    }
107
108    pub fn return_type(&self) -> &TypeExpr {
109        &self.signature.return_type
110    }
111
112    pub fn receiver_type(&self) -> &TypeExpr {
113        &self.receiver
114    }
115}
116
117impl TypeExpr {
118    pub fn instantiate(&self, generics: &HashMap<&'static str, Type>, span: Option<Span>) -> Type {
119        let span = span.unwrap_or_else(Span::dummy);
120        match self {
121            TypeExpr::Int => Type::new(TypeKind::Int, span),
122            TypeExpr::Float => Type::new(TypeKind::Float, span),
123            TypeExpr::Bool => Type::new(TypeKind::Bool, span),
124            TypeExpr::String => Type::new(TypeKind::String, span),
125            TypeExpr::Unit => Type::new(TypeKind::Unit, span),
126            TypeExpr::Unknown => Type::new(TypeKind::Unknown, span),
127            TypeExpr::Named(name) => Type::new(TypeKind::Named((*name).to_string()), span),
128            TypeExpr::Array(inner) => Type::new(
129                TypeKind::Array(Box::new(inner.instantiate(generics, Some(span)))),
130                span,
131            ),
132            TypeExpr::Map(key, value) => Type::new(
133                TypeKind::Map(
134                    Box::new(key.instantiate(generics, Some(span))),
135                    Box::new(value.instantiate(generics, Some(span))),
136                ),
137                span,
138            ),
139            TypeExpr::Result(ok, err) => Type::new(
140                TypeKind::Result(
141                    Box::new(ok.instantiate(generics, Some(span))),
142                    Box::new(err.instantiate(generics, Some(span))),
143                ),
144                span,
145            ),
146            TypeExpr::Option(inner) => Type::new(
147                TypeKind::Option(Box::new(inner.instantiate(generics, Some(span)))),
148                span,
149            ),
150            TypeExpr::Table => Type::new(TypeKind::Table, span),
151            TypeExpr::Generic(name) => generics
152                .get(name)
153                .cloned()
154                .unwrap_or_else(|| Type::new(TypeKind::Unknown, span)),
155            TypeExpr::SelfType => generics
156                .get("Self")
157                .cloned()
158                .unwrap_or_else(|| Type::new(TypeKind::Unknown, span)),
159            TypeExpr::Function {
160                params,
161                return_type,
162            } => Type::new(
163                TypeKind::Function {
164                    params: params
165                        .iter()
166                        .map(|param| param.instantiate(generics, Some(span)))
167                        .collect(),
168                    return_type: Box::new(return_type.instantiate(generics, Some(span))),
169                },
170                span,
171            ),
172        }
173    }
174}
175
176fn match_type_expr(
177    pattern: &TypeExpr,
178    actual: &Type,
179    bindings: &mut HashMap<&'static str, Type>,
180) -> bool {
181    match (pattern, &actual.kind) {
182        (TypeExpr::SelfType, _) => {
183            bindings.insert("Self", actual.clone());
184            true
185        }
186        (TypeExpr::Generic(name), _) => {
187            if let Some(existing) = bindings.get(name) {
188                existing.kind == actual.kind
189            } else {
190                bindings.insert(name, actual.clone());
191                true
192            }
193        }
194        (TypeExpr::Int, TypeKind::Int) => true,
195        (TypeExpr::Float, TypeKind::Float) => true,
196        (TypeExpr::Bool, TypeKind::Bool) => true,
197        (TypeExpr::String, TypeKind::String) => true,
198        (TypeExpr::Unit, TypeKind::Unit) => true,
199        (TypeExpr::Unknown, TypeKind::Unknown) => true,
200        (TypeExpr::Named(expected), TypeKind::Named(actual_name)) => expected == actual_name,
201        (TypeExpr::Array(pattern_inner), TypeKind::Array(actual_inner)) => {
202            match_type_expr(pattern_inner, actual_inner, bindings)
203        }
204        (TypeExpr::Map(pattern_key, pattern_value), TypeKind::Map(actual_key, actual_value)) => {
205            match_type_expr(pattern_key, actual_key, bindings)
206                && match_type_expr(pattern_value, actual_value, bindings)
207        }
208        (TypeExpr::Option(pattern_inner), TypeKind::Option(actual_inner)) => {
209            match_type_expr(pattern_inner, actual_inner, bindings)
210        }
211        (TypeExpr::Result(pattern_ok, pattern_err), TypeKind::Result(actual_ok, actual_err)) => {
212            match_type_expr(pattern_ok, actual_ok, bindings)
213                && match_type_expr(pattern_err, actual_err, bindings)
214        }
215        (TypeExpr::Table, TypeKind::Table) => true,
216        _ => false,
217    }
218}
219
220pub fn match_receiver(pattern: &TypeExpr, actual: &Type) -> Option<HashMap<&'static str, Type>> {
221    let mut bindings = HashMap::new();
222    if match_type_expr(pattern, actual, &mut bindings) {
223        Some(bindings)
224    } else {
225        None
226    }
227}
228
229fn method(
230    receiver: TypeExpr,
231    name: &'static str,
232    description: &'static str,
233    param_names: &'static [&'static str],
234    params: Vec<TypeExpr>,
235    return_type: TypeExpr,
236) -> BuiltinMethod {
237    BuiltinMethod {
238        receiver,
239        name,
240        description,
241        signature: BuiltinSignature {
242            params,
243            return_type,
244        },
245        param_names,
246        semantics: MethodSemantics::Simple,
247    }
248}
249
250fn method_with_semantics(
251    receiver: TypeExpr,
252    name: &'static str,
253    description: &'static str,
254    param_names: &'static [&'static str],
255    params: Vec<TypeExpr>,
256    return_type: TypeExpr,
257    semantics: MethodSemantics,
258) -> BuiltinMethod {
259    let mut m = method(
260        receiver,
261        name,
262        description,
263        param_names,
264        params,
265        return_type,
266    );
267    m.semantics = semantics;
268    m
269}
270
271fn string_methods() -> Vec<BuiltinMethod> {
272    vec![
273        method(
274            TypeExpr::String,
275            "len",
276            "Return the length of the string in bytes",
277            &[],
278            vec![],
279            TypeExpr::Int,
280        ),
281        method(
282            TypeExpr::String,
283            "substring",
284            "Extract a substring from the string",
285            &["start", "end"],
286            vec![TypeExpr::Int, TypeExpr::Int],
287            TypeExpr::String,
288        ),
289        method(
290            TypeExpr::String,
291            "find",
292            "Find the first occurrence of a substring",
293            &["pattern"],
294            vec![TypeExpr::String],
295            TypeExpr::Option(Box::new(TypeExpr::Int)),
296        ),
297        method(
298            TypeExpr::String,
299            "starts_with",
300            "Check whether the string starts with a prefix",
301            &["prefix"],
302            vec![TypeExpr::String],
303            TypeExpr::Bool,
304        ),
305        method(
306            TypeExpr::String,
307            "ends_with",
308            "Check whether the string ends with a suffix",
309            &["suffix"],
310            vec![TypeExpr::String],
311            TypeExpr::Bool,
312        ),
313        method(
314            TypeExpr::String,
315            "contains",
316            "Check whether the string contains a substring",
317            &["substring"],
318            vec![TypeExpr::String],
319            TypeExpr::Bool,
320        ),
321        method(
322            TypeExpr::String,
323            "split",
324            "Split the string on a separator",
325            &["delimiter"],
326            vec![TypeExpr::String],
327            TypeExpr::Array(Box::new(TypeExpr::String)),
328        ),
329        method(
330            TypeExpr::String,
331            "trim",
332            "Trim whitespace from both ends of the string",
333            &[],
334            vec![],
335            TypeExpr::String,
336        ),
337        method(
338            TypeExpr::String,
339            "trim_start",
340            "Trim whitespace from the start of the string",
341            &[],
342            vec![],
343            TypeExpr::String,
344        ),
345        method(
346            TypeExpr::String,
347            "trim_end",
348            "Trim whitespace from the end of the string",
349            &[],
350            vec![],
351            TypeExpr::String,
352        ),
353        method(
354            TypeExpr::String,
355            "replace",
356            "Replace occurrences of a substring",
357            &["from", "to"],
358            vec![TypeExpr::String, TypeExpr::String],
359            TypeExpr::String,
360        ),
361        method(
362            TypeExpr::String,
363            "to_upper",
364            "Convert the string to uppercase",
365            &[],
366            vec![],
367            TypeExpr::String,
368        ),
369        method(
370            TypeExpr::String,
371            "to_lower",
372            "Convert the string to lowercase",
373            &[],
374            vec![],
375            TypeExpr::String,
376        ),
377        method(
378            TypeExpr::String,
379            "is_empty",
380            "Check if the string is empty",
381            &[],
382            vec![],
383            TypeExpr::Bool,
384        ),
385        method(
386            TypeExpr::String,
387            "chars",
388            "Return the characters as an array of strings",
389            &[],
390            vec![],
391            TypeExpr::Array(Box::new(TypeExpr::String)),
392        ),
393        method(
394            TypeExpr::String,
395            "lines",
396            "Return the lines as an array of strings",
397            &[],
398            vec![],
399            TypeExpr::Array(Box::new(TypeExpr::String)),
400        ),
401        method(
402            TypeExpr::String,
403            "iter",
404            "Return an iterator over the characters of the string",
405            &[],
406            vec![],
407            TypeExpr::Named("Iterator"),
408        ),
409    ]
410}
411
412fn array_methods() -> Vec<BuiltinMethod> {
413    let receiver = TypeExpr::Array(Box::new(TypeExpr::Generic("T")));
414    let mut methods = Vec::new();
415    methods.push(method(
416        receiver.clone(),
417        "iter",
418        "Return an iterator over the array items",
419        &[],
420        vec![],
421        TypeExpr::Named("Iterator"),
422    ));
423    methods.push(method(
424        receiver.clone(),
425        "len",
426        "Return the number of elements in the array",
427        &[],
428        vec![],
429        TypeExpr::Int,
430    ));
431    methods.push(method(
432        receiver.clone(),
433        "get",
434        "Return the element at the given index, if any",
435        &["index"],
436        vec![TypeExpr::Int],
437        TypeExpr::Option(Box::new(TypeExpr::Generic("T"))),
438    ));
439    methods.push(method(
440        receiver.clone(),
441        "first",
442        "Return the first element, if any",
443        &[],
444        vec![],
445        TypeExpr::Option(Box::new(TypeExpr::Generic("T"))),
446    ));
447    methods.push(method(
448        receiver.clone(),
449        "last",
450        "Return the last element, if any",
451        &[],
452        vec![],
453        TypeExpr::Option(Box::new(TypeExpr::Generic("T"))),
454    ));
455    methods.push(method(
456        receiver.clone(),
457        "push",
458        "Append a value to the array",
459        &["value"],
460        vec![TypeExpr::Generic("T")],
461        TypeExpr::Unit,
462    ));
463    methods.push(method(
464        receiver.clone(),
465        "pop",
466        "Remove and return the last element, if any",
467        &[],
468        vec![],
469        TypeExpr::Option(Box::new(TypeExpr::Generic("T"))),
470    ));
471    methods.push(method_with_semantics(
472        receiver.clone(),
473        "map",
474        "Transform each element using the provided function",
475        &["func"],
476        vec![TypeExpr::Function {
477            params: vec![TypeExpr::Generic("T")],
478            return_type: Box::new(TypeExpr::Unknown),
479        }],
480        TypeExpr::Array(Box::new(TypeExpr::Unknown)),
481        MethodSemantics::ArrayMap,
482    ));
483    methods.push(method_with_semantics(
484        receiver.clone(),
485        "filter",
486        "Keep elements where the predicate returns true",
487        &["func"],
488        vec![TypeExpr::Function {
489            params: vec![TypeExpr::Generic("T")],
490            return_type: Box::new(TypeExpr::Bool),
491        }],
492        TypeExpr::Array(Box::new(TypeExpr::Generic("T"))),
493        MethodSemantics::ArrayFilter,
494    ));
495    methods.push(method_with_semantics(
496        receiver.clone(),
497        "reduce",
498        "Fold elements into a single value",
499        &["initial", "func"],
500        vec![
501            TypeExpr::Unknown,
502            TypeExpr::Function {
503                params: vec![TypeExpr::Unknown, TypeExpr::Generic("T")],
504                return_type: Box::new(TypeExpr::Unknown),
505            },
506        ],
507        TypeExpr::Unknown,
508        MethodSemantics::ArrayReduce,
509    ));
510    methods.push(method(
511        receiver.clone(),
512        "slice",
513        "Return a slice of the array between two indices",
514        &["start", "end"],
515        vec![TypeExpr::Int, TypeExpr::Int],
516        TypeExpr::Array(Box::new(TypeExpr::Generic("T"))),
517    ));
518    methods.push(method(
519        receiver.clone(),
520        "clear",
521        "Remove all elements from the array",
522        &[],
523        vec![],
524        TypeExpr::Unit,
525    ));
526    methods.push(method(
527        receiver,
528        "is_empty",
529        "Check if the array contains no elements",
530        &[],
531        vec![],
532        TypeExpr::Bool,
533    ));
534    methods
535}
536
537fn map_methods() -> Vec<BuiltinMethod> {
538    let receiver = TypeExpr::Map(
539        Box::new(TypeExpr::Generic("K")),
540        Box::new(TypeExpr::Generic("V")),
541    );
542    vec![
543        method(
544            receiver.clone(),
545            "iter",
546            "Iterate over key/value pairs",
547            &[],
548            vec![],
549            TypeExpr::Named("Iterator"),
550        ),
551        method(
552            receiver.clone(),
553            "len",
554            "Return the number of entries in the map",
555            &[],
556            vec![],
557            TypeExpr::Int,
558        ),
559        method(
560            receiver.clone(),
561            "get",
562            "Look up a value by key",
563            &["key"],
564            vec![TypeExpr::Generic("K")],
565            TypeExpr::Option(Box::new(TypeExpr::Generic("V"))),
566        ),
567        method(
568            receiver.clone(),
569            "set",
570            "Insert or overwrite a key/value pair",
571            &["key", "value"],
572            vec![TypeExpr::Generic("K"), TypeExpr::Generic("V")],
573            TypeExpr::Unit,
574        ),
575        method(
576            receiver.clone(),
577            "has",
578            "Check whether the map contains a key",
579            &["key"],
580            vec![TypeExpr::Generic("K")],
581            TypeExpr::Bool,
582        ),
583        method(
584            receiver.clone(),
585            "delete",
586            "Remove an entry from the map",
587            &["key"],
588            vec![TypeExpr::Generic("K")],
589            TypeExpr::Option(Box::new(TypeExpr::Generic("V"))),
590        ),
591        method(
592            receiver.clone(),
593            "keys",
594            "Return the keys as an array",
595            &[],
596            vec![],
597            TypeExpr::Array(Box::new(TypeExpr::Generic("K"))),
598        ),
599        method(
600            receiver,
601            "values",
602            "Return the values as an array",
603            &[],
604            vec![],
605            TypeExpr::Array(Box::new(TypeExpr::Generic("V"))),
606        ),
607    ]
608}
609
610fn table_methods() -> Vec<BuiltinMethod> {
611    vec![
612        method(
613            TypeExpr::Table,
614            "iter",
615            "Iterate over key/value pairs",
616            &[],
617            vec![],
618            TypeExpr::Named("Iterator"),
619        ),
620        method(
621            TypeExpr::Table,
622            "len",
623            "Return the number of entries in the table",
624            &[],
625            vec![],
626            TypeExpr::Int,
627        ),
628        method(
629            TypeExpr::Table,
630            "get",
631            "Look up a value by key",
632            &["key"],
633            vec![TypeExpr::Unknown],
634            TypeExpr::Option(Box::new(TypeExpr::Unknown)),
635        ),
636        method(
637            TypeExpr::Table,
638            "set",
639            "Insert or overwrite a key/value pair",
640            &["key", "value"],
641            vec![TypeExpr::Unknown, TypeExpr::Unknown],
642            TypeExpr::Unit,
643        ),
644        method(
645            TypeExpr::Table,
646            "has",
647            "Check whether the table contains a key",
648            &["key"],
649            vec![TypeExpr::Unknown],
650            TypeExpr::Bool,
651        ),
652        method(
653            TypeExpr::Table,
654            "delete",
655            "Remove an entry from the table",
656            &["key"],
657            vec![TypeExpr::Unknown],
658            TypeExpr::Option(Box::new(TypeExpr::Unknown)),
659        ),
660        method(
661            TypeExpr::Table,
662            "keys",
663            "Return the keys as an array",
664            &[],
665            vec![],
666            TypeExpr::Array(Box::new(TypeExpr::Unknown)),
667        ),
668        method(
669            TypeExpr::Table,
670            "values",
671            "Return the values as an array",
672            &[],
673            vec![],
674            TypeExpr::Array(Box::new(TypeExpr::Unknown)),
675        ),
676    ]
677}
678
679fn iterator_methods() -> Vec<BuiltinMethod> {
680    vec![
681        method(
682            TypeExpr::Named("Iterator"),
683            "iter",
684            "Return the iterator itself",
685            &[],
686            vec![],
687            TypeExpr::Named("Iterator"),
688        ),
689        method(
690            TypeExpr::Named("Iterator"),
691            "next",
692            "Advance the iterator and return the next value",
693            &[],
694            vec![],
695            TypeExpr::Option(Box::new(TypeExpr::Unknown)),
696        ),
697    ]
698}
699
700fn option_methods() -> Vec<BuiltinMethod> {
701    let receiver = TypeExpr::Option(Box::new(TypeExpr::Generic("T")));
702    vec![
703        method(
704            receiver.clone(),
705            "is_some",
706            "Check if the option contains a value",
707            &[],
708            vec![],
709            TypeExpr::Bool,
710        ),
711        method(
712            receiver.clone(),
713            "is_none",
714            "Check if the option is empty",
715            &[],
716            vec![],
717            TypeExpr::Bool,
718        ),
719        method(
720            receiver.clone(),
721            "unwrap",
722            "Unwrap the contained value, panicking if None",
723            &[],
724            vec![],
725            TypeExpr::Generic("T"),
726        ),
727        method(
728            receiver,
729            "unwrap_or",
730            "Return the value or a provided default",
731            &["default"],
732            vec![TypeExpr::Generic("T")],
733            TypeExpr::Generic("T"),
734        ),
735    ]
736}
737
738fn result_methods() -> Vec<BuiltinMethod> {
739    let receiver = TypeExpr::Result(
740        Box::new(TypeExpr::Generic("T")),
741        Box::new(TypeExpr::Generic("E")),
742    );
743    vec![
744        method(
745            receiver.clone(),
746            "is_ok",
747            "Check if the result is Ok",
748            &[],
749            vec![],
750            TypeExpr::Bool,
751        ),
752        method(
753            receiver.clone(),
754            "is_err",
755            "Check if the result is Err",
756            &[],
757            vec![],
758            TypeExpr::Bool,
759        ),
760        method(
761            receiver.clone(),
762            "unwrap",
763            "Unwrap the Ok value, panicking if Err",
764            &[],
765            vec![],
766            TypeExpr::Generic("T"),
767        ),
768        method(
769            receiver,
770            "unwrap_or",
771            "Return the Ok value or a provided default",
772            &["default"],
773            vec![TypeExpr::Generic("T")],
774            TypeExpr::Generic("T"),
775        ),
776    ]
777}
778
779fn float_methods() -> Vec<BuiltinMethod> {
780    vec![
781        method(
782            TypeExpr::Float,
783            "to_int",
784            "Convert the float to an integer by truncation",
785            &[],
786            vec![],
787            TypeExpr::Int,
788        ),
789        method(
790            TypeExpr::Float,
791            "floor",
792            "Return the greatest integer less than or equal to the value",
793            &[],
794            vec![],
795            TypeExpr::Float,
796        ),
797        method(
798            TypeExpr::Float,
799            "ceil",
800            "Return the smallest integer greater than or equal to the value",
801            &[],
802            vec![],
803            TypeExpr::Float,
804        ),
805        method(
806            TypeExpr::Float,
807            "round",
808            "Round the float to the nearest integer",
809            &[],
810            vec![],
811            TypeExpr::Float,
812        ),
813        method(
814            TypeExpr::Float,
815            "sqrt",
816            "Return the square root of the float",
817            &[],
818            vec![],
819            TypeExpr::Float,
820        ),
821        method(
822            TypeExpr::Float,
823            "abs",
824            "Return the absolute value of the float",
825            &[],
826            vec![],
827            TypeExpr::Float,
828        ),
829        method(
830            TypeExpr::Float,
831            "clamp",
832            "Clamp the float between a minimum and maximum value",
833            &["min", "max"],
834            vec![TypeExpr::Float, TypeExpr::Float],
835            TypeExpr::Float,
836        ),
837    ]
838}
839
840fn int_methods() -> Vec<BuiltinMethod> {
841    vec![
842        method(
843            TypeExpr::Int,
844            "to_float",
845            "Convert the integer to a float",
846            &[],
847            vec![],
848            TypeExpr::Float,
849        ),
850        method(
851            TypeExpr::Int,
852            "abs",
853            "Return the absolute value of the integer",
854            &[],
855            vec![],
856            TypeExpr::Int,
857        ),
858        method(
859            TypeExpr::Int,
860            "clamp",
861            "Clamp the integer between a minimum and maximum value",
862            &["min", "max"],
863            vec![TypeExpr::Int, TypeExpr::Int],
864            TypeExpr::Int,
865        ),
866    ]
867}
868
869static BASE_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
870
871fn build_base_functions() -> Vec<BuiltinFunction> {
872    vec![
873        BuiltinFunction {
874            name: "print",
875            description: "Print values without a newline",
876            signature: BuiltinSignature {
877                params: vec![TypeExpr::Unknown],
878                return_type: TypeExpr::Unit,
879            },
880            param_names: &["value"],
881        },
882        BuiltinFunction {
883            name: "println",
884            description: "Print values followed by a newline",
885            signature: BuiltinSignature {
886                params: vec![TypeExpr::Unknown],
887                return_type: TypeExpr::Unit,
888            },
889            param_names: &["value"],
890        },
891        BuiltinFunction {
892            name: "type",
893            description: "Return the runtime type name",
894            signature: BuiltinSignature {
895                params: vec![TypeExpr::Unknown],
896                return_type: TypeExpr::String,
897            },
898            param_names: &["value"],
899        },
900        BuiltinFunction {
901            name: "tostring",
902            description: "Convert a value to a string",
903            signature: BuiltinSignature {
904                params: vec![TypeExpr::Unknown],
905                return_type: TypeExpr::String,
906            },
907            param_names: &["value"],
908        },
909    ]
910}
911
912static TASK_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
913
914fn build_task_functions() -> Vec<BuiltinFunction> {
915    vec![
916        BuiltinFunction {
917            name: "task.run",
918            description: "Run a function as a task",
919            signature: BuiltinSignature {
920                params: vec![TypeExpr::Unknown],
921                return_type: TypeExpr::Named("Task"),
922            },
923            param_names: &["func"],
924        },
925        BuiltinFunction {
926            name: "task.create",
927            description: "Create a suspended task",
928            signature: BuiltinSignature {
929                params: vec![TypeExpr::Unknown],
930                return_type: TypeExpr::Named("Task"),
931            },
932            param_names: &["func"],
933        },
934        BuiltinFunction {
935            name: "task.status",
936            description: "Get the status of a task",
937            signature: BuiltinSignature {
938                params: vec![TypeExpr::Named("Task")],
939                return_type: TypeExpr::Named("TaskStatus"),
940            },
941            param_names: &["task"],
942        },
943        BuiltinFunction {
944            name: "task.info",
945            description: "Get detailed information about a task",
946            signature: BuiltinSignature {
947                params: vec![TypeExpr::Named("Task")],
948                return_type: TypeExpr::Named("TaskInfo"),
949            },
950            param_names: &["task"],
951        },
952        BuiltinFunction {
953            name: "task.resume",
954            description: "Resume a suspended task",
955            signature: BuiltinSignature {
956                params: vec![TypeExpr::Named("Task")],
957                return_type: TypeExpr::Named("TaskInfo"),
958            },
959            param_names: &["task"],
960        },
961        BuiltinFunction {
962            name: "task.yield",
963            description: "Yield from the current task",
964            signature: BuiltinSignature {
965                params: vec![TypeExpr::Unknown],
966                return_type: TypeExpr::Unknown,
967            },
968            param_names: &["value"],
969        },
970        BuiltinFunction {
971            name: "task.stop",
972            description: "Stop a running task",
973            signature: BuiltinSignature {
974                params: vec![TypeExpr::Named("Task")],
975                return_type: TypeExpr::Bool,
976            },
977            param_names: &["task"],
978        },
979        BuiltinFunction {
980            name: "task.restart",
981            description: "Restart a completed task",
982            signature: BuiltinSignature {
983                params: vec![TypeExpr::Named("Task")],
984                return_type: TypeExpr::Named("TaskInfo"),
985            },
986            param_names: &["task"],
987        },
988        BuiltinFunction {
989            name: "task.current",
990            description: "Return the currently executing task",
991            signature: BuiltinSignature {
992                params: vec![],
993                return_type: TypeExpr::Option(Box::new(TypeExpr::Named("Task"))),
994            },
995            param_names: &[],
996        },
997    ]
998}
999
1000static IO_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
1001
1002fn build_io_functions() -> Vec<BuiltinFunction> {
1003    vec![
1004        BuiltinFunction {
1005            name: "io.read_file",
1006            description: "Read the contents of a file",
1007            signature: BuiltinSignature {
1008                params: vec![TypeExpr::String],
1009                return_type: TypeExpr::Result(
1010                    Box::new(TypeExpr::String),
1011                    Box::new(TypeExpr::String),
1012                ),
1013            },
1014            param_names: &["path"],
1015        },
1016        BuiltinFunction {
1017            name: "io.read_file_bytes",
1018            description: "Read the contents of a file as byte values",
1019            signature: BuiltinSignature {
1020                params: vec![TypeExpr::String],
1021                return_type: TypeExpr::Result(
1022                    Box::new(TypeExpr::Array(Box::new(TypeExpr::Int))),
1023                    Box::new(TypeExpr::String),
1024                ),
1025            },
1026            param_names: &["path"],
1027        },
1028        BuiltinFunction {
1029            name: "io.write_file",
1030            description: "Write contents to a file",
1031            signature: BuiltinSignature {
1032                params: vec![TypeExpr::String, TypeExpr::Unknown],
1033                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1034            },
1035            param_names: &["path", "value"],
1036        },
1037        BuiltinFunction {
1038            name: "io.read_stdin",
1039            description: "Read all available stdin",
1040            signature: BuiltinSignature {
1041                params: vec![],
1042                return_type: TypeExpr::Result(
1043                    Box::new(TypeExpr::String),
1044                    Box::new(TypeExpr::String),
1045                ),
1046            },
1047            param_names: &[],
1048        },
1049        BuiltinFunction {
1050            name: "io.read_line",
1051            description: "Read a single line from stdin",
1052            signature: BuiltinSignature {
1053                params: vec![],
1054                return_type: TypeExpr::Result(
1055                    Box::new(TypeExpr::String),
1056                    Box::new(TypeExpr::String),
1057                ),
1058            },
1059            param_names: &[],
1060        },
1061        BuiltinFunction {
1062            name: "io.write_stdout",
1063            description: "Write a value to stdout",
1064            signature: BuiltinSignature {
1065                params: vec![TypeExpr::Unknown],
1066                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1067            },
1068            param_names: &["value"],
1069        },
1070    ]
1071}
1072
1073static OS_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
1074
1075fn build_os_functions() -> Vec<BuiltinFunction> {
1076    vec![
1077        BuiltinFunction {
1078            name: "os.create_file",
1079            description: "Create an empty file on disk",
1080            signature: BuiltinSignature {
1081                params: vec![TypeExpr::String],
1082                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1083            },
1084            param_names: &["path"],
1085        },
1086        BuiltinFunction {
1087            name: "os.create_dir",
1088            description: "Create a directory",
1089            signature: BuiltinSignature {
1090                params: vec![TypeExpr::String],
1091                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1092            },
1093            param_names: &["path"],
1094        },
1095        BuiltinFunction {
1096            name: "os.remove_file",
1097            description: "Remove a file from disk",
1098            signature: BuiltinSignature {
1099                params: vec![TypeExpr::String],
1100                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1101            },
1102            param_names: &["path"],
1103        },
1104        BuiltinFunction {
1105            name: "os.remove_dir",
1106            description: "Remove an empty directory",
1107            signature: BuiltinSignature {
1108                params: vec![TypeExpr::String],
1109                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1110            },
1111            param_names: &["path"],
1112        },
1113        BuiltinFunction {
1114            name: "os.rename",
1115            description: "Rename or move a path",
1116            signature: BuiltinSignature {
1117                params: vec![TypeExpr::String, TypeExpr::String],
1118                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1119            },
1120            param_names: &["from", "to"],
1121        },
1122    ]
1123}
1124
1125static BUILTIN_METHODS: StaticOnceCell<Vec<BuiltinMethod>> = StaticOnceCell::new();
1126
1127fn build_builtin_methods() -> Vec<BuiltinMethod> {
1128    let mut methods = Vec::new();
1129    methods.extend(string_methods());
1130    methods.extend(array_methods());
1131    methods.extend(map_methods());
1132    methods.extend(table_methods());
1133    methods.extend(iterator_methods());
1134    methods.extend(option_methods());
1135    methods.extend(result_methods());
1136    methods.extend(float_methods());
1137    methods.extend(int_methods());
1138    methods
1139}
1140
1141pub fn base_functions() -> &'static [BuiltinFunction] {
1142    BASE_FUNCTIONS.get_or_init(build_base_functions).as_slice()
1143}
1144
1145pub fn task_functions() -> &'static [BuiltinFunction] {
1146    TASK_FUNCTIONS.get_or_init(build_task_functions).as_slice()
1147}
1148
1149pub fn io_functions() -> &'static [BuiltinFunction] {
1150    IO_FUNCTIONS.get_or_init(build_io_functions).as_slice()
1151}
1152
1153pub fn os_functions() -> &'static [BuiltinFunction] {
1154    OS_FUNCTIONS.get_or_init(build_os_functions).as_slice()
1155}
1156
1157pub fn builtin_methods() -> &'static [BuiltinMethod] {
1158    BUILTIN_METHODS
1159        .get_or_init(build_builtin_methods)
1160        .as_slice()
1161}
1162
1163pub struct BuiltinModule {
1164    name: &'static str,
1165    description: &'static str,
1166    functions: Vec<&'static BuiltinFunction>,
1167}
1168
1169impl BuiltinModule {
1170    pub fn name(&self) -> &'static str {
1171        self.name
1172    }
1173
1174    pub fn description(&self) -> &'static str {
1175        self.description
1176    }
1177
1178    pub fn functions(&self) -> &[&'static BuiltinFunction] {
1179        &self.functions
1180    }
1181}
1182
1183pub struct BuiltinsDatabase {
1184    global_functions: Vec<&'static BuiltinFunction>,
1185    modules: BTreeMap<&'static str, BuiltinModule>,
1186    methods: HashMap<&'static str, Vec<&'static BuiltinMethod>>,
1187}
1188
1189impl BuiltinsDatabase {
1190    pub fn global_functions(&self) -> &[&'static BuiltinFunction] {
1191        &self.global_functions
1192    }
1193
1194    pub fn module(&self, name: &str) -> Option<&BuiltinModule> {
1195        self.modules.get(name)
1196    }
1197
1198    pub fn methods_for(&self, type_name: &str) -> Option<&[&'static BuiltinMethod]> {
1199        self.methods
1200            .get(type_name)
1201            .map(|methods| methods.as_slice())
1202    }
1203
1204    pub fn modules(&self) -> impl Iterator<Item = &BuiltinModule> {
1205        self.modules.values()
1206    }
1207}
1208
1209fn receiver_key(expr: &TypeExpr) -> Option<&'static str> {
1210    match expr {
1211        TypeExpr::String => Some("String"),
1212        TypeExpr::Array(_) => Some("Array"),
1213        TypeExpr::Map(_, _) => Some("Map"),
1214        TypeExpr::Table => Some("Table"),
1215        TypeExpr::Named(name) => Some(name),
1216        TypeExpr::Option(_) => Some("Option"),
1217        TypeExpr::Result(_, _) => Some("Result"),
1218        TypeExpr::Float => Some("Float"),
1219        TypeExpr::Int => Some("Int"),
1220        TypeExpr::Bool => Some("Bool"),
1221        TypeExpr::Unknown => Some("Unknown"),
1222        TypeExpr::Unit => Some("Unit"),
1223        TypeExpr::Generic(name) => Some(name),
1224        TypeExpr::SelfType => Some("Self"),
1225        TypeExpr::Function { .. } => Some("function"),
1226    }
1227}
1228
1229static BUILTINS_DATABASE: StaticOnceCell<BuiltinsDatabase> = StaticOnceCell::new();
1230
1231fn build_builtins_database() -> BuiltinsDatabase {
1232    let mut modules: BTreeMap<&'static str, BuiltinModule> = BTreeMap::new();
1233    let module_specs: [(&'static str, &'static str, &'static [BuiltinFunction]); 3] = [
1234        ("task", "task runtime module", task_functions()),
1235        ("io", "io file & console module", io_functions()),
1236        ("os", "os filesystem module", os_functions()),
1237    ];
1238    for (name, description, functions) in module_specs {
1239        let mut module_funcs: Vec<&'static BuiltinFunction> = functions.iter().collect();
1240        module_funcs.sort_by(|a, b| a.name.cmp(b.name));
1241        modules.insert(
1242            name,
1243            BuiltinModule {
1244                name,
1245                description,
1246                functions: module_funcs,
1247            },
1248        );
1249    }
1250
1251    let mut global_functions: Vec<&'static BuiltinFunction> = base_functions().iter().collect();
1252    global_functions.sort_by(|a, b| a.name.cmp(b.name));
1253
1254    let mut methods: HashMap<&'static str, Vec<&'static BuiltinMethod>> = HashMap::new();
1255    for method in builtin_methods() {
1256        if let Some(key) = receiver_key(&method.receiver) {
1257            methods.entry(key).or_default().push(method);
1258        }
1259    }
1260    for vec in methods.values_mut() {
1261        vec.sort_by(|a, b| a.name.cmp(b.name));
1262    }
1263
1264    BuiltinsDatabase {
1265        global_functions,
1266        modules,
1267        methods,
1268    }
1269}
1270
1271pub fn builtins() -> &'static BuiltinsDatabase {
1272    BUILTINS_DATABASE.get_or_init(build_builtins_database)
1273}
1274
1275pub fn lookup_builtin_method(
1276    receiver: &Type,
1277    name: &str,
1278) -> Option<(&'static BuiltinMethod, HashMap<&'static str, Type>)> {
1279    for method in builtin_methods() {
1280        if method.name == name {
1281            if let Some(bindings) = match_receiver(&method.receiver, receiver) {
1282                return Some((method, bindings));
1283            }
1284        }
1285    }
1286    None
1287}