1use crate::types::{Effect, StackType, Type};
6use std::collections::HashMap;
7
8pub fn builtin_signature(name: &str) -> Option<Effect> {
10 let signatures = builtin_signatures();
12 signatures.get(name).cloned()
13}
14
15pub fn builtin_signatures() -> HashMap<String, Effect> {
17 let mut sigs = HashMap::new();
18
19 sigs.insert(
21 "write_line".to_string(),
22 Effect::new(
23 StackType::RowVar("a".to_string()).push(Type::String), StackType::RowVar("a".to_string()),
25 ),
26 );
27
28 sigs.insert(
29 "read_line".to_string(),
30 Effect::new(
31 StackType::RowVar("a".to_string()), StackType::RowVar("a".to_string()).push(Type::String),
33 ),
34 );
35
36 sigs.insert(
39 "arg-count".to_string(),
40 Effect::new(
41 StackType::RowVar("a".to_string()),
42 StackType::RowVar("a".to_string()).push(Type::Int),
43 ),
44 );
45
46 sigs.insert(
48 "arg".to_string(),
49 Effect::new(
50 StackType::RowVar("a".to_string()).push(Type::Int),
51 StackType::RowVar("a".to_string()).push(Type::String),
52 ),
53 );
54
55 sigs.insert(
58 "file-slurp".to_string(),
59 Effect::new(
60 StackType::RowVar("a".to_string()).push(Type::String),
61 StackType::RowVar("a".to_string()).push(Type::String),
62 ),
63 );
64
65 sigs.insert(
67 "file-exists?".to_string(),
68 Effect::new(
69 StackType::RowVar("a".to_string()).push(Type::String),
70 StackType::RowVar("a".to_string()).push(Type::Int),
71 ),
72 );
73
74 sigs.insert(
75 "int->string".to_string(),
76 Effect::new(
77 StackType::RowVar("a".to_string()).push(Type::Int), StackType::RowVar("a".to_string()).push(Type::String),
79 ),
80 );
81
82 for op in &["add", "subtract", "multiply", "divide"] {
84 sigs.insert(
85 op.to_string(),
86 Effect::new(
87 StackType::RowVar("a".to_string())
88 .push(Type::Int)
89 .push(Type::Int),
90 StackType::RowVar("a".to_string()).push(Type::Int),
91 ),
92 );
93 }
94
95 for op in &["=", "<", ">", "<=", ">=", "<>"] {
98 sigs.insert(
99 op.to_string(),
100 Effect::new(
101 StackType::RowVar("a".to_string())
102 .push(Type::Int)
103 .push(Type::Int),
104 StackType::RowVar("a".to_string()).push(Type::Int),
105 ),
106 );
107 }
108
109 sigs.insert(
113 "and".to_string(),
114 Effect::new(
115 StackType::RowVar("a".to_string())
116 .push(Type::Int)
117 .push(Type::Int),
118 StackType::RowVar("a".to_string()).push(Type::Int),
119 ),
120 );
121
122 sigs.insert(
124 "or".to_string(),
125 Effect::new(
126 StackType::RowVar("a".to_string())
127 .push(Type::Int)
128 .push(Type::Int),
129 StackType::RowVar("a".to_string()).push(Type::Int),
130 ),
131 );
132
133 sigs.insert(
135 "not".to_string(),
136 Effect::new(
137 StackType::RowVar("a".to_string()).push(Type::Int),
138 StackType::RowVar("a".to_string()).push(Type::Int),
139 ),
140 );
141
142 sigs.insert(
145 "dup".to_string(),
146 Effect::new(
147 StackType::RowVar("a".to_string()).push(Type::Var("T".to_string())),
148 StackType::RowVar("a".to_string())
149 .push(Type::Var("T".to_string()))
150 .push(Type::Var("T".to_string())),
151 ),
152 );
153
154 sigs.insert(
156 "drop".to_string(),
157 Effect::new(
158 StackType::RowVar("a".to_string()).push(Type::Var("T".to_string())),
159 StackType::RowVar("a".to_string()),
160 ),
161 );
162
163 sigs.insert(
165 "swap".to_string(),
166 Effect::new(
167 StackType::RowVar("a".to_string())
168 .push(Type::Var("T".to_string()))
169 .push(Type::Var("U".to_string())),
170 StackType::RowVar("a".to_string())
171 .push(Type::Var("U".to_string()))
172 .push(Type::Var("T".to_string())),
173 ),
174 );
175
176 sigs.insert(
178 "over".to_string(),
179 Effect::new(
180 StackType::RowVar("a".to_string())
181 .push(Type::Var("T".to_string()))
182 .push(Type::Var("U".to_string())),
183 StackType::RowVar("a".to_string())
184 .push(Type::Var("T".to_string()))
185 .push(Type::Var("U".to_string()))
186 .push(Type::Var("T".to_string())),
187 ),
188 );
189
190 sigs.insert(
192 "rot".to_string(),
193 Effect::new(
194 StackType::RowVar("a".to_string())
195 .push(Type::Var("T".to_string()))
196 .push(Type::Var("U".to_string()))
197 .push(Type::Var("V".to_string())),
198 StackType::RowVar("a".to_string())
199 .push(Type::Var("U".to_string()))
200 .push(Type::Var("V".to_string()))
201 .push(Type::Var("T".to_string())),
202 ),
203 );
204
205 sigs.insert(
207 "nip".to_string(),
208 Effect::new(
209 StackType::RowVar("a".to_string())
210 .push(Type::Var("T".to_string()))
211 .push(Type::Var("U".to_string())),
212 StackType::RowVar("a".to_string()).push(Type::Var("U".to_string())),
213 ),
214 );
215
216 sigs.insert(
218 "tuck".to_string(),
219 Effect::new(
220 StackType::RowVar("a".to_string())
221 .push(Type::Var("T".to_string()))
222 .push(Type::Var("U".to_string())),
223 StackType::RowVar("a".to_string())
224 .push(Type::Var("U".to_string()))
225 .push(Type::Var("T".to_string()))
226 .push(Type::Var("U".to_string())),
227 ),
228 );
229
230 sigs.insert(
249 "pick".to_string(),
250 Effect::new(
251 StackType::RowVar("a".to_string())
252 .push(Type::Var("T".to_string()))
253 .push(Type::Int),
254 StackType::RowVar("a".to_string())
255 .push(Type::Var("T".to_string()))
256 .push(Type::Var("T".to_string())),
257 ),
258 );
259
260 sigs.insert(
270 "roll".to_string(),
271 Effect::new(
272 StackType::RowVar("a".to_string())
273 .push(Type::Var("T".to_string()))
274 .push(Type::Int),
275 StackType::RowVar("a".to_string()).push(Type::Var("T".to_string())),
276 ),
277 );
278
279 sigs.insert(
283 "make-channel".to_string(),
284 Effect::new(
285 StackType::RowVar("a".to_string()),
286 StackType::RowVar("a".to_string()).push(Type::Int),
287 ),
288 );
289
290 sigs.insert(
293 "send".to_string(),
294 Effect::new(
295 StackType::RowVar("a".to_string())
296 .push(Type::Var("T".to_string()))
297 .push(Type::Int),
298 StackType::RowVar("a".to_string()),
299 ),
300 );
301
302 sigs.insert(
305 "receive".to_string(),
306 Effect::new(
307 StackType::RowVar("a".to_string()).push(Type::Int),
308 StackType::RowVar("a".to_string()).push(Type::Var("T".to_string())),
309 ),
310 );
311
312 sigs.insert(
314 "close-channel".to_string(),
315 Effect::new(
316 StackType::RowVar("a".to_string()).push(Type::Int),
317 StackType::RowVar("a".to_string()),
318 ),
319 );
320
321 sigs.insert(
323 "yield".to_string(),
324 Effect::new(
325 StackType::RowVar("a".to_string()),
326 StackType::RowVar("a".to_string()),
327 ),
328 );
329
330 sigs.insert(
340 "call".to_string(),
341 Effect::new(
342 StackType::RowVar("a".to_string()).push(Type::Var("Q".to_string())),
343 StackType::RowVar("b".to_string()),
344 ),
345 );
346
347 sigs.insert(
350 "times".to_string(),
351 Effect::new(
352 StackType::RowVar("a".to_string())
353 .push(Type::Quotation(Box::new(Effect::new(
354 StackType::RowVar("a".to_string()),
355 StackType::RowVar("a".to_string()),
356 ))))
357 .push(Type::Int),
358 StackType::RowVar("a".to_string()),
359 ),
360 );
361
362 sigs.insert(
365 "while".to_string(),
366 Effect::new(
367 StackType::RowVar("a".to_string())
368 .push(Type::Quotation(Box::new(Effect::new(
369 StackType::RowVar("a".to_string()),
370 StackType::RowVar("a".to_string()).push(Type::Int),
371 ))))
372 .push(Type::Quotation(Box::new(Effect::new(
373 StackType::RowVar("a".to_string()),
374 StackType::RowVar("a".to_string()),
375 )))),
376 StackType::RowVar("a".to_string()),
377 ),
378 );
379
380 sigs.insert(
384 "until".to_string(),
385 Effect::new(
386 StackType::RowVar("a".to_string())
387 .push(Type::Quotation(Box::new(Effect::new(
388 StackType::RowVar("a".to_string()),
389 StackType::RowVar("a".to_string()),
390 ))))
391 .push(Type::Quotation(Box::new(Effect::new(
392 StackType::RowVar("a".to_string()),
393 StackType::RowVar("a".to_string()).push(Type::Int),
394 )))),
395 StackType::RowVar("a".to_string()),
396 ),
397 );
398
399 sigs.insert(
403 "forever".to_string(),
404 Effect::new(
405 StackType::RowVar("a".to_string()).push(Type::Quotation(Box::new(Effect::new(
406 StackType::RowVar("a".to_string()),
407 StackType::RowVar("a".to_string()),
408 )))),
409 StackType::RowVar("a".to_string()),
410 ),
411 );
412
413 sigs.insert(
417 "spawn".to_string(),
418 Effect::new(
419 StackType::RowVar("a".to_string()).push(Type::Quotation(Box::new(Effect::new(
420 StackType::Empty,
421 StackType::Empty,
422 )))),
423 StackType::RowVar("a".to_string()).push(Type::Int),
424 ),
425 );
426
427 sigs.insert(
434 "cond".to_string(),
435 Effect::new(
436 StackType::RowVar("a".to_string()),
437 StackType::RowVar("b".to_string()),
438 ),
439 );
440
441 sigs.insert(
445 "tcp-listen".to_string(),
446 Effect::new(
447 StackType::RowVar("a".to_string()).push(Type::Int),
448 StackType::RowVar("a".to_string()).push(Type::Int),
449 ),
450 );
451
452 sigs.insert(
455 "tcp-accept".to_string(),
456 Effect::new(
457 StackType::RowVar("a".to_string()).push(Type::Int),
458 StackType::RowVar("a".to_string()).push(Type::Int),
459 ),
460 );
461
462 sigs.insert(
465 "tcp-read".to_string(),
466 Effect::new(
467 StackType::RowVar("a".to_string()).push(Type::Int),
468 StackType::RowVar("a".to_string()).push(Type::String),
469 ),
470 );
471
472 sigs.insert(
475 "tcp-write".to_string(),
476 Effect::new(
477 StackType::RowVar("a".to_string())
478 .push(Type::String)
479 .push(Type::Int),
480 StackType::RowVar("a".to_string()),
481 ),
482 );
483
484 sigs.insert(
487 "tcp-close".to_string(),
488 Effect::new(
489 StackType::RowVar("a".to_string()).push(Type::Int),
490 StackType::RowVar("a".to_string()),
491 ),
492 );
493
494 sigs.insert(
498 "string-concat".to_string(),
499 Effect::new(
500 StackType::RowVar("a".to_string())
501 .push(Type::String)
502 .push(Type::String),
503 StackType::RowVar("a".to_string()).push(Type::String),
504 ),
505 );
506
507 sigs.insert(
510 "string-length".to_string(),
511 Effect::new(
512 StackType::RowVar("a".to_string()).push(Type::String),
513 StackType::RowVar("a".to_string()).push(Type::Int),
514 ),
515 );
516
517 sigs.insert(
520 "string-split".to_string(),
521 Effect::new(
522 StackType::RowVar("a".to_string())
523 .push(Type::String)
524 .push(Type::String),
525 StackType::RowVar("a".to_string()).push(Type::Var("V".to_string())),
526 ),
527 );
528
529 sigs.insert(
532 "string-contains".to_string(),
533 Effect::new(
534 StackType::RowVar("a".to_string())
535 .push(Type::String)
536 .push(Type::String),
537 StackType::RowVar("a".to_string()).push(Type::Int),
538 ),
539 );
540
541 sigs.insert(
544 "string-starts-with".to_string(),
545 Effect::new(
546 StackType::RowVar("a".to_string())
547 .push(Type::String)
548 .push(Type::String),
549 StackType::RowVar("a".to_string()).push(Type::Int),
550 ),
551 );
552
553 sigs.insert(
556 "string-empty".to_string(),
557 Effect::new(
558 StackType::RowVar("a".to_string()).push(Type::String),
559 StackType::RowVar("a".to_string()).push(Type::Int),
560 ),
561 );
562
563 sigs.insert(
566 "string-trim".to_string(),
567 Effect::new(
568 StackType::RowVar("a".to_string()).push(Type::String),
569 StackType::RowVar("a".to_string()).push(Type::String),
570 ),
571 );
572
573 sigs.insert(
576 "string-to-upper".to_string(),
577 Effect::new(
578 StackType::RowVar("a".to_string()).push(Type::String),
579 StackType::RowVar("a".to_string()).push(Type::String),
580 ),
581 );
582
583 sigs.insert(
586 "string-to-lower".to_string(),
587 Effect::new(
588 StackType::RowVar("a".to_string()).push(Type::String),
589 StackType::RowVar("a".to_string()).push(Type::String),
590 ),
591 );
592
593 sigs.insert(
596 "string-equal".to_string(),
597 Effect::new(
598 StackType::RowVar("a".to_string())
599 .push(Type::String)
600 .push(Type::String),
601 StackType::RowVar("a".to_string()).push(Type::Int),
602 ),
603 );
604
605 sigs.insert(
608 "string-byte-length".to_string(),
609 Effect::new(
610 StackType::RowVar("a".to_string()).push(Type::String),
611 StackType::RowVar("a".to_string()).push(Type::Int),
612 ),
613 );
614
615 sigs.insert(
618 "string-char-at".to_string(),
619 Effect::new(
620 StackType::RowVar("a".to_string())
621 .push(Type::String)
622 .push(Type::Int),
623 StackType::RowVar("a".to_string()).push(Type::Int),
624 ),
625 );
626
627 sigs.insert(
630 "string-substring".to_string(),
631 Effect::new(
632 StackType::RowVar("a".to_string())
633 .push(Type::String)
634 .push(Type::Int)
635 .push(Type::Int),
636 StackType::RowVar("a".to_string()).push(Type::String),
637 ),
638 );
639
640 sigs.insert(
643 "char->string".to_string(),
644 Effect::new(
645 StackType::RowVar("a".to_string()).push(Type::Int),
646 StackType::RowVar("a".to_string()).push(Type::String),
647 ),
648 );
649
650 sigs.insert(
653 "string-find".to_string(),
654 Effect::new(
655 StackType::RowVar("a".to_string())
656 .push(Type::String)
657 .push(Type::String),
658 StackType::RowVar("a".to_string()).push(Type::Int),
659 ),
660 );
661
662 sigs.insert(
666 "variant-field-count".to_string(),
667 Effect::new(
668 StackType::RowVar("a".to_string()).push(Type::Var("V".to_string())),
669 StackType::RowVar("a".to_string()).push(Type::Int),
670 ),
671 );
672
673 sigs.insert(
676 "variant-tag".to_string(),
677 Effect::new(
678 StackType::RowVar("a".to_string()).push(Type::Var("V".to_string())),
679 StackType::RowVar("a".to_string()).push(Type::Int),
680 ),
681 );
682
683 sigs.insert(
686 "variant-field-at".to_string(),
687 Effect::new(
688 StackType::RowVar("a".to_string())
689 .push(Type::Var("V".to_string()))
690 .push(Type::Int),
691 StackType::RowVar("a".to_string()).push(Type::Var("T".to_string())),
692 ),
693 );
694
695 sigs.insert(
699 "make-variant".to_string(),
700 Effect::new(
701 StackType::RowVar("a".to_string())
702 .push(Type::Int) .push(Type::Int), StackType::RowVar("a".to_string()).push(Type::Var("V".to_string())),
705 ),
706 );
707
708 sigs.insert(
712 "variant-append".to_string(),
713 Effect::new(
714 StackType::RowVar("a".to_string())
715 .push(Type::Var("V".to_string()))
716 .push(Type::Var("T".to_string())),
717 StackType::RowVar("a".to_string()).push(Type::Var("V2".to_string())),
718 ),
719 );
720
721 sigs.insert(
724 "variant-last".to_string(),
725 Effect::new(
726 StackType::RowVar("a".to_string()).push(Type::Var("V".to_string())),
727 StackType::RowVar("a".to_string()).push(Type::Var("T".to_string())),
728 ),
729 );
730
731 sigs.insert(
734 "variant-init".to_string(),
735 Effect::new(
736 StackType::RowVar("a".to_string()).push(Type::Var("V".to_string())),
737 StackType::RowVar("a".to_string()).push(Type::Var("V2".to_string())),
738 ),
739 );
740
741 for op in &["f.add", "f.subtract", "f.multiply", "f.divide"] {
743 sigs.insert(
744 op.to_string(),
745 Effect::new(
746 StackType::RowVar("a".to_string())
747 .push(Type::Float)
748 .push(Type::Float),
749 StackType::RowVar("a".to_string()).push(Type::Float),
750 ),
751 );
752 }
753
754 for op in &["f.=", "f.<", "f.>", "f.<=", "f.>=", "f.<>"] {
757 sigs.insert(
758 op.to_string(),
759 Effect::new(
760 StackType::RowVar("a".to_string())
761 .push(Type::Float)
762 .push(Type::Float),
763 StackType::RowVar("a".to_string()).push(Type::Int),
764 ),
765 );
766 }
767
768 sigs.insert(
771 "int->float".to_string(),
772 Effect::new(
773 StackType::RowVar("a".to_string()).push(Type::Int),
774 StackType::RowVar("a".to_string()).push(Type::Float),
775 ),
776 );
777
778 sigs.insert(
781 "float->int".to_string(),
782 Effect::new(
783 StackType::RowVar("a".to_string()).push(Type::Float),
784 StackType::RowVar("a".to_string()).push(Type::Int),
785 ),
786 );
787
788 sigs.insert(
791 "float->string".to_string(),
792 Effect::new(
793 StackType::RowVar("a".to_string()).push(Type::Float),
794 StackType::RowVar("a".to_string()).push(Type::String),
795 ),
796 );
797
798 sigs.insert(
801 "string->float".to_string(),
802 Effect::new(
803 StackType::RowVar("a".to_string()).push(Type::String),
804 StackType::RowVar("a".to_string())
805 .push(Type::Float)
806 .push(Type::Int),
807 ),
808 );
809
810 sigs
811}
812
813#[cfg(test)]
814mod tests {
815 use super::*;
816
817 #[test]
818 fn test_builtin_signature_write_line() {
819 let sig = builtin_signature("write_line").unwrap();
820 let (rest, top) = sig.inputs.clone().pop().unwrap();
822 assert_eq!(top, Type::String);
823 assert_eq!(rest, StackType::RowVar("a".to_string()));
824 assert_eq!(sig.outputs, StackType::RowVar("a".to_string()));
825 }
826
827 #[test]
828 fn test_builtin_signature_add() {
829 let sig = builtin_signature("add").unwrap();
830 let (rest, top) = sig.inputs.clone().pop().unwrap();
832 assert_eq!(top, Type::Int);
833 let (rest2, top2) = rest.pop().unwrap();
834 assert_eq!(top2, Type::Int);
835 assert_eq!(rest2, StackType::RowVar("a".to_string()));
836
837 let (rest3, top3) = sig.outputs.clone().pop().unwrap();
838 assert_eq!(top3, Type::Int);
839 assert_eq!(rest3, StackType::RowVar("a".to_string()));
840 }
841
842 #[test]
843 fn test_builtin_signature_dup() {
844 let sig = builtin_signature("dup").unwrap();
845 assert_eq!(
847 sig.inputs,
848 StackType::Cons {
849 rest: Box::new(StackType::RowVar("a".to_string())),
850 top: Type::Var("T".to_string())
851 }
852 );
853 let (rest, top) = sig.outputs.clone().pop().unwrap();
855 assert_eq!(top, Type::Var("T".to_string()));
856 let (rest2, top2) = rest.pop().unwrap();
857 assert_eq!(top2, Type::Var("T".to_string()));
858 assert_eq!(rest2, StackType::RowVar("a".to_string()));
859 }
860
861 #[test]
862 fn test_all_builtins_have_signatures() {
863 let sigs = builtin_signatures();
864
865 assert!(sigs.contains_key("write_line"));
867 assert!(sigs.contains_key("read_line"));
868 assert!(sigs.contains_key("int->string"));
869 assert!(sigs.contains_key("add"));
870 assert!(sigs.contains_key("dup"));
871 assert!(sigs.contains_key("swap"));
872 assert!(sigs.contains_key("make-channel"));
873 assert!(sigs.contains_key("send"));
874 assert!(sigs.contains_key("receive"));
875 assert!(
876 sigs.contains_key("string->float"),
877 "string->float should be a builtin"
878 );
879 }
880}