1#[allow(unused_imports)]
6use crate::ast::{SimpleNodeKindExt, TreeNodeExt};
7
8use super::types::{AttributeKind, TreePathExt, TreeStats, TreeStatsExt2};
9
10#[allow(dead_code)]
12pub fn parse_attribute_kind(s: &str) -> AttributeKind {
13 match s {
14 "simp" => AttributeKind::Simp,
15 "ext" => AttributeKind::Ext,
16 "instance" => AttributeKind::Instance,
17 "reducible" => AttributeKind::Reducible,
18 "irreducible" => AttributeKind::Irreducible,
19 "inline" => AttributeKind::Inline,
20 "noinline" => AttributeKind::NoInline,
21 "specialize" => AttributeKind::SpecializeAttr,
22 other => AttributeKind::Custom(other.to_string()),
23 }
24}
25pub type TacticRef = String;
27#[cfg(test)]
28mod tests {
29 use super::*;
30 use crate::ast_impl::*;
31 use crate::tokens::{Span, StringPart};
32 fn mk_span() -> Span {
33 Span::new(0, 1, 1, 1)
34 }
35 fn mk_located<T>(value: T) -> Located<T> {
36 Located::new(value, mk_span())
37 }
38 fn mk_var(name: &str) -> Located<SurfaceExpr> {
39 mk_located(SurfaceExpr::Var(name.to_string()))
40 }
41 fn mk_nat(n: u64) -> Located<SurfaceExpr> {
42 mk_located(SurfaceExpr::Lit(Literal::Nat(n)))
43 }
44 #[test]
45 fn test_surface_expr_var() {
46 let expr = SurfaceExpr::Var("x".to_string());
47 assert!(matches!(expr, SurfaceExpr::Var(_)));
48 }
49 #[test]
50 fn test_surface_expr_lit() {
51 let expr = SurfaceExpr::Lit(Literal::Nat(42));
52 assert_eq!(expr, SurfaceExpr::Lit(Literal::Nat(42)));
53 }
54 #[test]
55 fn test_located() {
56 let loc = Located::new(SurfaceExpr::Var("x".to_string()), mk_span());
57 assert_eq!(loc.value, SurfaceExpr::Var("x".to_string()));
58 }
59 #[test]
60 fn test_binder() {
61 let binder = Binder {
62 name: "x".to_string(),
63 ty: None,
64 info: BinderKind::Default,
65 };
66 assert_eq!(binder.name, "x");
67 assert!(binder.ty.is_none());
68 }
69 #[test]
70 fn test_sort_kind_display() {
71 assert_eq!(format!("{}", SortKind::Type), "Type");
72 assert_eq!(format!("{}", SortKind::Prop), "Prop");
73 assert_eq!(format!("{}", SortKind::TypeU("u".to_string())), "Type u");
74 }
75 #[test]
76 fn test_literal_display() {
77 assert_eq!(format!("{}", Literal::Nat(42)), "42");
78 assert_eq!(
79 format!("{}", Literal::String("hello".to_string())),
80 "\"hello\""
81 );
82 assert_eq!(format!("{}", Literal::Char('x')), "'x'");
83 }
84 #[test]
85 fn test_field_decl() {
86 let field = FieldDecl {
87 name: "x".to_string(),
88 ty: Located::new(SurfaceExpr::Var("Nat".to_string()), mk_span()),
89 default: None,
90 };
91 assert_eq!(field.name, "x");
92 assert!(field.default.is_none());
93 }
94 #[test]
95 fn test_new_expr_variants() {
96 let _have = SurfaceExpr::Have(
97 "h".to_string(),
98 Box::new(Located::new(SurfaceExpr::Var("T".to_string()), mk_span())),
99 Box::new(Located::new(SurfaceExpr::Hole, mk_span())),
100 Box::new(Located::new(
101 SurfaceExpr::Var("body".to_string()),
102 mk_span(),
103 )),
104 );
105 let _ctor = SurfaceExpr::AnonymousCtor(vec![
106 Located::new(SurfaceExpr::Lit(Literal::Nat(1)), mk_span()),
107 Located::new(SurfaceExpr::Lit(Literal::Nat(2)), mk_span()),
108 ]);
109 let _list = SurfaceExpr::ListLit(vec![Located::new(
110 SurfaceExpr::Lit(Literal::Nat(1)),
111 mk_span(),
112 )]);
113 let _tuple = SurfaceExpr::Tuple(vec![
114 Located::new(SurfaceExpr::Lit(Literal::Nat(1)), mk_span()),
115 Located::new(SurfaceExpr::Lit(Literal::Nat(2)), mk_span()),
116 ]);
117 }
118 #[test]
119 fn test_new_decl_variants() {
120 let span = mk_span();
121 let _structure = Decl::Structure {
122 name: "Point".to_string(),
123 univ_params: vec![],
124 extends: vec![],
125 fields: vec![FieldDecl {
126 name: "x".to_string(),
127 ty: Located::new(SurfaceExpr::Var("Nat".to_string()), span.clone()),
128 default: None,
129 }],
130 };
131 let _class = Decl::ClassDecl {
132 name: "Monad".to_string(),
133 univ_params: vec!["u".to_string()],
134 extends: vec![],
135 fields: vec![],
136 };
137 let _var = Decl::Variable {
138 binders: vec![Binder {
139 name: "n".to_string(),
140 ty: Some(Box::new(Located::new(
141 SurfaceExpr::Var("Nat".to_string()),
142 span.clone(),
143 ))),
144 info: BinderKind::Default,
145 }],
146 };
147 let _check = Decl::HashCmd {
148 cmd: "check".to_string(),
149 arg: Located::new(SurfaceExpr::Var("Nat".to_string()), span),
150 };
151 }
152 #[test]
153 fn test_mutual_decl() {
154 let span = mk_span();
155 let def1 = mk_located(Decl::Definition {
156 name: "even".to_string(),
157 univ_params: vec![],
158 ty: Some(mk_var("Nat_to_Bool")),
159 val: mk_var("even_body"),
160 where_clauses: vec![],
161 attrs: vec![],
162 });
163 let def2 = mk_located(Decl::Definition {
164 name: "odd".to_string(),
165 univ_params: vec![],
166 ty: Some(Located::new(
167 SurfaceExpr::Var("Nat_to_Bool".to_string()),
168 span,
169 )),
170 val: mk_var("odd_body"),
171 where_clauses: vec![],
172 attrs: vec![],
173 });
174 let mutual = Decl::Mutual {
175 decls: vec![def1, def2],
176 };
177 assert!(mutual.is_mutual());
178 match &mutual {
179 Decl::Mutual { decls } => assert_eq!(decls.len(), 2),
180 _ => panic!("expected Mutual"),
181 }
182 }
183 #[test]
184 fn test_derive_decl() {
185 let derive = Decl::Derive {
186 instances: vec!["DecidableEq".to_string(), "Repr".to_string()],
187 type_name: "Color".to_string(),
188 };
189 match &derive {
190 Decl::Derive {
191 instances,
192 type_name,
193 } => {
194 assert_eq!(instances.len(), 2);
195 assert_eq!(type_name, "Color");
196 }
197 _ => panic!("expected Derive"),
198 }
199 }
200 #[test]
201 fn test_notation_decl() {
202 let notation = Decl::NotationDecl {
203 kind: AstNotationKind::Infixl,
204 prec: Some(65),
205 name: "+".to_string(),
206 notation: "HAdd.hAdd".to_string(),
207 };
208 match ¬ation {
209 Decl::NotationDecl {
210 kind,
211 prec,
212 name,
213 notation,
214 } => {
215 assert_eq!(*kind, AstNotationKind::Infixl);
216 assert_eq!(*prec, Some(65));
217 assert_eq!(name, "+");
218 assert_eq!(notation, "HAdd.hAdd");
219 }
220 _ => panic!("expected NotationDecl"),
221 }
222 }
223 #[test]
224 fn test_universe_decl() {
225 let univ = Decl::Universe {
226 names: vec!["u".to_string(), "v".to_string()],
227 };
228 match &univ {
229 Decl::Universe { names } => {
230 assert_eq!(names.len(), 2);
231 assert_eq!(names[0], "u");
232 assert_eq!(names[1], "v");
233 }
234 _ => panic!("expected Universe"),
235 }
236 }
237 #[test]
238 fn test_where_clause() {
239 let wc = WhereClause {
240 name: "helper".to_string(),
241 params: vec![Binder {
242 name: "x".to_string(),
243 ty: Some(Box::new(mk_var("Nat"))),
244 info: BinderKind::Default,
245 }],
246 ty: Some(mk_var("Nat")),
247 val: mk_nat(42),
248 };
249 assert_eq!(wc.name, "helper");
250 assert_eq!(wc.params.len(), 1);
251 assert!(wc.ty.is_some());
252 }
253 #[test]
254 fn test_definition_with_where_clauses() {
255 let def = Decl::Definition {
256 name: "foo".to_string(),
257 univ_params: vec![],
258 ty: Some(mk_var("Nat")),
259 val: mk_var("bar_result"),
260 where_clauses: vec![WhereClause {
261 name: "bar".to_string(),
262 params: vec![],
263 ty: None,
264 val: mk_nat(10),
265 }],
266 attrs: vec![AttributeKind::Simp],
267 };
268 match &def {
269 Decl::Definition {
270 where_clauses,
271 attrs,
272 ..
273 } => {
274 assert_eq!(where_clauses.len(), 1);
275 assert_eq!(where_clauses[0].name, "bar");
276 assert_eq!(attrs.len(), 1);
277 assert_eq!(attrs[0], AttributeKind::Simp);
278 }
279 _ => panic!("expected Definition"),
280 }
281 }
282 #[test]
283 fn test_theorem_with_attrs() {
284 let thm = Decl::Theorem {
285 name: "add_comm".to_string(),
286 univ_params: vec![],
287 ty: mk_var("Prop_statement"),
288 proof: mk_var("proof_term"),
289 where_clauses: vec![],
290 attrs: vec![AttributeKind::Simp, AttributeKind::Ext],
291 };
292 let attrs = thm.typed_attrs();
293 assert_eq!(attrs.len(), 2);
294 assert_eq!(attrs[0], AttributeKind::Simp);
295 assert_eq!(attrs[1], AttributeKind::Ext);
296 }
297 #[test]
298 fn test_axiom_with_attrs() {
299 let ax = Decl::Axiom {
300 name: "propext".to_string(),
301 univ_params: vec![],
302 ty: mk_var("Prop_ext_type"),
303 attrs: vec![AttributeKind::Reducible],
304 };
305 let attrs = ax.typed_attrs();
306 assert_eq!(attrs.len(), 1);
307 assert_eq!(attrs[0], AttributeKind::Reducible);
308 }
309 #[test]
310 fn test_attribute_kind_display() {
311 assert_eq!(format!("{}", AttributeKind::Simp), "simp");
312 assert_eq!(format!("{}", AttributeKind::Ext), "ext");
313 assert_eq!(format!("{}", AttributeKind::Instance), "instance");
314 assert_eq!(format!("{}", AttributeKind::Reducible), "reducible");
315 assert_eq!(format!("{}", AttributeKind::Irreducible), "irreducible");
316 assert_eq!(format!("{}", AttributeKind::Inline), "inline");
317 assert_eq!(format!("{}", AttributeKind::NoInline), "noinline");
318 assert_eq!(format!("{}", AttributeKind::SpecializeAttr), "specialize");
319 assert_eq!(
320 format!("{}", AttributeKind::Custom("my_attr".to_string())),
321 "my_attr"
322 );
323 }
324 #[test]
325 fn test_attribute_kind_name() {
326 assert_eq!(AttributeKind::Simp.name(), "simp");
327 assert_eq!(AttributeKind::Custom("foo".to_string()).name(), "foo");
328 }
329 #[test]
330 fn test_attribute_kind_is_custom() {
331 assert!(!AttributeKind::Simp.is_custom());
332 assert!(AttributeKind::Custom("foo".to_string()).is_custom());
333 }
334 #[test]
335 fn test_parse_attribute_kind() {
336 assert_eq!(parse_attribute_kind("simp"), AttributeKind::Simp);
337 assert_eq!(parse_attribute_kind("ext"), AttributeKind::Ext);
338 assert_eq!(parse_attribute_kind("inline"), AttributeKind::Inline);
339 assert_eq!(
340 parse_attribute_kind("my_custom"),
341 AttributeKind::Custom("my_custom".to_string())
342 );
343 }
344 #[test]
345 fn test_return_expr() {
346 let ret = SurfaceExpr::Return(Box::new(mk_nat(42)));
347 match &ret {
348 SurfaceExpr::Return(inner) => {
349 assert_eq!(inner.value, SurfaceExpr::Lit(Literal::Nat(42)));
350 }
351 _ => panic!("expected Return"),
352 }
353 let display = format!("{}", ret);
354 assert!(display.contains("return"));
355 }
356 #[test]
357 fn test_string_interp_expr() {
358 let interp = SurfaceExpr::StringInterp(vec![
359 StringPart::Literal("hello ".to_string()),
360 StringPart::Interpolation(vec![]),
361 ]);
362 match &interp {
363 SurfaceExpr::StringInterp(parts) => {
364 assert_eq!(parts.len(), 2);
365 }
366 _ => panic!("expected StringInterp"),
367 }
368 }
369 #[test]
370 fn test_range_expr_full() {
371 let range = SurfaceExpr::Range(Some(Box::new(mk_nat(1))), Some(Box::new(mk_nat(10))));
372 let display = format!("{}", range);
373 assert!(display.contains(".."));
374 }
375 #[test]
376 fn test_range_expr_open_start() {
377 let range = SurfaceExpr::Range(None, Some(Box::new(mk_nat(10))));
378 let display = format!("{}", range);
379 assert!(display.starts_with(".."));
380 }
381 #[test]
382 fn test_range_expr_open_end() {
383 let range = SurfaceExpr::Range(Some(Box::new(mk_nat(1))), None);
384 let display = format!("{}", range);
385 assert!(display.contains(".."));
386 }
387 #[test]
388 fn test_by_tactic_expr() {
389 let by_tac = SurfaceExpr::ByTactic(vec![
390 mk_located("exact".to_string()),
391 mk_located("rfl".to_string()),
392 ]);
393 match &by_tac {
394 SurfaceExpr::ByTactic(tactics) => {
395 assert_eq!(tactics.len(), 2);
396 assert_eq!(tactics[0].value, "exact");
397 assert_eq!(tactics[1].value, "rfl");
398 }
399 _ => panic!("expected ByTactic"),
400 }
401 let display = format!("{}", by_tac);
402 assert!(display.contains("by"));
403 }
404 #[test]
405 fn test_calc_expr() {
406 let step = CalcStep {
407 lhs: mk_var("a"),
408 rel: "=".to_string(),
409 rhs: mk_var("b"),
410 proof: mk_var("proof_ab"),
411 };
412 let calc = SurfaceExpr::Calc(vec![step]);
413 match &calc {
414 SurfaceExpr::Calc(steps) => {
415 assert_eq!(steps.len(), 1);
416 assert_eq!(steps[0].rel, "=");
417 }
418 _ => panic!("expected Calc"),
419 }
420 let display = format!("{}", calc);
421 assert!(display.contains("calc"));
422 }
423 #[test]
424 fn test_calc_step_constructor() {
425 let step = CalcStep::new(mk_var("x"), "<".to_string(), mk_var("y"), mk_var("proof"));
426 assert_eq!(step.rel, "<");
427 }
428 #[test]
429 fn test_where_clause_constructor() {
430 let wc = WhereClause::new("aux".to_string(), vec![], None, mk_nat(0));
431 assert_eq!(wc.name, "aux");
432 assert!(wc.params.is_empty());
433 assert!(wc.ty.is_none());
434 }
435 #[test]
436 fn test_surface_expr_helpers() {
437 let v = SurfaceExpr::var("x");
438 assert!(v.is_var());
439 assert_eq!(v.as_var(), Some("x"));
440 let n = SurfaceExpr::nat(42);
441 assert!(!n.is_var());
442 let s = SurfaceExpr::string("hello");
443 assert!(matches!(s, SurfaceExpr::Lit(Literal::String(_))));
444 #[allow(clippy::approx_constant)]
445 let f = SurfaceExpr::float(3.14);
446 assert!(matches!(f, SurfaceExpr::Lit(Literal::Float(_))));
447 let h = SurfaceExpr::Hole;
448 assert!(h.is_hole());
449 }
450 #[test]
451 fn test_located_map() {
452 let loc = Located::new(42, mk_span());
453 let mapped = loc.map(|x| x * 2);
454 assert_eq!(mapped.value, 84);
455 }
456 #[test]
457 fn test_located_display() {
458 let loc = Located::new(SurfaceExpr::Var("x".to_string()), mk_span());
459 let display = format!("{}", loc);
460 assert_eq!(display, "x");
461 }
462 #[test]
463 fn test_decl_name() {
464 let def = Decl::Definition {
465 name: "foo".to_string(),
466 univ_params: vec![],
467 ty: None,
468 val: mk_var("bar"),
469 where_clauses: vec![],
470 attrs: vec![],
471 };
472 assert_eq!(def.name(), Some("foo"));
473 let import = Decl::Import {
474 path: vec!["M".to_string()],
475 };
476 assert_eq!(import.name(), None);
477 let derive = Decl::Derive {
478 instances: vec!["Repr".to_string()],
479 type_name: "MyType".to_string(),
480 };
481 assert_eq!(derive.name(), Some("MyType"));
482 }
483 #[test]
484 fn test_ast_notation_kind_display() {
485 assert_eq!(format!("{}", AstNotationKind::Prefix), "prefix");
486 assert_eq!(format!("{}", AstNotationKind::Postfix), "postfix");
487 assert_eq!(format!("{}", AstNotationKind::Infixl), "infixl");
488 assert_eq!(format!("{}", AstNotationKind::Infixr), "infixr");
489 assert_eq!(format!("{}", AstNotationKind::Notation), "notation");
490 }
491 #[test]
492 fn test_binder_kind_display() {
493 assert_eq!(format!("{}", BinderKind::Default), "explicit");
494 assert_eq!(format!("{}", BinderKind::Implicit), "implicit");
495 assert_eq!(format!("{}", BinderKind::Instance), "instance");
496 assert_eq!(format!("{}", BinderKind::StrictImplicit), "strict_implicit");
497 }
498 #[test]
499 fn test_where_clause_display() {
500 let wc = WhereClause {
501 name: "helper".to_string(),
502 params: vec![Binder {
503 name: "n".to_string(),
504 ty: Some(Box::new(mk_var("Nat"))),
505 info: BinderKind::Default,
506 }],
507 ty: Some(mk_var("Nat")),
508 val: mk_nat(0),
509 };
510 let display = format!("{}", wc);
511 assert!(display.contains("helper"));
512 assert!(display.contains("(n : ...)"));
513 }
514 #[test]
515 fn test_literal_float_display() {
516 #[allow(clippy::approx_constant)]
517 let val = 3.14;
518 assert_eq!(format!("{}", Literal::Float(val)), "3.14");
519 }
520 #[test]
521 fn test_do_action_return() {
522 let action = DoAction::Return(mk_nat(42));
523 match &action {
524 DoAction::Return(expr) => {
525 assert_eq!(expr.value, SurfaceExpr::Lit(Literal::Nat(42)));
526 }
527 _ => panic!("expected DoAction::Return"),
528 }
529 }
530 #[test]
531 fn test_surface_expr_display_comprehensive() {
532 assert_eq!(format!("{}", SurfaceExpr::Sort(SortKind::Type)), "Type");
533 assert_eq!(format!("{}", SurfaceExpr::Hole), "_");
534 let proj = SurfaceExpr::Proj(Box::new(mk_var("p")), "x".to_string());
535 assert_eq!(format!("{}", proj), "p.x");
536 let if_expr = SurfaceExpr::If(
537 Box::new(mk_var("cond")),
538 Box::new(mk_var("t")),
539 Box::new(mk_var("f")),
540 );
541 let display = format!("{}", if_expr);
542 assert!(display.contains("if"));
543 assert!(display.contains("then"));
544 assert!(display.contains("else"));
545 }
546 #[test]
547 fn test_all_notation_kinds_are_distinct() {
548 let kinds = [
549 AstNotationKind::Prefix,
550 AstNotationKind::Postfix,
551 AstNotationKind::Infixl,
552 AstNotationKind::Infixr,
553 AstNotationKind::Notation,
554 ];
555 for i in 0..kinds.len() {
556 for j in (i + 1)..kinds.len() {
557 assert_ne!(kinds[i], kinds[j]);
558 }
559 }
560 }
561 #[test]
562 fn test_multiple_calc_steps() {
563 let steps = vec![
564 CalcStep::new(mk_var("a"), "=".to_string(), mk_var("b"), mk_var("p1")),
565 CalcStep::new(mk_var("_"), "<".to_string(), mk_var("c"), mk_var("p2")),
566 CalcStep::new(mk_var("_"), "<=".to_string(), mk_var("d"), mk_var("p3")),
567 ];
568 let calc = SurfaceExpr::Calc(steps);
569 match &calc {
570 SurfaceExpr::Calc(steps) => assert_eq!(steps.len(), 3),
571 _ => panic!("expected Calc"),
572 }
573 }
574}
575#[allow(dead_code)]
577pub trait TreeTransformExt {
578 fn transform(&mut self, node: TreeNodeExt) -> TreeNodeExt;
580}
581#[allow(dead_code)]
583#[allow(missing_docs)]
584pub fn apply_transform_ext<T: TreeTransformExt>(root: TreeNodeExt, t: &mut T) -> TreeNodeExt {
585 t.transform(root)
586}
587#[allow(dead_code)]
589#[allow(missing_docs)]
590pub fn trees_equal_ext(a: &TreeNodeExt, b: &TreeNodeExt) -> bool {
591 if a.kind != b.kind {
592 return false;
593 }
594 if a.label != b.label {
595 return false;
596 }
597 if a.children.len() != b.children.len() {
598 return false;
599 }
600 a.children
601 .iter()
602 .zip(b.children.iter())
603 .all(|(ac, bc)| trees_equal_ext(ac, bc))
604}
605#[allow(dead_code)]
607#[allow(missing_docs)]
608pub fn follow_path_ext<'a>(root: &'a TreeNodeExt, path: &TreePathExt) -> Option<&'a TreeNodeExt> {
609 let mut node = root;
610 for &idx in &path.0 {
611 node = node.children.get(idx)?;
612 }
613 Some(node)
614}
615#[allow(dead_code)]
617#[allow(missing_docs)]
618pub fn count_label_ext(node: &TreeNodeExt, label: &str) -> usize {
619 let mut count = if node.label == label { 1 } else { 0 };
620 for child in &node.children {
621 count += count_label_ext(child, label);
622 }
623 count
624}
625#[cfg(test)]
626mod ast_impl_ext_tests {
627 use super::*;
628 use crate::ast_impl::*;
629 use crate::tokens::{Span, StringPart};
630 #[test]
631 fn test_identity_transform() {
632 let tree = TreeNodeExt::lam("x", TreeNodeExt::leaf("x"));
633 let mut t = IdentityTransformExt;
634 let result = t.transform(tree.clone());
635 assert!(trees_equal_ext(&result, &tree));
636 }
637 #[test]
638 fn test_rename_transform() {
639 let tree = TreeNodeExt::app(TreeNodeExt::leaf("x"), TreeNodeExt::leaf("y"));
640 let mut t = RenameTransformExt::new("x", "z");
641 let result = t.transform(tree);
642 assert_eq!(result.children[0].label, "z");
643 assert_eq!(result.children[1].label, "y");
644 assert_eq!(t.count, 1);
645 }
646 #[test]
647 fn test_trees_equal() {
648 let t1 = TreeNodeExt::leaf("x");
649 let t2 = TreeNodeExt::leaf("x");
650 let t3 = TreeNodeExt::leaf("y");
651 assert!(trees_equal_ext(&t1, &t2));
652 assert!(!trees_equal_ext(&t1, &t3));
653 }
654 #[test]
655 fn test_tree_path() {
656 let path = TreePathExt::root().child(0).child(1);
657 assert_eq!(path.depth(), 2);
658 assert_eq!(path.0, vec![0, 1]);
659 }
660 #[test]
661 fn test_follow_path() {
662 let tree = TreeNodeExt::app(TreeNodeExt::leaf("f"), TreeNodeExt::leaf("x"));
663 let path = TreePathExt::root().child(0);
664 let node = follow_path_ext(&tree, &path).expect("test operation should succeed");
665 assert_eq!(node.label, "f");
666 }
667 #[test]
668 fn test_count_label() {
669 let tree = TreeNodeExt::app(TreeNodeExt::leaf("x"), TreeNodeExt::leaf("x"));
670 assert_eq!(count_label_ext(&tree, "x"), 2);
671 assert_eq!(count_label_ext(&tree, "y"), 0);
672 }
673 #[test]
674 fn test_zipper_down_up() {
675 let tree = TreeNodeExt::app(TreeNodeExt::leaf("f"), TreeNodeExt::leaf("x"));
676 let zipper = TreeZipperExt::new(tree);
677 let z2 = zipper.down(0).expect("test operation should succeed");
678 assert_eq!(z2.focus.label, "f");
679 let (z3, child) = z2.up().expect("test operation should succeed");
680 assert_eq!(child.label, "f");
681 assert_eq!(z3.focus.kind, SimpleNodeKindExt::App);
682 }
683}
684pub fn collect_stats(node: &TreeNodeExt, depth: usize, stats: &mut TreeStats) {
685 stats.nodes += 1;
686 stats.total_size += 1;
687 if node.children.is_empty() {
688 stats.leaves += 1;
689 }
690 if depth > stats.max_depth {
691 stats.max_depth = depth;
692 }
693 for child in &node.children {
694 collect_stats(child, depth + 1, stats);
695 }
696}
697#[allow(dead_code)]
699#[allow(missing_docs)]
700pub fn shape_fingerprint(node: &TreeNodeExt) -> String {
701 if node.children.is_empty() {
702 return "L".to_string();
703 }
704 let child_shapes: Vec<String> = node.children.iter().map(shape_fingerprint).collect();
705 format!("({})", child_shapes.join(","))
706}
707#[cfg(test)]
708mod ast_impl_ext2_tests {
709 use super::*;
710 use crate::ast_impl::*;
711 use crate::tokens::{Span, StringPart};
712 #[test]
713 fn test_transform_memo() {
714 let mut memo = TransformMemo::new();
715 let node = TreeNodeExt::leaf("x");
716 memo.store(42, node.clone());
717 assert_eq!(memo.len(), 1);
718 let cached = memo.get(42).expect("key should exist");
719 assert_eq!(cached.label, "x");
720 }
721 #[test]
722 fn test_tree_stats() {
723 let tree = TreeNodeExt::app(TreeNodeExt::leaf("f"), TreeNodeExt::leaf("x"));
724 let stats = TreeStats::from_tree(&tree);
725 assert_eq!(stats.nodes, 3);
726 assert_eq!(stats.leaves, 2);
727 assert_eq!(stats.max_depth, 1);
728 }
729 #[test]
730 fn test_shape_fingerprint() {
731 let leaf = TreeNodeExt::leaf("x");
732 assert_eq!(shape_fingerprint(&leaf), "L");
733 let app = TreeNodeExt::app(TreeNodeExt::leaf("f"), TreeNodeExt::leaf("x"));
734 assert_eq!(shape_fingerprint(&app), "(L,L)");
735 }
736 #[test]
737 fn test_rename_transform_ext() {
738 let tree = TreeNodeExt::app(TreeNodeExt::leaf("x"), TreeNodeExt::leaf("y"));
739 let mut t = RenameTransformExt::new("x", "z");
740 let result = apply_transform_ext(tree, &mut t);
741 assert_eq!(result.children[0].label, "z");
742 assert_eq!(t.count, 1);
743 }
744}
745#[allow(dead_code)]
747#[allow(missing_docs)]
748pub fn collect_all_labels(node: &TreeNodeExt) -> Vec<String> {
749 let mut labels = vec![node.label.clone()];
750 for child in &node.children {
751 labels.extend(collect_all_labels(child));
752 }
753 labels
754}
755#[allow(dead_code)]
757#[allow(missing_docs)]
758pub fn collect_leaves(node: &TreeNodeExt) -> Vec<&TreeNodeExt> {
759 if node.children.is_empty() {
760 return vec![node];
761 }
762 let mut leaves = Vec::new();
763 for child in &node.children {
764 leaves.extend(collect_leaves(child));
765 }
766 leaves
767}
768#[allow(dead_code)]
770#[allow(missing_docs)]
771pub fn deep_clone(node: &TreeNodeExt) -> TreeNodeExt {
772 node.clone()
773}
774#[allow(dead_code)]
776#[allow(missing_docs)]
777pub fn contains_label(node: &TreeNodeExt, label: &str) -> bool {
778 if node.label == label {
779 return true;
780 }
781 node.children.iter().any(|c| contains_label(c, label))
782}
783#[cfg(test)]
784mod ast_impl_ext3_tests {
785 use super::*;
786 use crate::ast_impl::*;
787 use crate::tokens::{Span, StringPart};
788 #[test]
789 fn test_tree_cursor() {
790 let root = TreeNodeExt::app(TreeNodeExt::leaf("f"), TreeNodeExt::leaf("x"));
791 let cursor = TreeCursor::new(root);
792 assert_eq!(cursor.child_count(), 2);
793 assert_eq!(cursor.depth(), 0);
794 }
795 #[test]
796 fn test_collect_all_labels() {
797 let tree = TreeNodeExt::app(TreeNodeExt::leaf("f"), TreeNodeExt::leaf("x"));
798 let labels = collect_all_labels(&tree);
799 assert!(labels.contains(&"f".to_string()));
800 assert!(labels.contains(&"x".to_string()));
801 }
802 #[test]
803 fn test_collect_leaves() {
804 let tree = TreeNodeExt::lam("x", TreeNodeExt::leaf("x"));
805 let leaves = collect_leaves(&tree);
806 assert_eq!(leaves.len(), 1);
807 assert_eq!(leaves[0].label, "x");
808 }
809 #[test]
810 fn test_contains_label() {
811 let tree = TreeNodeExt::app(TreeNodeExt::leaf("f"), TreeNodeExt::leaf("x"));
812 assert!(contains_label(&tree, "f"));
813 assert!(!contains_label(&tree, "g"));
814 }
815}
816#[allow(dead_code)]
818#[allow(missing_docs)]
819pub fn memoised_depth(
820 node: &TreeNodeExt,
821 memo: &mut std::collections::HashMap<u64, usize>,
822) -> usize {
823 let key = crate::ast::tree_fingerprint_ext(node);
824 if let Some(&d) = memo.get(&key) {
825 return d;
826 }
827 let d = if node.children.is_empty() {
828 0
829 } else {
830 1 + node
831 .children
832 .iter()
833 .map(|c| memoised_depth(c, memo))
834 .max()
835 .unwrap_or(0)
836 };
837 memo.insert(key, d);
838 d
839}
840#[allow(dead_code)]
842#[allow(missing_docs)]
843pub fn serialise_tree(node: &TreeNodeExt) -> String {
844 if node.children.is_empty() {
845 return format!("{{{}}}", node.label);
846 }
847 let children: Vec<String> = node.children.iter().map(serialise_tree).collect();
848 format!("{{{}:{}}}", node.label, children.join(","))
849}
850#[allow(dead_code)]
852#[allow(missing_docs)]
853pub fn deserialise_tree_leaf(s: &str) -> TreeNodeExt {
854 TreeNodeExt::leaf(s.trim_matches(|c| c == '{' || c == '}'))
855}
856#[allow(dead_code)]
858#[allow(missing_docs)]
859pub fn tree_height(node: &TreeNodeExt) -> usize {
860 if node.children.is_empty() {
861 return 0;
862 }
863 1 + node.children.iter().map(tree_height).max().unwrap_or(0)
864}
865#[allow(dead_code)]
867#[allow(missing_docs)]
868pub fn branching_factor(node: &TreeNodeExt) -> f64 {
869 let mut total_children = 0usize;
870 let mut internal_nodes = 0usize;
871 count_branching(node, &mut total_children, &mut internal_nodes);
872 if internal_nodes == 0 {
873 return 0.0;
874 }
875 total_children as f64 / internal_nodes as f64
876}
877pub(super) fn count_branching(node: &TreeNodeExt, total: &mut usize, internals: &mut usize) {
878 if !node.children.is_empty() {
879 *internals += 1;
880 *total += node.children.len();
881 }
882 for child in &node.children {
883 count_branching(child, total, internals);
884 }
885}
886#[cfg(test)]
887mod ast_impl_final_tests {
888 use super::*;
889 use crate::ast_impl::*;
890 use crate::tokens::{Span, StringPart};
891 #[test]
892 fn test_serialise_tree() {
893 let leaf = TreeNodeExt::leaf("x");
894 assert_eq!(serialise_tree(&leaf), "{x}");
895 let app = TreeNodeExt::app(TreeNodeExt::leaf("f"), TreeNodeExt::leaf("x"));
896 let s = serialise_tree(&app);
897 assert!(s.starts_with("{@:"));
898 }
899 #[test]
900 fn test_tree_height() {
901 let leaf = TreeNodeExt::leaf("x");
902 assert_eq!(tree_height(&leaf), 0);
903 let app = TreeNodeExt::app(TreeNodeExt::leaf("f"), TreeNodeExt::leaf("x"));
904 assert_eq!(tree_height(&app), 1);
905 }
906 #[test]
907 fn test_branching_factor() {
908 let leaf = TreeNodeExt::leaf("x");
909 assert_eq!(branching_factor(&leaf), 0.0);
910 let app = TreeNodeExt::app(TreeNodeExt::leaf("f"), TreeNodeExt::leaf("x"));
911 assert!((branching_factor(&app) - 2.0).abs() < 0.01);
912 }
913 #[test]
914 fn test_memoised_depth() {
915 let tree = TreeNodeExt::app(TreeNodeExt::leaf("f"), TreeNodeExt::leaf("x"));
916 let mut memo = std::collections::HashMap::new();
917 let d = memoised_depth(&tree, &mut memo);
918 assert_eq!(d, 1);
919 }
920}
921#[allow(dead_code)]
923#[allow(missing_docs)]
924pub fn map_leaves<F: Fn(&str) -> String>(node: &TreeNodeExt, f: &F) -> TreeNodeExt {
925 if node.children.is_empty() {
926 return TreeNodeExt::leaf(&f(&node.label));
927 }
928 let children = node.children.iter().map(|c| map_leaves(c, f)).collect();
929 TreeNodeExt {
930 kind: node.kind.clone(),
931 label: node.label.clone(),
932 children,
933 }
934}
935#[allow(dead_code)]
937#[allow(missing_docs)]
938pub fn any_leaf<F: Fn(&str) -> bool>(node: &TreeNodeExt, pred: &F) -> bool {
939 if node.children.is_empty() {
940 return pred(&node.label);
941 }
942 node.children.iter().any(|c| any_leaf(c, pred))
943}
944#[cfg(test)]
945mod ast_impl_pad {
946 use super::*;
947 use crate::ast_impl::*;
948 use crate::tokens::{Span, StringPart};
949 #[test]
950 fn test_node_cache() {
951 let mut c = NodeCache::new();
952 c.store("x", 42);
953 assert_eq!(c.get("x"), Some(42));
954 assert_eq!(c.get("y"), None);
955 }
956 #[test]
957 fn test_map_leaves() {
958 let tree = TreeNodeExt::app(TreeNodeExt::leaf("x"), TreeNodeExt::leaf("y"));
959 let mapped = map_leaves(&tree, &|s: &str| s.to_uppercase());
960 assert_eq!(mapped.children[0].label, "X");
961 assert_eq!(mapped.children[1].label, "Y");
962 }
963 #[test]
964 fn test_any_leaf() {
965 let tree = TreeNodeExt::app(TreeNodeExt::leaf("x"), TreeNodeExt::leaf("y"));
966 assert!(any_leaf(&tree, &|s: &str| s == "x"));
967 assert!(!any_leaf(&tree, &|s: &str| s == "z"));
968 }
969}
970#[allow(dead_code)]
972#[allow(missing_docs)]
973pub fn compute_tree_stats(node: &TreeNodeExt) -> TreeStatsExt2 {
974 fn go(node: &TreeNodeExt, depth: usize, stats: &mut TreeStatsExt2) {
975 stats.node_count += 1;
976 if depth > stats.max_depth {
977 stats.max_depth = depth;
978 }
979 if node.children.is_empty() {
980 stats.leaf_count += 1;
981 } else {
982 let b = node.children.len();
983 if b > stats.max_branching {
984 stats.max_branching = b;
985 }
986 for child in &node.children {
987 go(child, depth + 1, stats);
988 }
989 }
990 }
991 let mut stats = TreeStatsExt2::default();
992 go(node, 0, &mut stats);
993 stats
994}
995#[allow(dead_code)]
997#[allow(missing_docs)]
998pub fn shape_fingerprint_ext2(node: &TreeNodeExt) -> String {
999 if node.children.is_empty() {
1000 return "L".to_string();
1001 }
1002 let children_fp: String = node
1003 .children
1004 .iter()
1005 .map(shape_fingerprint_ext2)
1006 .collect::<Vec<_>>()
1007 .join(",");
1008 format!("N({})", children_fp)
1009}
1010#[allow(dead_code)]
1012#[allow(missing_docs)]
1013pub fn deep_clone_ext2(node: &TreeNodeExt) -> TreeNodeExt {
1014 node.clone()
1015}
1016#[allow(dead_code)]
1018#[allow(missing_docs)]
1019pub fn collect_all_labels_ext2(node: &TreeNodeExt) -> Vec<String> {
1020 let mut labels = vec![node.label.clone()];
1021 for child in &node.children {
1022 labels.extend(collect_all_labels_ext2(child));
1023 }
1024 labels
1025}
1026#[allow(dead_code)]
1028#[allow(missing_docs)]
1029pub fn collect_leaves_ext2(node: &TreeNodeExt) -> Vec<String> {
1030 if node.children.is_empty() {
1031 return vec![node.label.clone()];
1032 }
1033 node.children.iter().flat_map(collect_leaves_ext2).collect()
1034}
1035#[allow(dead_code)]
1037#[allow(missing_docs)]
1038pub fn tree_height_ext2(node: &TreeNodeExt) -> usize {
1039 if node.children.is_empty() {
1040 return 0;
1041 }
1042 1 + node
1043 .children
1044 .iter()
1045 .map(tree_height_ext2)
1046 .max()
1047 .unwrap_or(0)
1048}
1049#[allow(dead_code)]
1051#[allow(missing_docs)]
1052pub fn contains_label_ext2(node: &TreeNodeExt, label: &str) -> bool {
1053 if node.label == label {
1054 return true;
1055 }
1056 node.children.iter().any(|c| contains_label_ext2(c, label))
1057}
1058#[cfg(test)]
1059mod ast_impl_pad2 {
1060 use super::*;
1061 use crate::ast_impl::*;
1062 use crate::tokens::{Span, StringPart};
1063 #[test]
1064 fn test_transform_memo() {
1065 let mut m = TransformMemoExt2::new();
1066 m.insert("foo", "FOO");
1067 assert_eq!(m.get("foo"), Some("FOO"));
1068 assert!(m.has("foo"));
1069 assert!(!m.has("bar"));
1070 }
1071 #[test]
1072 fn test_compute_tree_stats() {
1073 let tree = TreeNodeExt::app(TreeNodeExt::leaf("x"), TreeNodeExt::leaf("y"));
1074 let stats = compute_tree_stats(&tree);
1075 assert_eq!(stats.node_count, 3);
1076 assert_eq!(stats.leaf_count, 2);
1077 assert_eq!(stats.max_depth, 1);
1078 }
1079 #[test]
1080 fn test_shape_fingerprint_ext2() {
1081 let tree = TreeNodeExt::app(TreeNodeExt::leaf("x"), TreeNodeExt::leaf("y"));
1082 let fp = shape_fingerprint_ext2(&tree);
1083 assert!(fp.starts_with("N("));
1084 assert!(fp.contains("L"));
1085 }
1086 #[test]
1087 fn test_collect_labels_and_leaves() {
1088 let tree = TreeNodeExt::app(TreeNodeExt::leaf("a"), TreeNodeExt::leaf("b"));
1089 let labels = collect_all_labels_ext2(&tree);
1090 assert!(labels.contains(&"a".to_string()));
1091 assert!(labels.contains(&"b".to_string()));
1092 let leaves = collect_leaves_ext2(&tree);
1093 assert_eq!(leaves, vec!["a".to_string(), "b".to_string()]);
1094 }
1095 #[test]
1096 fn test_tree_height_ext2_and_contains() {
1097 let leaf = TreeNodeExt::leaf("x");
1098 assert_eq!(tree_height_ext2(&leaf), 0);
1099 let tree = TreeNodeExt::app(TreeNodeExt::leaf("a"), TreeNodeExt::leaf("b"));
1100 assert_eq!(tree_height_ext2(&tree), 1);
1101 assert!(contains_label_ext2(&tree, "a"));
1102 assert!(!contains_label_ext2(&tree, "z"));
1103 }
1104}
1105#[cfg(test)]
1106mod ast_impl_pad3 {
1107 use super::*;
1108 use crate::ast_impl::*;
1109 use crate::tokens::{Span, StringPart};
1110 #[test]
1111 fn test_tree_zipper() {
1112 let tree = TreeNodeExt::app(TreeNodeExt::leaf("a"), TreeNodeExt::leaf("b"));
1113 let z = TreeZipper::new(tree);
1114 assert_eq!(z.depth(), 0);
1115 let z2 = z.down(0).expect("test operation should succeed");
1116 assert_eq!(z2.depth(), 1);
1117 assert_eq!(z2.label(), "a");
1118 }
1119}