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 "min",
760 "Return the smaller of two numbers",
761 &["other"],
762 vec![TypeExpr::Float],
763 TypeExpr::Float,
764 ),
765 method(
766 TypeExpr::Float,
767 "max",
768 "Return the larger of two numbers",
769 &["other"],
770 vec![TypeExpr::Float],
771 TypeExpr::Float,
772 ),
773 method(
774 TypeExpr::Float,
775 "clamp",
776 "Clamp the float between a minimum and maximum value",
777 &["min", "max"],
778 vec![TypeExpr::Float, TypeExpr::Float],
779 TypeExpr::Float,
780 ),
781 ]
782}
783
784fn int_methods() -> Vec<BuiltinMethod> {
785 vec![
786 method(
787 TypeExpr::Int,
788 "to_float",
789 "Convert the integer to a float",
790 &[],
791 vec![],
792 TypeExpr::Float,
793 ),
794 method(
795 TypeExpr::Int,
796 "abs",
797 "Return the absolute value of the integer",
798 &[],
799 vec![],
800 TypeExpr::Int,
801 ),
802 method(
803 TypeExpr::Int,
804 "min",
805 "Return the smaller of two integers",
806 &["other"],
807 vec![TypeExpr::Int],
808 TypeExpr::Int,
809 ),
810 method(
811 TypeExpr::Int,
812 "max",
813 "Return the larger of two integers",
814 &["other"],
815 vec![TypeExpr::Int],
816 TypeExpr::Int,
817 ),
818 method(
819 TypeExpr::Int,
820 "clamp",
821 "Clamp the integer between a minimum and maximum value",
822 &["min", "max"],
823 vec![TypeExpr::Int, TypeExpr::Int],
824 TypeExpr::Int,
825 ),
826 ]
827}
828
829fn lua_table_methods() -> Vec<BuiltinMethod> {
830 vec![
831 method(
832 TypeExpr::Named("LuaTable"),
833 "len",
834 "Return the length of the array portion (1-based contiguous keys)",
835 &[],
836 vec![],
837 TypeExpr::Int,
838 ),
839 method(
840 TypeExpr::Named("LuaTable"),
841 "push",
842 "Append a value to the array portion",
843 &["value"],
844 vec![TypeExpr::Unknown],
845 TypeExpr::Unit,
846 ),
847 method(
848 TypeExpr::Named("LuaTable"),
849 "insert",
850 "Insert a value into the array portion at a position",
851 &["pos", "value"],
852 vec![TypeExpr::Unknown, TypeExpr::Unknown],
853 TypeExpr::Unit,
854 ),
855 method(
856 TypeExpr::Named("LuaTable"),
857 "remove",
858 "Remove a value from the array portion at a position",
859 &["pos"],
860 vec![TypeExpr::Unknown],
861 TypeExpr::Unknown,
862 ),
863 method(
864 TypeExpr::Named("LuaTable"),
865 "concat",
866 "Concatenate array elements into a string",
867 &["sep", "i", "j"],
868 vec![TypeExpr::Unknown, TypeExpr::Unknown, TypeExpr::Unknown],
869 TypeExpr::String,
870 ),
871 method(
872 TypeExpr::Named("LuaTable"),
873 "unpack",
874 "Unpack array elements as multiple returns",
875 &["i", "j"],
876 vec![TypeExpr::Unknown, TypeExpr::Unknown],
877 TypeExpr::Unknown,
878 ),
879 method(
880 TypeExpr::Named("LuaTable"),
881 "sort",
882 "Sort the array portion",
883 &["comp"],
884 vec![TypeExpr::Unknown],
885 TypeExpr::Unit,
886 ),
887 method(
888 TypeExpr::Named("LuaTable"),
889 "maxn",
890 "Find the largest positive numeric index",
891 &[],
892 vec![],
893 TypeExpr::Int,
894 ),
895 ]
896}
897
898static BASE_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
899
900fn build_base_functions() -> Vec<BuiltinFunction> {
901 vec![
902 BuiltinFunction {
903 name: "print",
904 description: "Print values without a newline",
905 signature: BuiltinSignature {
906 params: vec![TypeExpr::Unknown],
907 return_type: TypeExpr::Unit,
908 },
909 param_names: &["value"],
910 },
911 BuiltinFunction {
912 name: "println",
913 description: "Print values followed by a newline",
914 signature: BuiltinSignature {
915 params: vec![TypeExpr::Unknown],
916 return_type: TypeExpr::Unit,
917 },
918 param_names: &["value"],
919 },
920 BuiltinFunction {
921 name: "type",
922 description: "Return the runtime type name",
923 signature: BuiltinSignature {
924 params: vec![TypeExpr::Unknown],
925 return_type: TypeExpr::String,
926 },
927 param_names: &["value"],
928 },
929 BuiltinFunction {
930 name: "tostring",
931 description: "Convert a value to a string",
932 signature: BuiltinSignature {
933 params: vec![TypeExpr::Unknown],
934 return_type: TypeExpr::String,
935 },
936 param_names: &["value"],
937 },
938 BuiltinFunction {
939 name: "error",
940 description: "Raise a runtime error",
941 signature: BuiltinSignature {
942 params: vec![TypeExpr::Unknown],
943 return_type: TypeExpr::Unknown,
944 },
945 param_names: &["message"],
946 },
947 BuiltinFunction {
948 name: "assert",
949 description: "Assert a condition or raise an error",
950 signature: BuiltinSignature {
951 params: vec![TypeExpr::Unknown, TypeExpr::Unknown],
952 return_type: TypeExpr::Unknown,
953 },
954 param_names: &["cond", "message"],
955 },
956 BuiltinFunction {
957 name: "tonumber",
958 description: "Convert a value to a number",
959 signature: BuiltinSignature {
960 params: vec![TypeExpr::Unknown, TypeExpr::Unknown],
961 return_type: TypeExpr::Unknown,
962 },
963 param_names: &["value", "base"],
964 },
965 BuiltinFunction {
966 name: "pairs",
967 description: "Iterate over key/value pairs",
968 signature: BuiltinSignature {
969 params: vec![TypeExpr::Unknown],
970 return_type: TypeExpr::Named("Iterator"),
971 },
972 param_names: &["table"],
973 },
974 BuiltinFunction {
975 name: "ipairs",
976 description: "Iterate over array elements with indices",
977 signature: BuiltinSignature {
978 params: vec![TypeExpr::Unknown],
979 return_type: TypeExpr::Named("Iterator"),
980 },
981 param_names: &["array"],
982 },
983 BuiltinFunction {
984 name: "select",
985 description: "Return arguments starting at an index or the argument count",
986 signature: BuiltinSignature {
987 params: vec![TypeExpr::Unknown, TypeExpr::Unknown],
988 return_type: TypeExpr::Unknown,
989 },
990 param_names: &["index_or_hash", "..."],
991 },
992 BuiltinFunction {
993 name: "random",
994 description: "Generate a random number in an optional range",
995 signature: BuiltinSignature {
996 params: vec![TypeExpr::Unknown, TypeExpr::Unknown],
997 return_type: TypeExpr::Unknown,
998 },
999 param_names: &["m", "n"],
1000 },
1001 BuiltinFunction {
1002 name: "randomseed",
1003 description: "Seed the random number generator",
1004 signature: BuiltinSignature {
1005 params: vec![TypeExpr::Unknown],
1006 return_type: TypeExpr::Unit,
1007 },
1008 param_names: &["seed"],
1009 },
1010 BuiltinFunction {
1011 name: "unpack",
1012 description: "Unpack array elements into multiple returns",
1013 signature: BuiltinSignature {
1014 params: vec![TypeExpr::Unknown, TypeExpr::Unknown, TypeExpr::Unknown],
1015 return_type: TypeExpr::Unknown,
1016 },
1017 param_names: &["table", "i", "j"],
1018 },
1019 BuiltinFunction {
1020 name: "setmetatable",
1021 description: "Assign a metatable to a Lua table value",
1022 signature: BuiltinSignature {
1023 params: vec![TypeExpr::Unknown, TypeExpr::Unknown],
1024 return_type: TypeExpr::Unknown,
1025 },
1026 param_names: &["table", "meta"],
1027 },
1028 ]
1029}
1030
1031static STRING_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
1032static TASK_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
1033static LUA_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
1034
1035fn build_task_functions() -> Vec<BuiltinFunction> {
1036 vec![
1037 BuiltinFunction {
1038 name: "task.run",
1039 description: "Run a function as a task",
1040 signature: BuiltinSignature {
1041 params: vec![TypeExpr::Unknown],
1042 return_type: TypeExpr::Named("Task"),
1043 },
1044 param_names: &["func"],
1045 },
1046 BuiltinFunction {
1047 name: "task.create",
1048 description: "Create a suspended task",
1049 signature: BuiltinSignature {
1050 params: vec![TypeExpr::Unknown],
1051 return_type: TypeExpr::Named("Task"),
1052 },
1053 param_names: &["func"],
1054 },
1055 BuiltinFunction {
1056 name: "task.status",
1057 description: "Get the status of a task",
1058 signature: BuiltinSignature {
1059 params: vec![TypeExpr::Named("Task")],
1060 return_type: TypeExpr::Named("TaskStatus"),
1061 },
1062 param_names: &["task"],
1063 },
1064 BuiltinFunction {
1065 name: "task.info",
1066 description: "Get detailed information about a task",
1067 signature: BuiltinSignature {
1068 params: vec![TypeExpr::Named("Task")],
1069 return_type: TypeExpr::Named("TaskInfo"),
1070 },
1071 param_names: &["task"],
1072 },
1073 BuiltinFunction {
1074 name: "task.resume",
1075 description: "Resume a suspended task",
1076 signature: BuiltinSignature {
1077 params: vec![TypeExpr::Named("Task")],
1078 return_type: TypeExpr::Named("TaskInfo"),
1079 },
1080 param_names: &["task"],
1081 },
1082 BuiltinFunction {
1083 name: "task.yield",
1084 description: "Yield from the current task",
1085 signature: BuiltinSignature {
1086 params: vec![TypeExpr::Unknown],
1087 return_type: TypeExpr::Unknown,
1088 },
1089 param_names: &["value"],
1090 },
1091 BuiltinFunction {
1092 name: "task.stop",
1093 description: "Stop a running task",
1094 signature: BuiltinSignature {
1095 params: vec![TypeExpr::Named("Task")],
1096 return_type: TypeExpr::Bool,
1097 },
1098 param_names: &["task"],
1099 },
1100 BuiltinFunction {
1101 name: "task.restart",
1102 description: "Restart a completed task",
1103 signature: BuiltinSignature {
1104 params: vec![TypeExpr::Named("Task")],
1105 return_type: TypeExpr::Named("TaskInfo"),
1106 },
1107 param_names: &["task"],
1108 },
1109 BuiltinFunction {
1110 name: "task.current",
1111 description: "Return the currently executing task",
1112 signature: BuiltinSignature {
1113 params: vec![],
1114 return_type: TypeExpr::Option(Box::new(TypeExpr::Named("Task"))),
1115 },
1116 param_names: &[],
1117 },
1118 ]
1119}
1120
1121fn build_lua_functions() -> Vec<BuiltinFunction> {
1122 vec![
1123 BuiltinFunction {
1124 name: "lua.to_value",
1125 description: "Wrap a Lust value in LuaValue",
1126 signature: BuiltinSignature {
1127 params: vec![TypeExpr::Unknown],
1128 return_type: TypeExpr::Named("LuaValue"),
1129 },
1130 param_names: &["value"],
1131 },
1132 BuiltinFunction {
1133 name: "lua.require",
1134 description: "Lua-style module resolver (loads from already-initialized globals when available)",
1135 signature: BuiltinSignature {
1136 params: vec![TypeExpr::Unknown],
1137 return_type: TypeExpr::Unknown,
1138 },
1139 param_names: &["name"],
1140 },
1141 BuiltinFunction {
1142 name: "lua.table",
1143 description: "Create an empty Lua-style table",
1144 signature: BuiltinSignature {
1145 params: vec![],
1146 return_type: TypeExpr::Named("LuaTable"),
1147 },
1148 param_names: &[],
1149 },
1150 BuiltinFunction {
1151 name: "lua.setmetatable",
1152 description: "Set the metatable for a Lua table value",
1153 signature: BuiltinSignature {
1154 params: vec![TypeExpr::Named("LuaValue"), TypeExpr::Named("LuaValue")],
1155 return_type: TypeExpr::Named("LuaValue"),
1156 },
1157 param_names: &["table", "meta"],
1158 },
1159 BuiltinFunction {
1160 name: "lua.getmetatable",
1161 description: "Get the metatable for a Lua table value",
1162 signature: BuiltinSignature {
1163 params: vec![TypeExpr::Named("LuaValue")],
1164 return_type: TypeExpr::Named("LuaValue"),
1165 },
1166 param_names: &["table"],
1167 },
1168 BuiltinFunction {
1169 name: "lua.unwrap",
1170 description: "Extract a raw Lust value from a LuaValue wrapper",
1171 signature: BuiltinSignature {
1172 params: vec![TypeExpr::Unknown],
1173 return_type: TypeExpr::Unknown,
1174 },
1175 param_names: &["value"],
1176 },
1177 ]
1178}
1179
1180fn build_string_functions() -> Vec<BuiltinFunction> {
1181 vec![
1182 BuiltinFunction {
1183 name: "string.len",
1184 description: "Return the length of a string",
1185 signature: BuiltinSignature {
1186 params: vec![TypeExpr::Unknown],
1187 return_type: TypeExpr::Int,
1188 },
1189 param_names: &["s"],
1190 },
1191 BuiltinFunction {
1192 name: "string.lower",
1193 description: "Lowercase a string",
1194 signature: BuiltinSignature {
1195 params: vec![TypeExpr::Unknown],
1196 return_type: TypeExpr::String,
1197 },
1198 param_names: &["s"],
1199 },
1200 BuiltinFunction {
1201 name: "string.upper",
1202 description: "Uppercase a string",
1203 signature: BuiltinSignature {
1204 params: vec![TypeExpr::Unknown],
1205 return_type: TypeExpr::String,
1206 },
1207 param_names: &["s"],
1208 },
1209 BuiltinFunction {
1210 name: "string.sub",
1211 description: "Extract a substring using Lua-style indices",
1212 signature: BuiltinSignature {
1213 params: vec![TypeExpr::Unknown, TypeExpr::Unknown, TypeExpr::Unknown],
1214 return_type: TypeExpr::String,
1215 },
1216 param_names: &["s", "i", "j"],
1217 },
1218 BuiltinFunction {
1219 name: "string.byte",
1220 description: "Return byte values from a string slice",
1221 signature: BuiltinSignature {
1222 params: vec![TypeExpr::Unknown, TypeExpr::Unknown, TypeExpr::Unknown],
1223 return_type: TypeExpr::Unknown,
1224 },
1225 param_names: &["s", "i", "j"],
1226 },
1227 BuiltinFunction {
1228 name: "string.char",
1229 description: "Create a string from numeric bytes",
1230 signature: BuiltinSignature {
1231 params: vec![TypeExpr::Unknown],
1232 return_type: TypeExpr::String,
1233 },
1234 param_names: &["byte"],
1235 },
1236 BuiltinFunction {
1237 name: "string.find",
1238 description: "Find a pattern within a string",
1239 signature: BuiltinSignature {
1240 params: vec![
1241 TypeExpr::Unknown,
1242 TypeExpr::Unknown,
1243 TypeExpr::Unknown,
1244 TypeExpr::Unknown,
1245 ],
1246 return_type: TypeExpr::Unknown,
1247 },
1248 param_names: &["s", "pattern", "init", "plain"],
1249 },
1250 BuiltinFunction {
1251 name: "string.gsub",
1252 description: "Globally substitute occurrences of a pattern",
1253 signature: BuiltinSignature {
1254 params: vec![
1255 TypeExpr::Unknown,
1256 TypeExpr::Unknown,
1257 TypeExpr::Unknown,
1258 TypeExpr::Unknown,
1259 ],
1260 return_type: TypeExpr::Unknown,
1261 },
1262 param_names: &["s", "pattern", "repl", "n"],
1263 },
1264 BuiltinFunction {
1265 name: "string.format",
1266 description: "Format values according to a pattern",
1267 signature: BuiltinSignature {
1268 params: vec![TypeExpr::Unknown],
1269 return_type: TypeExpr::String,
1270 },
1271 param_names: &["fmt"],
1272 },
1273 ]
1274}
1275
1276static IO_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
1277
1278fn build_io_functions() -> Vec<BuiltinFunction> {
1279 vec![
1280 BuiltinFunction {
1281 name: "io.read_file",
1282 description: "Read the contents of a file",
1283 signature: BuiltinSignature {
1284 params: vec![TypeExpr::String],
1285 return_type: TypeExpr::Result(
1286 Box::new(TypeExpr::String),
1287 Box::new(TypeExpr::String),
1288 ),
1289 },
1290 param_names: &["path"],
1291 },
1292 BuiltinFunction {
1293 name: "io.read_file_bytes",
1294 description: "Read the contents of a file as byte values",
1295 signature: BuiltinSignature {
1296 params: vec![TypeExpr::String],
1297 return_type: TypeExpr::Result(
1298 Box::new(TypeExpr::Array(Box::new(TypeExpr::Int))),
1299 Box::new(TypeExpr::String),
1300 ),
1301 },
1302 param_names: &["path"],
1303 },
1304 BuiltinFunction {
1305 name: "io.write_file",
1306 description: "Write contents to a file",
1307 signature: BuiltinSignature {
1308 params: vec![TypeExpr::String, TypeExpr::Unknown],
1309 return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1310 },
1311 param_names: &["path", "value"],
1312 },
1313 BuiltinFunction {
1314 name: "io.read_stdin",
1315 description: "Read all available stdin",
1316 signature: BuiltinSignature {
1317 params: vec![],
1318 return_type: TypeExpr::Result(
1319 Box::new(TypeExpr::String),
1320 Box::new(TypeExpr::String),
1321 ),
1322 },
1323 param_names: &[],
1324 },
1325 BuiltinFunction {
1326 name: "io.read_line",
1327 description: "Read a single line from stdin",
1328 signature: BuiltinSignature {
1329 params: vec![],
1330 return_type: TypeExpr::Result(
1331 Box::new(TypeExpr::String),
1332 Box::new(TypeExpr::String),
1333 ),
1334 },
1335 param_names: &[],
1336 },
1337 BuiltinFunction {
1338 name: "io.write_stdout",
1339 description: "Write a value to stdout",
1340 signature: BuiltinSignature {
1341 params: vec![TypeExpr::Unknown],
1342 return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1343 },
1344 param_names: &["value"],
1345 },
1346 ]
1347}
1348
1349static OS_FUNCTIONS: StaticOnceCell<Vec<BuiltinFunction>> = StaticOnceCell::new();
1350
1351fn build_os_functions() -> Vec<BuiltinFunction> {
1352 vec![
1353 BuiltinFunction {
1354 name: "os.time",
1355 description: "Get the current UNIX timestamp with sub-second precision",
1356 signature: BuiltinSignature {
1357 params: vec![],
1358 return_type: TypeExpr::Float,
1359 },
1360 param_names: &[],
1361 },
1362 BuiltinFunction {
1363 name: "os.sleep",
1364 description: "Sleep for the given number of seconds",
1365 signature: BuiltinSignature {
1366 params: vec![TypeExpr::Float],
1367 return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1368 },
1369 param_names: &["seconds"],
1370 },
1371 BuiltinFunction {
1372 name: "os.create_file",
1373 description: "Create an empty file on disk",
1374 signature: BuiltinSignature {
1375 params: vec![TypeExpr::String],
1376 return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1377 },
1378 param_names: &["path"],
1379 },
1380 BuiltinFunction {
1381 name: "os.create_dir",
1382 description: "Create a directory",
1383 signature: BuiltinSignature {
1384 params: vec![TypeExpr::String],
1385 return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1386 },
1387 param_names: &["path"],
1388 },
1389 BuiltinFunction {
1390 name: "os.remove_file",
1391 description: "Remove a file from disk",
1392 signature: BuiltinSignature {
1393 params: vec![TypeExpr::String],
1394 return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1395 },
1396 param_names: &["path"],
1397 },
1398 BuiltinFunction {
1399 name: "os.remove_dir",
1400 description: "Remove an empty directory",
1401 signature: BuiltinSignature {
1402 params: vec![TypeExpr::String],
1403 return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1404 },
1405 param_names: &["path"],
1406 },
1407 BuiltinFunction {
1408 name: "os.rename",
1409 description: "Rename or move a path",
1410 signature: BuiltinSignature {
1411 params: vec![TypeExpr::String, TypeExpr::String],
1412 return_type: TypeExpr::Result(Box::new(TypeExpr::Unit), Box::new(TypeExpr::String)),
1413 },
1414 param_names: &["from", "to"],
1415 },
1416 ]
1417}
1418
1419static BUILTIN_METHODS: StaticOnceCell<Vec<BuiltinMethod>> = StaticOnceCell::new();
1420
1421fn build_builtin_methods() -> Vec<BuiltinMethod> {
1422 let mut methods = Vec::new();
1423 methods.extend(string_methods());
1424 methods.extend(array_methods());
1425 methods.extend(map_methods());
1426 methods.extend(lua_table_methods());
1427 methods.extend(iterator_methods());
1428 methods.extend(option_methods());
1429 methods.extend(result_methods());
1430 methods.extend(float_methods());
1431 methods.extend(int_methods());
1432 methods
1433}
1434
1435pub fn base_functions() -> &'static [BuiltinFunction] {
1436 BASE_FUNCTIONS.get_or_init(build_base_functions).as_slice()
1437}
1438
1439pub fn string_functions() -> &'static [BuiltinFunction] {
1440 STRING_FUNCTIONS.get_or_init(build_string_functions).as_slice()
1441}
1442
1443pub fn task_functions() -> &'static [BuiltinFunction] {
1444 TASK_FUNCTIONS.get_or_init(build_task_functions).as_slice()
1445}
1446
1447pub fn lua_functions() -> &'static [BuiltinFunction] {
1448 LUA_FUNCTIONS.get_or_init(build_lua_functions).as_slice()
1449}
1450
1451pub fn io_functions() -> &'static [BuiltinFunction] {
1452 IO_FUNCTIONS.get_or_init(build_io_functions).as_slice()
1453}
1454
1455pub fn os_functions() -> &'static [BuiltinFunction] {
1456 OS_FUNCTIONS.get_or_init(build_os_functions).as_slice()
1457}
1458
1459pub fn builtin_methods() -> &'static [BuiltinMethod] {
1460 BUILTIN_METHODS
1461 .get_or_init(build_builtin_methods)
1462 .as_slice()
1463}
1464
1465pub struct BuiltinModule {
1466 name: &'static str,
1467 description: &'static str,
1468 functions: Vec<&'static BuiltinFunction>,
1469}
1470
1471impl BuiltinModule {
1472 pub fn name(&self) -> &'static str {
1473 self.name
1474 }
1475
1476 pub fn description(&self) -> &'static str {
1477 self.description
1478 }
1479
1480 pub fn functions(&self) -> &[&'static BuiltinFunction] {
1481 &self.functions
1482 }
1483}
1484
1485pub struct BuiltinsDatabase {
1486 global_functions: Vec<&'static BuiltinFunction>,
1487 modules: BTreeMap<&'static str, BuiltinModule>,
1488 methods: HashMap<&'static str, Vec<&'static BuiltinMethod>>,
1489}
1490
1491impl BuiltinsDatabase {
1492 pub fn global_functions(&self) -> &[&'static BuiltinFunction] {
1493 &self.global_functions
1494 }
1495
1496 pub fn module(&self, name: &str) -> Option<&BuiltinModule> {
1497 self.modules.get(name)
1498 }
1499
1500 pub fn methods_for(&self, type_name: &str) -> Option<&[&'static BuiltinMethod]> {
1501 self.methods
1502 .get(type_name)
1503 .map(|methods| methods.as_slice())
1504 }
1505
1506 pub fn modules(&self) -> impl Iterator<Item = &BuiltinModule> {
1507 self.modules.values()
1508 }
1509}
1510
1511fn receiver_key(expr: &TypeExpr) -> Option<&'static str> {
1512 match expr {
1513 TypeExpr::String => Some("String"),
1514 TypeExpr::Array(_) => Some("Array"),
1515 TypeExpr::Map(_, _) => Some("Map"),
1516 TypeExpr::Named(name) => Some(name),
1517 TypeExpr::Option(_) => Some("Option"),
1518 TypeExpr::Result(_, _) => Some("Result"),
1519 TypeExpr::Float => Some("Float"),
1520 TypeExpr::Int => Some("Int"),
1521 TypeExpr::Bool => Some("Bool"),
1522 TypeExpr::Unknown => Some("Unknown"),
1523 TypeExpr::Unit => Some("Unit"),
1524 TypeExpr::Generic(name) => Some(name),
1525 TypeExpr::SelfType => Some("Self"),
1526 TypeExpr::Function { .. } => Some("function"),
1527 }
1528}
1529
1530static BUILTINS_DATABASE: StaticOnceCell<BuiltinsDatabase> = StaticOnceCell::new();
1531
1532fn build_builtins_database() -> BuiltinsDatabase {
1533 let mut modules: BTreeMap<&'static str, BuiltinModule> = BTreeMap::new();
1534 let module_specs: [(&'static str, &'static str, &'static [BuiltinFunction]); 4] = [
1535 ("task", "task runtime module", task_functions()),
1536 ("io", "io file & console module", io_functions()),
1537 ("os", "os filesystem module", os_functions()),
1538 ("string", "string compatibility module", string_functions()),
1539 ];
1540 for (name, description, functions) in module_specs {
1541 let mut module_funcs: Vec<&'static BuiltinFunction> = functions.iter().collect();
1542 module_funcs.sort_by(|a, b| a.name.cmp(b.name));
1543 modules.insert(
1544 name,
1545 BuiltinModule {
1546 name,
1547 description,
1548 functions: module_funcs,
1549 },
1550 );
1551 }
1552
1553 let mut global_functions: Vec<&'static BuiltinFunction> = base_functions().iter().collect();
1554 global_functions.sort_by(|a, b| a.name.cmp(b.name));
1555
1556 let mut methods: HashMap<&'static str, Vec<&'static BuiltinMethod>> = HashMap::new();
1557 for method in builtin_methods() {
1558 if let Some(key) = receiver_key(&method.receiver) {
1559 methods.entry(key).or_default().push(method);
1560 }
1561 }
1562 for vec in methods.values_mut() {
1563 vec.sort_by(|a, b| a.name.cmp(b.name));
1564 }
1565
1566 BuiltinsDatabase {
1567 global_functions,
1568 modules,
1569 methods,
1570 }
1571}
1572
1573pub fn builtins() -> &'static BuiltinsDatabase {
1574 BUILTINS_DATABASE.get_or_init(build_builtins_database)
1575}
1576
1577pub fn lookup_builtin_method(
1578 receiver: &Type,
1579 name: &str,
1580) -> Option<(&'static BuiltinMethod, HashMap<&'static str, Type>)> {
1581 for method in builtin_methods() {
1582 if method.name == name {
1583 if let Some(bindings) = match_receiver(&method.receiver, receiver) {
1584 return Some((method, bindings));
1585 }
1586 }
1587 }
1588 None
1589}