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            "clamp",
760            "Clamp the float between a minimum and maximum value",
761            &["min", "max"],
762            vec![TypeExpr::Float, TypeExpr::Float],
763            TypeExpr::Float,
764        ),
765    ]
766}
767
768fn int_methods() -> Vec<BuiltinMethod> {
769    vec![
770        method(
771            TypeExpr::Int,
772            "to_float",
773            "Convert the integer to a float",
774            &[],
775            vec![],
776            TypeExpr::Float,
777        ),
778        method(
779            TypeExpr::Int,
780            "abs",
781            "Return the absolute value of the integer",
782            &[],
783            vec![],
784            TypeExpr::Int,
785        ),
786        method(
787            TypeExpr::Int,
788            "clamp",
789            "Clamp the integer between a minimum and maximum value",
790            &["min", "max"],
791            vec![TypeExpr::Int, TypeExpr::Int],
792            TypeExpr::Int,
793        ),
794    ]
795}
796
797static BASE_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
798
799fn build_base_functions() -> Vec<BuiltinFunction> {
800    vec![
801        BuiltinFunction {
802            name: "print",
803            description: "Print values without a newline",
804            signature: BuiltinSignature {
805                params: vec![TypeExpr::Unknown],
806                return_type: TypeExpr::Unit,
807            },
808            param_names: &["value"],
809        },
810        BuiltinFunction {
811            name: "println",
812            description: "Print values followed by a newline",
813            signature: BuiltinSignature {
814                params: vec![TypeExpr::Unknown],
815                return_type: TypeExpr::Unit,
816            },
817            param_names: &["value"],
818        },
819        BuiltinFunction {
820            name: "type",
821            description: "Return the runtime type name",
822            signature: BuiltinSignature {
823                params: vec![TypeExpr::Unknown],
824                return_type: TypeExpr::String,
825            },
826            param_names: &["value"],
827        },
828        BuiltinFunction {
829            name: "tostring",
830            description: "Convert a value to a string",
831            signature: BuiltinSignature {
832                params: vec![TypeExpr::Unknown],
833                return_type: TypeExpr::String,
834            },
835            param_names: &["value"],
836        },
837    ]
838}
839
840static TASK_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
841
842fn build_task_functions() -> Vec<BuiltinFunction> {
843    vec![
844        BuiltinFunction {
845            name: "task.run",
846            description: "Run a function as a task",
847            signature: BuiltinSignature {
848                params: vec![TypeExpr::Unknown],
849                return_type: TypeExpr::Named("Task"),
850            },
851            param_names: &["func"],
852        },
853        BuiltinFunction {
854            name: "task.create",
855            description: "Create a suspended task",
856            signature: BuiltinSignature {
857                params: vec![TypeExpr::Unknown],
858                return_type: TypeExpr::Named("Task"),
859            },
860            param_names: &["func"],
861        },
862        BuiltinFunction {
863            name: "task.status",
864            description: "Get the status of a task",
865            signature: BuiltinSignature {
866                params: vec![TypeExpr::Named("Task")],
867                return_type: TypeExpr::Named("TaskStatus"),
868            },
869            param_names: &["task"],
870        },
871        BuiltinFunction {
872            name: "task.info",
873            description: "Get detailed information about a task",
874            signature: BuiltinSignature {
875                params: vec![TypeExpr::Named("Task")],
876                return_type: TypeExpr::Named("TaskInfo"),
877            },
878            param_names: &["task"],
879        },
880        BuiltinFunction {
881            name: "task.resume",
882            description: "Resume a suspended task",
883            signature: BuiltinSignature {
884                params: vec![TypeExpr::Named("Task")],
885                return_type: TypeExpr::Named("TaskInfo"),
886            },
887            param_names: &["task"],
888        },
889        BuiltinFunction {
890            name: "task.yield",
891            description: "Yield from the current task",
892            signature: BuiltinSignature {
893                params: vec![TypeExpr::Unknown],
894                return_type: TypeExpr::Unknown,
895            },
896            param_names: &["value"],
897        },
898        BuiltinFunction {
899            name: "task.stop",
900            description: "Stop a running task",
901            signature: BuiltinSignature {
902                params: vec![TypeExpr::Named("Task")],
903                return_type: TypeExpr::Bool,
904            },
905            param_names: &["task"],
906        },
907        BuiltinFunction {
908            name: "task.restart",
909            description: "Restart a completed task",
910            signature: BuiltinSignature {
911                params: vec![TypeExpr::Named("Task")],
912                return_type: TypeExpr::Named("TaskInfo"),
913            },
914            param_names: &["task"],
915        },
916        BuiltinFunction {
917            name: "task.current",
918            description: "Return the currently executing task",
919            signature: BuiltinSignature {
920                params: vec![],
921                return_type: TypeExpr::Option(Box::new(TypeExpr::Named("Task"))),
922            },
923            param_names: &[],
924        },
925    ]
926}
927
928static IO_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
929
930fn build_io_functions() -> Vec<BuiltinFunction> {
931    vec![
932        BuiltinFunction {
933            name: "io.read_file",
934            description: "Read the contents of a file",
935            signature: BuiltinSignature {
936                params: vec![TypeExpr::String],
937                return_type: TypeExpr::Result(
938                    Box::new(TypeExpr::String),
939                    Box::new(TypeExpr::String),
940                ),
941            },
942            param_names: &["path"],
943        },
944        BuiltinFunction {
945            name: "io.read_file_bytes",
946            description: "Read the contents of a file as byte values",
947            signature: BuiltinSignature {
948                params: vec![TypeExpr::String],
949                return_type: TypeExpr::Result(
950                    Box::new(TypeExpr::Array(Box::new(TypeExpr::Int))),
951                    Box::new(TypeExpr::String),
952                ),
953            },
954            param_names: &["path"],
955        },
956        BuiltinFunction {
957            name: "io.write_file",
958            description: "Write contents to a file",
959            signature: BuiltinSignature {
960                params: vec![TypeExpr::String, TypeExpr::Unknown],
961                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
962            },
963            param_names: &["path", "value"],
964        },
965        BuiltinFunction {
966            name: "io.read_stdin",
967            description: "Read all available stdin",
968            signature: BuiltinSignature {
969                params: vec![],
970                return_type: TypeExpr::Result(
971                    Box::new(TypeExpr::String),
972                    Box::new(TypeExpr::String),
973                ),
974            },
975            param_names: &[],
976        },
977        BuiltinFunction {
978            name: "io.read_line",
979            description: "Read a single line from stdin",
980            signature: BuiltinSignature {
981                params: vec![],
982                return_type: TypeExpr::Result(
983                    Box::new(TypeExpr::String),
984                    Box::new(TypeExpr::String),
985                ),
986            },
987            param_names: &[],
988        },
989        BuiltinFunction {
990            name: "io.write_stdout",
991            description: "Write a value to stdout",
992            signature: BuiltinSignature {
993                params: vec![TypeExpr::Unknown],
994                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
995            },
996            param_names: &["value"],
997        },
998    ]
999}
1000
1001static OS_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
1002
1003fn build_os_functions() -> Vec<BuiltinFunction> {
1004    vec![
1005        BuiltinFunction {
1006            name: "os.time",
1007            description: "Get the current UNIX timestamp with sub-second precision",
1008            signature: BuiltinSignature {
1009                params: vec![],
1010                return_type: TypeExpr::Float,
1011            },
1012            param_names: &[],
1013        },
1014        BuiltinFunction {
1015            name: "os.sleep",
1016            description: "Sleep for the given number of seconds",
1017            signature: BuiltinSignature {
1018                params: vec![TypeExpr::Float],
1019                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1020            },
1021            param_names: &["seconds"],
1022        },
1023        BuiltinFunction {
1024            name: "os.create_file",
1025            description: "Create an empty file on disk",
1026            signature: BuiltinSignature {
1027                params: vec![TypeExpr::String],
1028                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1029            },
1030            param_names: &["path"],
1031        },
1032        BuiltinFunction {
1033            name: "os.create_dir",
1034            description: "Create a directory",
1035            signature: BuiltinSignature {
1036                params: vec![TypeExpr::String],
1037                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1038            },
1039            param_names: &["path"],
1040        },
1041        BuiltinFunction {
1042            name: "os.remove_file",
1043            description: "Remove a file from disk",
1044            signature: BuiltinSignature {
1045                params: vec![TypeExpr::String],
1046                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1047            },
1048            param_names: &["path"],
1049        },
1050        BuiltinFunction {
1051            name: "os.remove_dir",
1052            description: "Remove an empty directory",
1053            signature: BuiltinSignature {
1054                params: vec![TypeExpr::String],
1055                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1056            },
1057            param_names: &["path"],
1058        },
1059        BuiltinFunction {
1060            name: "os.rename",
1061            description: "Rename or move a path",
1062            signature: BuiltinSignature {
1063                params: vec![TypeExpr::String, TypeExpr::String],
1064                return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1065            },
1066            param_names: &["from", "to"],
1067        },
1068    ]
1069}
1070
1071static BUILTIN_METHODS: StaticOnceCell<Vec<BuiltinMethod>> = StaticOnceCell::new();
1072
1073fn build_builtin_methods() -> Vec<BuiltinMethod> {
1074    let mut methods = Vec::new();
1075    methods.extend(string_methods());
1076    methods.extend(array_methods());
1077    methods.extend(map_methods());
1078    methods.extend(iterator_methods());
1079    methods.extend(option_methods());
1080    methods.extend(result_methods());
1081    methods.extend(float_methods());
1082    methods.extend(int_methods());
1083    methods
1084}
1085
1086pub fn base_functions() -> &'static [BuiltinFunction] {
1087    BASE_FUNCTIONS.get_or_init(build_base_functions).as_slice()
1088}
1089
1090pub fn task_functions() -> &'static [BuiltinFunction] {
1091    TASK_FUNCTIONS.get_or_init(build_task_functions).as_slice()
1092}
1093
1094pub fn io_functions() -> &'static [BuiltinFunction] {
1095    IO_FUNCTIONS.get_or_init(build_io_functions).as_slice()
1096}
1097
1098pub fn os_functions() -> &'static [BuiltinFunction] {
1099    OS_FUNCTIONS.get_or_init(build_os_functions).as_slice()
1100}
1101
1102pub fn builtin_methods() -> &'static [BuiltinMethod] {
1103    BUILTIN_METHODS
1104        .get_or_init(build_builtin_methods)
1105        .as_slice()
1106}
1107
1108pub struct BuiltinModule {
1109    name: &'static str,
1110    description: &'static str,
1111    functions: Vec<&'static BuiltinFunction>,
1112}
1113
1114impl BuiltinModule {
1115    pub fn name(&self) -> &'static str {
1116        self.name
1117    }
1118
1119    pub fn description(&self) -> &'static str {
1120        self.description
1121    }
1122
1123    pub fn functions(&self) -> &[&'static BuiltinFunction] {
1124        &self.functions
1125    }
1126}
1127
1128pub struct BuiltinsDatabase {
1129    global_functions: Vec<&'static BuiltinFunction>,
1130    modules: BTreeMap<&'static str, BuiltinModule>,
1131    methods: HashMap<&'static str, Vec<&'static BuiltinMethod>>,
1132}
1133
1134impl BuiltinsDatabase {
1135    pub fn global_functions(&self) -> &[&'static BuiltinFunction] {
1136        &self.global_functions
1137    }
1138
1139    pub fn module(&self, name: &str) -> Option<&BuiltinModule> {
1140        self.modules.get(name)
1141    }
1142
1143    pub fn methods_for(&self, type_name: &str) -> Option<&[&'static BuiltinMethod]> {
1144        self.methods
1145            .get(type_name)
1146            .map(|methods| methods.as_slice())
1147    }
1148
1149    pub fn modules(&self) -> impl Iterator<Item = &BuiltinModule> {
1150        self.modules.values()
1151    }
1152}
1153
1154fn receiver_key(expr: &TypeExpr) -> Option<&'static str> {
1155    match expr {
1156        TypeExpr::String => Some("String"),
1157        TypeExpr::Array(_) => Some("Array"),
1158        TypeExpr::Map(_, _) => Some("Map"),
1159        TypeExpr::Named(name) => Some(name),
1160        TypeExpr::Option(_) => Some("Option"),
1161        TypeExpr::Result(_, _) => Some("Result"),
1162        TypeExpr::Float => Some("Float"),
1163        TypeExpr::Int => Some("Int"),
1164        TypeExpr::Bool => Some("Bool"),
1165        TypeExpr::Unknown => Some("Unknown"),
1166        TypeExpr::Unit => Some("Unit"),
1167        TypeExpr::Generic(name) => Some(name),
1168        TypeExpr::SelfType => Some("Self"),
1169        TypeExpr::Function { .. } => Some("function"),
1170    }
1171}
1172
1173static BUILTINS_DATABASE: StaticOnceCell<BuiltinsDatabase> = StaticOnceCell::new();
1174
1175fn build_builtins_database() -> BuiltinsDatabase {
1176    let mut modules: BTreeMap<&'static str, BuiltinModule> = BTreeMap::new();
1177    let module_specs: [(&'static str, &'static str, &'static [BuiltinFunction]); 3] = [
1178        ("task", "task runtime module", task_functions()),
1179        ("io", "io file & console module", io_functions()),
1180        ("os", "os filesystem module", os_functions()),
1181    ];
1182    for (name, description, functions) in module_specs {
1183        let mut module_funcs: Vec<&'static BuiltinFunction> = functions.iter().collect();
1184        module_funcs.sort_by(|a, b| a.name.cmp(b.name));
1185        modules.insert(
1186            name,
1187            BuiltinModule {
1188                name,
1189                description,
1190                functions: module_funcs,
1191            },
1192        );
1193    }
1194
1195    let mut global_functions: Vec<&'static BuiltinFunction> = base_functions().iter().collect();
1196    global_functions.sort_by(|a, b| a.name.cmp(b.name));
1197
1198    let mut methods: HashMap<&'static str, Vec<&'static BuiltinMethod>> = HashMap::new();
1199    for method in builtin_methods() {
1200        if let Some(key) = receiver_key(&method.receiver) {
1201            methods.entry(key).or_default().push(method);
1202        }
1203    }
1204    for vec in methods.values_mut() {
1205        vec.sort_by(|a, b| a.name.cmp(b.name));
1206    }
1207
1208    BuiltinsDatabase {
1209        global_functions,
1210        modules,
1211        methods,
1212    }
1213}
1214
1215pub fn builtins() -> &'static BuiltinsDatabase {
1216    BUILTINS_DATABASE.get_or_init(build_builtins_database)
1217}
1218
1219pub fn lookup_builtin_method(
1220    receiver: &Type,
1221    name: &str,
1222) -> Option<(&'static BuiltinMethod, HashMap<&'static str, Type>)> {
1223    for method in builtin_methods() {
1224        if method.name == name {
1225            if let Some(bindings) = match_receiver(&method.receiver, receiver) {
1226                return Some((method, bindings));
1227            }
1228        }
1229    }
1230    None
1231}