Skip to main content

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    Generic(&'static str),
53    SelfType,
54    Function {
55        params: Vec<TypeExpr>,
56        return_type: Box<TypeExpr>,
57    },
58}
59
60impl BuiltinFunction {
61    pub fn to_signature(&self, span: Span) -> FunctionSignature {
62        FunctionSignature {
63            params: self
64                .signature
65                .params
66                .iter()
67                .map(|expr| expr.instantiate(&HashMap::new(), Some(span)))
68                .collect(),
69            return_type: self
70                .signature
71                .return_type
72                .instantiate(&HashMap::new(), Some(span)),
73            is_method: false,
74        }
75    }
76
77    pub fn parameters(&self) -> Vec<(&'static str, &TypeExpr)> {
78        self.signature
79            .params
80            .iter()
81            .enumerate()
82            .map(|(idx, ty)| {
83                let name = self.param_names.get(idx).copied().unwrap_or("");
84                (name, ty)
85            })
86            .collect()
87    }
88
89    pub fn return_type(&self) -> &TypeExpr {
90        &self.signature.return_type
91    }
92}
93
94impl BuiltinMethod {
95    pub fn parameters(&self) -> Vec<(&'static str, &TypeExpr)> {
96        self.signature
97            .params
98            .iter()
99            .enumerate()
100            .map(|(idx, ty)| {
101                let name = self.param_names.get(idx).copied().unwrap_or("");
102                (name, ty)
103            })
104            .collect()
105    }
106
107    pub fn return_type(&self) -> &TypeExpr {
108        &self.signature.return_type
109    }
110
111    pub fn receiver_type(&self) -> &TypeExpr {
112        &self.receiver
113    }
114}
115
116impl TypeExpr {
117    pub fn instantiate(&self, generics: &HashMap<&'static str, Type>, span: Option<Span>) -> Type {
118        let span = span.unwrap_or_else(Span::dummy);
119        match self {
120            TypeExpr::Int => Type::new(TypeKind::Int, span),
121            TypeExpr::Float => Type::new(TypeKind::Float, span),
122            TypeExpr::Bool => Type::new(TypeKind::Bool, span),
123            TypeExpr::String => Type::new(TypeKind::String, span),
124            TypeExpr::Unit => Type::new(TypeKind::Unit, span),
125            TypeExpr::Unknown => Type::new(TypeKind::Unknown, span),
126            TypeExpr::Named(name) => Type::new(TypeKind::Named((*name).to_string()), span),
127            TypeExpr::Array(inner) => Type::new(
128                TypeKind::Array(Box::new(inner.instantiate(generics, Some(span)))),
129                span,
130            ),
131            TypeExpr::Map(key, value) => Type::new(
132                TypeKind::Map(
133                    Box::new(key.instantiate(generics, Some(span))),
134                    Box::new(value.instantiate(generics, Some(span))),
135                ),
136                span,
137            ),
138            TypeExpr::Result(ok, err) => Type::new(
139                TypeKind::Result(
140                    Box::new(ok.instantiate(generics, Some(span))),
141                    Box::new(err.instantiate(generics, Some(span))),
142                ),
143                span,
144            ),
145            TypeExpr::Option(inner) => Type::new(
146                TypeKind::Option(Box::new(inner.instantiate(generics, Some(span)))),
147                span,
148            ),
149            TypeExpr::Generic(name) => generics
150                .get(name)
151                .cloned()
152                .unwrap_or_else(|| Type::new(TypeKind::Unknown, span)),
153            TypeExpr::SelfType => generics
154                .get("Self")
155                .cloned()
156                .unwrap_or_else(|| Type::new(TypeKind::Unknown, span)),
157            TypeExpr::Function {
158                params,
159                return_type,
160            } => Type::new(
161                TypeKind::Function {
162                    params: params
163                        .iter()
164                        .map(|param| param.instantiate(generics, Some(span)))
165                        .collect(),
166                    return_type: Box::new(return_type.instantiate(generics, Some(span))),
167                },
168                span,
169            ),
170        }
171    }
172}
173
174fn match_type_expr(
175    pattern: &TypeExpr,
176    actual: &Type,
177    bindings: &mut HashMap<&'static str, Type>,
178) -> bool {
179    match (pattern, &actual.kind) {
180        (TypeExpr::SelfType, _) => {
181            bindings.insert("Self", actual.clone());
182            true
183        }
184        (TypeExpr::Generic(name), _) => {
185            if let Some(existing) = bindings.get(name) {
186                existing.kind == actual.kind
187            } else {
188                bindings.insert(name, actual.clone());
189                true
190            }
191        }
192        (TypeExpr::Int, TypeKind::Int) => true,
193        (TypeExpr::Float, TypeKind::Float) => true,
194        (TypeExpr::Bool, TypeKind::Bool) => true,
195        (TypeExpr::String, TypeKind::String) => true,
196        (TypeExpr::Unit, TypeKind::Unit) => true,
197        (TypeExpr::Unknown, TypeKind::Unknown) => true,
198        (TypeExpr::Named(expected), TypeKind::Named(actual_name)) => expected == actual_name,
199        (TypeExpr::Array(pattern_inner), TypeKind::Array(actual_inner)) => {
200            match_type_expr(pattern_inner, actual_inner, bindings)
201        }
202        (TypeExpr::Map(pattern_key, pattern_value), TypeKind::Map(actual_key, actual_value)) => {
203            match_type_expr(pattern_key, actual_key, bindings)
204                && match_type_expr(pattern_value, actual_value, bindings)
205        }
206        (TypeExpr::Option(pattern_inner), TypeKind::Option(actual_inner)) => {
207            match_type_expr(pattern_inner, actual_inner, bindings)
208        }
209        (TypeExpr::Result(pattern_ok, pattern_err), TypeKind::Result(actual_ok, actual_err)) => {
210            match_type_expr(pattern_ok, actual_ok, bindings)
211                && match_type_expr(pattern_err, actual_err, bindings)
212        }
213        _ => false,
214    }
215}
216
217pub fn match_receiver(pattern: &TypeExpr, actual: &Type) -> Option<HashMap<&'static str, Type>> {
218    let mut bindings = HashMap::new();
219    if match_type_expr(pattern, actual, &mut bindings) {
220        Some(bindings)
221    } else {
222        None
223    }
224}
225
226fn method(
227    receiver: TypeExpr,
228    name: &'static str,
229    description: &'static str,
230    param_names: &'static [&'static str],
231    params: Vec<TypeExpr>,
232    return_type: TypeExpr,
233) -> BuiltinMethod {
234    BuiltinMethod {
235        receiver,
236        name,
237        description,
238        signature: BuiltinSignature {
239            params,
240            return_type,
241        },
242        param_names,
243        semantics: MethodSemantics::Simple,
244    }
245}
246
247fn method_with_semantics(
248    receiver: TypeExpr,
249    name: &'static str,
250    description: &'static str,
251    param_names: &'static [&'static str],
252    params: Vec<TypeExpr>,
253    return_type: TypeExpr,
254    semantics: MethodSemantics,
255) -> BuiltinMethod {
256    let mut m = method(
257        receiver,
258        name,
259        description,
260        param_names,
261        params,
262        return_type,
263    );
264    m.semantics = semantics;
265    m
266}
267
268fn string_methods() -> Vec<BuiltinMethod> {
269    vec![
270        method(
271            TypeExpr::String,
272            "len",
273            "Return the length of the string in bytes",
274            &[],
275            vec![],
276            TypeExpr::Int,
277        ),
278        method(
279            TypeExpr::String,
280            "substring",
281            "Extract a substring from the string",
282            &["start", "end"],
283            vec![TypeExpr::Int, TypeExpr::Int],
284            TypeExpr::String,
285        ),
286        method(
287            TypeExpr::String,
288            "find",
289            "Find the first occurrence of a substring",
290            &["pattern"],
291            vec![TypeExpr::String],
292            TypeExpr::Option(Box::new(TypeExpr::Int)),
293        ),
294        method(
295            TypeExpr::String,
296            "starts_with",
297            "Check whether the string starts with a prefix",
298            &["prefix"],
299            vec![TypeExpr::String],
300            TypeExpr::Bool,
301        ),
302        method(
303            TypeExpr::String,
304            "ends_with",
305            "Check whether the string ends with a suffix",
306            &["suffix"],
307            vec![TypeExpr::String],
308            TypeExpr::Bool,
309        ),
310        method(
311            TypeExpr::String,
312            "contains",
313            "Check whether the string contains a substring",
314            &["substring"],
315            vec![TypeExpr::String],
316            TypeExpr::Bool,
317        ),
318        method(
319            TypeExpr::String,
320            "split",
321            "Split the string on a separator",
322            &["delimiter"],
323            vec![TypeExpr::String],
324            TypeExpr::Array(Box::new(TypeExpr::String)),
325        ),
326        method(
327            TypeExpr::String,
328            "trim",
329            "Trim whitespace from both ends of the string",
330            &[],
331            vec![],
332            TypeExpr::String,
333        ),
334        method(
335            TypeExpr::String,
336            "trim_start",
337            "Trim whitespace from the start of the string",
338            &[],
339            vec![],
340            TypeExpr::String,
341        ),
342        method(
343            TypeExpr::String,
344            "trim_end",
345            "Trim whitespace from the end of the string",
346            &[],
347            vec![],
348            TypeExpr::String,
349        ),
350        method(
351            TypeExpr::String,
352            "replace",
353            "Replace occurrences of a substring",
354            &["from", "to"],
355            vec![TypeExpr::String, TypeExpr::String],
356            TypeExpr::String,
357        ),
358        method(
359            TypeExpr::String,
360            "to_upper",
361            "Convert the string to uppercase",
362            &[],
363            vec![],
364            TypeExpr::String,
365        ),
366        method(
367            TypeExpr::String,
368            "to_lower",
369            "Convert the string to lowercase",
370            &[],
371            vec![],
372            TypeExpr::String,
373        ),
374        method(
375            TypeExpr::String,
376            "is_empty",
377            "Check if the string is empty",
378            &[],
379            vec![],
380            TypeExpr::Bool,
381        ),
382        method(
383            TypeExpr::String,
384            "chars",
385            "Return the characters as an array of strings",
386            &[],
387            vec![],
388            TypeExpr::Array(Box::new(TypeExpr::String)),
389        ),
390        method(
391            TypeExpr::String,
392            "lines",
393            "Return the lines as an array of strings",
394            &[],
395            vec![],
396            TypeExpr::Array(Box::new(TypeExpr::String)),
397        ),
398        method(
399            TypeExpr::String,
400            "iter",
401            "Return an iterator over the characters of the string",
402            &[],
403            vec![],
404            TypeExpr::Named("Iterator"),
405        ),
406    ]
407}
408
409fn array_methods() -> Vec<BuiltinMethod> {
410    let receiver = TypeExpr::Array(Box::new(TypeExpr::Generic("T")));
411    let mut methods = Vec::new();
412    methods.push(method(
413        receiver.clone(),
414        "iter",
415        "Return an iterator over the array items",
416        &[],
417        vec![],
418        TypeExpr::Named("Iterator"),
419    ));
420    methods.push(method(
421        receiver.clone(),
422        "len",
423        "Return the number of elements in the array",
424        &[],
425        vec![],
426        TypeExpr::Int,
427    ));
428    methods.push(method(
429        receiver.clone(),
430        "get",
431        "Return the element at the given index, if any",
432        &["index"],
433        vec![TypeExpr::Int],
434        TypeExpr::Option(Box::new(TypeExpr::Generic("T"))),
435    ));
436    methods.push(method(
437        receiver.clone(),
438        "first",
439        "Return the first element, if any",
440        &[],
441        vec![],
442        TypeExpr::Option(Box::new(TypeExpr::Generic("T"))),
443    ));
444    methods.push(method(
445        receiver.clone(),
446        "last",
447        "Return the last element, if any",
448        &[],
449        vec![],
450        TypeExpr::Option(Box::new(TypeExpr::Generic("T"))),
451    ));
452    methods.push(method(
453        receiver.clone(),
454        "push",
455        "Append a value to the array",
456        &["value"],
457        vec![TypeExpr::Generic("T")],
458        TypeExpr::Unit,
459    ));
460    methods.push(method(
461        receiver.clone(),
462        "pop",
463        "Remove and return the last element, if any",
464        &[],
465        vec![],
466        TypeExpr::Option(Box::new(TypeExpr::Generic("T"))),
467    ));
468    methods.push(method_with_semantics(
469        receiver.clone(),
470        "map",
471        "Transform each element using the provided function",
472        &["func"],
473        vec![TypeExpr::Function {
474            params: vec![TypeExpr::Generic("T")],
475            return_type: Box::new(TypeExpr::Unknown),
476        }],
477        TypeExpr::Array(Box::new(TypeExpr::Unknown)),
478        MethodSemantics::ArrayMap,
479    ));
480    methods.push(method_with_semantics(
481        receiver.clone(),
482        "filter",
483        "Keep elements where the predicate returns true",
484        &["func"],
485        vec![TypeExpr::Function {
486            params: vec![TypeExpr::Generic("T")],
487            return_type: Box::new(TypeExpr::Bool),
488        }],
489        TypeExpr::Array(Box::new(TypeExpr::Generic("T"))),
490        MethodSemantics::ArrayFilter,
491    ));
492    methods.push(method_with_semantics(
493        receiver.clone(),
494        "reduce",
495        "Fold elements into a single value",
496        &["initial", "func"],
497        vec![
498            TypeExpr::Unknown,
499            TypeExpr::Function {
500                params: vec![TypeExpr::Unknown, TypeExpr::Generic("T")],
501                return_type: Box::new(TypeExpr::Unknown),
502            },
503        ],
504        TypeExpr::Unknown,
505        MethodSemantics::ArrayReduce,
506    ));
507    methods.push(method(
508        receiver.clone(),
509        "slice",
510        "Return a slice of the array between two indices",
511        &["start", "end"],
512        vec![TypeExpr::Int, TypeExpr::Int],
513        TypeExpr::Array(Box::new(TypeExpr::Generic("T"))),
514    ));
515    methods.push(method(
516        receiver.clone(),
517        "clear",
518        "Remove all elements from the array",
519        &[],
520        vec![],
521        TypeExpr::Unit,
522    ));
523    methods.push(method(
524        receiver,
525        "is_empty",
526        "Check if the array contains no elements",
527        &[],
528        vec![],
529        TypeExpr::Bool,
530    ));
531    methods
532}
533
534fn map_methods() -> Vec<BuiltinMethod> {
535    let receiver = TypeExpr::Map(
536        Box::new(TypeExpr::Generic("K")),
537        Box::new(TypeExpr::Generic("V")),
538    );
539    vec![
540        method(
541            receiver.clone(),
542            "iter",
543            "Iterate over key/value pairs",
544            &[],
545            vec![],
546            TypeExpr::Named("Iterator"),
547        ),
548        method(
549            receiver.clone(),
550            "len",
551            "Return the number of entries in the map",
552            &[],
553            vec![],
554            TypeExpr::Int,
555        ),
556        method(
557            receiver.clone(),
558            "get",
559            "Look up a value by key",
560            &["key"],
561            vec![TypeExpr::Generic("K")],
562            TypeExpr::Option(Box::new(TypeExpr::Generic("V"))),
563        ),
564        method(
565            receiver.clone(),
566            "set",
567            "Insert or overwrite a key/value pair",
568            &["key", "value"],
569            vec![TypeExpr::Generic("K"), TypeExpr::Generic("V")],
570            TypeExpr::Unit,
571        ),
572        method(
573            receiver.clone(),
574            "has",
575            "Check whether the map contains a key",
576            &["key"],
577            vec![TypeExpr::Generic("K")],
578            TypeExpr::Bool,
579        ),
580        method(
581            receiver.clone(),
582            "delete",
583            "Remove an entry from the map",
584            &["key"],
585            vec![TypeExpr::Generic("K")],
586            TypeExpr::Option(Box::new(TypeExpr::Generic("V"))),
587        ),
588        method(
589            receiver.clone(),
590            "keys",
591            "Return the keys as an array",
592            &[],
593            vec![],
594            TypeExpr::Array(Box::new(TypeExpr::Generic("K"))),
595        ),
596        method(
597            receiver,
598            "values",
599            "Return the values as an array",
600            &[],
601            vec![],
602            TypeExpr::Array(Box::new(TypeExpr::Generic("V"))),
603        ),
604    ]
605}
606
607fn iterator_methods() -> Vec<BuiltinMethod> {
608    vec![
609        method(
610            TypeExpr::Named("Iterator"),
611            "iter",
612            "Return the iterator itself",
613            &[],
614            vec![],
615            TypeExpr::Named("Iterator"),
616        ),
617        method(
618            TypeExpr::Named("Iterator"),
619            "next",
620            "Advance the iterator and return the next value",
621            &[],
622            vec![],
623            TypeExpr::Option(Box::new(TypeExpr::Unknown)),
624        ),
625    ]
626}
627
628fn option_methods() -> Vec<BuiltinMethod> {
629    let receiver = TypeExpr::Option(Box::new(TypeExpr::Generic("T")));
630    vec![
631        method(
632            receiver.clone(),
633            "is_some",
634            "Check if the option contains a value",
635            &[],
636            vec![],
637            TypeExpr::Bool,
638        ),
639        method(
640            receiver.clone(),
641            "is_none",
642            "Check if the option is empty",
643            &[],
644            vec![],
645            TypeExpr::Bool,
646        ),
647        method(
648            receiver.clone(),
649            "unwrap",
650            "Unwrap the contained value, panicking if None",
651            &[],
652            vec![],
653            TypeExpr::Generic("T"),
654        ),
655        method(
656            receiver,
657            "unwrap_or",
658            "Return the value or a provided default",
659            &["default"],
660            vec![TypeExpr::Generic("T")],
661            TypeExpr::Generic("T"),
662        ),
663    ]
664}
665
666fn result_methods() -> Vec<BuiltinMethod> {
667    let receiver = TypeExpr::Result(
668        Box::new(TypeExpr::Generic("T")),
669        Box::new(TypeExpr::Generic("E")),
670    );
671    vec![
672        method(
673            receiver.clone(),
674            "is_ok",
675            "Check if the result is Ok",
676            &[],
677            vec![],
678            TypeExpr::Bool,
679        ),
680        method(
681            receiver.clone(),
682            "is_err",
683            "Check if the result is Err",
684            &[],
685            vec![],
686            TypeExpr::Bool,
687        ),
688        method(
689            receiver.clone(),
690            "unwrap",
691            "Unwrap the Ok value, panicking if Err",
692            &[],
693            vec![],
694            TypeExpr::Generic("T"),
695        ),
696        method(
697            receiver,
698            "unwrap_or",
699            "Return the Ok value or a provided default",
700            &["default"],
701            vec![TypeExpr::Generic("T")],
702            TypeExpr::Generic("T"),
703        ),
704    ]
705}
706
707fn float_methods() -> Vec<BuiltinMethod> {
708    vec![
709        method(
710            TypeExpr::Float,
711            "to_int",
712            "Convert the float to an integer by truncation",
713            &[],
714            vec![],
715            TypeExpr::Int,
716        ),
717        method(
718            TypeExpr::Float,
719            "floor",
720            "Return the greatest integer less than or equal to the value",
721            &[],
722            vec![],
723            TypeExpr::Float,
724        ),
725        method(
726            TypeExpr::Float,
727            "ceil",
728            "Return the smallest integer greater than or equal to the value",
729            &[],
730            vec![],
731            TypeExpr::Float,
732        ),
733        method(
734            TypeExpr::Float,
735            "round",
736            "Round the float to the nearest integer",
737            &[],
738            vec![],
739            TypeExpr::Float,
740        ),
741        method(
742            TypeExpr::Float,
743            "sqrt",
744            "Return the square root of the float",
745            &[],
746            vec![],
747            TypeExpr::Float,
748        ),
749        method(
750            TypeExpr::Float,
751            "abs",
752            "Return the absolute value of the float",
753            &[],
754            vec![],
755            TypeExpr::Float,
756        ),
757        method(
758            TypeExpr::Float,
759            "sin",
760            "Return the sine of the float in radians",
761            &[],
762            vec![],
763            TypeExpr::Float,
764        ),
765        method(
766            TypeExpr::Float,
767            "cos",
768            "Return the cosine of the float in radians",
769            &[],
770            vec![],
771            TypeExpr::Float,
772        ),
773        method(
774            TypeExpr::Float,
775            "tan",
776            "Return the tangent of the float in radians",
777            &[],
778            vec![],
779            TypeExpr::Float,
780        ),
781        method(
782            TypeExpr::Float,
783            "asin",
784            "Return the arcsine of the float in radians",
785            &[],
786            vec![],
787            TypeExpr::Float,
788        ),
789        method(
790            TypeExpr::Float,
791            "acos",
792            "Return the arccosine of the float in radians",
793            &[],
794            vec![],
795            TypeExpr::Float,
796        ),
797        method(
798            TypeExpr::Float,
799            "atan",
800            "Return the arctangent of the float in radians",
801            &[],
802            vec![],
803            TypeExpr::Float,
804        ),
805        method(
806            TypeExpr::Float,
807            "atan2",
808            "Return the arctangent of y/x using the receiver as y",
809            &["other"],
810            vec![TypeExpr::Float],
811            TypeExpr::Float,
812        ),
813        method(
814            TypeExpr::Float,
815            "min",
816            "Return the smaller of two numbers",
817            &["other"],
818            vec![TypeExpr::Float],
819            TypeExpr::Float,
820        ),
821        method(
822            TypeExpr::Float,
823            "max",
824            "Return the larger of two numbers",
825            &["other"],
826            vec![TypeExpr::Float],
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            "min",
861            "Return the smaller of two integers",
862            &["other"],
863            vec![TypeExpr::Int],
864            TypeExpr::Int,
865        ),
866        method(
867            TypeExpr::Int,
868            "max",
869            "Return the larger of two integers",
870            &["other"],
871            vec![TypeExpr::Int],
872            TypeExpr::Int,
873        ),
874        method(
875            TypeExpr::Int,
876            "clamp",
877            "Clamp the integer between a minimum and maximum value",
878            &["min", "max"],
879            vec![TypeExpr::Int, TypeExpr::Int],
880            TypeExpr::Int,
881        ),
882    ]
883}
884
885fn lua_table_methods() -> Vec<BuiltinMethod> {
886    vec![
887        method(
888            TypeExpr::Named("LuaTable"),
889            "len",
890            "Return the length of the array portion (1-based contiguous keys)",
891            &[],
892            vec![],
893            TypeExpr::Int,
894        ),
895        method(
896            TypeExpr::Named("LuaTable"),
897            "push",
898            "Append a value to the array portion",
899            &["value"],
900            vec![TypeExpr::Unknown],
901            TypeExpr::Unit,
902        ),
903        method(
904            TypeExpr::Named("LuaTable"),
905            "insert",
906            "Insert a value into the array portion at a position",
907            &["pos", "value"],
908            vec![TypeExpr::Unknown, TypeExpr::Unknown],
909            TypeExpr::Unit,
910        ),
911        method(
912            TypeExpr::Named("LuaTable"),
913            "remove",
914            "Remove a value from the array portion at a position",
915            &["pos"],
916            vec![TypeExpr::Unknown],
917            TypeExpr::Unknown,
918        ),
919        method(
920            TypeExpr::Named("LuaTable"),
921            "concat",
922            "Concatenate array elements into a string",
923            &["sep", "i", "j"],
924            vec![TypeExpr::Unknown, TypeExpr::Unknown, TypeExpr::Unknown],
925            TypeExpr::String,
926        ),
927        method(
928            TypeExpr::Named("LuaTable"),
929            "unpack",
930            "Unpack array elements as multiple returns",
931            &["i", "j"],
932            vec![TypeExpr::Unknown, TypeExpr::Unknown],
933            TypeExpr::Unknown,
934        ),
935        method(
936            TypeExpr::Named("LuaTable"),
937            "sort",
938            "Sort the array portion",
939            &["comp"],
940            vec![TypeExpr::Unknown],
941            TypeExpr::Unit,
942        ),
943        method(
944            TypeExpr::Named("LuaTable"),
945            "maxn",
946            "Find the largest positive numeric index",
947            &[],
948            vec![],
949            TypeExpr::Int,
950        ),
951    ]
952}
953
954static BASE_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
955
956fn build_base_functions() -> Vec<BuiltinFunction> {
957    vec![
958        BuiltinFunction {
959            name: "print",
960            description: "Print values without a newline",
961            signature: BuiltinSignature {
962                params: vec![TypeExpr::Unknown],
963                return_type: TypeExpr::Unit,
964            },
965            param_names: &["value"],
966        },
967        BuiltinFunction {
968            name: "println",
969            description: "Print values followed by a newline",
970            signature: BuiltinSignature {
971                params: vec![TypeExpr::Unknown],
972                return_type: TypeExpr::Unit,
973            },
974            param_names: &["value"],
975        },
976        BuiltinFunction {
977            name: "type",
978            description: "Return the runtime type name",
979            signature: BuiltinSignature {
980                params: vec![TypeExpr::Unknown],
981                return_type: TypeExpr::String,
982            },
983            param_names: &["value"],
984        },
985        BuiltinFunction {
986            name: "tostring",
987            description: "Convert a value to a string",
988            signature: BuiltinSignature {
989                params: vec![TypeExpr::Unknown],
990                return_type: TypeExpr::String,
991            },
992            param_names: &["value"],
993        },
994        BuiltinFunction {
995            name: "error",
996            description: "Raise a runtime error",
997            signature: BuiltinSignature {
998                params: vec![TypeExpr::Unknown],
999                return_type: TypeExpr::Unknown,
1000            },
1001            param_names: &["message"],
1002        },
1003        BuiltinFunction {
1004            name: "assert",
1005            description: "Assert a condition or raise an error",
1006            signature: BuiltinSignature {
1007                params: vec![TypeExpr::Unknown, TypeExpr::Unknown],
1008                return_type: TypeExpr::Unknown,
1009            },
1010            param_names: &["cond", "message"],
1011        },
1012        BuiltinFunction {
1013            name: "tonumber",
1014            description: "Convert a value to a number",
1015            signature: BuiltinSignature {
1016                params: vec![TypeExpr::Unknown, TypeExpr::Unknown],
1017                return_type: TypeExpr::Unknown,
1018            },
1019            param_names: &["value", "base"],
1020        },
1021        BuiltinFunction {
1022            name: "pairs",
1023            description: "Iterate over key/value pairs",
1024            signature: BuiltinSignature {
1025                params: vec![TypeExpr::Unknown],
1026                return_type: TypeExpr::Named("Iterator"),
1027            },
1028            param_names: &["table"],
1029        },
1030        BuiltinFunction {
1031            name: "ipairs",
1032            description: "Iterate over array elements with indices",
1033            signature: BuiltinSignature {
1034                params: vec![TypeExpr::Unknown],
1035                return_type: TypeExpr::Named("Iterator"),
1036            },
1037            param_names: &["array"],
1038        },
1039        BuiltinFunction {
1040            name: "select",
1041            description: "Return arguments starting at an index or the argument count",
1042            signature: BuiltinSignature {
1043                params: vec![TypeExpr::Unknown, TypeExpr::Unknown],
1044                return_type: TypeExpr::Unknown,
1045            },
1046            param_names: &["index_or_hash", "..."],
1047        },
1048        BuiltinFunction {
1049            name: "random",
1050            description: "Generate a random number in an optional range",
1051            signature: BuiltinSignature {
1052                params: vec![TypeExpr::Unknown, TypeExpr::Unknown],
1053                return_type: TypeExpr::Unknown,
1054            },
1055            param_names: &["m", "n"],
1056        },
1057        BuiltinFunction {
1058            name: "randomseed",
1059            description: "Seed the random number generator",
1060            signature: BuiltinSignature {
1061                params: vec![TypeExpr::Unknown],
1062                return_type: TypeExpr::Unit,
1063            },
1064            param_names: &["seed"],
1065        },
1066        BuiltinFunction {
1067            name: "unpack",
1068            description: "Unpack array elements into multiple returns",
1069            signature: BuiltinSignature {
1070                params: vec![TypeExpr::Unknown, TypeExpr::Unknown, TypeExpr::Unknown],
1071                return_type: TypeExpr::Unknown,
1072            },
1073            param_names: &["table", "i", "j"],
1074        },
1075        BuiltinFunction {
1076            name: "setmetatable",
1077            description: "Assign a metatable to a Lua table value",
1078            signature: BuiltinSignature {
1079                params: vec![TypeExpr::Unknown, TypeExpr::Unknown],
1080                return_type: TypeExpr::Unknown,
1081            },
1082            param_names: &["table", "meta"],
1083        },
1084    ]
1085}
1086
1087static STRING_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
1088static TASK_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
1089static LUA_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
1090
1091fn build_task_functions() -> Vec<BuiltinFunction> {
1092    vec![
1093        BuiltinFunction {
1094            name: "task.run",
1095            description: "Run a function as a task",
1096            signature: BuiltinSignature {
1097                params: vec![TypeExpr::Unknown],
1098                return_type: TypeExpr::Named("Task"),
1099            },
1100            param_names: &["func"],
1101        },
1102        BuiltinFunction {
1103            name: "task.create",
1104            description: "Create a suspended task",
1105            signature: BuiltinSignature {
1106                params: vec![TypeExpr::Unknown],
1107                return_type: TypeExpr::Named("Task"),
1108            },
1109            param_names: &["func"],
1110        },
1111        BuiltinFunction {
1112            name: "task.status",
1113            description: "Get the status of a task",
1114            signature: BuiltinSignature {
1115                params: vec![TypeExpr::Named("Task")],
1116                return_type: TypeExpr::Named("TaskStatus"),
1117            },
1118            param_names: &["task"],
1119        },
1120        BuiltinFunction {
1121            name: "task.info",
1122            description: "Get detailed information about a task",
1123            signature: BuiltinSignature {
1124                params: vec![TypeExpr::Named("Task")],
1125                return_type: TypeExpr::Named("TaskInfo"),
1126            },
1127            param_names: &["task"],
1128        },
1129        BuiltinFunction {
1130            name: "task.resume",
1131            description: "Resume a suspended task",
1132            signature: BuiltinSignature {
1133                params: vec![TypeExpr::Named("Task")],
1134                return_type: TypeExpr::Named("TaskInfo"),
1135            },
1136            param_names: &["task"],
1137        },
1138        BuiltinFunction {
1139            name: "task.yield",
1140            description: "Yield from the current task",
1141            signature: BuiltinSignature {
1142                params: vec![TypeExpr::Unknown],
1143                return_type: TypeExpr::Unknown,
1144            },
1145            param_names: &["value"],
1146        },
1147        BuiltinFunction {
1148            name: "task.stop",
1149            description: "Stop a running task",
1150            signature: BuiltinSignature {
1151                params: vec![TypeExpr::Named("Task")],
1152                return_type: TypeExpr::Bool,
1153            },
1154            param_names: &["task"],
1155        },
1156        BuiltinFunction {
1157            name: "task.restart",
1158            description: "Restart a completed task",
1159            signature: BuiltinSignature {
1160                params: vec![TypeExpr::Named("Task")],
1161                return_type: TypeExpr::Named("TaskInfo"),
1162            },
1163            param_names: &["task"],
1164        },
1165        BuiltinFunction {
1166            name: "task.current",
1167            description: "Return the currently executing task",
1168            signature: BuiltinSignature {
1169                params: vec![],
1170                return_type: TypeExpr::Option(Box::new(TypeExpr::Named("Task"))),
1171            },
1172            param_names: &[],
1173        },
1174    ]
1175}
1176
1177fn build_lua_functions() -> Vec<BuiltinFunction> {
1178    vec![
1179        BuiltinFunction {
1180            name: "lua.to_value",
1181            description: "Wrap a Lust value in LuaValue",
1182            signature: BuiltinSignature {
1183                params: vec![TypeExpr::Unknown],
1184                return_type: TypeExpr::Named("LuaValue"),
1185            },
1186            param_names: &["value"],
1187        },
1188        BuiltinFunction {
1189            name: "lua.require",
1190            description: "Lua-style module resolver (loads from already-initialized globals when available)",
1191            signature: BuiltinSignature {
1192                params: vec![TypeExpr::Unknown],
1193                return_type: TypeExpr::Unknown,
1194            },
1195            param_names: &["name"],
1196        },
1197        BuiltinFunction {
1198            name: "lua.table",
1199            description: "Create an empty Lua-style table",
1200            signature: BuiltinSignature {
1201                params: vec![],
1202                return_type: TypeExpr::Named("LuaTable"),
1203            },
1204            param_names: &[],
1205        },
1206        BuiltinFunction {
1207            name: "lua.setmetatable",
1208            description: "Set the metatable for a Lua table value",
1209            signature: BuiltinSignature {
1210                params: vec![TypeExpr::Named("LuaValue"), TypeExpr::Named("LuaValue")],
1211                return_type: TypeExpr::Named("LuaValue"),
1212            },
1213            param_names: &["table", "meta"],
1214        },
1215        BuiltinFunction {
1216            name: "lua.getmetatable",
1217            description: "Get the metatable for a Lua table value",
1218            signature: BuiltinSignature {
1219                params: vec![TypeExpr::Named("LuaValue")],
1220                return_type: TypeExpr::Named("LuaValue"),
1221            },
1222            param_names: &["table"],
1223        },
1224        BuiltinFunction {
1225            name: "lua.unwrap",
1226            description: "Extract a raw Lust value from a LuaValue wrapper",
1227            signature: BuiltinSignature {
1228                params: vec![TypeExpr::Unknown],
1229                return_type: TypeExpr::Unknown,
1230            },
1231            param_names: &["value"],
1232        },
1233    ]
1234}
1235
1236fn build_string_functions() -> Vec<BuiltinFunction> {
1237    vec![
1238        BuiltinFunction {
1239            name: "string.len",
1240            description: "Return the length of a string",
1241            signature: BuiltinSignature {
1242                params: vec![TypeExpr::Unknown],
1243                return_type: TypeExpr::Int,
1244            },
1245            param_names: &["s"],
1246        },
1247        BuiltinFunction {
1248            name: "string.lower",
1249            description: "Lowercase a string",
1250            signature: BuiltinSignature {
1251                params: vec![TypeExpr::Unknown],
1252                return_type: TypeExpr::String,
1253            },
1254            param_names: &["s"],
1255        },
1256        BuiltinFunction {
1257            name: "string.upper",
1258            description: "Uppercase a string",
1259            signature: BuiltinSignature {
1260                params: vec![TypeExpr::Unknown],
1261                return_type: TypeExpr::String,
1262            },
1263            param_names: &["s"],
1264        },
1265        BuiltinFunction {
1266            name: "string.sub",
1267            description: "Extract a substring using Lua-style indices",
1268            signature: BuiltinSignature {
1269                params: vec![TypeExpr::Unknown, TypeExpr::Unknown, TypeExpr::Unknown],
1270                return_type: TypeExpr::String,
1271            },
1272            param_names: &["s", "i", "j"],
1273        },
1274        BuiltinFunction {
1275            name: "string.byte",
1276            description: "Return byte values from a string slice",
1277            signature: BuiltinSignature {
1278                params: vec![TypeExpr::Unknown, TypeExpr::Unknown, TypeExpr::Unknown],
1279                return_type: TypeExpr::Unknown,
1280            },
1281            param_names: &["s", "i", "j"],
1282        },
1283        BuiltinFunction {
1284            name: "string.char",
1285            description: "Create a string from numeric bytes",
1286            signature: BuiltinSignature {
1287                params: vec![TypeExpr::Unknown],
1288                return_type: TypeExpr::String,
1289            },
1290            param_names: &["byte"],
1291        },
1292        BuiltinFunction {
1293            name: "string.find",
1294            description: "Find a pattern within a string",
1295            signature: BuiltinSignature {
1296                params: vec![
1297                    TypeExpr::Unknown,
1298                    TypeExpr::Unknown,
1299                    TypeExpr::Unknown,
1300                    TypeExpr::Unknown,
1301                ],
1302                return_type: TypeExpr::Unknown,
1303            },
1304            param_names: &["s", "pattern", "init", "plain"],
1305        },
1306        BuiltinFunction {
1307            name: "string.gsub",
1308            description: "Globally substitute occurrences of a pattern",
1309            signature: BuiltinSignature {
1310                params: vec![
1311                    TypeExpr::Unknown,
1312                    TypeExpr::Unknown,
1313                    TypeExpr::Unknown,
1314                    TypeExpr::Unknown,
1315                ],
1316                return_type: TypeExpr::Unknown,
1317            },
1318            param_names: &["s", "pattern", "repl", "n"],
1319        },
1320        BuiltinFunction {
1321            name: "string.format",
1322            description: "Format values according to a pattern",
1323            signature: BuiltinSignature {
1324                params: vec![TypeExpr::Unknown],
1325                return_type: TypeExpr::String,
1326            },
1327            param_names: &["fmt"],
1328        },
1329    ]
1330}
1331
1332static IO_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
1333
1334fn build_io_functions() -> Vec<BuiltinFunction> {
1335    vec![
1336        BuiltinFunction {
1337            name: "io.read_file",
1338            description: "Read the contents of a file",
1339            signature: BuiltinSignature {
1340                params: vec![TypeExpr::String],
1341                return_type: TypeExpr::Result(
1342                    Box::new(TypeExpr::String),
1343                    Box::new(TypeExpr::String),
1344                ),
1345            },
1346            param_names: &["path"],
1347        },
1348        BuiltinFunction {
1349            name: "io.read_file_bytes",
1350            description: "Read the contents of a file as byte values",
1351            signature: BuiltinSignature {
1352                params: vec![TypeExpr::String],
1353                return_type: TypeExpr::Result(
1354                    Box::new(TypeExpr::Array(Box::new(TypeExpr::Int))),
1355                    Box::new(TypeExpr::String),
1356                ),
1357            },
1358            param_names: &["path"],
1359        },
1360        BuiltinFunction {
1361            name: "io.write_file",
1362            description: "Write contents to a file",
1363            signature: BuiltinSignature {
1364                params: vec![TypeExpr::String, TypeExpr::Unknown],
1365                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1366            },
1367            param_names: &["path", "value"],
1368        },
1369        BuiltinFunction {
1370            name: "io.read_stdin",
1371            description: "Read all available stdin",
1372            signature: BuiltinSignature {
1373                params: vec![],
1374                return_type: TypeExpr::Result(
1375                    Box::new(TypeExpr::String),
1376                    Box::new(TypeExpr::String),
1377                ),
1378            },
1379            param_names: &[],
1380        },
1381        BuiltinFunction {
1382            name: "io.read_line",
1383            description: "Read a single line from stdin",
1384            signature: BuiltinSignature {
1385                params: vec![],
1386                return_type: TypeExpr::Result(
1387                    Box::new(TypeExpr::String),
1388                    Box::new(TypeExpr::String),
1389                ),
1390            },
1391            param_names: &[],
1392        },
1393        BuiltinFunction {
1394            name: "io.write_stdout",
1395            description: "Write a value to stdout",
1396            signature: BuiltinSignature {
1397                params: vec![TypeExpr::Unknown],
1398                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1399            },
1400            param_names: &["value"],
1401        },
1402    ]
1403}
1404
1405static OS_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
1406
1407fn build_os_functions() -> Vec<BuiltinFunction> {
1408    vec![
1409        BuiltinFunction {
1410            name: "os.time",
1411            description: "Get the current UNIX timestamp with sub-second precision",
1412            signature: BuiltinSignature {
1413                params: vec![],
1414                return_type: TypeExpr::Float,
1415            },
1416            param_names: &[],
1417        },
1418        BuiltinFunction {
1419            name: "os.sleep",
1420            description: "Sleep for the given number of seconds",
1421            signature: BuiltinSignature {
1422                params: vec![TypeExpr::Float],
1423                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1424            },
1425            param_names: &["seconds"],
1426        },
1427        BuiltinFunction {
1428            name: "os.create_file",
1429            description: "Create an empty file on disk",
1430            signature: BuiltinSignature {
1431                params: vec![TypeExpr::String],
1432                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1433            },
1434            param_names: &["path"],
1435        },
1436        BuiltinFunction {
1437            name: "os.create_dir",
1438            description: "Create a directory",
1439            signature: BuiltinSignature {
1440                params: vec![TypeExpr::String],
1441                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1442            },
1443            param_names: &["path"],
1444        },
1445        BuiltinFunction {
1446            name: "os.remove_file",
1447            description: "Remove a file from disk",
1448            signature: BuiltinSignature {
1449                params: vec![TypeExpr::String],
1450                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1451            },
1452            param_names: &["path"],
1453        },
1454        BuiltinFunction {
1455            name: "os.remove_dir",
1456            description: "Remove an empty directory",
1457            signature: BuiltinSignature {
1458                params: vec![TypeExpr::String],
1459                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1460            },
1461            param_names: &["path"],
1462        },
1463        BuiltinFunction {
1464            name: "os.rename",
1465            description: "Rename or move a path",
1466            signature: BuiltinSignature {
1467                params: vec![TypeExpr::String, TypeExpr::String],
1468                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1469            },
1470            param_names: &["from", "to"],
1471        },
1472    ]
1473}
1474
1475static BUILTIN_METHODS: StaticOnceCell<Vec<BuiltinMethod>> = StaticOnceCell::new();
1476
1477fn build_builtin_methods() -> Vec<BuiltinMethod> {
1478    let mut methods = Vec::new();
1479    methods.extend(string_methods());
1480    methods.extend(array_methods());
1481    methods.extend(map_methods());
1482    methods.extend(lua_table_methods());
1483    methods.extend(iterator_methods());
1484    methods.extend(option_methods());
1485    methods.extend(result_methods());
1486    methods.extend(float_methods());
1487    methods.extend(int_methods());
1488    methods
1489}
1490
1491pub fn base_functions() -> &'static [BuiltinFunction] {
1492    BASE_FUNCTIONS.get_or_init(build_base_functions).as_slice()
1493}
1494
1495pub fn string_functions() -> &'static [BuiltinFunction] {
1496    STRING_FUNCTIONS.get_or_init(build_string_functions).as_slice()
1497}
1498
1499pub fn task_functions() -> &'static [BuiltinFunction] {
1500    TASK_FUNCTIONS.get_or_init(build_task_functions).as_slice()
1501}
1502
1503pub fn lua_functions() -> &'static [BuiltinFunction] {
1504    LUA_FUNCTIONS.get_or_init(build_lua_functions).as_slice()
1505}
1506
1507pub fn io_functions() -> &'static [BuiltinFunction] {
1508    IO_FUNCTIONS.get_or_init(build_io_functions).as_slice()
1509}
1510
1511pub fn os_functions() -> &'static [BuiltinFunction] {
1512    OS_FUNCTIONS.get_or_init(build_os_functions).as_slice()
1513}
1514
1515pub fn builtin_methods() -> &'static [BuiltinMethod] {
1516    BUILTIN_METHODS
1517        .get_or_init(build_builtin_methods)
1518        .as_slice()
1519}
1520
1521pub struct BuiltinModule {
1522    name: &'static str,
1523    description: &'static str,
1524    functions: Vec<&'static BuiltinFunction>,
1525}
1526
1527impl BuiltinModule {
1528    pub fn name(&self) -> &'static str {
1529        self.name
1530    }
1531
1532    pub fn description(&self) -> &'static str {
1533        self.description
1534    }
1535
1536    pub fn functions(&self) -> &[&'static BuiltinFunction] {
1537        &self.functions
1538    }
1539}
1540
1541pub struct BuiltinsDatabase {
1542    global_functions: Vec<&'static BuiltinFunction>,
1543    modules: BTreeMap<&'static str, BuiltinModule>,
1544    methods: HashMap<&'static str, Vec<&'static BuiltinMethod>>,
1545}
1546
1547impl BuiltinsDatabase {
1548    pub fn global_functions(&self) -> &[&'static BuiltinFunction] {
1549        &self.global_functions
1550    }
1551
1552    pub fn module(&self, name: &str) -> Option<&BuiltinModule> {
1553        self.modules.get(name)
1554    }
1555
1556    pub fn methods_for(&self, type_name: &str) -> Option<&[&'static BuiltinMethod]> {
1557        self.methods
1558            .get(type_name)
1559            .map(|methods| methods.as_slice())
1560    }
1561
1562    pub fn modules(&self) -> impl Iterator<Item = &BuiltinModule> {
1563        self.modules.values()
1564    }
1565}
1566
1567fn receiver_key(expr: &TypeExpr) -> Option<&'static str> {
1568    match expr {
1569        TypeExpr::String => Some("String"),
1570        TypeExpr::Array(_) => Some("Array"),
1571        TypeExpr::Map(_, _) => Some("Map"),
1572        TypeExpr::Named(name) => Some(name),
1573        TypeExpr::Option(_) => Some("Option"),
1574        TypeExpr::Result(_, _) => Some("Result"),
1575        TypeExpr::Float => Some("Float"),
1576        TypeExpr::Int => Some("Int"),
1577        TypeExpr::Bool => Some("Bool"),
1578        TypeExpr::Unknown => Some("Unknown"),
1579        TypeExpr::Unit => Some("Unit"),
1580        TypeExpr::Generic(name) => Some(name),
1581        TypeExpr::SelfType => Some("Self"),
1582        TypeExpr::Function { .. } => Some("function"),
1583    }
1584}
1585
1586static BUILTINS_DATABASE: StaticOnceCell<BuiltinsDatabase> = StaticOnceCell::new();
1587
1588fn build_builtins_database() -> BuiltinsDatabase {
1589    let mut modules: BTreeMap<&'static str, BuiltinModule> = BTreeMap::new();
1590    let module_specs: [(&'static str, &'static str, &'static [BuiltinFunction]); 4] = [
1591        ("task", "task runtime module", task_functions()),
1592        ("io", "io file & console module", io_functions()),
1593        ("os", "os filesystem module", os_functions()),
1594        ("string", "string compatibility module", string_functions()),
1595    ];
1596    for (name, description, functions) in module_specs {
1597        let mut module_funcs: Vec<&'static BuiltinFunction> = functions.iter().collect();
1598        module_funcs.sort_by(|a, b| a.name.cmp(b.name));
1599        modules.insert(
1600            name,
1601            BuiltinModule {
1602                name,
1603                description,
1604                functions: module_funcs,
1605            },
1606        );
1607    }
1608
1609    let mut global_functions: Vec<&'static BuiltinFunction> = base_functions().iter().collect();
1610    global_functions.sort_by(|a, b| a.name.cmp(b.name));
1611
1612    let mut methods: HashMap<&'static str, Vec<&'static BuiltinMethod>> = HashMap::new();
1613    for method in builtin_methods() {
1614        if let Some(key) = receiver_key(&method.receiver) {
1615            methods.entry(key).or_default().push(method);
1616        }
1617    }
1618    for vec in methods.values_mut() {
1619        vec.sort_by(|a, b| a.name.cmp(b.name));
1620    }
1621
1622    BuiltinsDatabase {
1623        global_functions,
1624        modules,
1625        methods,
1626    }
1627}
1628
1629pub fn builtins() -> &'static BuiltinsDatabase {
1630    BUILTINS_DATABASE.get_or_init(build_builtins_database)
1631}
1632
1633pub fn lookup_builtin_method(
1634    receiver: &Type,
1635    name: &str,
1636) -> Option<(&'static BuiltinMethod, HashMap<&'static str, Type>)> {
1637    for method in builtin_methods() {
1638        if method.name == name {
1639            if let Some(bindings) = match_receiver(&method.receiver, receiver) {
1640                return Some((method, bindings));
1641            }
1642        }
1643    }
1644    None
1645}