bend/fun/
builtins.rs

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}