1use super::{
2 parser::{FunParser, ParseBook},
3 Book, Name, Num, Pattern, Term,
4};
5use crate::maybe_grow;
6
7const BUILTINS: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/fun/builtins.bend"));
8
9pub const LIST: &str = "List";
10pub const LCONS: &str = "List/Cons";
11pub const LNIL: &str = "List/Nil";
12pub const LCONS_TAG: u32 = 1;
13pub const LNIL_TAG_REF: &str = "List/Nil/tag";
14pub const LCONS_TAG_REF: &str = "List/Cons/tag";
15
16pub const HEAD: &str = "head";
17pub const TAIL: &str = "tail";
18
19pub const STRING: &str = "String";
20pub const SCONS: &str = "String/Cons";
21pub const SNIL: &str = "String/Nil";
22pub const SCONS_TAG: u32 = 1;
23pub const SNIL_TAG_REF: &str = "String/Nil/tag";
24pub const SCONS_TAG_REF: &str = "String/Cons/tag";
25
26pub const NAT: &str = "Nat";
27pub const NAT_SUCC: &str = "Nat/Succ";
28pub const NAT_ZERO: &str = "Nat/Zero";
29pub const NAT_SUCC_TAG: u32 = 0;
30
31pub const TREE: &str = "Tree";
32pub const TREE_NODE: &str = "Tree/Node";
33pub const TREE_LEAF: &str = "Tree/Leaf";
34
35pub const MAP: &str = "Map";
36pub const MAP_NODE: &str = "Map/Node";
37pub const MAP_LEAF: &str = "Map/Leaf";
38
39pub const IO: &str = "IO";
40pub const IO_DONE: &str = "IO/Done";
41pub const IO_CALL: &str = "IO/Call";
42
43pub const BUILTIN_CTRS: &[&str] =
44 &[LCONS, LNIL, SCONS, SNIL, NAT_SUCC, NAT_ZERO, TREE_NODE, TREE_LEAF, MAP_NODE, MAP_LEAF, IO_DONE, IO_CALL];
45
46pub const BUILTIN_TYPES: &[&str] = &[LIST, STRING, NAT, TREE, MAP, IO];
47
48impl ParseBook {
49 pub fn builtins() -> Self {
50 let book =
51 FunParser::new(Name::new("/src/fun/builtins.bend"), BUILTINS, true).parse_book(Self::default());
52 book.unwrap_or_else(|e| panic!("Error parsing builtin file, this should not happen:\n{e}"))
53 }
54}
55
56impl Book {
57 pub fn encode_builtins(&mut self) {
58 for def in self.defs.values_mut() {
59 for rule in def.rules.iter_mut() {
60 rule.pats.iter_mut().for_each(Pattern::encode_builtins);
61 rule.body.encode_builtins();
62 }
63 }
64 }
65}
66
67impl Term {
68 fn encode_builtins(&mut self) {
69 maybe_grow(|| match self {
70 Term::List { els } => *self = Term::encode_list(std::mem::take(els)),
71 Term::Str { val } => *self = Term::encode_str(val),
72 Term::Nat { val } => *self = Term::encode_nat(*val),
73 Term::Def { def, nxt } => {
74 for rule in def.rules.iter_mut() {
75 rule.pats.iter_mut().for_each(Pattern::encode_builtins);
76 rule.body.encode_builtins();
77 }
78 nxt.encode_builtins();
79 }
80 _ => {
81 for child in self.children_mut() {
82 child.encode_builtins();
83 }
84 }
85 })
86 }
87
88 fn encode_list(elements: Vec<Term>) -> Term {
89 elements.into_iter().rfold(Term::r#ref(LNIL), |acc, mut nxt| {
90 nxt.encode_builtins();
91 Term::call(Term::r#ref(LCONS), [nxt, acc])
92 })
93 }
94
95 pub fn encode_str(val: &str) -> Term {
96 val.chars().rfold(Term::r#ref(SNIL), |acc, char| {
97 Term::call(Term::r#ref(SCONS), [Term::Num { val: Num::U24(char as u32 & 0x00ff_ffff) }, acc])
98 })
99 }
100
101 pub fn encode_nat(val: u32) -> Term {
102 (0..val).fold(Term::r#ref(NAT_ZERO), |acc, _| Term::app(Term::r#ref(NAT_SUCC), acc))
103 }
104}
105
106impl Pattern {
107 pub fn encode_builtins(&mut self) {
108 match self {
109 Pattern::Lst(pats) => *self = Self::encode_list(std::mem::take(pats)),
110 Pattern::Str(str) => *self = Self::encode_str(str),
111 _ => {
112 for pat in self.children_mut() {
113 pat.encode_builtins();
114 }
115 }
116 }
117 }
118
119 fn encode_list(elements: Vec<Pattern>) -> Pattern {
120 let lnil = Pattern::Ctr(Name::new(LNIL), vec![]);
121
122 elements.into_iter().rfold(lnil, |acc, mut nxt| {
123 nxt.encode_builtins();
124 Pattern::Ctr(Name::new(LCONS), vec![nxt, acc])
125 })
126 }
127
128 fn encode_str(str: &str) -> Pattern {
129 let lnil = Pattern::Ctr(Name::new(SNIL), vec![]);
130
131 str.chars().rfold(lnil, |tail, head| {
132 let head = Pattern::Num(head as u32);
133 Pattern::Ctr(Name::new(SCONS), vec![head, tail])
134 })
135 }
136}