1use std::collections::HashMap;
17
18use crate::arena::Arena;
19use crate::ast::stmt::{BinaryOpKind, Block, Expr, Literal, Stmt};
20use crate::intern::{Interner, Symbol};
21
22const MAX_INLINE_DEPTH: usize = 64;
23const MAX_INLINE_STEPS: usize = 10_000;
24
25#[derive(Debug, Clone)]
26enum Value {
27 Int(i64),
28 Float(f64),
29 Bool(bool),
30 Text(Symbol),
31 Nothing,
32}
33
34impl PartialEq for Value {
35 fn eq(&self, other: &Self) -> bool {
36 match (self, other) {
37 (Value::Int(a), Value::Int(b)) => a == b,
38 (Value::Float(a), Value::Float(b)) => a.to_bits() == b.to_bits(),
39 (Value::Bool(a), Value::Bool(b)) => a == b,
40 (Value::Text(a), Value::Text(b)) => a == b,
41 (Value::Nothing, Value::Nothing) => true,
42 _ => false,
43 }
44 }
45}
46
47impl Eq for Value {}
48
49impl std::hash::Hash for Value {
50 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
51 std::mem::discriminant(self).hash(state);
52 match self {
53 Value::Int(n) => n.hash(state),
54 Value::Float(f) => f.to_bits().hash(state),
55 Value::Bool(b) => b.hash(state),
56 Value::Text(s) => s.hash(state),
57 Value::Nothing => {}
58 }
59 }
60}
61
62struct FuncDef<'a> {
63 params: Vec<Symbol>,
64 body: Block<'a>,
65}
66
67#[derive(Clone)]
68struct Configuration<'a> {
69 expr: &'a Expr<'a>,
70 store_snapshot: HashMap<Symbol, Value>,
71}
72
73struct History<'a> {
74 entries: Vec<Configuration<'a>>,
75}
76
77impl<'a> History<'a> {
78 fn new() -> Self {
79 Self { entries: Vec::new() }
80 }
81
82 fn push(&mut self, config: Configuration<'a>) {
83 if self.entries.len() >= 16 {
84 self.entries.remove(0);
85 }
86 self.entries.push(config);
87 }
88
89 fn check_embedding(&self, new_expr: &Expr<'a>) -> Option<&Configuration<'a>> {
90 self.entries.iter().find(|c| embeds(c.expr, new_expr))
91 }
92}
93
94struct SuperEnv<'a> {
95 store: HashMap<Symbol, Value>,
96 funcs: HashMap<Symbol, FuncDef<'a>>,
97 memo: HashMap<(Symbol, Vec<Value>), Option<Value>>,
98 steps: usize,
99 history: History<'a>,
100}
101
102impl<'a> SuperEnv<'a> {
103 fn new() -> Self {
104 Self {
105 store: HashMap::new(),
106 funcs: HashMap::new(),
107 memo: HashMap::new(),
108 steps: 0,
109 history: History::new(),
110 }
111 }
112}
113
114fn is_pure_body(stmts: &[Stmt]) -> bool {
115 stmts.iter().all(is_pure_stmt)
116}
117
118fn is_pure_stmt(stmt: &Stmt) -> bool {
119 match stmt {
120 Stmt::Let { value, .. } => is_pure_expr(value),
121 Stmt::Set { value, .. } => is_pure_expr(value),
122 Stmt::Return { value } => value.map_or(true, is_pure_expr),
123 Stmt::If { cond, then_block, else_block } => {
124 is_pure_expr(cond)
125 && is_pure_body(then_block)
126 && else_block.map_or(true, |eb| is_pure_body(eb))
127 }
128 Stmt::While { cond, body, .. } => is_pure_expr(cond) && is_pure_body(body),
129 Stmt::Call { .. } => true,
130 _ => false,
131 }
132}
133
134fn is_pure_expr(expr: &Expr) -> bool {
135 match expr {
136 Expr::Literal(_) | Expr::Identifier(_) | Expr::OptionNone => true,
137 Expr::BinaryOp { left, right, .. } => is_pure_expr(left) && is_pure_expr(right),
138 Expr::Not { operand } => is_pure_expr(operand),
139 Expr::Call { args, .. } => args.iter().all(|a| is_pure_expr(a)),
140 Expr::Length { collection } => is_pure_expr(collection),
141 Expr::FieldAccess { object, .. } => is_pure_expr(object),
142 Expr::Index { collection, index } => is_pure_expr(collection) && is_pure_expr(index),
143 _ => false,
144 }
145}
146
147fn collect_pure_funcs<'a>(stmts: &[Stmt<'a>]) -> HashMap<Symbol, FuncDef<'a>> {
148 let mut funcs = HashMap::new();
149 for stmt in stmts {
150 if let Stmt::FunctionDef { name, params, body, is_native, .. } = stmt {
151 if *is_native {
152 continue;
153 }
154 if is_pure_body(body) {
155 let param_syms: Vec<Symbol> = params.iter().map(|(s, _)| *s).collect();
156 funcs.insert(*name, FuncDef { params: param_syms, body });
157 }
158 }
159 }
160 funcs
161}
162
163fn eval_expr_to_value(
168 expr: &Expr,
169 locals: &HashMap<Symbol, Value>,
170 funcs: &HashMap<Symbol, FuncDef>,
171 memo: &mut HashMap<(Symbol, Vec<Value>), Option<Value>>,
172 steps: &mut usize,
173 depth: usize,
174) -> Option<Value> {
175 if *steps >= MAX_INLINE_STEPS || depth >= MAX_INLINE_DEPTH {
176 return None;
177 }
178 *steps += 1;
179
180 match expr {
181 Expr::Literal(Literal::Number(n)) => Some(Value::Int(*n)),
182 Expr::Literal(Literal::Float(f)) => Some(Value::Float(*f)),
183 Expr::Literal(Literal::Boolean(b)) => Some(Value::Bool(*b)),
184 Expr::Literal(Literal::Text(s)) => Some(Value::Text(*s)),
185 Expr::Literal(Literal::Nothing) => Some(Value::Nothing),
186 Expr::Identifier(sym) => locals.get(sym).cloned(),
187 Expr::BinaryOp { op, left, right } => {
188 let lv = eval_expr_to_value(left, locals, funcs, memo, steps, depth)?;
189 let rv = eval_expr_to_value(right, locals, funcs, memo, steps, depth)?;
190 eval_binop(*op, &lv, &rv)
191 }
192 Expr::Not { operand } => {
193 if let Value::Bool(b) = eval_expr_to_value(operand, locals, funcs, memo, steps, depth)? {
194 Some(Value::Bool(!b))
195 } else {
196 None
197 }
198 }
199 Expr::Call { function, args } => {
200 let func = funcs.get(function)?;
201 if args.len() != func.params.len() {
202 return None;
203 }
204 let mut arg_vals = Vec::with_capacity(args.len());
205 for arg in args {
206 arg_vals.push(eval_expr_to_value(arg, locals, funcs, memo, steps, depth)?);
207 }
208
209 let memo_key = (*function, arg_vals.clone());
210 if let Some(cached) = memo.get(&memo_key) {
211 return cached.clone();
212 }
213
214 memo.insert(memo_key.clone(), None);
216
217 let mut call_locals = HashMap::new();
218 for (param, val) in func.params.iter().zip(arg_vals.iter()) {
219 call_locals.insert(*param, val.clone());
220 }
221
222 let result = eval_block_to_value(func.body, &mut call_locals, funcs, memo, steps, depth + 1);
223 memo.insert(memo_key, result.clone());
224 result
225 }
226 _ => None,
227 }
228}
229
230fn eval_binop(op: BinaryOpKind, lv: &Value, rv: &Value) -> Option<Value> {
231 match (op, lv, rv) {
232 (BinaryOpKind::Add, Value::Int(a), Value::Int(b)) => a.checked_add(*b).map(Value::Int),
236 (BinaryOpKind::Subtract, Value::Int(a), Value::Int(b)) => a.checked_sub(*b).map(Value::Int),
237 (BinaryOpKind::Multiply, Value::Int(a), Value::Int(b)) => a.checked_mul(*b).map(Value::Int),
238 (BinaryOpKind::Divide, Value::Int(a), Value::Int(b)) if *b != 0 => a.checked_div(*b).map(Value::Int),
239 (BinaryOpKind::Modulo, Value::Int(a), Value::Int(b)) if *b != 0 => a.checked_rem(*b).map(Value::Int),
240 (BinaryOpKind::Shl, Value::Int(a), Value::Int(b)) if *b >= 0 && *b < 64 => {
241 Some(Value::Int(a.wrapping_shl(*b as u32)))
242 }
243 (BinaryOpKind::Shr, Value::Int(a), Value::Int(b)) if *b >= 0 && *b < 64 => {
244 Some(Value::Int(a.wrapping_shr(*b as u32)))
245 }
246 (BinaryOpKind::BitXor, Value::Int(a), Value::Int(b)) => Some(Value::Int(a ^ b)),
247 (BinaryOpKind::And, Value::Int(a), Value::Int(b)) => Some(Value::Int(a & b)),
248 (BinaryOpKind::Or, Value::Int(a), Value::Int(b)) => Some(Value::Int(a | b)),
249 (BinaryOpKind::Eq, Value::Int(a), Value::Int(b)) => Some(Value::Bool(a == b)),
250 (BinaryOpKind::NotEq, Value::Int(a), Value::Int(b)) => Some(Value::Bool(a != b)),
251 (BinaryOpKind::Lt, Value::Int(a), Value::Int(b)) => Some(Value::Bool(a < b)),
252 (BinaryOpKind::Gt, Value::Int(a), Value::Int(b)) => Some(Value::Bool(a > b)),
253 (BinaryOpKind::LtEq, Value::Int(a), Value::Int(b)) => Some(Value::Bool(a <= b)),
254 (BinaryOpKind::GtEq, Value::Int(a), Value::Int(b)) => Some(Value::Bool(a >= b)),
255 (BinaryOpKind::Add, Value::Float(a), Value::Float(b)) => Some(Value::Float(a + b)),
256 (BinaryOpKind::Subtract, Value::Float(a), Value::Float(b)) => Some(Value::Float(a - b)),
257 (BinaryOpKind::Multiply, Value::Float(a), Value::Float(b)) => Some(Value::Float(a * b)),
258 (BinaryOpKind::Divide, Value::Float(a), Value::Float(b)) if *b != 0.0 => Some(Value::Float(a / b)),
259 (BinaryOpKind::And, Value::Bool(a), Value::Bool(b)) => Some(Value::Bool(*a && *b)),
260 (BinaryOpKind::Or, Value::Bool(a), Value::Bool(b)) => Some(Value::Bool(*a || *b)),
261 (BinaryOpKind::Eq, Value::Text(a), Value::Text(b)) => Some(Value::Bool(a == b)),
262 (BinaryOpKind::NotEq, Value::Text(a), Value::Text(b)) => Some(Value::Bool(a != b)),
263 _ => None,
264 }
265}
266
267enum EvalResult {
268 Continue,
269 Return(Value),
270}
271
272fn eval_block_to_value(
273 stmts: &[Stmt],
274 locals: &mut HashMap<Symbol, Value>,
275 funcs: &HashMap<Symbol, FuncDef>,
276 memo: &mut HashMap<(Symbol, Vec<Value>), Option<Value>>,
277 steps: &mut usize,
278 depth: usize,
279) -> Option<Value> {
280 for stmt in stmts {
281 match eval_stmt_to_value(stmt, locals, funcs, memo, steps, depth)? {
282 EvalResult::Continue => {}
283 EvalResult::Return(v) => return Some(v),
284 }
285 }
286 Some(Value::Nothing)
287}
288
289fn eval_stmt_to_value(
290 stmt: &Stmt,
291 locals: &mut HashMap<Symbol, Value>,
292 funcs: &HashMap<Symbol, FuncDef>,
293 memo: &mut HashMap<(Symbol, Vec<Value>), Option<Value>>,
294 steps: &mut usize,
295 depth: usize,
296) -> Option<EvalResult> {
297 if *steps >= MAX_INLINE_STEPS {
298 return None;
299 }
300 *steps += 1;
301
302 match stmt {
303 Stmt::Let { var, value, .. } => {
304 let v = eval_expr_to_value(value, locals, funcs, memo, steps, depth)?;
305 locals.insert(*var, v);
306 Some(EvalResult::Continue)
307 }
308 Stmt::Set { target, value } => {
309 let v = eval_expr_to_value(value, locals, funcs, memo, steps, depth)?;
310 locals.insert(*target, v);
311 Some(EvalResult::Continue)
312 }
313 Stmt::Return { value } => {
314 if let Some(v) = value {
315 let result = eval_expr_to_value(v, locals, funcs, memo, steps, depth)?;
316 Some(EvalResult::Return(result))
317 } else {
318 Some(EvalResult::Return(Value::Nothing))
319 }
320 }
321 Stmt::If { cond, then_block, else_block } => {
322 let cv = eval_expr_to_value(cond, locals, funcs, memo, steps, depth)?;
323 if let Value::Bool(b) = cv {
324 if b {
325 for s in *then_block {
326 match eval_stmt_to_value(s, locals, funcs, memo, steps, depth)? {
327 EvalResult::Continue => {}
328 EvalResult::Return(v) => return Some(EvalResult::Return(v)),
329 }
330 }
331 } else if let Some(eb) = else_block {
332 for s in *eb {
333 match eval_stmt_to_value(s, locals, funcs, memo, steps, depth)? {
334 EvalResult::Continue => {}
335 EvalResult::Return(v) => return Some(EvalResult::Return(v)),
336 }
337 }
338 }
339 Some(EvalResult::Continue)
340 } else {
341 None
342 }
343 }
344 Stmt::While { cond, body, .. } => {
345 loop {
346 let cv = eval_expr_to_value(cond, locals, funcs, memo, steps, depth)?;
347 match cv {
348 Value::Bool(false) => break,
349 Value::Bool(true) => {
350 for s in *body {
351 match eval_stmt_to_value(s, locals, funcs, memo, steps, depth)? {
352 EvalResult::Continue => {}
353 EvalResult::Return(v) => return Some(EvalResult::Return(v)),
354 }
355 }
356 }
357 _ => return None,
358 }
359 }
360 Some(EvalResult::Continue)
361 }
362 _ => None,
363 }
364}
365
366fn value_to_literal(val: &Value) -> Option<Literal> {
371 match val {
372 Value::Int(n) => Some(Literal::Number(*n)),
373 Value::Float(f) => Some(Literal::Float(*f)),
374 Value::Bool(b) => Some(Literal::Boolean(*b)),
375 Value::Text(s) => Some(Literal::Text(*s)),
376 Value::Nothing => Some(Literal::Nothing),
377 }
378}
379
380fn value_to_expr<'a>(val: &Value, arena: &'a Arena<Expr<'a>>) -> &'a Expr<'a> {
381 match value_to_literal(val) {
382 Some(lit) => arena.alloc(Expr::Literal(lit)),
383 None => unreachable!(),
384 }
385}
386
387fn expr_to_value(expr: &Expr, store: &HashMap<Symbol, Value>) -> Option<Value> {
388 match expr {
389 Expr::Literal(Literal::Number(n)) => Some(Value::Int(*n)),
390 Expr::Literal(Literal::Float(f)) => Some(Value::Float(*f)),
391 Expr::Literal(Literal::Boolean(b)) => Some(Value::Bool(*b)),
392 Expr::Literal(Literal::Text(s)) => Some(Value::Text(*s)),
393 Expr::Literal(Literal::Nothing) => Some(Value::Nothing),
394 Expr::Identifier(sym) => store.get(sym).cloned(),
395 _ => None,
396 }
397}
398
399fn try_eval_expr<'a>(
400 expr: &'a Expr<'a>,
401 env: &mut SuperEnv<'a>,
402 depth: usize,
403) -> Option<Value> {
404 eval_expr_to_value(
405 expr,
406 &env.store,
407 &env.funcs,
408 &mut env.memo,
409 &mut env.steps,
410 depth,
411 )
412}
413
414fn drive_expr<'a>(
415 expr: &'a Expr<'a>,
416 env: &mut SuperEnv<'a>,
417 expr_arena: &'a Arena<Expr<'a>>,
418 depth: usize,
419) -> &'a Expr<'a> {
420 if depth >= MAX_INLINE_DEPTH {
421 return expr;
422 }
423
424 match expr {
425 Expr::Identifier(sym) => {
426 if let Some(val) = env.store.get(sym) {
427 match val {
431 Value::Int(_) | Value::Float(_) | Value::Bool(_) | Value::Nothing => {
432 if let Some(lit) = value_to_literal(val) {
433 return expr_arena.alloc(Expr::Literal(lit));
434 }
435 }
436 Value::Text(s) => {
437 return expr_arena.alloc(Expr::Literal(Literal::Text(*s)));
438 }
439 }
440 }
441 expr
442 }
443 Expr::BinaryOp { op, left, right } => {
444 let dl = drive_expr(left, env, expr_arena, depth);
445 let dr = drive_expr(right, env, expr_arena, depth);
446 if let (Some(lv), Some(rv)) = (expr_to_value(dl, &env.store), expr_to_value(dr, &env.store)) {
448 if let Some(result) = eval_binop(*op, &lv, &rv) {
449 return value_to_expr(&result, expr_arena);
450 }
451 }
452 if std::ptr::eq(dl, *left) && std::ptr::eq(dr, *right) {
453 expr
454 } else {
455 expr_arena.alloc(Expr::BinaryOp { op: *op, left: dl, right: dr })
456 }
457 }
458 Expr::Not { operand } => {
459 let d = drive_expr(operand, env, expr_arena, depth);
460 if let Expr::Literal(Literal::Boolean(b)) = d {
461 return expr_arena.alloc(Expr::Literal(Literal::Boolean(!b)));
462 }
463 if std::ptr::eq(d, *operand) { expr } else { expr_arena.alloc(Expr::Not { operand: d }) }
464 }
465 Expr::Call { function, args } => {
466 let driven_args: Vec<&'a Expr<'a>> = args.iter()
467 .map(|a| drive_expr(a, env, expr_arena, depth))
468 .collect();
469 let changed = driven_args.iter().zip(args.iter()).any(|(d, o)| !std::ptr::eq(*d, *o));
472 if changed {
473 expr_arena.alloc(Expr::Call { function: *function, args: driven_args })
474 } else {
475 expr
476 }
477 }
478 Expr::Length { collection } => {
479 let d = drive_expr(collection, env, expr_arena, depth);
480 if std::ptr::eq(d, *collection) { expr } else { expr_arena.alloc(Expr::Length { collection: d }) }
481 }
482 Expr::Index { .. } | Expr::Slice { .. } => expr,
487 Expr::Contains { collection, value } => {
488 let dc = drive_expr(collection, env, expr_arena, depth);
489 let dv = drive_expr(value, env, expr_arena, depth);
490 if std::ptr::eq(dc, *collection) && std::ptr::eq(dv, *value) {
491 expr
492 } else {
493 expr_arena.alloc(Expr::Contains { collection: dc, value: dv })
494 }
495 }
496 Expr::FieldAccess { object, field } => {
497 let d = drive_expr(object, env, expr_arena, depth);
498 if std::ptr::eq(d, *object) { expr } else { expr_arena.alloc(Expr::FieldAccess { object: d, field: *field }) }
499 }
500 Expr::OptionSome { value } => {
501 let d = drive_expr(value, env, expr_arena, depth);
502 if std::ptr::eq(d, *value) { expr } else { expr_arena.alloc(Expr::OptionSome { value: d }) }
503 }
504 Expr::Copy { expr: inner } => {
505 let d = drive_expr(inner, env, expr_arena, depth);
506 if std::ptr::eq(d, *inner) { expr } else { expr_arena.alloc(Expr::Copy { expr: d }) }
507 }
508 Expr::Give { value } => {
509 let d = drive_expr(value, env, expr_arena, depth);
510 if std::ptr::eq(d, *value) { expr } else { expr_arena.alloc(Expr::Give { value: d }) }
511 }
512 Expr::List(elems) => {
513 let driven: Vec<&'a Expr<'a>> = elems.iter()
514 .map(|e| drive_expr(e, env, expr_arena, depth))
515 .collect();
516 let changed = driven.iter().zip(elems.iter()).any(|(d, o)| !std::ptr::eq(*d, *o));
517 if changed { expr_arena.alloc(Expr::List(driven)) } else { expr }
518 }
519 Expr::Tuple(elems) => {
520 let driven: Vec<&'a Expr<'a>> = elems.iter()
521 .map(|e| drive_expr(e, env, expr_arena, depth))
522 .collect();
523 let changed = driven.iter().zip(elems.iter()).any(|(d, o)| !std::ptr::eq(*d, *o));
524 if changed { expr_arena.alloc(Expr::Tuple(driven)) } else { expr }
525 }
526 _ => expr,
528 }
529}
530
531fn drive_stmt<'a>(
532 stmt: Stmt<'a>,
533 env: &mut SuperEnv<'a>,
534 expr_arena: &'a Arena<Expr<'a>>,
535 stmt_arena: &'a Arena<Stmt<'a>>,
536 interner: &mut Interner,
537 depth: usize,
538) -> Option<Stmt<'a>> {
539 match stmt {
540 Stmt::Let { var, ty, value, mutable } => {
541 let driven = drive_expr(value, env, expr_arena, depth);
542 if !mutable {
543 if let Some(val) = expr_to_value(driven, &env.store) {
545 env.store.insert(var, val);
546 } else {
547 if let Some(val) = try_eval_expr(driven, env, depth) {
550 env.store.insert(var, val);
551 }
552 }
553 }
554 Some(Stmt::Let { var, ty, value: driven, mutable })
555 }
556 Stmt::Set { target, value } => {
557 let driven = drive_expr(value, env, expr_arena, depth);
558 if let Some(val) = expr_to_value(driven, &env.store) {
560 env.store.insert(target, val);
561 } else {
562 env.store.remove(&target);
564 }
565 Some(Stmt::Set { target, value: driven })
566 }
567 Stmt::If { cond, then_block, else_block } => {
568 let driven_cond = drive_expr(cond, env, expr_arena, depth);
569 if let Expr::Literal(Literal::Boolean(b)) = driven_cond {
571 if *b {
572 let driven_then = drive_block(then_block, env, expr_arena, stmt_arena, interner, depth);
574 Some(Stmt::If {
575 cond: driven_cond,
576 then_block: driven_then,
577 else_block: None,
578 })
579 } else {
580 if let Some(eb) = else_block {
582 let driven_else = drive_block(eb, env, expr_arena, stmt_arena, interner, depth);
583 Some(Stmt::If {
584 cond: driven_cond,
585 then_block: stmt_arena.alloc_slice(vec![]),
586 else_block: Some(driven_else),
587 })
588 } else {
589 None }
591 }
592 } else {
593 let snapshot = env.store.clone();
595 let driven_then = drive_block(then_block, env, expr_arena, stmt_arena, interner, depth);
596 let then_store = env.store.clone();
597
598 env.store = snapshot;
599 let driven_else = else_block.map(|eb| {
600 drive_block(eb, env, expr_arena, stmt_arena, interner, depth)
601 });
602 let else_store = env.store.clone();
603
604 let mut joined = HashMap::new();
606 for (sym, then_val) in &then_store {
607 if let Some(else_val) = else_store.get(sym) {
608 if then_val == else_val {
609 joined.insert(*sym, then_val.clone());
610 }
611 }
612 }
613 env.store = joined;
614
615 Some(Stmt::If {
616 cond: driven_cond,
617 then_block: driven_then,
618 else_block: driven_else,
619 })
620 }
621 }
622 Stmt::While { cond, body, decreasing } => {
623 let modified = collect_modified_vars_block(body);
624 let snapshot = env.store.clone();
625
626 let pre_config = Configuration {
628 expr: cond,
629 store_snapshot: snapshot.clone(),
630 };
631
632 for sym in &modified {
634 env.store.remove(sym);
635 }
636
637 let driven_cond = drive_expr(cond, env, expr_arena, depth);
638 if let Expr::Literal(Literal::Boolean(false)) = driven_cond {
640 env.store = snapshot;
641 return None;
642 }
643
644 if let Some(prev) = env.history.check_embedding(driven_cond) {
647 let generalized = msg(prev.expr, driven_cond, expr_arena, interner);
648 for i in 0..generalized.num_substitutions {
650 let name = format!("__msg_{}", i);
651 let sym = interner.intern(&name);
652 env.store.remove(&sym);
653 }
654 }
655
656 env.history.push(pre_config);
658
659 let driven_body = drive_block(body, env, expr_arena, stmt_arena, interner, depth);
660
661 let mut post_loop_store = HashMap::new();
663 for (sym, val) in &snapshot {
664 if !modified.contains(sym) {
665 post_loop_store.insert(*sym, val.clone());
666 }
667 }
668 env.store = post_loop_store;
669
670 Some(Stmt::While { cond: driven_cond, body: driven_body, decreasing })
671 }
672 Stmt::Repeat { pattern, iterable, body } => {
673 let driven_iter = drive_expr(iterable, env, expr_arena, depth);
674 if let crate::ast::stmt::Pattern::Identifier(sym) = &pattern {
676 env.store.remove(sym);
677 }
678 let modified = collect_modified_vars_block(body);
679 for sym in &modified {
680 env.store.remove(sym);
681 }
682 let driven_body = drive_block(body, env, expr_arena, stmt_arena, interner, depth);
683 Some(Stmt::Repeat { pattern, iterable: driven_iter, body: driven_body })
684 }
685 Stmt::Show { object, recipient } => {
686 let driven = drive_expr(object, env, expr_arena, depth);
687 Some(Stmt::Show { object: driven, recipient })
688 }
689 Stmt::Return { value } => {
690 let driven = value.map(|v| drive_expr(v, env, expr_arena, depth));
691 Some(Stmt::Return { value: driven })
692 }
693 Stmt::Call { function, args } => {
694 let driven_args: Vec<&'a Expr<'a>> = args.into_iter()
695 .map(|a| drive_expr(a, env, expr_arena, depth))
696 .collect();
697 Some(Stmt::Call { function, args: driven_args })
698 }
699 Stmt::Push { value, collection } => {
700 let driven_val = drive_expr(value, env, expr_arena, depth);
701 if let Expr::Identifier(sym) = collection {
703 env.store.remove(sym);
704 }
705 Some(Stmt::Push { value: driven_val, collection })
706 }
707 Stmt::SetIndex { collection, index, value } => {
708 if let Expr::Identifier(sym) = collection {
710 env.store.remove(sym);
711 }
712 Some(Stmt::SetIndex { collection, index, value })
713 }
714 Stmt::SetField { object, field, value } => {
715 let dv = drive_expr(value, env, expr_arena, depth);
716 if let Expr::Identifier(sym) = object {
717 env.store.remove(sym);
718 }
719 Some(Stmt::SetField { object, field, value: dv })
720 }
721 Stmt::RuntimeAssert { condition, hard } => {
722 let driven = drive_expr(condition, env, expr_arena, depth);
723 Some(Stmt::RuntimeAssert { condition: driven , hard })
724 }
725 Stmt::FunctionDef { name, params, generics, body, return_type, is_native, native_path, is_exported, export_target, opt_flags } => {
726 let snapshot = env.store.clone();
728 env.store.clear();
729 let driven_body = drive_block(body, env, expr_arena, stmt_arena, interner, depth);
730 env.store = snapshot;
731 Some(Stmt::FunctionDef {
732 name, params, generics,
733 body: driven_body,
734 return_type, is_native, native_path, is_exported, export_target, opt_flags,
735 })
736 }
737 Stmt::Zone { .. } => Some(stmt),
740 other => Some(other),
742 }
743}
744
745fn drive_block<'a>(
746 block: &'a [Stmt<'a>],
747 env: &mut SuperEnv<'a>,
748 expr_arena: &'a Arena<Expr<'a>>,
749 stmt_arena: &'a Arena<Stmt<'a>>,
750 interner: &mut Interner,
751 depth: usize,
752) -> &'a [Stmt<'a>] {
753 let mut result = Vec::with_capacity(block.len());
754 for stmt in block.iter().cloned() {
755 if let Some(driven) = drive_stmt(stmt, env, expr_arena, stmt_arena, interner, depth) {
756 result.push(driven);
757 }
758 }
759 stmt_arena.alloc_slice(result)
760}
761
762fn collect_modified_vars_block(stmts: &[Stmt]) -> Vec<Symbol> {
763 let mut modified = Vec::new();
764 for stmt in stmts {
765 collect_modified_vars_stmt(stmt, &mut modified);
766 }
767 modified
768}
769
770fn collect_modified_vars_stmt(stmt: &Stmt, out: &mut Vec<Symbol>) {
771 match stmt {
772 Stmt::Set { target, .. } => out.push(*target),
773 Stmt::Let { var, mutable: true, .. } => out.push(*var),
774 Stmt::If { then_block, else_block, .. } => {
775 for s in *then_block {
776 collect_modified_vars_stmt(s, out);
777 }
778 if let Some(eb) = else_block {
779 for s in *eb {
780 collect_modified_vars_stmt(s, out);
781 }
782 }
783 }
784 Stmt::While { body, .. } => {
785 for s in *body {
786 collect_modified_vars_stmt(s, out);
787 }
788 }
789 Stmt::Repeat { body, .. } => {
790 for s in *body {
791 collect_modified_vars_stmt(s, out);
792 }
793 }
794 Stmt::Inspect { arms, .. } => {
795 for arm in arms {
796 for s in arm.body {
797 collect_modified_vars_stmt(s, out);
798 }
799 }
800 }
801 Stmt::Zone { body, .. } => {
802 for s in *body {
803 collect_modified_vars_stmt(s, out);
804 }
805 }
806 _ => {}
807 }
808}
809
810pub fn supercompile_stmts<'a>(
815 stmts: Vec<Stmt<'a>>,
816 expr_arena: &'a Arena<Expr<'a>>,
817 stmt_arena: &'a Arena<Stmt<'a>>,
818 interner: &mut Interner,
819) -> Vec<Stmt<'a>> {
820 let funcs = collect_pure_funcs(&stmts);
821 let mut env = SuperEnv::new();
822 env.funcs = funcs;
823
824 let mut result = Vec::with_capacity(stmts.len());
825 for stmt in stmts {
826 if let Some(driven) = drive_stmt(stmt, &mut env, expr_arena, stmt_arena, interner, 0) {
827 result.push(driven);
828 }
829 }
830 result
831}
832
833pub fn embeds<'a>(e1: &Expr<'a>, e2: &Expr<'a>) -> bool {
839 match (e1, e2) {
840 (Expr::BinaryOp { op: op1, left: l1, right: r1 },
842 Expr::BinaryOp { op: op2, left: l2, right: r2 }) if op1 == op2 =>
843 embeds(l1, l2) && embeds(r1, r2),
844 (Expr::Call { function: f1, args: a1 },
845 Expr::Call { function: f2, args: a2 }) if f1 == f2 && a1.len() == a2.len() =>
846 a1.iter().zip(a2.iter()).all(|(x, y)| embeds(x, y)),
847 (Expr::Not { operand: e1_inner }, Expr::Not { operand: e2_inner }) =>
848 embeds(e1_inner, e2_inner),
849 (Expr::Literal(l1), Expr::Literal(l2)) => l1 == l2,
851 (Expr::Identifier(s1), Expr::Identifier(s2)) => s1 == s2,
852 (_, Expr::BinaryOp { left, right, .. }) =>
854 embeds(e1, left) || embeds(e1, right),
855 (_, Expr::Call { args, .. }) =>
856 args.iter().any(|a| embeds(e1, a)),
857 (_, Expr::Not { operand }) =>
858 embeds(e1, operand),
859 _ => false,
860 }
861}
862
863pub struct MsgResult<'a> {
865 pub expr: &'a Expr<'a>,
867 pub num_substitutions: usize,
869}
870
871pub fn msg<'a>(
877 e1: &'a Expr<'a>,
878 e2: &'a Expr<'a>,
879 arena: &'a Arena<Expr<'a>>,
880 interner: &mut Interner,
881) -> MsgResult<'a> {
882 let mut counter = 0;
883 let expr = msg_inner(e1, e2, arena, interner, &mut counter);
884 MsgResult { expr, num_substitutions: counter }
885}
886
887fn msg_inner<'a>(
888 e1: &'a Expr<'a>,
889 e2: &'a Expr<'a>,
890 arena: &'a Arena<Expr<'a>>,
891 interner: &mut Interner,
892 counter: &mut usize,
893) -> &'a Expr<'a> {
894 match (e1, e2) {
895 (Expr::Literal(l1), Expr::Literal(l2)) if l1 == l2 => e1,
897 (Expr::Identifier(s1), Expr::Identifier(s2)) if s1 == s2 => e1,
898 (Expr::BinaryOp { op: op1, left: l1, right: r1 },
900 Expr::BinaryOp { op: op2, left: l2, right: r2 }) if op1 == op2 => {
901 let left = msg_inner(l1, l2, arena, interner, counter);
902 let right = msg_inner(r1, r2, arena, interner, counter);
903 arena.alloc(Expr::BinaryOp { op: *op1, left, right })
904 }
905 (Expr::Call { function: f1, args: a1 },
907 Expr::Call { function: f2, args: a2 }) if f1 == f2 && a1.len() == a2.len() => {
908 let args: Vec<&'a Expr<'a>> = a1.iter().zip(a2.iter())
909 .map(|(x, y)| msg_inner(x, y, arena, interner, counter))
910 .collect();
911 arena.alloc(Expr::Call { function: *f1, args })
912 }
913 (Expr::Not { operand: e1_inner }, Expr::Not { operand: e2_inner }) => {
915 let inner = msg_inner(e1_inner, e2_inner, arena, interner, counter);
916 arena.alloc(Expr::Not { operand: inner })
917 }
918 _ => {
920 let name = format!("__msg_{}", counter);
921 *counter += 1;
922 let sym = interner.intern(&name);
923 arena.alloc(Expr::Identifier(sym))
924 }
925 }
926}