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}