1use crate::node_memo::NodeMemo;
6use crate::Node;
7use crate::{Expr, FVarId, Level, LevelView, Name};
8use std::rc::Rc;
9
10use super::types::{
11 ConfigNode, DecisionNode, Either2, Fixture, FlatSubstitution, FocusStack, LabelSet, MinHeap,
12 NonEmptyVec, PathBuf, PrefixCounter, RewriteRule, RewriteRuleSet, SimpleDag, SlidingSum,
13 SmallMap, SparseVec, StackCalc, StatSummary, Stopwatch, StringPool, TokenBucket, TransformStat,
14 TransitiveClosure, VersionedRecord, WindowIterator, WriteOnce,
15};
16
17pub fn get_app_fn(e: &Expr) -> &Expr {
21 match e {
22 Expr::App(f, _) => get_app_fn(f),
23 _ => e,
24 }
25}
26pub fn get_app_args(e: &Expr) -> Vec<&Expr> {
30 let mut args = Vec::new();
31 get_app_args_aux(e, &mut args);
32 args
33}
34fn get_app_args_aux<'a>(e: &'a Expr, args: &mut Vec<&'a Expr>) {
35 if let Expr::App(f, a) = e {
36 get_app_args_aux(f, args);
37 args.push(a);
38 }
39}
40pub fn get_app_fn_args(e: &Expr) -> (&Expr, Vec<&Expr>) {
44 let mut args = Vec::new();
45 let f = get_app_fn_args_aux(e, &mut args);
46 (f, args)
47}
48fn get_app_fn_args_aux<'a>(e: &'a Expr, args: &mut Vec<&'a Expr>) -> &'a Expr {
49 match e {
50 Expr::App(f, a) => {
51 let head = get_app_fn_args_aux(f, args);
52 args.push(a);
53 head
54 }
55 _ => e,
56 }
57}
58pub fn get_app_num_args(e: &Expr) -> usize {
60 match e {
61 Expr::App(f, _) => 1 + get_app_num_args(f),
62 _ => 0,
63 }
64}
65pub fn mk_app(f: Expr, args: &[Expr]) -> Expr {
69 args.iter().fold(f, |acc, arg| {
70 Expr::App(Node::new(acc), Node::new(arg.clone()))
71 })
72}
73pub fn mk_app_refs(f: Expr, args: &[&Expr]) -> Expr {
81 args.iter().fold(f, |acc, arg| {
82 Expr::App(Node::new(acc), Node::new((*arg).clone()))
83 })
84}
85pub(crate) fn get_app_arg_nodes(e: &Expr) -> Vec<&Node> {
93 let mut args = Vec::new();
94 let mut cur = e;
95 while let Expr::App(f, a) = cur {
96 args.push(a);
97 cur = f;
98 }
99 args.reverse();
100 args
101}
102pub(crate) fn mk_app_nodes(f: Expr, args: &[&Node]) -> Expr {
109 crate::fuel::charge(args.len() as u64);
111 args.iter()
112 .fold(f, |acc, arg| Expr::App(Node::new(acc), (*arg).clone()))
113}
114pub fn mk_app_range(f: Expr, args: &[Expr], begin: usize, end: usize) -> Expr {
118 let end = end.min(args.len());
119 let begin = begin.min(end);
120 mk_app(f, &args[begin..end])
121}
122pub fn has_loose_bvars(e: &Expr) -> bool {
130 e.range() > 0
131}
132pub fn has_loose_bvar_ge(e: &Expr, depth: u32) -> bool {
134 match e {
135 Expr::BVar(n) => *n >= depth,
136 Expr::Sort(_) | Expr::FVar(_) | Expr::Const(_, _) | Expr::Lit(_) => false,
137 Expr::App(f, a) => has_loose_bvar_ge(f, depth) || has_loose_bvar_ge(a, depth),
138 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
139 has_loose_bvar_ge(ty, depth) || has_loose_bvar_ge(body, depth + 1)
140 }
141 Expr::Let(_, ty, val, body) => {
142 has_loose_bvar_ge(ty, depth)
143 || has_loose_bvar_ge(val, depth)
144 || has_loose_bvar_ge(body, depth + 1)
145 }
146 Expr::Proj(_, _, e) => has_loose_bvar_ge(e, depth),
147 }
148}
149pub fn expr_size_within(e: &Expr, cap: usize) -> bool {
174 let cost = u64::from(e.rebuild_cost());
175 let cap_wide = cap as u64;
177 if cost < u64::from(crate::expr::REBUILD_COST_MAX) && cost <= cap_wide {
178 return true;
179 }
180 if cost > cap_wide.saturating_mul(2) {
181 return false;
182 }
183 expr_size_within_by_walk(e, cap)
184}
185fn expr_size_within_by_walk(e: &Expr, cap: usize) -> bool {
189 let mut remaining = cap;
190 let mut stack: Vec<&Expr> = vec![e];
191 while let Some(cur) = stack.pop() {
192 if remaining == 0 {
193 return false;
194 }
195 remaining -= 1;
196 match cur {
197 Expr::Sort(_) | Expr::BVar(_) | Expr::FVar(_) | Expr::Const(_, _) | Expr::Lit(_) => {}
198 Expr::App(f, a) => {
199 stack.push(f);
200 stack.push(a);
201 }
202 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
203 stack.push(ty);
204 stack.push(body);
205 }
206 Expr::Let(_, ty, val, body) => {
207 stack.push(ty);
208 stack.push(val);
209 stack.push(body);
210 }
211 Expr::Proj(_, _, inner) => stack.push(inner),
212 }
213 }
214 true
215}
216pub fn has_loose_bvar(e: &Expr, level: u32) -> bool {
218 match e {
219 Expr::BVar(n) => *n == level,
220 Expr::Sort(_) | Expr::FVar(_) | Expr::Const(_, _) | Expr::Lit(_) => false,
221 Expr::App(f, a) => has_loose_bvar(f, level) || has_loose_bvar(a, level),
222 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
223 has_loose_bvar(ty, level) || has_loose_bvar(body, level + 1)
224 }
225 Expr::Let(_, ty, val, body) => {
226 has_loose_bvar(ty, level)
227 || has_loose_bvar(val, level)
228 || has_loose_bvar(body, level + 1)
229 }
230 Expr::Proj(_, _, e) => has_loose_bvar(e, level),
231 }
232}
233pub fn has_fvar(e: &Expr, fvar: FVarId) -> bool {
235 match e {
236 Expr::FVar(id) => *id == fvar,
237 Expr::Sort(_) | Expr::BVar(_) | Expr::Const(_, _) | Expr::Lit(_) => false,
238 Expr::App(f, a) => has_fvar(f, fvar) || has_fvar(a, fvar),
239 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
240 has_fvar(ty, fvar) || has_fvar(body, fvar)
241 }
242 Expr::Let(_, ty, val, body) => {
243 has_fvar(ty, fvar) || has_fvar(val, fvar) || has_fvar(body, fvar)
244 }
245 Expr::Proj(_, _, e) => has_fvar(e, fvar),
246 }
247}
248pub fn has_any_fvar(e: &Expr) -> bool {
252 e.has_fvar()
253}
254pub fn for_each_expr(e: &Expr, f: &mut dyn FnMut(&Expr, u32) -> bool) {
259 for_each_expr_aux(e, f, 0);
260}
261fn for_each_expr_aux(e: &Expr, f: &mut dyn FnMut(&Expr, u32) -> bool, depth: u32) {
262 if !f(e, depth) {
263 return;
264 }
265 match e {
266 Expr::App(fun, arg) => {
267 for_each_expr_aux(fun, f, depth);
268 for_each_expr_aux(arg, f, depth);
269 }
270 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
271 for_each_expr_aux(ty, f, depth);
272 for_each_expr_aux(body, f, depth + 1);
273 }
274 Expr::Let(_, ty, val, body) => {
275 for_each_expr_aux(ty, f, depth);
276 for_each_expr_aux(val, f, depth);
277 for_each_expr_aux(body, f, depth + 1);
278 }
279 Expr::Proj(_, _, e) => {
280 for_each_expr_aux(e, f, depth);
281 }
282 Expr::Sort(_) | Expr::BVar(_) | Expr::FVar(_) | Expr::Const(_, _) | Expr::Lit(_) => {}
283 }
284}
285pub fn replace_expr(e: &Expr, f: &mut dyn FnMut(&Expr, u32) -> Option<Expr>) -> Expr {
290 replace_expr_aux(e, f, 0)
291}
292fn replace_expr_aux(e: &Expr, f: &mut dyn FnMut(&Expr, u32) -> Option<Expr>, depth: u32) -> Expr {
293 if let Some(replacement) = f(e, depth) {
294 return replacement;
295 }
296 match e {
297 Expr::App(fun, arg) => {
298 let new_fun = replace_expr_aux(fun, f, depth);
299 let new_arg = replace_expr_aux(arg, f, depth);
300 Expr::App(Node::new(new_fun), Node::new(new_arg))
301 }
302 Expr::Lam(bi, name, ty, body) => {
303 let new_ty = replace_expr_aux(ty, f, depth);
304 let new_body = replace_expr_aux(body, f, depth + 1);
305 Expr::Lam(*bi, name.clone(), Node::new(new_ty), Node::new(new_body))
306 }
307 Expr::Pi(bi, name, ty, body) => {
308 let new_ty = replace_expr_aux(ty, f, depth);
309 let new_body = replace_expr_aux(body, f, depth + 1);
310 Expr::Pi(*bi, name.clone(), Node::new(new_ty), Node::new(new_body))
311 }
312 Expr::Let(name, ty, val, body) => {
313 let new_ty = replace_expr_aux(ty, f, depth);
314 let new_val = replace_expr_aux(val, f, depth);
315 let new_body = replace_expr_aux(body, f, depth + 1);
316 Expr::Let(
317 name.clone(),
318 Node::new(new_ty),
319 Node::new(new_val),
320 Node::new(new_body),
321 )
322 }
323 Expr::Proj(name, idx, e_inner) => {
324 let new_e = replace_expr_aux(e_inner, f, depth);
325 Expr::Proj(name.clone(), *idx, Node::new(new_e))
326 }
327 Expr::Sort(_) | Expr::BVar(_) | Expr::FVar(_) | Expr::Const(_, _) | Expr::Lit(_) => {
328 e.clone()
329 }
330 }
331}
332pub fn collect_fvars(e: &Expr) -> Vec<FVarId> {
334 let mut fvars = Vec::new();
335 for_each_expr(e, &mut |sub, _depth| {
336 if let Expr::FVar(id) = sub {
337 if !fvars.contains(id) {
338 fvars.push(*id);
339 }
340 }
341 true
342 });
343 fvars
344}
345pub fn collect_consts(e: &Expr) -> Vec<Name> {
347 let mut consts = Vec::new();
348 for_each_expr(e, &mut |sub, _depth| {
349 if let Expr::Const(name, _) = sub {
350 if !consts.contains(name) {
351 consts.push(name.clone());
352 }
353 }
354 true
355 });
356 consts
357}
358pub fn lift_loose_bvars(e: &Expr, n: u32, offset: u32) -> Expr {
368 if n == 0 || e.range() <= offset {
369 return e.clone();
371 }
372 let mut walk = Lift {
373 by: n,
374 lifted: NodeMemo::new(),
375 };
376 crate::fuel::charge(1);
377 walk.rebuild(e, offset)
378}
379
380struct Lift<'term> {
382 by: u32,
384 lifted: NodeMemo<'term, Node>,
387}
388
389impl<'term> Lift<'term> {
390 fn node(&mut self, node: &'term Node, depth: u32) -> Node {
392 crate::fuel::charge(1);
393 if node.range() <= depth {
394 return node.clone();
396 }
397 if matches!(&**node, Expr::BVar(_)) {
398 return Node::new(self.rebuild(node, depth));
400 }
401 let shared = node.is_shared();
402 if shared {
403 if let Some(done) = self.lifted.get(node, depth) {
404 return done.clone();
405 }
406 }
407 let result = Node::new(self.rebuild(node, depth));
408 if shared {
409 self.lifted.insert(node, depth, result.clone());
410 }
411 result
412 }
413
414 fn rebuild(&mut self, e: &'term Expr, depth: u32) -> Expr {
416 match e {
417 Expr::BVar(idx) => {
418 if *idx >= depth {
419 Expr::BVar(idx.saturating_add(self.by))
423 } else {
424 e.clone()
425 }
426 }
427 Expr::Sort(_) | Expr::FVar(_) | Expr::Const(_, _) | Expr::Lit(_) => e.clone(),
428 Expr::App(f, a) => Expr::App(self.node(f, depth), self.node(a, depth)),
429 Expr::Lam(bi, name, ty, body) => Expr::Lam(
430 *bi,
431 name.clone(),
432 self.node(ty, depth),
433 self.node(body, depth + 1),
434 ),
435 Expr::Pi(bi, name, ty, body) => Expr::Pi(
436 *bi,
437 name.clone(),
438 self.node(ty, depth),
439 self.node(body, depth + 1),
440 ),
441 Expr::Let(name, ty, val, body) => Expr::Let(
442 name.clone(),
443 self.node(ty, depth),
444 self.node(val, depth),
445 self.node(body, depth + 1),
446 ),
447 Expr::Proj(name, idx, inner) => Expr::Proj(name.clone(), *idx, self.node(inner, depth)),
448 }
449 }
450}
451pub fn occurs_const(e: &Expr, name: &Name) -> bool {
453 match e {
454 Expr::Const(n, _) => n == name,
455 Expr::App(f, a) => occurs_const(f, name) || occurs_const(a, name),
456 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
457 occurs_const(ty, name) || occurs_const(body, name)
458 }
459 Expr::Let(_, ty, val, body) => {
460 occurs_const(ty, name) || occurs_const(val, name) || occurs_const(body, name)
461 }
462 Expr::Proj(_, _, e) => occurs_const(e, name),
463 _ => false,
464 }
465}
466pub fn find_mentioned_name<'a>(
478 e: &'a Expr,
479 mut wanted: impl FnMut(&Name) -> bool,
480) -> Option<&'a Name> {
481 let mut seen: std::collections::HashSet<*const Expr, crate::node_memo::WordBuildHasher> =
482 std::collections::HashSet::default();
483 let mut pending: Vec<&'a Node> = Vec::new();
484 let mut current: Option<&'a Expr> = Some(e);
485 loop {
486 let cur: &'a Expr = match current.take() {
487 Some(cur) => cur,
488 None => match pending.pop() {
489 Some(node) => {
490 if !seen.insert(node.as_ptr()) {
491 continue;
492 }
493 node
494 }
495 None => return None,
496 },
497 };
498 match cur {
499 Expr::Const(n, _) => {
500 if wanted(n) {
501 return Some(n);
502 }
503 }
504 Expr::App(f, a) => {
505 pending.push(a);
506 pending.push(f);
507 }
508 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
509 pending.push(body);
510 pending.push(ty);
511 }
512 Expr::Let(_, ty, val, body) => {
513 pending.push(body);
514 pending.push(val);
515 pending.push(ty);
516 }
517 Expr::Proj(n, _, inner) => {
518 if wanted(n) {
519 return Some(n);
520 }
521 pending.push(inner);
522 }
523 Expr::BVar(_) | Expr::FVar(_) | Expr::Sort(_) | Expr::Lit(_) => {}
524 }
525 }
526}
527pub fn count_lambdas(e: &Expr) -> u32 {
529 match e {
530 Expr::Lam(_, _, _, body) => 1 + count_lambdas(body),
531 _ => 0,
532 }
533}
534pub fn count_pis(e: &Expr) -> u32 {
536 match e {
537 Expr::Pi(_, _, _, body) => 1 + count_pis(body),
538 _ => 0,
539 }
540}
541pub fn strip_lambdas(e: &Expr, n: u32) -> &Expr {
543 if n == 0 {
544 return e;
545 }
546 match e {
547 Expr::Lam(_, _, _, body) => strip_lambdas(body, n - 1),
548 _ => e,
549 }
550}
551pub fn strip_pis(e: &Expr, n: u32) -> &Expr {
553 if n == 0 {
554 return e;
555 }
556 match e {
557 Expr::Pi(_, _, _, body) => strip_pis(body, n - 1),
558 _ => e,
559 }
560}
561pub fn level_has_mvar(l: &Level) -> bool {
563 match l.view() {
564 LevelView::MVar(_) => true,
565 LevelView::Succ(l) => level_has_mvar(l),
566 LevelView::Max(l1, l2) | LevelView::IMax(l1, l2) => {
567 level_has_mvar(l1) || level_has_mvar(l2)
568 }
569 LevelView::Zero | LevelView::Param(_) => false,
570 }
571}
572pub fn has_level_mvar(e: &Expr) -> bool {
577 e.has_level_mvar()
578}
579pub fn has_level_param(e: &Expr) -> bool {
583 e.has_level_param()
584}
585pub fn expr_weight(e: &Expr) -> usize {
587 match e {
588 Expr::Sort(_) | Expr::BVar(_) | Expr::FVar(_) | Expr::Lit(_) => 1,
589 Expr::Const(_, _) => 1,
590 Expr::App(f, a) => 1 + expr_weight(f) + expr_weight(a),
591 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
592 1 + expr_weight(ty) + expr_weight(body)
593 }
594 Expr::Let(_, ty, val, body) => 1 + expr_weight(ty) + expr_weight(val) + expr_weight(body),
595 Expr::Proj(_, _, e) => 1 + expr_weight(e),
596 }
597}
598pub fn is_app_of(e: &Expr, name: &Name) -> bool {
600 matches!(get_app_fn(e), Expr::Const(n, _) if n == name)
601}
602pub fn mk_arrow(a: Expr, b: Expr) -> Expr {
604 Expr::Pi(
605 crate::BinderInfo::Default,
606 Name::anonymous(),
607 Node::new(a),
608 Node::new(lift_loose_bvars(&b, 1, 0)),
609 )
610}
611pub fn mk_prop() -> Expr {
613 Expr::Sort(Level::zero())
614}
615pub fn mk_type(u: Level) -> Expr {
617 Expr::Sort(Level::succ(u))
618}
619pub fn mk_type0() -> Expr {
621 Expr::Sort(Level::succ(Level::zero()))
622}
623pub fn var(name: &str) -> Expr {
625 Expr::Const(Name::str(name), vec![])
626}
627pub fn bvar(idx: u32) -> Expr {
629 Expr::BVar(idx)
630}
631pub fn app(f: Expr, a: Expr) -> Expr {
633 Expr::App(Node::new(f), Node::new(a))
634}
635pub fn lam(name: &str, ty: Expr, body: Expr) -> Expr {
637 Expr::Lam(
638 crate::BinderInfo::Default,
639 Name::str(name),
640 Node::new(ty),
641 Node::new(body),
642 )
643}
644pub fn pi(name: &str, ty: Expr, body: Expr) -> Expr {
646 Expr::Pi(
647 crate::BinderInfo::Default,
648 Name::str(name),
649 Node::new(ty),
650 Node::new(body),
651 )
652}
653pub fn prop() -> Expr {
655 Expr::Sort(crate::Level::zero())
656}
657pub fn sort() -> Expr {
659 Expr::Sort(crate::Level::zero())
660}
661pub fn type0() -> Expr {
663 Expr::Sort(crate::Level::succ(crate::Level::zero()))
664}
665#[cfg(test)]
666mod size_tests {
667 use super::*;
668 use crate::{BinderInfo, Level, Literal};
669
670 fn leaf(i: u32) -> Expr {
671 match i % 5 {
672 0 => Expr::BVar(i),
673 1 => Expr::Const(Name::str("c"), vec![Level::zero()]),
674 2 => Expr::Sort(Level::zero()),
675 3 => Expr::Lit(Literal::nat(u64::from(i))),
676 _ => Expr::FVar(crate::FVarId(u64::from(i))),
677 }
678 }
679
680 fn shapes() -> Vec<Expr> {
684 let mut terms: Vec<Expr> = (0..5).map(leaf).collect();
685 let mut chain = leaf(1);
687 for i in 0..12 {
688 chain = Expr::Proj(Name::str("S"), i, Node::new(chain));
689 terms.push(chain.clone());
690 }
691 let mut spine = leaf(1);
693 for i in 0..12 {
694 spine = Expr::App(Node::new(spine), Node::new(leaf(i)));
695 terms.push(spine.clone());
696 }
697 let mut tree = leaf(0);
700 for _ in 0..8 {
701 let shared = Node::new(tree);
702 tree = Expr::App(shared.clone(), shared);
703 terms.push(tree.clone());
704 }
705 for i in 0..6usize {
707 let ty = Node::new(terms[i * 3].clone());
708 let body = Node::new(terms[i * 5 + 1].clone());
709 terms.push(Expr::Lam(
710 BinderInfo::Default,
711 Name::str("x"),
712 ty.clone(),
713 body.clone(),
714 ));
715 terms.push(Expr::Pi(
716 BinderInfo::Implicit,
717 Name::str("x"),
718 ty.clone(),
719 body.clone(),
720 ));
721 terms.push(Expr::Let(Name::str("x"), ty.clone(), body.clone(), ty));
722 }
723 terms
724 }
725
726 fn size(e: &Expr) -> usize {
728 match e {
729 Expr::Sort(_) | Expr::BVar(_) | Expr::FVar(_) | Expr::Const(_, _) | Expr::Lit(_) => 1,
730 Expr::App(f, a) => 1 + size(f) + size(a),
731 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => 1 + size(ty) + size(body),
732 Expr::Let(_, ty, val, body) => 1 + size(ty) + size(val) + size(body),
733 Expr::Proj(_, _, inner) => 1 + size(inner),
734 }
735 }
736
737 #[test]
738 fn the_cached_cost_brackets_the_size() {
739 for (i, term) in shapes().iter().enumerate() {
740 let n = size(term) as u64;
741 let cost = u64::from(term.rebuild_cost());
742 assert!(
743 n <= cost && cost <= 2 * n,
744 "term {i}: size {n}, cost {cost}"
745 );
746 }
747 }
748
749 #[test]
750 fn size_within_agrees_with_counting_at_every_cap() {
751 let terms = shapes();
752 let mut by_cost = 0usize;
753 let mut by_walk = 0usize;
754 for (i, term) in terms.iter().enumerate() {
755 let n = size(term);
756 let cost = term.rebuild_cost() as usize;
757 for cap in (0..=2 * n + 3).chain([4096, usize::MAX / 2, usize::MAX]) {
758 let expected = n <= cap;
759 assert_eq!(
760 expr_size_within(term, cap),
761 expected,
762 "term {i} (size {n}, cost {cost}) at cap {cap}"
763 );
764 assert_eq!(
765 expr_size_within_by_walk(term, cap),
766 expected,
767 "walk: term {i} (size {n}) at cap {cap}"
768 );
769 if cost <= cap || cost > 2 * cap {
770 by_cost += 1;
771 } else {
772 by_walk += 1;
773 }
774 }
775 }
776 assert!(by_cost > 1000, "{by_cost} caps decided by the cost");
778 assert!(by_walk > 1000, "{by_walk} caps decided by counting");
779 }
780
781 #[test]
782 fn a_saturated_cost_never_reads_as_small() {
783 use crate::expr::REBUILD_COST_MAX;
784 let mut tower = leaf(0);
786 for _ in 0..40 {
787 let shared = Node::new(tower);
788 tower = Expr::App(shared.clone(), shared);
789 }
790 assert_eq!(tower.rebuild_cost(), REBUILD_COST_MAX);
791 assert!(!expr_size_within(&tower, 0));
794 assert!(!expr_size_within(&tower, 4096));
795 assert!(!expr_size_within(
796 &tower,
797 (REBUILD_COST_MAX as usize) / 2 - 1
798 ));
799 let mut smaller = leaf(0);
803 for _ in 0..28 {
804 let shared = Node::new(smaller);
805 smaller = Expr::App(shared.clone(), shared);
806 }
807 assert_eq!(smaller.rebuild_cost(), REBUILD_COST_MAX);
808 assert!(!expr_size_within(&smaller, 1 << 27));
809 let mut exact = leaf(0);
811 for _ in 0..26 {
812 let shared = Node::new(exact);
813 exact = Expr::App(shared.clone(), shared);
814 }
815 assert_eq!(exact.rebuild_cost(), 3 * (1 << 26) - 1);
817 assert!(exact.rebuild_cost() < REBUILD_COST_MAX);
818 assert!(expr_size_within(&exact, 3 * (1 << 26)));
819 assert!(!expr_size_within(&exact, 1 << 20));
820 }
821}
822#[cfg(test)]
823mod tests {
824 use super::*;
825 use crate::BinderInfo;
826 fn nat() -> Expr {
827 Expr::Const(Name::str("Nat"), vec![])
828 }
829 fn bool_ty() -> Expr {
830 Expr::Const(Name::str("Bool"), vec![])
831 }
832 #[test]
833 fn test_get_app_fn() {
834 let f = nat();
835 let e = Expr::App(
836 Node::new(Expr::App(Node::new(f.clone()), Node::new(Expr::BVar(0)))),
837 Node::new(Expr::BVar(1)),
838 );
839 assert_eq!(get_app_fn(&e), &f);
840 }
841 #[test]
842 fn test_get_app_args() {
843 let f = nat();
844 let a1 = Expr::BVar(0);
845 let a2 = Expr::BVar(1);
846 let e = Expr::App(
847 Node::new(Expr::App(Node::new(f), Node::new(a1.clone()))),
848 Node::new(a2.clone()),
849 );
850 let args = get_app_args(&e);
851 assert_eq!(args.len(), 2);
852 assert_eq!(args[0], &a1);
853 assert_eq!(args[1], &a2);
854 }
855 #[test]
856 fn test_get_app_fn_args() {
857 let f = nat();
858 let a = Expr::BVar(0);
859 let e = Expr::App(Node::new(f.clone()), Node::new(a.clone()));
860 let (head, args) = get_app_fn_args(&e);
861 assert_eq!(head, &f);
862 assert_eq!(args, vec![&a]);
863 }
864 #[test]
865 fn test_mk_app() {
866 let f = nat();
867 let a1 = Expr::BVar(0);
868 let a2 = Expr::BVar(1);
869 let result = mk_app(f.clone(), &[a1.clone(), a2.clone()]);
870 let (head, args) = get_app_fn_args(&result);
871 assert_eq!(head, &f);
872 assert_eq!(args.len(), 2);
873 }
874 #[test]
875 fn test_has_loose_bvars() {
876 assert!(has_loose_bvars(&Expr::BVar(0)));
877 assert!(!has_loose_bvars(&nat()));
878 assert!(!has_loose_bvars(&Expr::FVar(FVarId(1))));
879 let lam = Expr::Lam(
880 BinderInfo::Default,
881 Name::str("x"),
882 Node::new(nat()),
883 Node::new(Expr::BVar(0)),
884 );
885 assert!(!has_loose_bvars(&lam));
886 let lam2 = Expr::Lam(
887 BinderInfo::Default,
888 Name::str("x"),
889 Node::new(nat()),
890 Node::new(Expr::BVar(1)),
891 );
892 assert!(has_loose_bvars(&lam2));
893 }
894 #[test]
895 fn test_has_fvar() {
896 let id = FVarId(42);
897 let e = Expr::App(Node::new(Expr::FVar(id)), Node::new(Expr::FVar(FVarId(99))));
898 assert!(has_fvar(&e, id));
899 assert!(has_fvar(&e, FVarId(99)));
900 assert!(!has_fvar(&e, FVarId(1)));
901 }
902 #[test]
903 fn test_collect_fvars() {
904 let e = Expr::App(
905 Node::new(Expr::FVar(FVarId(1))),
906 Node::new(Expr::App(
907 Node::new(Expr::FVar(FVarId(2))),
908 Node::new(Expr::FVar(FVarId(1))),
909 )),
910 );
911 let fvars = collect_fvars(&e);
912 assert_eq!(fvars.len(), 2);
913 assert!(fvars.contains(&FVarId(1)));
914 assert!(fvars.contains(&FVarId(2)));
915 }
916 #[test]
917 fn test_for_each_expr() {
918 let e = Expr::App(Node::new(nat()), Node::new(Expr::BVar(0)));
919 let mut count = 0;
920 for_each_expr(&e, &mut |_, _| {
921 count += 1;
922 true
923 });
924 assert_eq!(count, 3);
925 }
926 #[test]
927 fn test_replace_expr() {
928 let e = Expr::App(Node::new(Expr::BVar(0)), Node::new(Expr::BVar(1)));
929 let result = replace_expr(&e, &mut |sub, _depth| {
930 if let Expr::BVar(0) = sub {
931 Some(nat())
932 } else {
933 None
934 }
935 });
936 match &result {
937 Expr::App(f, _) => assert_eq!(**f, nat()),
938 _ => panic!("Expected App"),
939 }
940 }
941 #[test]
942 fn test_lift_loose_bvars() {
943 let e = Expr::BVar(0);
944 let lifted = lift_loose_bvars(&e, 2, 0);
945 assert_eq!(lifted, Expr::BVar(2));
946 let lam = Expr::Lam(
947 BinderInfo::Default,
948 Name::str("x"),
949 Node::new(nat()),
950 Node::new(Expr::BVar(0)),
951 );
952 let lifted_lam = lift_loose_bvars(&lam, 1, 0);
953 if let Expr::Lam(_, _, _, body) = &lifted_lam {
954 assert_eq!(**body, Expr::BVar(0));
955 } else {
956 panic!("Expected Lam");
957 }
958 }
959 #[test]
960 fn test_count_lambdas_pis() {
961 let e = Expr::Lam(
962 BinderInfo::Default,
963 Name::str("x"),
964 Node::new(nat()),
965 Node::new(Expr::Lam(
966 BinderInfo::Default,
967 Name::str("y"),
968 Node::new(nat()),
969 Node::new(Expr::BVar(0)),
970 )),
971 );
972 assert_eq!(count_lambdas(&e), 2);
973 let pi = Expr::Pi(
974 BinderInfo::Default,
975 Name::str("x"),
976 Node::new(nat()),
977 Node::new(nat()),
978 );
979 assert_eq!(count_pis(&pi), 1);
980 }
981 #[test]
982 fn test_is_app_of() {
983 let e = Expr::App(
984 Node::new(Expr::Const(Name::str("f"), vec![])),
985 Node::new(Expr::BVar(0)),
986 );
987 assert!(is_app_of(&e, &Name::str("f")));
988 assert!(!is_app_of(&e, &Name::str("g")));
989 }
990 #[test]
991 fn test_mk_arrow() {
992 let arrow = mk_arrow(nat(), bool_ty());
993 assert!(arrow.is_pi());
994 }
995 #[test]
996 fn test_expr_weight() {
997 assert_eq!(expr_weight(&nat()), 1);
998 let app = Expr::App(Node::new(nat()), Node::new(Expr::BVar(0)));
999 assert_eq!(expr_weight(&app), 3);
1000 }
1001 #[test]
1002 fn test_mk_app_range() {
1003 let f = nat();
1004 let args = vec![Expr::BVar(0), Expr::BVar(1), Expr::BVar(2)];
1005 let result = mk_app_range(f.clone(), &args, 1, 3);
1006 assert_eq!(get_app_num_args(&result), 2);
1007 }
1008 #[test]
1009 fn test_occurs_const() {
1010 let e = Expr::App(Node::new(nat()), Node::new(bool_ty()));
1011 assert!(occurs_const(&e, &Name::str("Nat")));
1012 assert!(occurs_const(&e, &Name::str("Bool")));
1013 assert!(!occurs_const(&e, &Name::str("Int")));
1014 }
1015}
1016#[inline]
1018pub fn is_sort(e: &Expr) -> bool {
1019 matches!(e, Expr::Sort(_))
1020}
1021#[inline]
1023pub fn is_prop(e: &Expr) -> bool {
1024 matches!(e, Expr::Sort(l) if matches!(l.view(), LevelView::Zero))
1025}
1026#[inline]
1028pub fn is_type0(e: &Expr) -> bool {
1029 matches!(e, Expr::Sort(l) if matches!(l.view(), LevelView::Succ(inner) if matches!(inner.view(), LevelView::Zero)))
1030}
1031#[inline]
1033pub fn is_lambda(e: &Expr) -> bool {
1034 matches!(e, Expr::Lam(_, _, _, _))
1035}
1036#[inline]
1038pub fn is_pi(e: &Expr) -> bool {
1039 matches!(e, Expr::Pi(_, _, _, _))
1040}
1041#[inline]
1043pub fn is_fvar(e: &Expr) -> bool {
1044 matches!(e, Expr::FVar(_))
1045}
1046#[inline]
1048pub fn is_bvar(e: &Expr) -> bool {
1049 matches!(e, Expr::BVar(_))
1050}
1051#[inline]
1053pub fn is_literal(e: &Expr) -> bool {
1054 matches!(e, Expr::Lit(_))
1055}
1056#[inline]
1058pub fn is_const(e: &Expr) -> bool {
1059 matches!(e, Expr::Const(_, _))
1060}
1061#[inline]
1063pub fn is_app(e: &Expr) -> bool {
1064 matches!(e, Expr::App(_, _))
1065}
1066#[inline]
1068pub fn is_let(e: &Expr) -> bool {
1069 matches!(e, Expr::Let(_, _, _, _))
1070}
1071#[inline]
1073pub fn is_proj(e: &Expr) -> bool {
1074 matches!(e, Expr::Proj(_, _, _))
1075}
1076#[inline]
1078pub fn get_sort_level(e: &Expr) -> Option<&Level> {
1079 if let Expr::Sort(l) = e {
1080 Some(l)
1081 } else {
1082 None
1083 }
1084}
1085#[inline]
1087pub fn get_const_name(e: &Expr) -> Option<&Name> {
1088 if let Expr::Const(n, _) = e {
1089 Some(n)
1090 } else {
1091 None
1092 }
1093}
1094#[inline]
1096pub fn get_const_levels(e: &Expr) -> Option<&[Level]> {
1097 if let Expr::Const(_, ls) = e {
1098 Some(ls)
1099 } else {
1100 None
1101 }
1102}
1103#[inline]
1105pub fn get_fvar_id(e: &Expr) -> Option<FVarId> {
1106 if let Expr::FVar(id) = e {
1107 Some(*id)
1108 } else {
1109 None
1110 }
1111}
1112#[inline]
1114pub fn get_bvar_idx(e: &Expr) -> Option<u32> {
1115 if let Expr::BVar(i) = e {
1116 Some(*i)
1117 } else {
1118 None
1119 }
1120}
1121#[inline]
1123pub fn decompose_let(e: &Expr) -> Option<(&Expr, &Expr, &Expr)> {
1124 if let Expr::Let(_, ty, val, body) = e {
1125 Some((ty, val, body))
1126 } else {
1127 None
1128 }
1129}
1130#[inline]
1132pub fn decompose_pi(e: &Expr) -> Option<(crate::BinderInfo, &Expr, &Expr)> {
1133 if let Expr::Pi(bi, _, dom, cod) = e {
1134 Some((*bi, dom, cod))
1135 } else {
1136 None
1137 }
1138}
1139#[inline]
1141pub fn decompose_lam(e: &Expr) -> Option<(crate::BinderInfo, &Expr, &Expr)> {
1142 if let Expr::Lam(bi, _, dom, body) = e {
1143 Some((*bi, dom, body))
1144 } else {
1145 None
1146 }
1147}
1148#[inline]
1150pub fn decompose_proj(e: &Expr) -> Option<(&Name, usize, &Expr)> {
1151 if let Expr::Proj(n, idx, val) = e {
1152 Some((n, *idx as usize, val))
1153 } else {
1154 None
1155 }
1156}
1157pub fn mk_pi_n(binders: &[(crate::BinderInfo, Expr)], ret: Expr) -> Expr {
1162 binders.iter().rev().fold(ret, |acc, (bi, ty)| {
1163 Expr::Pi(
1164 *bi,
1165 crate::Name::anonymous(),
1166 Node::new(ty.clone()),
1167 Node::new(acc),
1168 )
1169 })
1170}
1171pub fn mk_lam_n(binders: &[(crate::BinderInfo, Expr)], body: Expr) -> Expr {
1173 binders.iter().rev().fold(body, |acc, (bi, ty)| {
1174 Expr::Lam(
1175 *bi,
1176 crate::Name::anonymous(),
1177 Node::new(ty.clone()),
1178 Node::new(acc),
1179 )
1180 })
1181}
1182pub fn is_app_of_fvar(e: &Expr, id: FVarId) -> bool {
1184 get_app_fn(e) == &Expr::FVar(id)
1185}
1186pub fn get_nth_arg(e: &Expr, n: usize) -> Option<&Expr> {
1188 let args = get_app_args(e);
1189 args.get(n).copied()
1190}
1191pub fn is_simple(e: &Expr) -> bool {
1193 matches!(
1194 e,
1195 Expr::Sort(_) | Expr::BVar(_) | Expr::FVar(_) | Expr::Const(_, _) | Expr::Lit(_)
1196 )
1197}
1198#[cfg(test)]
1199mod extended_tests {
1200 use super::*;
1201 use crate::{BinderInfo, Level};
1202 fn nat() -> Expr {
1203 Expr::Const(Name::str("Nat"), vec![])
1204 }
1205 fn prop() -> Expr {
1206 Expr::Sort(Level::zero())
1207 }
1208 fn bv(i: u32) -> Expr {
1209 Expr::BVar(i)
1210 }
1211 #[test]
1212 fn test_is_prop() {
1213 assert!(is_prop(&prop()));
1214 assert!(!is_prop(&nat()));
1215 }
1216 #[test]
1217 fn test_is_sort() {
1218 assert!(is_sort(&prop()));
1219 assert!(is_sort(&Expr::Sort(Level::succ(Level::zero()))));
1220 assert!(!is_sort(&nat()));
1221 }
1222 #[test]
1223 fn test_is_lambda_pi() {
1224 let lam = Expr::Lam(
1225 BinderInfo::Default,
1226 crate::Name::anonymous(),
1227 Node::new(prop()),
1228 Node::new(bv(0)),
1229 );
1230 let pi = Expr::Pi(
1231 BinderInfo::Default,
1232 crate::Name::anonymous(),
1233 Node::new(prop()),
1234 Node::new(bv(0)),
1235 );
1236 assert!(is_lambda(&lam));
1237 assert!(!is_lambda(&pi));
1238 assert!(is_pi(&pi));
1239 assert!(!is_pi(&lam));
1240 }
1241 #[test]
1242 fn test_is_fvar_bvar() {
1243 use crate::FVarId;
1244 assert!(is_fvar(&Expr::FVar(FVarId(0))));
1245 assert!(is_bvar(&bv(0)));
1246 assert!(!is_fvar(&nat()));
1247 }
1248 #[test]
1249 fn test_get_sort_level() {
1250 let s = Expr::Sort(Level::zero());
1251 assert_eq!(get_sort_level(&s), Some(&Level::zero()));
1252 assert_eq!(get_sort_level(&nat()), None);
1253 }
1254 #[test]
1255 fn test_get_const_name() {
1256 assert_eq!(get_const_name(&nat()), Some(&Name::str("Nat")));
1257 assert_eq!(get_const_name(&prop()), None);
1258 }
1259 #[test]
1260 fn test_get_bvar_idx() {
1261 assert_eq!(get_bvar_idx(&bv(3)), Some(3));
1262 assert_eq!(get_bvar_idx(&nat()), None);
1263 }
1264 #[test]
1265 fn test_decompose_let() {
1266 let e = Expr::Let(
1267 crate::Name::anonymous(),
1268 Node::new(nat()),
1269 Node::new(bv(0)),
1270 Node::new(bv(0)),
1271 );
1272 let (ty, val, body) = decompose_let(&e).expect("value should be present");
1273 assert_eq!(ty, &nat());
1274 assert_eq!(val, &bv(0));
1275 assert_eq!(body, &bv(0));
1276 }
1277 #[test]
1278 fn test_decompose_pi() {
1279 let e = Expr::Pi(
1280 BinderInfo::Default,
1281 crate::Name::anonymous(),
1282 Node::new(nat()),
1283 Node::new(prop()),
1284 );
1285 let (bi, dom, cod) = decompose_pi(&e).expect("value should be present");
1286 assert_eq!(bi, BinderInfo::Default);
1287 assert_eq!(dom, &nat());
1288 assert_eq!(cod, &prop());
1289 }
1290 #[test]
1291 fn test_decompose_lam() {
1292 let e = Expr::Lam(
1293 BinderInfo::Implicit,
1294 crate::Name::anonymous(),
1295 Node::new(nat()),
1296 Node::new(bv(0)),
1297 );
1298 let (bi, dom, body) = decompose_lam(&e).expect("value should be present");
1299 assert_eq!(bi, BinderInfo::Implicit);
1300 assert_eq!(dom, &nat());
1301 assert_eq!(body, &bv(0));
1302 }
1303 #[test]
1304 fn test_mk_pi_n_empty() {
1305 let ret = nat();
1306 let result = mk_pi_n(&[], ret.clone());
1307 assert_eq!(result, ret);
1308 }
1309 #[test]
1310 fn test_mk_pi_n_two() {
1311 let binders = vec![(BinderInfo::Default, nat()), (BinderInfo::Default, prop())];
1312 let ret = bv(0);
1313 let result = mk_pi_n(&binders, ret);
1314 assert!(is_pi(&result));
1315 let (_, _, inner) = decompose_pi(&result).expect("value should be present");
1316 assert!(is_pi(inner));
1317 }
1318 #[test]
1319 fn test_mk_lam_n_two() {
1320 let binders = vec![(BinderInfo::Default, nat()), (BinderInfo::Implicit, prop())];
1321 let result = mk_lam_n(&binders, bv(0));
1322 assert!(is_lambda(&result));
1323 }
1324 #[test]
1325 fn test_is_simple() {
1326 assert!(is_simple(&nat()));
1327 assert!(is_simple(&bv(0)));
1328 assert!(is_simple(&prop()));
1329 let app = Expr::App(Node::new(nat()), Node::new(bv(0)));
1330 assert!(!is_simple(&app));
1331 }
1332 #[test]
1333 fn test_get_nth_arg() {
1334 let f = nat();
1335 let arg0 = bv(0);
1336 let arg1 = bv(1);
1337 let app = Expr::App(
1338 Node::new(Expr::App(Node::new(f), Node::new(arg0.clone()))),
1339 Node::new(arg1.clone()),
1340 );
1341 assert_eq!(get_nth_arg(&app, 0), Some(&arg0));
1342 assert_eq!(get_nth_arg(&app, 1), Some(&arg1));
1343 assert_eq!(get_nth_arg(&app, 2), None);
1344 }
1345 #[test]
1346 fn test_is_literal() {
1347 use crate::Literal;
1348 let lit = Expr::Lit(Literal::nat(42));
1349 assert!(is_literal(&lit));
1350 assert!(!is_literal(&nat()));
1351 }
1352}
1353#[cfg(test)]
1354mod tests_padding_infra {
1355 use super::*;
1356 #[test]
1357 fn test_stat_summary() {
1358 let mut ss = StatSummary::new();
1359 ss.record(10.0);
1360 ss.record(20.0);
1361 ss.record(30.0);
1362 assert_eq!(ss.count(), 3);
1363 assert!((ss.mean().expect("mean should succeed") - 20.0).abs() < 1e-9);
1364 assert_eq!(ss.min().expect("min should succeed") as i64, 10);
1365 assert_eq!(ss.max().expect("max should succeed") as i64, 30);
1366 }
1367 #[test]
1368 fn test_transform_stat() {
1369 let mut ts = TransformStat::new();
1370 ts.record_before(100.0);
1371 ts.record_after(80.0);
1372 let ratio = ts.mean_ratio().expect("ratio should be present");
1373 assert!((ratio - 0.8).abs() < 1e-9);
1374 }
1375 #[test]
1376 fn test_small_map() {
1377 let mut m: SmallMap<u32, &str> = SmallMap::new();
1378 m.insert(3, "three");
1379 m.insert(1, "one");
1380 m.insert(2, "two");
1381 assert_eq!(m.get(&2), Some(&"two"));
1382 assert_eq!(m.len(), 3);
1383 let keys = m.keys();
1384 assert_eq!(*keys[0], 1);
1385 assert_eq!(*keys[2], 3);
1386 }
1387 #[test]
1388 fn test_label_set() {
1389 let mut ls = LabelSet::new();
1390 ls.add("foo");
1391 ls.add("bar");
1392 ls.add("foo");
1393 assert_eq!(ls.count(), 2);
1394 assert!(ls.has("bar"));
1395 assert!(!ls.has("baz"));
1396 }
1397 #[test]
1398 fn test_config_node() {
1399 let mut root = ConfigNode::section("root");
1400 let child = ConfigNode::leaf("key", "value");
1401 root.add_child(child);
1402 assert_eq!(root.num_children(), 1);
1403 }
1404 #[test]
1405 fn test_versioned_record() {
1406 let mut vr = VersionedRecord::new(0u32);
1407 vr.update(1);
1408 vr.update(2);
1409 assert_eq!(*vr.current(), 2);
1410 assert_eq!(vr.version(), 2);
1411 assert!(vr.has_history());
1412 assert_eq!(*vr.at_version(0).expect("value should be present"), 0);
1413 }
1414 #[test]
1415 fn test_simple_dag() {
1416 let mut dag = SimpleDag::new(4);
1417 dag.add_edge(0, 1);
1418 dag.add_edge(1, 2);
1419 dag.add_edge(2, 3);
1420 assert!(dag.can_reach(0, 3));
1421 assert!(!dag.can_reach(3, 0));
1422 let order = dag.topological_sort().expect("order should be present");
1423 assert_eq!(order, vec![0, 1, 2, 3]);
1424 }
1425 #[test]
1426 fn test_focus_stack() {
1427 let mut fs: FocusStack<&str> = FocusStack::new();
1428 fs.focus("a");
1429 fs.focus("b");
1430 assert_eq!(fs.current(), Some(&"b"));
1431 assert_eq!(fs.depth(), 2);
1432 fs.blur();
1433 assert_eq!(fs.current(), Some(&"a"));
1434 }
1435}
1436#[cfg(test)]
1437mod tests_extra_iterators {
1438 use super::*;
1439 #[test]
1440 fn test_window_iterator() {
1441 let data = vec![1u32, 2, 3, 4, 5];
1442 let windows: Vec<_> = WindowIterator::new(&data, 3).collect();
1443 assert_eq!(windows.len(), 3);
1444 assert_eq!(windows[0], &[1, 2, 3]);
1445 assert_eq!(windows[2], &[3, 4, 5]);
1446 }
1447 #[test]
1448 fn test_non_empty_vec() {
1449 let mut nev = NonEmptyVec::singleton(10u32);
1450 nev.push(20);
1451 nev.push(30);
1452 assert_eq!(nev.len(), 3);
1453 assert_eq!(*nev.first(), 10);
1454 assert_eq!(*nev.last(), 30);
1455 }
1456}
1457#[cfg(test)]
1458mod tests_padding2 {
1459 use super::*;
1460 #[test]
1461 fn test_sliding_sum() {
1462 let mut ss = SlidingSum::new(3);
1463 ss.push(1.0);
1464 ss.push(2.0);
1465 ss.push(3.0);
1466 assert!((ss.sum() - 6.0).abs() < 1e-9);
1467 ss.push(4.0);
1468 assert!((ss.sum() - 9.0).abs() < 1e-9);
1469 assert_eq!(ss.count(), 3);
1470 }
1471 #[test]
1472 fn test_path_buf() {
1473 let mut pb = PathBuf::new();
1474 pb.push("src");
1475 pb.push("main");
1476 assert_eq!(pb.as_str(), "src/main");
1477 assert_eq!(pb.depth(), 2);
1478 pb.pop();
1479 assert_eq!(pb.as_str(), "src");
1480 }
1481 #[test]
1482 fn test_string_pool() {
1483 let mut pool = StringPool::new();
1484 let s = pool.take();
1485 assert!(s.is_empty());
1486 pool.give("hello".to_string());
1487 let s2 = pool.take();
1488 assert!(s2.is_empty());
1489 assert_eq!(pool.free_count(), 0);
1490 }
1491 #[test]
1492 fn test_transitive_closure() {
1493 let mut tc = TransitiveClosure::new(4);
1494 tc.add_edge(0, 1);
1495 tc.add_edge(1, 2);
1496 tc.add_edge(2, 3);
1497 assert!(tc.can_reach(0, 3));
1498 assert!(!tc.can_reach(3, 0));
1499 let r = tc.reachable_from(0);
1500 assert_eq!(r.len(), 4);
1501 }
1502 #[test]
1503 fn test_token_bucket() {
1504 let mut tb = TokenBucket::new(100, 0);
1505 assert_eq!(tb.available(), 100);
1506 assert!(tb.try_consume(50));
1507 assert_eq!(tb.available(), 50);
1508 assert!(!tb.try_consume(60));
1509 assert_eq!(tb.capacity(), 100);
1510 }
1511 #[test]
1512 fn test_rewrite_rule_set() {
1513 let mut rrs = RewriteRuleSet::new();
1514 rrs.add(RewriteRule::unconditional(
1515 "beta",
1516 "App(Lam(x, b), v)",
1517 "b[x:=v]",
1518 ));
1519 rrs.add(RewriteRule::conditional("comm", "a + b", "b + a"));
1520 assert_eq!(rrs.len(), 2);
1521 assert_eq!(rrs.unconditional_rules().len(), 1);
1522 assert_eq!(rrs.conditional_rules().len(), 1);
1523 assert!(rrs.get("beta").is_some());
1524 let disp = rrs
1525 .get("beta")
1526 .expect("element at \'beta\' should exist")
1527 .display();
1528 assert!(disp.contains("→"));
1529 }
1530}
1531#[cfg(test)]
1532mod tests_padding3 {
1533 use super::*;
1534 #[test]
1535 fn test_decision_node() {
1536 let tree = DecisionNode::Branch {
1537 key: "x".into(),
1538 val: "1".into(),
1539 yes_branch: Box::new(DecisionNode::Leaf("yes".into())),
1540 no_branch: Box::new(DecisionNode::Leaf("no".into())),
1541 };
1542 let mut ctx = std::collections::HashMap::new();
1543 ctx.insert("x".into(), "1".into());
1544 assert_eq!(tree.evaluate(&ctx), "yes");
1545 ctx.insert("x".into(), "2".into());
1546 assert_eq!(tree.evaluate(&ctx), "no");
1547 assert_eq!(tree.depth(), 1);
1548 }
1549 #[test]
1550 fn test_flat_substitution() {
1551 let mut sub = FlatSubstitution::new();
1552 sub.add("foo", "bar");
1553 sub.add("baz", "qux");
1554 assert_eq!(sub.apply("foo and baz"), "bar and qux");
1555 assert_eq!(sub.len(), 2);
1556 }
1557 #[test]
1558 fn test_stopwatch() {
1559 let mut sw = Stopwatch::start();
1560 sw.split();
1561 sw.split();
1562 assert_eq!(sw.num_splits(), 2);
1563 assert!(sw.elapsed_ms() >= 0.0);
1564 for &s in sw.splits() {
1565 assert!(s >= 0.0);
1566 }
1567 }
1568 #[test]
1569 fn test_either2() {
1570 let e: Either2<i32, &str> = Either2::First(42);
1571 assert!(e.is_first());
1572 let mapped = e.map_first(|x| x * 2);
1573 assert_eq!(mapped.first(), Some(84));
1574 let e2: Either2<i32, &str> = Either2::Second("hello");
1575 assert!(e2.is_second());
1576 assert_eq!(e2.second(), Some("hello"));
1577 }
1578 #[test]
1579 fn test_write_once() {
1580 let wo: WriteOnce<u32> = WriteOnce::new();
1581 assert!(!wo.is_written());
1582 assert!(wo.write(42));
1583 assert!(!wo.write(99));
1584 assert_eq!(wo.read(), Some(42));
1585 }
1586 #[test]
1587 fn test_sparse_vec() {
1588 let mut sv: SparseVec<i32> = SparseVec::new(100);
1589 sv.set(5, 10);
1590 sv.set(50, 20);
1591 assert_eq!(*sv.get(5), 10);
1592 assert_eq!(*sv.get(50), 20);
1593 assert_eq!(*sv.get(0), 0);
1594 assert_eq!(sv.nnz(), 2);
1595 sv.set(5, 0);
1596 assert_eq!(sv.nnz(), 1);
1597 }
1598 #[test]
1599 fn test_stack_calc() {
1600 let mut calc = StackCalc::new();
1601 calc.push(3);
1602 calc.push(4);
1603 assert_eq!(calc.add(), Some(7));
1604 assert_eq!(calc.peek(), Some(7));
1605 calc.push(2);
1606 assert_eq!(calc.mul(), Some(14));
1607 assert_eq!(calc.peek(), Some(14));
1608 }
1609}
1610#[cfg(test)]
1611mod tests_final_padding {
1612 use super::*;
1613 #[test]
1614 fn test_min_heap() {
1615 let mut h = MinHeap::new();
1616 h.push(5u32);
1617 h.push(1u32);
1618 h.push(3u32);
1619 assert_eq!(h.peek(), Some(&1));
1620 assert_eq!(h.pop(), Some(1));
1621 assert_eq!(h.pop(), Some(3));
1622 assert_eq!(h.pop(), Some(5));
1623 assert!(h.is_empty());
1624 }
1625 #[test]
1626 fn test_prefix_counter() {
1627 let mut pc = PrefixCounter::new();
1628 pc.record("hello");
1629 pc.record("help");
1630 pc.record("world");
1631 assert_eq!(pc.count_with_prefix("hel"), 2);
1632 assert_eq!(pc.count_with_prefix("wor"), 1);
1633 assert_eq!(pc.count_with_prefix("xyz"), 0);
1634 }
1635 #[test]
1636 fn test_fixture() {
1637 let mut f = Fixture::new();
1638 f.set("key1", "val1");
1639 f.set("key2", "val2");
1640 assert_eq!(f.get("key1"), Some("val1"));
1641 assert_eq!(f.get("key3"), None);
1642 assert_eq!(f.len(), 2);
1643 }
1644}