Skip to main content

oxilean_kernel/builtin/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::declaration::{
6    AxiomVal, ConstantInfo, ConstantVal, ConstructorVal, InductiveVal, RecursorRule, RecursorVal,
7};
8use crate::{BinderInfo, Declaration, Environment, Expr, Level, Name};
9
10use super::types::{
11    BuiltinInfo, BuiltinKind, ConfigNode, DecisionNode, Either2, FlatSubstitution, FocusStack,
12    LabelSet, NonEmptyVec, PathBuf, RewriteRule, RewriteRuleSet, SimpleDag, SlidingSum, SmallMap,
13    SparseVec, StackCalc, StatSummary, Stopwatch, StringPool, TokenBucket, TransformStat,
14    TransitiveClosure, VersionedRecord, WindowIterator, WriteOnce,
15};
16
17/// Initialize the environment with built-in types and axioms.
18pub fn init_builtin_env(env: &mut Environment) -> Result<(), String> {
19    add_legacy_axioms(env)?;
20    add_bool_inductive(env)?;
21    add_unit_inductive(env)?;
22    add_empty_inductive(env)?;
23    add_nat_inductive(env)?;
24    add_string_type(env)?;
25    add_core_axioms(env)?;
26    add_decidable_eq(env)?;
27    add_eq_inductive(env)?;
28    add_prod_inductive(env)?;
29    add_list_inductive(env)?;
30    Ok(())
31}
32/// Add legacy axiom declarations (backward compat).
33/// Uses the old flat-name convention.
34pub(super) fn add_legacy_axioms(env: &mut Environment) -> Result<(), String> {
35    let type0 = Expr::Sort(Level::zero());
36    let type1 = Expr::Sort(Level::succ(Level::zero()));
37    env.add(Declaration::Axiom {
38        name: Name::str("Bool"),
39        univ_params: vec![],
40        ty: type1.clone(),
41    })
42    .map_err(|e| e.to_string())?;
43    env.add(Declaration::Axiom {
44        name: Name::str("true"),
45        univ_params: vec![],
46        ty: Expr::Const(Name::str("Bool"), vec![]),
47    })
48    .map_err(|e| e.to_string())?;
49    env.add(Declaration::Axiom {
50        name: Name::str("false"),
51        univ_params: vec![],
52        ty: Expr::Const(Name::str("Bool"), vec![]),
53    })
54    .map_err(|e| e.to_string())?;
55    env.add(Declaration::Axiom {
56        name: Name::str("Unit"),
57        univ_params: vec![],
58        ty: type1,
59    })
60    .map_err(|e| e.to_string())?;
61    env.add(Declaration::Axiom {
62        name: Name::str("unit"),
63        univ_params: vec![],
64        ty: Expr::Const(Name::str("Unit"), vec![]),
65    })
66    .map_err(|e| e.to_string())?;
67    env.add(Declaration::Axiom {
68        name: Name::str("Empty"),
69        univ_params: vec![],
70        ty: type0.clone(),
71    })
72    .map_err(|e| e.to_string())?;
73    let rec_ty = Expr::Pi(
74        BinderInfo::Implicit,
75        Name::str("C"),
76        Box::new(type0),
77        Box::new(Expr::Pi(
78            BinderInfo::Default,
79            Name::str("_"),
80            Box::new(Expr::Const(Name::str("Empty"), vec![])),
81            Box::new(Expr::BVar(1)),
82        )),
83    );
84    env.add(Declaration::Axiom {
85        name: Name::str("Empty.rec"),
86        univ_params: vec![],
87        ty: rec_ty,
88    })
89    .map_err(|e| e.to_string())?;
90    Ok(())
91}
92/// Add Bool as a proper inductive type (ConstantInfo only, no legacy overlap).
93pub(super) fn add_bool_inductive(env: &mut Environment) -> Result<(), String> {
94    let type1 = Expr::Sort(Level::succ(Level::zero()));
95    let bool_const = Expr::Const(Name::str("Bool"), vec![]);
96    let ctor_true = ConstantInfo::Constructor(ConstructorVal {
97        common: ConstantVal {
98            name: Name::str("Bool.true"),
99            level_params: vec![],
100            ty: bool_const.clone(),
101        },
102        induct: Name::str("Bool"),
103        cidx: 0,
104        num_params: 0,
105        num_fields: 0,
106        is_unsafe: false,
107    });
108    let ctor_false = ConstantInfo::Constructor(ConstructorVal {
109        common: ConstantVal {
110            name: Name::str("Bool.false"),
111            level_params: vec![],
112            ty: bool_const,
113        },
114        induct: Name::str("Bool"),
115        cidx: 1,
116        num_params: 0,
117        num_fields: 0,
118        is_unsafe: false,
119    });
120    let ind = ConstantInfo::Inductive(InductiveVal {
121        common: ConstantVal {
122            name: Name::str("Bool.ind"),
123            level_params: vec![],
124            ty: type1,
125        },
126        num_params: 0,
127        num_indices: 0,
128        all: vec![Name::str("Bool")],
129        ctors: vec![Name::str("Bool.true"), Name::str("Bool.false")],
130        num_nested: 0,
131        is_rec: false,
132        is_unsafe: false,
133        is_reflexive: false,
134        is_prop: false,
135    });
136    let rec = ConstantInfo::Recursor(RecursorVal {
137        common: ConstantVal {
138            name: Name::str("Bool.rec"),
139            level_params: vec![Name::str("u_1")],
140            ty: Expr::Sort(Level::zero()),
141        },
142        all: vec![Name::str("Bool")],
143        num_params: 0,
144        num_indices: 0,
145        num_motives: 1,
146        num_minors: 2,
147        rules: vec![
148            RecursorRule {
149                ctor: Name::str("Bool.true"),
150                nfields: 0,
151                rhs: Expr::BVar(0),
152            },
153            RecursorRule {
154                ctor: Name::str("Bool.false"),
155                nfields: 0,
156                rhs: Expr::BVar(0),
157            },
158        ],
159        k: false,
160        is_unsafe: false,
161    });
162    env.add_constant(ind).map_err(|e| e.to_string())?;
163    env.add_constant(ctor_true).map_err(|e| e.to_string())?;
164    env.add_constant(ctor_false).map_err(|e| e.to_string())?;
165    env.add_constant(rec).map_err(|e| e.to_string())?;
166    Ok(())
167}
168/// Add Unit as a proper inductive type.
169pub(super) fn add_unit_inductive(env: &mut Environment) -> Result<(), String> {
170    let type1 = Expr::Sort(Level::succ(Level::zero()));
171    let unit_const = Expr::Const(Name::str("Unit"), vec![]);
172    let ind = ConstantInfo::Inductive(InductiveVal {
173        common: ConstantVal {
174            name: Name::str("Unit.ind"),
175            level_params: vec![],
176            ty: type1,
177        },
178        num_params: 0,
179        num_indices: 0,
180        all: vec![Name::str("Unit")],
181        ctors: vec![Name::str("Unit.unit")],
182        num_nested: 0,
183        is_rec: false,
184        is_unsafe: false,
185        is_reflexive: false,
186        is_prop: false,
187    });
188    let ctor = ConstantInfo::Constructor(ConstructorVal {
189        common: ConstantVal {
190            name: Name::str("Unit.unit"),
191            level_params: vec![],
192            ty: unit_const,
193        },
194        induct: Name::str("Unit"),
195        cidx: 0,
196        num_params: 0,
197        num_fields: 0,
198        is_unsafe: false,
199    });
200    let rec = ConstantInfo::Recursor(RecursorVal {
201        common: ConstantVal {
202            name: Name::str("Unit.rec"),
203            level_params: vec![Name::str("u_1")],
204            ty: Expr::Sort(Level::zero()),
205        },
206        all: vec![Name::str("Unit")],
207        num_params: 0,
208        num_indices: 0,
209        num_motives: 1,
210        num_minors: 1,
211        rules: vec![RecursorRule {
212            ctor: Name::str("Unit.unit"),
213            nfields: 0,
214            rhs: Expr::BVar(0),
215        }],
216        k: false,
217        is_unsafe: false,
218    });
219    env.add_constant(ind).map_err(|e| e.to_string())?;
220    env.add_constant(ctor).map_err(|e| e.to_string())?;
221    env.add_constant(rec).map_err(|e| e.to_string())?;
222    Ok(())
223}
224/// Add Empty as a proper inductive type (no constructors).
225pub(super) fn add_empty_inductive(env: &mut Environment) -> Result<(), String> {
226    let type0 = Expr::Sort(Level::zero());
227    let ind = ConstantInfo::Inductive(InductiveVal {
228        common: ConstantVal {
229            name: Name::str("Empty.ind"),
230            level_params: vec![],
231            ty: type0,
232        },
233        num_params: 0,
234        num_indices: 0,
235        all: vec![Name::str("Empty")],
236        ctors: vec![],
237        num_nested: 0,
238        is_rec: false,
239        is_unsafe: false,
240        is_reflexive: false,
241        is_prop: true,
242    });
243    env.add_constant(ind).map_err(|e| e.to_string())?;
244    Ok(())
245}
246/// Add Nat as a proper inductive type.
247pub(super) fn add_nat_inductive(env: &mut Environment) -> Result<(), String> {
248    let type1 = Expr::Sort(Level::succ(Level::zero()));
249    let nat_const = Expr::Const(Name::str("Nat"), vec![]);
250    let ind = ConstantInfo::Inductive(InductiveVal {
251        common: ConstantVal {
252            name: Name::str("Nat"),
253            level_params: vec![],
254            ty: type1,
255        },
256        num_params: 0,
257        num_indices: 0,
258        all: vec![Name::str("Nat")],
259        ctors: vec![Name::str("Nat.zero"), Name::str("Nat.succ")],
260        num_nested: 0,
261        is_rec: true,
262        is_unsafe: false,
263        is_reflexive: false,
264        is_prop: false,
265    });
266    let ctor_zero = ConstantInfo::Constructor(ConstructorVal {
267        common: ConstantVal {
268            name: Name::str("Nat.zero"),
269            level_params: vec![],
270            ty: nat_const.clone(),
271        },
272        induct: Name::str("Nat"),
273        cidx: 0,
274        num_params: 0,
275        num_fields: 0,
276        is_unsafe: false,
277    });
278    let succ_ty = Expr::Pi(
279        BinderInfo::Default,
280        Name::str("n"),
281        Box::new(nat_const.clone()),
282        Box::new(nat_const),
283    );
284    let ctor_succ = ConstantInfo::Constructor(ConstructorVal {
285        common: ConstantVal {
286            name: Name::str("Nat.succ"),
287            level_params: vec![],
288            ty: succ_ty,
289        },
290        induct: Name::str("Nat"),
291        cidx: 1,
292        num_params: 0,
293        num_fields: 1,
294        is_unsafe: false,
295    });
296    let rec = ConstantInfo::Recursor(RecursorVal {
297        common: ConstantVal {
298            name: Name::str("Nat.rec"),
299            level_params: vec![Name::str("u_1")],
300            ty: Expr::Sort(Level::zero()),
301        },
302        all: vec![Name::str("Nat")],
303        num_params: 0,
304        num_indices: 0,
305        num_motives: 1,
306        num_minors: 2,
307        rules: vec![
308            RecursorRule {
309                ctor: Name::str("Nat.zero"),
310                nfields: 0,
311                rhs: Expr::BVar(0),
312            },
313            RecursorRule {
314                ctor: Name::str("Nat.succ"),
315                nfields: 1,
316                rhs: Expr::BVar(0),
317            },
318        ],
319        k: false,
320        is_unsafe: false,
321    });
322    env.add_constant(ind).map_err(|e| e.to_string())?;
323    env.add_constant(ctor_zero).map_err(|e| e.to_string())?;
324    env.add_constant(ctor_succ).map_err(|e| e.to_string())?;
325    env.add_constant(rec).map_err(|e| e.to_string())?;
326    register_nat_ops(env)?;
327    Ok(())
328}
329/// Register built-in Nat arithmetic operations.
330pub(super) fn register_nat_ops(env: &mut Environment) -> Result<(), String> {
331    let nat = Expr::Const(Name::str("Nat"), vec![]);
332    let bool_ty = Expr::Const(Name::str("Bool"), vec![]);
333    let nat_binop = Expr::Pi(
334        BinderInfo::Default,
335        Name::str("a"),
336        Box::new(nat.clone()),
337        Box::new(Expr::Pi(
338            BinderInfo::Default,
339            Name::str("b"),
340            Box::new(nat.clone()),
341            Box::new(nat.clone()),
342        )),
343    );
344    let nat_cmp = Expr::Pi(
345        BinderInfo::Default,
346        Name::str("a"),
347        Box::new(nat.clone()),
348        Box::new(Expr::Pi(
349            BinderInfo::Default,
350            Name::str("b"),
351            Box::new(nat),
352            Box::new(bool_ty),
353        )),
354    );
355    let binop_names = [
356        "Nat.add",
357        "Nat.sub",
358        "Nat.mul",
359        "Nat.div",
360        "Nat.mod",
361        "Nat.pow",
362        "Nat.gcd",
363        "Nat.land",
364        "Nat.lor",
365        "Nat.xor",
366        "Nat.shiftLeft",
367        "Nat.shiftRight",
368    ];
369    for name in &binop_names {
370        env.add_constant(ConstantInfo::Axiom(AxiomVal {
371            common: ConstantVal {
372                name: Name::str(*name),
373                level_params: vec![],
374                ty: nat_binop.clone(),
375            },
376            is_unsafe: false,
377        }))
378        .map_err(|e| e.to_string())?;
379    }
380    let cmp_names = ["Nat.beq", "Nat.ble", "Nat.blt"];
381    for name in &cmp_names {
382        env.add_constant(ConstantInfo::Axiom(AxiomVal {
383            common: ConstantVal {
384                name: Name::str(*name),
385                level_params: vec![],
386                ty: nat_cmp.clone(),
387            },
388            is_unsafe: false,
389        }))
390        .map_err(|e| e.to_string())?;
391    }
392    Ok(())
393}
394/// Add the String type.
395pub(super) fn add_string_type(env: &mut Environment) -> Result<(), String> {
396    let type1 = Expr::Sort(Level::succ(Level::zero()));
397    let str_ty = Expr::Const(Name::str("String"), vec![]);
398    let nat_ty = Expr::Const(Name::str("Nat"), vec![]);
399    let bool_ty = Expr::Const(Name::str("Bool"), vec![]);
400    env.add_constant(ConstantInfo::Axiom(AxiomVal {
401        common: ConstantVal {
402            name: Name::str("String"),
403            level_params: vec![],
404            ty: type1,
405        },
406        is_unsafe: false,
407    }))
408    .map_err(|e| e.to_string())?;
409    env.add_constant(ConstantInfo::Axiom(AxiomVal {
410        common: ConstantVal {
411            name: Name::str("String.length"),
412            level_params: vec![],
413            ty: Expr::Pi(
414                BinderInfo::Default,
415                Name::str("s"),
416                Box::new(str_ty.clone()),
417                Box::new(nat_ty),
418            ),
419        },
420        is_unsafe: false,
421    }))
422    .map_err(|e| e.to_string())?;
423    env.add_constant(ConstantInfo::Axiom(AxiomVal {
424        common: ConstantVal {
425            name: Name::str("String.append"),
426            level_params: vec![],
427            ty: Expr::Pi(
428                BinderInfo::Default,
429                Name::str("a"),
430                Box::new(str_ty.clone()),
431                Box::new(Expr::Pi(
432                    BinderInfo::Default,
433                    Name::str("b"),
434                    Box::new(str_ty.clone()),
435                    Box::new(str_ty.clone()),
436                )),
437            ),
438        },
439        is_unsafe: false,
440    }))
441    .map_err(|e| e.to_string())?;
442    env.add_constant(ConstantInfo::Axiom(AxiomVal {
443        common: ConstantVal {
444            name: Name::str("String.beq"),
445            level_params: vec![],
446            ty: Expr::Pi(
447                BinderInfo::Default,
448                Name::str("a"),
449                Box::new(str_ty.clone()),
450                Box::new(Expr::Pi(
451                    BinderInfo::Default,
452                    Name::str("b"),
453                    Box::new(str_ty),
454                    Box::new(bool_ty),
455                )),
456            ),
457        },
458        is_unsafe: false,
459    }))
460    .map_err(|e| e.to_string())?;
461    Ok(())
462}
463/// Add core logical axioms.
464pub(super) fn add_core_axioms(env: &mut Environment) -> Result<(), String> {
465    let type0 = Expr::Sort(Level::zero());
466    let propext_ty = Expr::Pi(
467        BinderInfo::Implicit,
468        Name::str("a"),
469        Box::new(type0.clone()),
470        Box::new(Expr::Pi(
471            BinderInfo::Implicit,
472            Name::str("b"),
473            Box::new(type0.clone()),
474            Box::new(type0.clone()),
475        )),
476    );
477    env.add_constant(ConstantInfo::Axiom(AxiomVal {
478        common: ConstantVal {
479            name: Name::str("propext"),
480            level_params: vec![],
481            ty: propext_ty,
482        },
483        is_unsafe: false,
484    }))
485    .map_err(|e| e.to_string())?;
486    let quot_ty = Expr::Pi(
487        BinderInfo::Implicit,
488        Name::str("α"),
489        Box::new(Expr::Sort(Level::param(Name::str("u")))),
490        Box::new(Expr::Pi(
491            BinderInfo::Default,
492            Name::str("r"),
493            Box::new(type0.clone()),
494            Box::new(Expr::Sort(Level::param(Name::str("u")))),
495        )),
496    );
497    env.add_constant(ConstantInfo::Axiom(AxiomVal {
498        common: ConstantVal {
499            name: Name::str("Quot"),
500            level_params: vec![Name::str("u")],
501            ty: quot_ty,
502        },
503        is_unsafe: false,
504    }))
505    .map_err(|e| e.to_string())?;
506    let choice_ty = Expr::Pi(
507        BinderInfo::Implicit,
508        Name::str("α"),
509        Box::new(Expr::Sort(Level::param(Name::str("u")))),
510        Box::new(Expr::Pi(
511            BinderInfo::Default,
512            Name::str("_"),
513            Box::new(type0),
514            Box::new(Expr::BVar(1)),
515        )),
516    );
517    env.add_constant(ConstantInfo::Axiom(AxiomVal {
518        common: ConstantVal {
519            name: Name::str("Classical.choice"),
520            level_params: vec![Name::str("u")],
521            ty: choice_ty,
522        },
523        is_unsafe: false,
524    }))
525    .map_err(|e| e.to_string())?;
526    Ok(())
527}
528/// Add decidable equality.
529pub(super) fn add_decidable_eq(env: &mut Environment) -> Result<(), String> {
530    let type1 = Expr::Sort(Level::succ(Level::zero()));
531    let type0 = Expr::Sort(Level::zero());
532    let decidable_eq_ty = Expr::Pi(
533        BinderInfo::Default,
534        Name::str("α"),
535        Box::new(type1.clone()),
536        Box::new(type0),
537    );
538    env.add(Declaration::Axiom {
539        name: Name::str("DecidableEq"),
540        univ_params: vec![],
541        ty: decidable_eq_ty,
542    })
543    .map_err(|e| e.to_string())?;
544    let decide_ty = Expr::Pi(
545        BinderInfo::Implicit,
546        Name::str("α"),
547        Box::new(type1),
548        Box::new(Expr::Pi(
549            BinderInfo::InstImplicit,
550            Name::str("_"),
551            Box::new(Expr::App(
552                Box::new(Expr::Const(Name::str("DecidableEq"), vec![])),
553                Box::new(Expr::BVar(0)),
554            )),
555            Box::new(Expr::Pi(
556                BinderInfo::Default,
557                Name::str("a"),
558                Box::new(Expr::BVar(1)),
559                Box::new(Expr::Pi(
560                    BinderInfo::Default,
561                    Name::str("b"),
562                    Box::new(Expr::BVar(2)),
563                    Box::new(Expr::Const(Name::str("Bool"), vec![])),
564                )),
565            )),
566        )),
567    );
568    env.add(Declaration::Axiom {
569        name: Name::str("DecidableEq.decide"),
570        univ_params: vec![],
571        ty: decide_ty,
572    })
573    .map_err(|e| e.to_string())?;
574    Ok(())
575}
576/// Add Eq (propositional equality) as a proper inductive type.
577///
578/// ```text
579/// inductive Eq.{u} : {α : Sort u} → α → α → Prop where
580///   | refl : ∀ {α : Sort u} (a : α), Eq a a
581/// ```
582pub(super) fn add_eq_inductive(env: &mut Environment) -> Result<(), String> {
583    let u = Level::param(Name::str("u"));
584    let prop = Expr::Sort(Level::zero());
585    let sort_u = Expr::Sort(u.clone());
586    let eq_ty = Expr::Pi(
587        BinderInfo::Implicit,
588        Name::str("α"),
589        Box::new(sort_u.clone()),
590        Box::new(Expr::Pi(
591            BinderInfo::Default,
592            Name::str("a"),
593            Box::new(Expr::BVar(0)),
594            Box::new(Expr::Pi(
595                BinderInfo::Default,
596                Name::str("b"),
597                Box::new(Expr::BVar(1)),
598                Box::new(prop.clone()),
599            )),
600        )),
601    );
602    let ind = ConstantInfo::Inductive(InductiveVal {
603        common: ConstantVal {
604            name: Name::str("Eq"),
605            level_params: vec![Name::str("u")],
606            ty: eq_ty,
607        },
608        num_params: 1,
609        num_indices: 2,
610        all: vec![Name::str("Eq")],
611        ctors: vec![Name::str("Eq.refl")],
612        num_nested: 0,
613        is_rec: false,
614        is_unsafe: false,
615        is_reflexive: false,
616        is_prop: true,
617    });
618    let eq_refl_ty = Expr::Pi(
619        BinderInfo::Implicit,
620        Name::str("α"),
621        Box::new(sort_u),
622        Box::new(Expr::Pi(
623            BinderInfo::Default,
624            Name::str("a"),
625            Box::new(Expr::BVar(0)),
626            Box::new(Expr::App(
627                Box::new(Expr::App(
628                    Box::new(Expr::App(
629                        Box::new(Expr::Const(Name::str("Eq"), vec![u.clone()])),
630                        Box::new(Expr::BVar(1)),
631                    )),
632                    Box::new(Expr::BVar(0)),
633                )),
634                Box::new(Expr::BVar(0)),
635            )),
636        )),
637    );
638    let ctor_refl = ConstantInfo::Constructor(ConstructorVal {
639        common: ConstantVal {
640            name: Name::str("Eq.refl"),
641            level_params: vec![Name::str("u")],
642            ty: eq_refl_ty,
643        },
644        induct: Name::str("Eq"),
645        cidx: 0,
646        num_params: 1,
647        num_fields: 1,
648        is_unsafe: false,
649    });
650    let rec = ConstantInfo::Recursor(RecursorVal {
651        common: ConstantVal {
652            name: Name::str("Eq.rec"),
653            level_params: vec![Name::str("u"), Name::str("v")],
654            ty: prop.clone(),
655        },
656        all: vec![Name::str("Eq")],
657        num_params: 1,
658        num_indices: 2,
659        num_motives: 1,
660        num_minors: 1,
661        rules: vec![RecursorRule {
662            ctor: Name::str("Eq.refl"),
663            nfields: 1,
664            rhs: Expr::BVar(0),
665        }],
666        k: true,
667        is_unsafe: false,
668    });
669    env.add_constant(ind).map_err(|e| e.to_string())?;
670    env.add_constant(ctor_refl).map_err(|e| e.to_string())?;
671    env.add_constant(rec).map_err(|e| e.to_string())?;
672    Ok(())
673}
674/// Add Prod (dependent pair / product type) as a proper inductive type.
675///
676/// ```text
677/// structure Prod.{u, v} (α : Type u) (β : Type v) : Type (max u v) where
678///   | mk : α → β → Prod α β
679/// ```
680pub(super) fn add_prod_inductive(env: &mut Environment) -> Result<(), String> {
681    let u = Level::param(Name::str("u"));
682    let v = Level::param(Name::str("v"));
683    let type_u = Expr::Sort(Level::succ(u.clone()));
684    let type_v = Expr::Sort(Level::succ(v.clone()));
685    let type_max = Expr::Sort(Level::succ(Level::max(u.clone(), v.clone())));
686    let prod_ty = Expr::Pi(
687        BinderInfo::Default,
688        Name::str("α"),
689        Box::new(type_u.clone()),
690        Box::new(Expr::Pi(
691            BinderInfo::Default,
692            Name::str("β"),
693            Box::new(type_v.clone()),
694            Box::new(type_max),
695        )),
696    );
697    let ind = ConstantInfo::Inductive(InductiveVal {
698        common: ConstantVal {
699            name: Name::str("Prod"),
700            level_params: vec![Name::str("u"), Name::str("v")],
701            ty: prod_ty,
702        },
703        num_params: 2,
704        num_indices: 0,
705        all: vec![Name::str("Prod")],
706        ctors: vec![Name::str("Prod.mk")],
707        num_nested: 0,
708        is_rec: false,
709        is_unsafe: false,
710        is_reflexive: false,
711        is_prop: false,
712    });
713    let prod_mk_ty = Expr::Pi(
714        BinderInfo::Implicit,
715        Name::str("α"),
716        Box::new(type_u),
717        Box::new(Expr::Pi(
718            BinderInfo::Implicit,
719            Name::str("β"),
720            Box::new(type_v),
721            Box::new(Expr::Pi(
722                BinderInfo::Default,
723                Name::str("fst"),
724                Box::new(Expr::BVar(1)),
725                Box::new(Expr::Pi(
726                    BinderInfo::Default,
727                    Name::str("snd"),
728                    Box::new(Expr::BVar(1)),
729                    Box::new(Expr::App(
730                        Box::new(Expr::App(
731                            Box::new(Expr::Const(Name::str("Prod"), vec![u.clone(), v.clone()])),
732                            Box::new(Expr::BVar(3)),
733                        )),
734                        Box::new(Expr::BVar(2)),
735                    )),
736                )),
737            )),
738        )),
739    );
740    let ctor_mk = ConstantInfo::Constructor(ConstructorVal {
741        common: ConstantVal {
742            name: Name::str("Prod.mk"),
743            level_params: vec![Name::str("u"), Name::str("v")],
744            ty: prod_mk_ty,
745        },
746        induct: Name::str("Prod"),
747        cidx: 0,
748        num_params: 2,
749        num_fields: 2,
750        is_unsafe: false,
751    });
752    let rec = ConstantInfo::Recursor(RecursorVal {
753        common: ConstantVal {
754            name: Name::str("Prod.rec"),
755            level_params: vec![Name::str("u"), Name::str("v"), Name::str("w")],
756            ty: Expr::Sort(Level::zero()),
757        },
758        all: vec![Name::str("Prod")],
759        num_params: 2,
760        num_indices: 0,
761        num_motives: 1,
762        num_minors: 1,
763        rules: vec![RecursorRule {
764            ctor: Name::str("Prod.mk"),
765            nfields: 2,
766            rhs: Expr::BVar(0),
767        }],
768        k: false,
769        is_unsafe: false,
770    });
771    env.add_constant(ind).map_err(|e| e.to_string())?;
772    env.add_constant(ctor_mk).map_err(|e| e.to_string())?;
773    env.add_constant(rec).map_err(|e| e.to_string())?;
774    Ok(())
775}
776/// Add List as a proper inductive type.
777///
778/// ```text
779/// inductive List.{u} (α : Type u) : Type u where
780///   | nil : List α
781///   | cons : α → List α → List α
782/// ```
783pub(super) fn add_list_inductive(env: &mut Environment) -> Result<(), String> {
784    let u = Level::param(Name::str("u"));
785    let type_u = Expr::Sort(Level::succ(u.clone()));
786    let list_bvar0 = Expr::App(
787        Box::new(Expr::Const(Name::str("List"), vec![u.clone()])),
788        Box::new(Expr::BVar(0)),
789    );
790    let list_ty = Expr::Pi(
791        BinderInfo::Default,
792        Name::str("α"),
793        Box::new(type_u.clone()),
794        Box::new(type_u.clone()),
795    );
796    let ind = ConstantInfo::Inductive(InductiveVal {
797        common: ConstantVal {
798            name: Name::str("List"),
799            level_params: vec![Name::str("u")],
800            ty: list_ty,
801        },
802        num_params: 1,
803        num_indices: 0,
804        all: vec![Name::str("List")],
805        ctors: vec![Name::str("List.nil"), Name::str("List.cons")],
806        num_nested: 0,
807        is_rec: true,
808        is_unsafe: false,
809        is_reflexive: false,
810        is_prop: false,
811    });
812    let nil_ty = Expr::Pi(
813        BinderInfo::Implicit,
814        Name::str("α"),
815        Box::new(type_u.clone()),
816        Box::new(list_bvar0.clone()),
817    );
818    let ctor_nil = ConstantInfo::Constructor(ConstructorVal {
819        common: ConstantVal {
820            name: Name::str("List.nil"),
821            level_params: vec![Name::str("u")],
822            ty: nil_ty,
823        },
824        induct: Name::str("List"),
825        cidx: 0,
826        num_params: 1,
827        num_fields: 0,
828        is_unsafe: false,
829    });
830    let cons_ty = Expr::Pi(
831        BinderInfo::Implicit,
832        Name::str("α"),
833        Box::new(type_u),
834        Box::new(Expr::Pi(
835            BinderInfo::Default,
836            Name::str("head"),
837            Box::new(Expr::BVar(0)),
838            Box::new(Expr::Pi(
839                BinderInfo::Default,
840                Name::str("tail"),
841                Box::new(list_bvar0.clone()),
842                Box::new(list_bvar0),
843            )),
844        )),
845    );
846    let ctor_cons = ConstantInfo::Constructor(ConstructorVal {
847        common: ConstantVal {
848            name: Name::str("List.cons"),
849            level_params: vec![Name::str("u")],
850            ty: cons_ty,
851        },
852        induct: Name::str("List"),
853        cidx: 1,
854        num_params: 1,
855        num_fields: 2,
856        is_unsafe: false,
857    });
858    let rec = ConstantInfo::Recursor(RecursorVal {
859        common: ConstantVal {
860            name: Name::str("List.rec"),
861            level_params: vec![Name::str("u"), Name::str("v")],
862            ty: Expr::Sort(Level::zero()),
863        },
864        all: vec![Name::str("List")],
865        num_params: 1,
866        num_indices: 0,
867        num_motives: 1,
868        num_minors: 2,
869        rules: vec![
870            RecursorRule {
871                ctor: Name::str("List.nil"),
872                nfields: 0,
873                rhs: Expr::BVar(0),
874            },
875            RecursorRule {
876                ctor: Name::str("List.cons"),
877                nfields: 2,
878                rhs: Expr::BVar(0),
879            },
880        ],
881        k: false,
882        is_unsafe: false,
883    });
884    env.add_constant(ind).map_err(|e| e.to_string())?;
885    env.add_constant(ctor_nil).map_err(|e| e.to_string())?;
886    env.add_constant(ctor_cons).map_err(|e| e.to_string())?;
887    env.add_constant(rec).map_err(|e| e.to_string())?;
888    Ok(())
889}
890/// Check if a name is a built-in primitive.
891pub fn is_builtin(name: &Name) -> bool {
892    let s = name.to_string();
893    matches!(
894        s.as_str(),
895        "Bool"
896            | "Bool.ind"
897            | "Bool.true"
898            | "Bool.false"
899            | "Bool.rec"
900            | "true"
901            | "false"
902            | "Unit"
903            | "Unit.ind"
904            | "Unit.unit"
905            | "Unit.rec"
906            | "unit"
907            | "Empty"
908            | "Empty.ind"
909            | "Empty.rec"
910            | "Nat"
911            | "Nat.zero"
912            | "Nat.succ"
913            | "Nat.rec"
914            | "String"
915            | "DecidableEq"
916            | "DecidableEq.decide"
917            | "propext"
918            | "Quot"
919            | "Classical.choice"
920    )
921}
922/// Check if a name is a built-in Nat operation.
923pub fn is_nat_op(name: &Name) -> bool {
924    let s = name.to_string();
925    matches!(
926        s.as_str(),
927        "Nat.add"
928            | "Nat.sub"
929            | "Nat.mul"
930            | "Nat.div"
931            | "Nat.mod"
932            | "Nat.pow"
933            | "Nat.gcd"
934            | "Nat.beq"
935            | "Nat.ble"
936            | "Nat.blt"
937            | "Nat.land"
938            | "Nat.lor"
939            | "Nat.xor"
940            | "Nat.shiftLeft"
941            | "Nat.shiftRight"
942    )
943}
944/// Check if a name is a built-in String operation.
945pub fn is_string_op(name: &Name) -> bool {
946    let s = name.to_string();
947    matches!(s.as_str(), "String.length" | "String.append" | "String.beq")
948}
949#[cfg(test)]
950mod tests {
951    use super::*;
952    #[test]
953    fn test_init_builtin_env() {
954        let mut env = Environment::new();
955        assert!(init_builtin_env(&mut env).is_ok());
956        assert!(env.get(&Name::str("Bool")).is_some());
957        assert!(env.get(&Name::str("true")).is_some());
958        assert!(env.get(&Name::str("false")).is_some());
959        assert!(env.get(&Name::str("Unit")).is_some());
960        assert!(env.get(&Name::str("unit")).is_some());
961        assert!(env.get(&Name::str("Empty")).is_some());
962    }
963    #[test]
964    fn test_bool_axioms() {
965        let mut env = Environment::new();
966        init_builtin_env(&mut env).expect("value should be present");
967        let bool_decl = env
968            .get(&Name::str("Bool"))
969            .expect("bool_decl should be present");
970        assert!(matches!(bool_decl, Declaration::Axiom { .. }));
971        let true_decl = env
972            .get(&Name::str("true"))
973            .expect("true_decl should be present");
974        assert!(matches!(true_decl, Declaration::Axiom { .. }));
975    }
976    #[test]
977    fn test_unit_axioms() {
978        let mut env = Environment::new();
979        init_builtin_env(&mut env).expect("value should be present");
980        let unit_decl = env
981            .get(&Name::str("Unit"))
982            .expect("unit_decl should be present");
983        assert!(matches!(unit_decl, Declaration::Axiom { .. }));
984        let unit_val = env
985            .get(&Name::str("unit"))
986            .expect("unit_val should be present");
987        assert!(matches!(unit_val, Declaration::Axiom { .. }));
988    }
989    #[test]
990    fn test_empty_axioms() {
991        let mut env = Environment::new();
992        init_builtin_env(&mut env).expect("value should be present");
993        let empty_decl = env
994            .get(&Name::str("Empty"))
995            .expect("empty_decl should be present");
996        assert!(matches!(empty_decl, Declaration::Axiom { .. }));
997        let rec_decl = env
998            .get(&Name::str("Empty.rec"))
999            .expect("rec_decl should be present");
1000        assert!(matches!(rec_decl, Declaration::Axiom { .. }));
1001    }
1002    #[test]
1003    fn test_decidable_eq() {
1004        let mut env = Environment::new();
1005        init_builtin_env(&mut env).expect("value should be present");
1006        let dec_eq = env
1007            .get(&Name::str("DecidableEq"))
1008            .expect("dec_eq should be present");
1009        assert!(matches!(dec_eq, Declaration::Axiom { .. }));
1010        let decide = env
1011            .get(&Name::str("DecidableEq.decide"))
1012            .expect("decide should be present");
1013        assert!(matches!(decide, Declaration::Axiom { .. }));
1014    }
1015    #[test]
1016    fn test_is_builtin() {
1017        assert!(is_builtin(&Name::str("Bool")));
1018        assert!(is_builtin(&Name::str("true")));
1019        assert!(is_builtin(&Name::str("Unit")));
1020        assert!(is_builtin(&Name::str("Nat")));
1021        assert!(is_builtin(&Name::str("String")));
1022        assert!(!is_builtin(&Name::str("CustomType")));
1023    }
1024    #[test]
1025    fn test_bool_inductive() {
1026        let mut env = Environment::new();
1027        init_builtin_env(&mut env).expect("value should be present");
1028        assert!(env.is_constructor(&Name::str("Bool.true")));
1029        assert!(env.is_constructor(&Name::str("Bool.false")));
1030        assert!(env.is_recursor(&Name::str("Bool.rec")));
1031    }
1032    #[test]
1033    fn test_nat_inductive() {
1034        let mut env = Environment::new();
1035        init_builtin_env(&mut env).expect("value should be present");
1036        assert!(env.is_inductive(&Name::str("Nat")));
1037        assert!(env.is_constructor(&Name::str("Nat.zero")));
1038        assert!(env.is_constructor(&Name::str("Nat.succ")));
1039        assert!(env.is_recursor(&Name::str("Nat.rec")));
1040    }
1041    #[test]
1042    fn test_nat_ops_registered() {
1043        let mut env = Environment::new();
1044        init_builtin_env(&mut env).expect("value should be present");
1045        assert!(env.find(&Name::str("Nat.add")).is_some());
1046        assert!(env.find(&Name::str("Nat.mul")).is_some());
1047        assert!(env.find(&Name::str("Nat.sub")).is_some());
1048        assert!(env.find(&Name::str("Nat.div")).is_some());
1049        assert!(env.find(&Name::str("Nat.beq")).is_some());
1050    }
1051    #[test]
1052    fn test_string_ops_registered() {
1053        let mut env = Environment::new();
1054        init_builtin_env(&mut env).expect("value should be present");
1055        assert!(env.find(&Name::str("String")).is_some());
1056        assert!(env.find(&Name::str("String.length")).is_some());
1057        assert!(env.find(&Name::str("String.append")).is_some());
1058        assert!(env.find(&Name::str("String.beq")).is_some());
1059    }
1060    #[test]
1061    fn test_core_axioms_registered() {
1062        let mut env = Environment::new();
1063        init_builtin_env(&mut env).expect("value should be present");
1064        assert!(env.find(&Name::str("propext")).is_some());
1065        assert!(env.find(&Name::str("Quot")).is_some());
1066        assert!(env.find(&Name::str("Classical.choice")).is_some());
1067    }
1068    #[test]
1069    fn test_is_nat_op() {
1070        assert!(is_nat_op(&Name::str("Nat.add")));
1071        assert!(is_nat_op(&Name::str("Nat.mul")));
1072        assert!(is_nat_op(&Name::str("Nat.gcd")));
1073        assert!(!is_nat_op(&Name::str("Nat.zero")));
1074    }
1075    #[test]
1076    fn test_is_string_op() {
1077        assert!(is_string_op(&Name::str("String.length")));
1078        assert!(is_string_op(&Name::str("String.append")));
1079        assert!(!is_string_op(&Name::str("String")));
1080    }
1081}
1082/// Classify a name into its `BuiltinKind`.
1083#[allow(dead_code)]
1084pub fn classify_builtin(name: &Name) -> BuiltinKind {
1085    let s = name.to_string();
1086    if is_nat_op(name) {
1087        return BuiltinKind::ArithOp;
1088    }
1089    if is_string_op(name) {
1090        return BuiltinKind::StringOp;
1091    }
1092    match s.as_str() {
1093        "Bool" | "Unit" | "Empty" | "Nat" | "String" => BuiltinKind::Type,
1094        "Bool.true" | "Bool.false" | "Unit.unit" | "Nat.zero" | "Nat.succ" | "true" | "false"
1095        | "unit" => BuiltinKind::Constructor,
1096        "Bool.rec" | "Unit.rec" | "Nat.rec" | "Empty.rec" => BuiltinKind::Recursor,
1097        "propext" | "Quot" | "Classical.choice" => BuiltinKind::Axiom,
1098        "Nat.beq" | "Nat.ble" | "Nat.blt" => BuiltinKind::CmpOp,
1099        "DecidableEq" | "DecidableEq.decide" => BuiltinKind::TypeClass,
1100        _ => BuiltinKind::Unknown,
1101    }
1102}
1103/// Check whether a name is a core logical connective.
1104#[allow(dead_code)]
1105pub fn is_logical_connective(name: &Name) -> bool {
1106    let s = name.to_string();
1107    matches!(
1108        s.as_str(),
1109        "And" | "Or" | "Not" | "Iff" | "True" | "False" | "Exists"
1110    )
1111}
1112/// Check whether a name is a primitive value (not a type).
1113#[allow(dead_code)]
1114pub fn is_primitive_value(name: &Name) -> bool {
1115    let s = name.to_string();
1116    matches!(
1117        s.as_str(),
1118        "true" | "false" | "unit" | "Bool.true" | "Bool.false" | "Unit.unit" | "Nat.zero"
1119    )
1120}
1121/// Return the universe level of a builtin type (0 = Prop, 1 = Typeâ‚€).
1122#[allow(dead_code)]
1123pub fn builtin_universe_level(name: &Name) -> Option<u32> {
1124    let s = name.to_string();
1125    match s.as_str() {
1126        "Empty" => Some(0),
1127        "Bool" | "Unit" | "Nat" | "String" => Some(1),
1128        _ => None,
1129    }
1130}
1131/// Return the number of constructors for a builtin inductive type.
1132#[allow(dead_code)]
1133pub fn builtin_ctor_count(name: &Name) -> Option<usize> {
1134    let s = name.to_string();
1135    match s.as_str() {
1136        "Bool" => Some(2),
1137        "Unit" => Some(1),
1138        "Empty" => Some(0),
1139        "Nat" => Some(2),
1140        _ => None,
1141    }
1142}
1143/// Check whether a builtin type is recursive.
1144#[allow(dead_code)]
1145pub fn builtin_is_recursive(name: &Name) -> bool {
1146    name.to_string() == "Nat"
1147}
1148/// Check whether a builtin type is in Prop.
1149#[allow(dead_code)]
1150pub fn builtin_is_prop(name: &Name) -> bool {
1151    let s = name.to_string();
1152    matches!(s.as_str(), "Empty" | "True" | "False")
1153}
1154/// Get the full list of all builtin names.
1155#[allow(dead_code)]
1156pub fn all_builtin_names() -> Vec<&'static str> {
1157    vec![
1158        "Bool",
1159        "Bool.ind",
1160        "Bool.true",
1161        "Bool.false",
1162        "Bool.rec",
1163        "true",
1164        "false",
1165        "Unit",
1166        "Unit.ind",
1167        "Unit.unit",
1168        "Unit.rec",
1169        "unit",
1170        "Empty",
1171        "Empty.ind",
1172        "Empty.rec",
1173        "Nat",
1174        "Nat.zero",
1175        "Nat.succ",
1176        "Nat.rec",
1177        "Nat.add",
1178        "Nat.sub",
1179        "Nat.mul",
1180        "Nat.div",
1181        "Nat.mod",
1182        "Nat.pow",
1183        "Nat.gcd",
1184        "Nat.beq",
1185        "Nat.ble",
1186        "Nat.blt",
1187        "Nat.land",
1188        "Nat.lor",
1189        "Nat.xor",
1190        "Nat.shiftLeft",
1191        "Nat.shiftRight",
1192        "String",
1193        "String.length",
1194        "String.append",
1195        "String.beq",
1196        "propext",
1197        "Quot",
1198        "Classical.choice",
1199        "DecidableEq",
1200        "DecidableEq.decide",
1201    ]
1202}
1203/// Count the total number of builtin names.
1204#[allow(dead_code)]
1205pub fn builtin_count() -> usize {
1206    all_builtin_names().len()
1207}
1208/// Check if all builtin names are registered in an environment.
1209#[allow(dead_code)]
1210pub fn verify_builtins(env: &Environment) -> Vec<&'static str> {
1211    all_builtin_names()
1212        .into_iter()
1213        .filter(|n| env.find(&Name::str(*n)).is_none() && env.get(&Name::str(*n)).is_none())
1214        .collect()
1215}
1216/// Return the Lean 4 equivalent name for a builtin OxiLean name.
1217#[allow(dead_code)]
1218pub fn lean4_name(name: &Name) -> Option<&'static str> {
1219    let s = name.to_string();
1220    match s.as_str() {
1221        "Bool.true" => Some("Bool.true"),
1222        "Bool.false" => Some("Bool.false"),
1223        "true" => Some("Bool.true"),
1224        "false" => Some("Bool.false"),
1225        "unit" => Some("Unit.unit"),
1226        "Nat.zero" => Some("Nat.zero"),
1227        "Nat.succ" => Some("Nat.succ"),
1228        _ => None,
1229    }
1230}
1231/// Return info for all core builtin types.
1232#[allow(dead_code)]
1233pub fn core_builtin_infos() -> Vec<BuiltinInfo> {
1234    vec![
1235        BuiltinInfo {
1236            name: "Bool",
1237            kind: BuiltinKind::Type,
1238            description: "Boolean type",
1239        },
1240        BuiltinInfo {
1241            name: "Unit",
1242            kind: BuiltinKind::Type,
1243            description: "Unit type (single-element)",
1244        },
1245        BuiltinInfo {
1246            name: "Empty",
1247            kind: BuiltinKind::Type,
1248            description: "Empty type (no elements)",
1249        },
1250        BuiltinInfo {
1251            name: "Nat",
1252            kind: BuiltinKind::Type,
1253            description: "Natural numbers",
1254        },
1255        BuiltinInfo {
1256            name: "String",
1257            kind: BuiltinKind::Type,
1258            description: "Unicode string type",
1259        },
1260        BuiltinInfo {
1261            name: "propext",
1262            kind: BuiltinKind::Axiom,
1263            description: "Propositional extensionality",
1264        },
1265        BuiltinInfo {
1266            name: "Quot",
1267            kind: BuiltinKind::Axiom,
1268            description: "Quotient type constructor",
1269        },
1270        BuiltinInfo {
1271            name: "Classical.choice",
1272            kind: BuiltinKind::Axiom,
1273            description: "Classical choice axiom",
1274        },
1275    ]
1276}
1277#[cfg(test)]
1278mod extended_builtin_tests {
1279    use super::*;
1280    #[test]
1281    fn test_classify_builtin_type() {
1282        assert_eq!(classify_builtin(&Name::str("Bool")), BuiltinKind::Type);
1283        assert_eq!(classify_builtin(&Name::str("Nat")), BuiltinKind::Type);
1284    }
1285    #[test]
1286    fn test_classify_builtin_ctor() {
1287        assert_eq!(
1288            classify_builtin(&Name::str("Bool.true")),
1289            BuiltinKind::Constructor
1290        );
1291        assert_eq!(
1292            classify_builtin(&Name::str("Nat.zero")),
1293            BuiltinKind::Constructor
1294        );
1295    }
1296    #[test]
1297    fn test_classify_builtin_arith() {
1298        assert_eq!(
1299            classify_builtin(&Name::str("Nat.add")),
1300            BuiltinKind::ArithOp
1301        );
1302        assert_eq!(
1303            classify_builtin(&Name::str("Nat.mul")),
1304            BuiltinKind::ArithOp
1305        );
1306    }
1307    #[test]
1308    fn test_classify_builtin_axiom() {
1309        assert_eq!(classify_builtin(&Name::str("propext")), BuiltinKind::Axiom);
1310        assert_eq!(
1311            classify_builtin(&Name::str("Classical.choice")),
1312            BuiltinKind::Axiom
1313        );
1314    }
1315    #[test]
1316    fn test_classify_builtin_unknown() {
1317        assert_eq!(
1318            classify_builtin(&Name::str("CustomThing")),
1319            BuiltinKind::Unknown
1320        );
1321    }
1322    #[test]
1323    fn test_is_primitive_value() {
1324        assert!(is_primitive_value(&Name::str("true")));
1325        assert!(is_primitive_value(&Name::str("false")));
1326        assert!(is_primitive_value(&Name::str("unit")));
1327        assert!(!is_primitive_value(&Name::str("Nat")));
1328    }
1329    #[test]
1330    fn test_builtin_universe_level() {
1331        assert_eq!(builtin_universe_level(&Name::str("Empty")), Some(0));
1332        assert_eq!(builtin_universe_level(&Name::str("Bool")), Some(1));
1333        assert_eq!(builtin_universe_level(&Name::str("CustomType")), None);
1334    }
1335    #[test]
1336    fn test_builtin_ctor_count() {
1337        assert_eq!(builtin_ctor_count(&Name::str("Bool")), Some(2));
1338        assert_eq!(builtin_ctor_count(&Name::str("Empty")), Some(0));
1339        assert_eq!(builtin_ctor_count(&Name::str("Unit")), Some(1));
1340    }
1341    #[test]
1342    fn test_builtin_is_recursive() {
1343        assert!(builtin_is_recursive(&Name::str("Nat")));
1344        assert!(!builtin_is_recursive(&Name::str("Bool")));
1345    }
1346    #[test]
1347    fn test_builtin_is_prop() {
1348        assert!(builtin_is_prop(&Name::str("Empty")));
1349        assert!(!builtin_is_prop(&Name::str("Nat")));
1350    }
1351    #[test]
1352    fn test_all_builtin_names_nonempty() {
1353        assert!(!all_builtin_names().is_empty());
1354        assert!(builtin_count() > 20);
1355    }
1356    #[test]
1357    fn test_core_builtin_infos() {
1358        let infos = core_builtin_infos();
1359        assert!(!infos.is_empty());
1360        assert!(infos.iter().any(|i| i.name == "Bool"));
1361    }
1362    #[test]
1363    fn test_builtin_kind_description() {
1364        assert_eq!(BuiltinKind::Type.description(), "primitive type");
1365        assert_eq!(BuiltinKind::Axiom.description(), "logical axiom");
1366        assert_eq!(BuiltinKind::Unknown.description(), "not a builtin");
1367    }
1368    #[test]
1369    fn test_lean4_name() {
1370        assert_eq!(lean4_name(&Name::str("true")), Some("Bool.true"));
1371        assert_eq!(lean4_name(&Name::str("unit")), Some("Unit.unit"));
1372        assert_eq!(lean4_name(&Name::str("CustomFn")), None);
1373    }
1374    #[test]
1375    fn test_verify_builtins() {
1376        let mut env = Environment::new();
1377        init_builtin_env(&mut env).expect("value should be present");
1378        let missing = verify_builtins(&env);
1379        assert!(missing.len() < 15);
1380    }
1381    #[test]
1382    fn test_is_logical_connective() {
1383        assert!(is_logical_connective(&Name::str("And")));
1384        assert!(is_logical_connective(&Name::str("Or")));
1385        assert!(is_logical_connective(&Name::str("Iff")));
1386        assert!(!is_logical_connective(&Name::str("Nat")));
1387    }
1388}
1389#[cfg(test)]
1390mod tests_padding_infra {
1391    use super::*;
1392    #[test]
1393    fn test_stat_summary() {
1394        let mut ss = StatSummary::new();
1395        ss.record(10.0);
1396        ss.record(20.0);
1397        ss.record(30.0);
1398        assert_eq!(ss.count(), 3);
1399        assert!((ss.mean().expect("mean should succeed") - 20.0).abs() < 1e-9);
1400        assert_eq!(ss.min().expect("min should succeed") as i64, 10);
1401        assert_eq!(ss.max().expect("max should succeed") as i64, 30);
1402    }
1403    #[test]
1404    fn test_transform_stat() {
1405        let mut ts = TransformStat::new();
1406        ts.record_before(100.0);
1407        ts.record_after(80.0);
1408        let ratio = ts.mean_ratio().expect("ratio should be present");
1409        assert!((ratio - 0.8).abs() < 1e-9);
1410    }
1411    #[test]
1412    fn test_small_map() {
1413        let mut m: SmallMap<u32, &str> = SmallMap::new();
1414        m.insert(3, "three");
1415        m.insert(1, "one");
1416        m.insert(2, "two");
1417        assert_eq!(m.get(&2), Some(&"two"));
1418        assert_eq!(m.len(), 3);
1419        let keys = m.keys();
1420        assert_eq!(*keys[0], 1);
1421        assert_eq!(*keys[2], 3);
1422    }
1423    #[test]
1424    fn test_label_set() {
1425        let mut ls = LabelSet::new();
1426        ls.add("foo");
1427        ls.add("bar");
1428        ls.add("foo");
1429        assert_eq!(ls.count(), 2);
1430        assert!(ls.has("bar"));
1431        assert!(!ls.has("baz"));
1432    }
1433    #[test]
1434    fn test_config_node() {
1435        let mut root = ConfigNode::section("root");
1436        let child = ConfigNode::leaf("key", "value");
1437        root.add_child(child);
1438        assert_eq!(root.num_children(), 1);
1439    }
1440    #[test]
1441    fn test_versioned_record() {
1442        let mut vr = VersionedRecord::new(0u32);
1443        vr.update(1);
1444        vr.update(2);
1445        assert_eq!(*vr.current(), 2);
1446        assert_eq!(vr.version(), 2);
1447        assert!(vr.has_history());
1448        assert_eq!(*vr.at_version(0).expect("value should be present"), 0);
1449    }
1450    #[test]
1451    fn test_simple_dag() {
1452        let mut dag = SimpleDag::new(4);
1453        dag.add_edge(0, 1);
1454        dag.add_edge(1, 2);
1455        dag.add_edge(2, 3);
1456        assert!(dag.can_reach(0, 3));
1457        assert!(!dag.can_reach(3, 0));
1458        let order = dag.topological_sort().expect("order should be present");
1459        assert_eq!(order, vec![0, 1, 2, 3]);
1460    }
1461    #[test]
1462    fn test_focus_stack() {
1463        let mut fs: FocusStack<&str> = FocusStack::new();
1464        fs.focus("a");
1465        fs.focus("b");
1466        assert_eq!(fs.current(), Some(&"b"));
1467        assert_eq!(fs.depth(), 2);
1468        fs.blur();
1469        assert_eq!(fs.current(), Some(&"a"));
1470    }
1471}
1472#[cfg(test)]
1473mod tests_extra_iterators {
1474    use super::*;
1475    #[test]
1476    fn test_window_iterator() {
1477        let data = vec![1u32, 2, 3, 4, 5];
1478        let windows: Vec<_> = WindowIterator::new(&data, 3).collect();
1479        assert_eq!(windows.len(), 3);
1480        assert_eq!(windows[0], &[1, 2, 3]);
1481        assert_eq!(windows[2], &[3, 4, 5]);
1482    }
1483    #[test]
1484    fn test_non_empty_vec() {
1485        let mut nev = NonEmptyVec::singleton(10u32);
1486        nev.push(20);
1487        nev.push(30);
1488        assert_eq!(nev.len(), 3);
1489        assert_eq!(*nev.first(), 10);
1490        assert_eq!(*nev.last(), 30);
1491    }
1492}
1493#[cfg(test)]
1494mod tests_padding2 {
1495    use super::*;
1496    #[test]
1497    fn test_sliding_sum() {
1498        let mut ss = SlidingSum::new(3);
1499        ss.push(1.0);
1500        ss.push(2.0);
1501        ss.push(3.0);
1502        assert!((ss.sum() - 6.0).abs() < 1e-9);
1503        ss.push(4.0);
1504        assert!((ss.sum() - 9.0).abs() < 1e-9);
1505        assert_eq!(ss.count(), 3);
1506    }
1507    #[test]
1508    fn test_path_buf() {
1509        let mut pb = PathBuf::new();
1510        pb.push("src");
1511        pb.push("main");
1512        assert_eq!(pb.as_str(), "src/main");
1513        assert_eq!(pb.depth(), 2);
1514        pb.pop();
1515        assert_eq!(pb.as_str(), "src");
1516    }
1517    #[test]
1518    fn test_string_pool() {
1519        let mut pool = StringPool::new();
1520        let s = pool.take();
1521        assert!(s.is_empty());
1522        pool.give("hello".to_string());
1523        let s2 = pool.take();
1524        assert!(s2.is_empty());
1525        assert_eq!(pool.free_count(), 0);
1526    }
1527    #[test]
1528    fn test_transitive_closure() {
1529        let mut tc = TransitiveClosure::new(4);
1530        tc.add_edge(0, 1);
1531        tc.add_edge(1, 2);
1532        tc.add_edge(2, 3);
1533        assert!(tc.can_reach(0, 3));
1534        assert!(!tc.can_reach(3, 0));
1535        let r = tc.reachable_from(0);
1536        assert_eq!(r.len(), 4);
1537    }
1538    #[test]
1539    fn test_token_bucket() {
1540        let mut tb = TokenBucket::new(100, 10);
1541        assert_eq!(tb.available(), 100);
1542        assert!(tb.try_consume(50));
1543        assert_eq!(tb.available(), 50);
1544        assert!(!tb.try_consume(60));
1545        assert_eq!(tb.capacity(), 100);
1546    }
1547    #[test]
1548    fn test_rewrite_rule_set() {
1549        let mut rrs = RewriteRuleSet::new();
1550        rrs.add(RewriteRule::unconditional(
1551            "beta",
1552            "App(Lam(x, b), v)",
1553            "b[x:=v]",
1554        ));
1555        rrs.add(RewriteRule::conditional("comm", "a + b", "b + a"));
1556        assert_eq!(rrs.len(), 2);
1557        assert_eq!(rrs.unconditional_rules().len(), 1);
1558        assert_eq!(rrs.conditional_rules().len(), 1);
1559        assert!(rrs.get("beta").is_some());
1560        let disp = rrs
1561            .get("beta")
1562            .expect("element at \'beta\' should exist")
1563            .display();
1564        assert!(disp.contains("→"));
1565    }
1566}
1567#[cfg(test)]
1568mod tests_padding3 {
1569    use super::*;
1570    #[test]
1571    fn test_decision_node() {
1572        let tree = DecisionNode::Branch {
1573            key: "x".into(),
1574            val: "1".into(),
1575            yes_branch: Box::new(DecisionNode::Leaf("yes".into())),
1576            no_branch: Box::new(DecisionNode::Leaf("no".into())),
1577        };
1578        let mut ctx = std::collections::HashMap::new();
1579        ctx.insert("x".into(), "1".into());
1580        assert_eq!(tree.evaluate(&ctx), "yes");
1581        ctx.insert("x".into(), "2".into());
1582        assert_eq!(tree.evaluate(&ctx), "no");
1583        assert_eq!(tree.depth(), 1);
1584    }
1585    #[test]
1586    fn test_flat_substitution() {
1587        let mut sub = FlatSubstitution::new();
1588        sub.add("foo", "bar");
1589        sub.add("baz", "qux");
1590        assert_eq!(sub.apply("foo and baz"), "bar and qux");
1591        assert_eq!(sub.len(), 2);
1592    }
1593    #[test]
1594    fn test_stopwatch() {
1595        let mut sw = Stopwatch::start();
1596        sw.split();
1597        sw.split();
1598        assert_eq!(sw.num_splits(), 2);
1599        assert!(sw.elapsed_ms() >= 0.0);
1600        for &s in sw.splits() {
1601            assert!(s >= 0.0);
1602        }
1603    }
1604    #[test]
1605    fn test_either2() {
1606        let e: Either2<i32, &str> = Either2::First(42);
1607        assert!(e.is_first());
1608        let mapped = e.map_first(|x| x * 2);
1609        assert_eq!(mapped.first(), Some(84));
1610        let e2: Either2<i32, &str> = Either2::Second("hello");
1611        assert!(e2.is_second());
1612        assert_eq!(e2.second(), Some("hello"));
1613    }
1614    #[test]
1615    fn test_write_once() {
1616        let wo: WriteOnce<u32> = WriteOnce::new();
1617        assert!(!wo.is_written());
1618        assert!(wo.write(42));
1619        assert!(!wo.write(99));
1620        assert_eq!(wo.read(), Some(42));
1621    }
1622    #[test]
1623    fn test_sparse_vec() {
1624        let mut sv: SparseVec<i32> = SparseVec::new(100);
1625        sv.set(5, 10);
1626        sv.set(50, 20);
1627        assert_eq!(*sv.get(5), 10);
1628        assert_eq!(*sv.get(50), 20);
1629        assert_eq!(*sv.get(0), 0);
1630        assert_eq!(sv.nnz(), 2);
1631        sv.set(5, 0);
1632        assert_eq!(sv.nnz(), 1);
1633    }
1634    #[test]
1635    fn test_stack_calc() {
1636        let mut calc = StackCalc::new();
1637        calc.push(3);
1638        calc.push(4);
1639        calc.add();
1640        assert_eq!(calc.peek(), Some(7));
1641        calc.push(2);
1642        calc.mul();
1643        assert_eq!(calc.peek(), Some(14));
1644    }
1645}