1use crate::{
2 expression::{Expr, ExprId},
3 io::{Input, Output},
4 util::{num_repr, NumRepr},
5};
6use anyhow::{bail, Result};
7use std::{
8 collections::VecDeque,
9 mem::{size_of, swap},
10};
11
12pub struct LazyKRunner {
13 e: Vec<Expr>,
14 church_chars: Vec<ExprId>,
15 pub s: ExprId,
16 pub k: ExprId,
17 pub i: ExprId,
18 pub ki: ExprId,
19 pub inc: ExprId,
20 pub zero: ExprId,
21 pub iota: ExprId,
22 input: Input,
23
24 gc_free_ptr: usize,
27 gc_queue: VecDeque<ExprId>,
28}
29
30static GC_LIMIT_BYTES: usize = 256 * 1024 * 1024;
32static GC_LIMIT_EXPR: usize = GC_LIMIT_BYTES / size_of::<Expr>();
33static PREAMBLE_LENGTH: usize = 448;
35static EOF_MARKER: u16 = 256;
37
38impl LazyKRunner {
39 pub fn new() -> Self {
40 let mut pool: Vec<Expr> = Vec::with_capacity(1000000);
41 pool.push(Expr::Free);
42 let mut n = |expr: Expr| {
43 pool.push(expr);
44 (pool.len() - 1) as ExprId
45 };
46
47 let k = n(Expr::K);
48 let s = n(Expr::S);
49 let i = n(Expr::I);
50 let ki = n(Expr::K1(i));
51 let ks = n(Expr::K1(s));
52 let kk = n(Expr::K1(k));
53 let sksk = n(Expr::S2(ks, k));
54 let siks = n(Expr::S2(i, ks));
55 let iota = n(Expr::S2(siks, kk));
56 let inc = n(Expr::Inc);
57 let zero = n(Expr::Num(0));
58
59 let mut church_chars = vec![ki, i];
60 for i in 2..=EOF_MARKER {
61 let church_expr = match num_repr(i) {
62 NumRepr::Pow(a, b) => Expr::A(church_chars[b], church_chars[a]),
63 NumRepr::Mul(a, b) => Expr::S2(n(Expr::K1(church_chars[a])), church_chars[b]),
64 NumRepr::Inc(a) => Expr::S2(sksk, church_chars[a]),
65 };
66 church_chars.push(n(church_expr));
67 }
68 assert!(pool.len() <= PREAMBLE_LENGTH);
69 Self {
70 e: pool,
71 church_chars,
72 s,
73 k,
74 i,
75 ki,
76 inc,
77 zero,
78 iota,
79 input: Input::Null,
80 gc_free_ptr: 0,
81 gc_queue: VecDeque::new(),
82 }
83 }
84
85 #[inline(always)]
86 fn new_expr_push(&mut self, expr: Expr) -> ExprId {
87 let ans = self.e.len() as ExprId;
88 self.e.push(expr);
89 ans
90 }
91
92 pub(crate) fn new_expr(&mut self, expr: Expr) -> ExprId {
93 if self.gc_free_ptr == 0 {
94 return self.new_expr_push(expr);
95 }
96 for i in self.gc_free_ptr..self.e.len() {
98 if let Expr::Free = self.e[i] {
99 self.e[i] = expr;
100 self.gc_free_ptr = i + 1;
101 return i as ExprId;
102 }
103 }
104 self.gc_free_ptr = 0;
106 self.new_expr_push(expr)
107 }
108
109 fn garbage_collect(&mut self, expr_id: ExprId) {
111 let fp = self.gc_free_ptr;
112 let n = self.e.len();
113 let need_gc = (fp == 0 && n > GC_LIMIT_EXPR) || (fp > GC_LIMIT_EXPR);
114 if !need_gc {
115 return;
116 }
117
118 let mut needed: Vec<bool> = vec![false; n];
120 self.gc_queue.push_back(expr_id);
121 while let Some(next_id) = self.gc_queue.pop_front() {
122 if needed[next_id as usize] {
123 continue;
124 }
125 needed[next_id as usize] = true;
126 match &self.e[next_id as usize] {
127 Expr::A(arg1, arg2) | Expr::S2(arg1, arg2) => {
128 self.gc_queue.push_back(*arg1);
129 self.gc_queue.push_back(*arg2);
130 }
131 Expr::K1(arg1) | Expr::S1(arg1) | Expr::I1(arg1) => self.gc_queue.push_back(*arg1),
132 _ => {}
133 }
134 }
135 #[allow(clippy::needless_range_loop)]
136 for i in PREAMBLE_LENGTH..n {
137 if !needed[i] {
138 self.e[i] = Expr::Free;
139 }
140 }
141 self.gc_free_ptr = PREAMBLE_LENGTH;
142 }
143
144 fn partial_eval_primitive_application(&mut self, expr_id: ExprId) {
145 match self.e[expr_id as usize] {
146 Expr::A(lhs, rhs) => {
147 self.e[expr_id as usize] = self.partial_eval_primitive_application_2(lhs, rhs);
148 }
149 _ => panic!("Not an application!"),
150 }
151 }
152
153 fn partial_eval_primitive_application_2(&mut self, lhs: ExprId, rhs: ExprId) -> Expr {
154 let rhs = self.drop_i1(rhs);
155 match &self.e[lhs as usize] {
156 Expr::K => Expr::K1(rhs),
157 Expr::K1(arg1) => Expr::I1(*arg1),
158 Expr::S => Expr::S1(rhs),
159 Expr::I => Expr::I1(rhs),
160 Expr::S1(arg1) => Expr::S2(*arg1, rhs),
161 Expr::LazyRead => self.apply_lazy_read(lhs, rhs),
162 Expr::S2(arg1, arg2) => self.apply_s2(*arg1, *arg2, rhs),
163 Expr::Inc => {
164 let rhs2 = self.partial_eval(rhs);
165 match self.e[rhs2 as usize] {
166 Expr::Num(num) => Expr::Num(num + 1),
167 _ => panic!("Attempted to apply inc to a non-number"),
168 }
169 }
170 _ => panic!("Unreachable code."),
171 }
172 }
173
174 fn apply_lazy_read(&mut self, lhs: ExprId, rhs: ExprId) -> Expr {
176 let next_char = match self.input.read_byte() {
177 Some(ch) => ch as u16,
178 None => EOF_MARKER,
179 };
180 let ch = self.church_char(next_char);
181 let x_rhs = self.new_expr(Expr::K1(ch));
182 let x = self.new_expr(Expr::S2(self.i, x_rhs));
183 let new_lazy_read = self.new_expr(Expr::LazyRead);
184 let y = self.new_expr(Expr::K1(new_lazy_read));
185 self.e[lhs as usize] = Expr::S2(x, y);
186 self.partial_eval_primitive_application_2(lhs, rhs)
187 }
188
189 fn apply_s2(&mut self, arg1: ExprId, arg2: ExprId, rhs: ExprId) -> Expr {
190 let new_lhs = self.partial_apply(arg1, rhs);
191 Expr::A(new_lhs, self.partial_apply(arg2, rhs))
192 }
193
194 pub fn partial_apply(&mut self, lhs: ExprId, rhs: ExprId) -> ExprId {
195 self.new_expr(Expr::A(lhs, rhs))
196 }
197
198 fn drop_i1(&self, mut expr: ExprId) -> ExprId {
199 while let Expr::I1(arg1) = self.e[expr as usize] {
200 expr = arg1;
201 }
202 expr
203 }
204
205 fn partial_eval(&mut self, mut cur: ExprId) -> ExprId {
206 let mut prev: ExprId = 0;
207 loop {
208 cur = self.drop_i1(cur);
209 while let Expr::A(arg1, _) = &mut self.e[cur as usize] {
210 swap(arg1, &mut prev);
211 prev = self.drop_i1(prev);
212 swap(&mut cur, &mut prev);
213 }
214 if prev == 0 {
215 return cur;
216 }
217
218 if let Expr::A(arg1, _) = &mut self.e[prev as usize] {
219 swap(arg1, &mut cur);
220 } else {
221 panic!("Unreachable code")
222 }
223 swap(&mut cur, &mut prev);
224
225 self.partial_eval_primitive_application(cur);
226 }
227 }
228
229 pub fn church2int(&mut self, church: ExprId) -> Result<u16> {
230 let inc = self.partial_apply(church, self.inc);
231 let e = self.partial_apply(inc, self.zero);
232 let result_id = self.partial_eval(e);
233 match self.e[result_id as usize] {
234 Expr::Num(num) => Ok(num),
235 _ => bail!("Program's output is not a church numeral."),
236 }
237 }
238
239 fn car(&mut self, list: ExprId) -> ExprId {
240 self.partial_apply(list, self.k)
241 }
242
243 fn cdr(&mut self, list: ExprId) -> ExprId {
244 self.partial_apply(list, self.ki)
245 }
246
247 pub(crate) fn pair(&mut self, x: ExprId, y: ExprId) -> ExprId {
250 let d = self.new_expr(Expr::K1(x));
251 let a = self.new_expr(Expr::S2(self.i, d));
252 let b = self.new_expr(Expr::K1(y));
253 self.new_expr(Expr::S2(a, b))
254 }
255
256 pub fn church_char(&self, mut idx: u16) -> ExprId {
257 if idx > EOF_MARKER {
258 idx = EOF_MARKER;
259 }
260 self.church_chars[idx as usize]
261 }
262
263 pub fn run(
264 &mut self,
265 expr_id: ExprId,
266 input: Input,
267 output: &mut Output,
268 output_limit: Option<usize>,
269 ) -> Result<u16> {
270 self.input = input;
271 let lr = self.new_expr(Expr::LazyRead);
272 let mut e = self.partial_apply(expr_id, lr);
273 let mut output_size = 0;
274 loop {
275 let head = self.car(e);
276 let ch = self.church2int(head)?;
277 if ch >= EOF_MARKER {
278 return Ok(ch - EOF_MARKER);
279 }
280 output.write_char(ch as u8)?;
281 e = self.cdr(e);
282 output_size += 1;
283 self.garbage_collect(e);
284 if output_limit.is_some() && output_limit.unwrap() == output_size {
285 return Ok(1);
286 }
287 }
288 }
289
290 pub(crate) fn get_expr(&'_ self, expr_id: ExprId) -> &'_ Expr {
291 &self.e[expr_id as usize]
292 }
293}
294
295impl Default for LazyKRunner {
296 fn default() -> Self {
297 Self::new()
298 }
299}