Skip to main content

oxilean_kernel/check/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::{Declaration, Environment, KernelError, TypeChecker};
6#[cfg(test)]
7use crate::{Expr, Name};
8
9use super::functions::*;
10use std::collections::HashMap;
11
12/// Configuration for declaration checking.
13///
14/// Controls what level of checking is performed and whether certain
15/// optional checks are enabled.
16#[derive(Debug, Clone)]
17pub struct CheckConfig {
18    /// Whether to check that the declared type is a sort.
19    pub check_type_is_sort: bool,
20    /// Whether to check that the value has the declared type.
21    pub check_value_type: bool,
22    /// Whether to check for free variables in the type and value.
23    pub check_no_free_vars: bool,
24    /// Maximum depth for type inference (0 = unlimited).
25    pub max_depth: u32,
26    /// Whether to allow axioms (false = proof-irrelevant mode).
27    pub allow_axioms: bool,
28}
29impl CheckConfig {
30    /// Create a new default configuration.
31    pub fn new() -> Self {
32        Self::default()
33    }
34    /// Create a lenient configuration that skips optional checks.
35    pub fn lenient() -> Self {
36        CheckConfig {
37            check_type_is_sort: true,
38            check_value_type: false,
39            check_no_free_vars: false,
40            max_depth: 0,
41            allow_axioms: true,
42        }
43    }
44    /// Create a strict configuration that enables all checks.
45    pub fn strict() -> Self {
46        CheckConfig {
47            check_type_is_sort: true,
48            check_value_type: true,
49            check_no_free_vars: true,
50            max_depth: 500,
51            allow_axioms: false,
52        }
53    }
54}
55/// A scope guard for temporarily adding declarations to an environment.
56///
57/// Useful for checking declarations in a hypothetical context (e.g., inside
58/// a `section` or `namespace`) without permanently mutating the environment.
59///
60/// NOTE: This struct borrows the environment mutably and removes the added
61/// declarations when dropped. This is a lightweight simulation for testing.
62pub struct TempEnvScope<'a> {
63    env: &'a mut Environment,
64    added_names: Vec<crate::Name>,
65}
66impl<'a> TempEnvScope<'a> {
67    /// Create a new temporary scope backed by `env`.
68    pub fn new(env: &'a mut Environment) -> Self {
69        TempEnvScope {
70            env,
71            added_names: Vec::new(),
72        }
73    }
74    /// Add a declaration to the scope. Returns `true` on success.
75    #[allow(clippy::result_large_err)]
76    pub fn add(&mut self, decl: Declaration) -> Result<(), KernelError> {
77        let name = decl.name().clone();
78        check_declaration(self.env, decl)?;
79        self.added_names.push(name);
80        Ok(())
81    }
82    /// Get a reference to the underlying environment.
83    pub fn env(&self) -> &Environment {
84        self.env
85    }
86    /// Get a mutable reference to the underlying environment.
87    pub fn env_mut(&mut self) -> &mut Environment {
88        self.env
89    }
90    /// Return the number of declarations added in this scope.
91    pub fn num_added(&self) -> usize {
92        self.added_names.len()
93    }
94}
95/// A window iterator that yields overlapping windows of size `n`.
96#[allow(dead_code)]
97pub struct WindowIterator<'a, T> {
98    pub(super) data: &'a [T],
99    pub(super) pos: usize,
100    pub(super) window: usize,
101}
102#[allow(dead_code)]
103impl<'a, T> WindowIterator<'a, T> {
104    /// Creates a new window iterator.
105    pub fn new(data: &'a [T], window: usize) -> Self {
106        Self {
107            data,
108            pos: 0,
109            window,
110        }
111    }
112}
113/// The kind of a declaration.
114#[derive(Debug, Clone, PartialEq, Eq)]
115pub enum DeclKind {
116    /// An axiom (assumed without proof).
117    Axiom,
118    /// A definition with a body.
119    Definition,
120    /// A theorem with a proof term.
121    Theorem,
122    /// An opaque definition (body not unfolded by default).
123    Opaque,
124}
125impl DeclKind {
126    /// Returns the string representation of the declaration kind.
127    pub fn as_str(&self) -> &'static str {
128        match self {
129            DeclKind::Axiom => "axiom",
130            DeclKind::Definition => "def",
131            DeclKind::Theorem => "theorem",
132            DeclKind::Opaque => "opaque",
133        }
134    }
135    /// Returns `true` if this kind represents a proven statement.
136    pub fn is_proven(&self) -> bool {
137        matches!(self, DeclKind::Theorem)
138    }
139    /// Returns `true` if this kind is assumed without proof.
140    pub fn is_assumed(&self) -> bool {
141        matches!(self, DeclKind::Axiom)
142    }
143    /// Returns `true` if this kind is a definition (has a body).
144    pub fn is_definition(&self) -> bool {
145        matches!(self, DeclKind::Definition | DeclKind::Opaque)
146    }
147}
148/// Statistics gathered during declaration checking.
149#[derive(Debug, Clone, Default)]
150pub struct CheckStats {
151    /// Number of axioms checked.
152    pub num_axioms: usize,
153    /// Number of definitions checked.
154    pub num_definitions: usize,
155    /// Number of theorems checked.
156    pub num_theorems: usize,
157    /// Number of opaque definitions checked.
158    pub num_opaques: usize,
159    /// Number of failures.
160    pub num_failures: usize,
161}
162impl CheckStats {
163    /// Create a new empty statistics record.
164    pub fn new() -> Self {
165        Self::default()
166    }
167    /// Total number of declarations processed (including failures).
168    pub fn total(&self) -> usize {
169        self.num_axioms + self.num_definitions + self.num_theorems + self.num_opaques
170    }
171    /// Total number of successful checks.
172    pub fn num_ok(&self) -> usize {
173        self.total()
174    }
175}
176/// A reusable scratch buffer for path computations.
177#[allow(dead_code)]
178pub struct PathBuf {
179    components: Vec<String>,
180}
181#[allow(dead_code)]
182impl PathBuf {
183    /// Creates a new empty path buffer.
184    pub fn new() -> Self {
185        Self {
186            components: Vec::new(),
187        }
188    }
189    /// Pushes a component.
190    pub fn push(&mut self, comp: impl Into<String>) {
191        self.components.push(comp.into());
192    }
193    /// Pops the last component.
194    pub fn pop(&mut self) {
195        self.components.pop();
196    }
197    /// Returns the current path as a `/`-separated string.
198    pub fn as_str(&self) -> String {
199        self.components.join("/")
200    }
201    /// Returns the depth of the path.
202    pub fn depth(&self) -> usize {
203        self.components.len()
204    }
205    /// Clears the path.
206    pub fn clear(&mut self) {
207        self.components.clear();
208    }
209}
210/// A set of rewrite rules.
211#[allow(dead_code)]
212pub struct RewriteRuleSet {
213    rules: Vec<RewriteRule>,
214}
215#[allow(dead_code)]
216impl RewriteRuleSet {
217    /// Creates an empty rule set.
218    pub fn new() -> Self {
219        Self { rules: Vec::new() }
220    }
221    /// Adds a rule.
222    pub fn add(&mut self, rule: RewriteRule) {
223        self.rules.push(rule);
224    }
225    /// Returns the number of rules.
226    pub fn len(&self) -> usize {
227        self.rules.len()
228    }
229    /// Returns `true` if the set is empty.
230    pub fn is_empty(&self) -> bool {
231        self.rules.is_empty()
232    }
233    /// Returns all conditional rules.
234    pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
235        self.rules.iter().filter(|r| r.conditional).collect()
236    }
237    /// Returns all unconditional rules.
238    pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
239        self.rules.iter().filter(|r| !r.conditional).collect()
240    }
241    /// Looks up a rule by name.
242    pub fn get(&self, name: &str) -> Option<&RewriteRule> {
243        self.rules.iter().find(|r| r.name == name)
244    }
245}
246/// A simple decision tree node for rule dispatching.
247#[allow(dead_code)]
248#[allow(missing_docs)]
249pub enum DecisionNode {
250    /// A leaf with an action string.
251    Leaf(String),
252    /// An interior node: check `key` equals `val` → `yes_branch`, else `no_branch`.
253    Branch {
254        key: String,
255        val: String,
256        yes_branch: Box<DecisionNode>,
257        no_branch: Box<DecisionNode>,
258    },
259}
260#[allow(dead_code)]
261impl DecisionNode {
262    /// Evaluates the decision tree with the given context.
263    pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
264        match self {
265            DecisionNode::Leaf(action) => action.as_str(),
266            DecisionNode::Branch {
267                key,
268                val,
269                yes_branch,
270                no_branch,
271            } => {
272                let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
273                if actual == val.as_str() {
274                    yes_branch.evaluate(ctx)
275                } else {
276                    no_branch.evaluate(ctx)
277                }
278            }
279        }
280    }
281    /// Returns the depth of the decision tree.
282    pub fn depth(&self) -> usize {
283        match self {
284            DecisionNode::Leaf(_) => 0,
285            DecisionNode::Branch {
286                yes_branch,
287                no_branch,
288                ..
289            } => 1 + yes_branch.depth().max(no_branch.depth()),
290        }
291    }
292}
293/// A tagged union for representing a simple two-case discriminated union.
294#[allow(dead_code)]
295pub enum Either2<A, B> {
296    /// The first alternative.
297    First(A),
298    /// The second alternative.
299    Second(B),
300}
301#[allow(dead_code)]
302impl<A, B> Either2<A, B> {
303    /// Returns `true` if this is the first alternative.
304    pub fn is_first(&self) -> bool {
305        matches!(self, Either2::First(_))
306    }
307    /// Returns `true` if this is the second alternative.
308    pub fn is_second(&self) -> bool {
309        matches!(self, Either2::Second(_))
310    }
311    /// Returns the first value if present.
312    pub fn first(self) -> Option<A> {
313        match self {
314            Either2::First(a) => Some(a),
315            _ => None,
316        }
317    }
318    /// Returns the second value if present.
319    pub fn second(self) -> Option<B> {
320        match self {
321            Either2::Second(b) => Some(b),
322            _ => None,
323        }
324    }
325    /// Maps over the first alternative.
326    pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
327        match self {
328            Either2::First(a) => Either2::First(f(a)),
329            Either2::Second(b) => Either2::Second(b),
330        }
331    }
332}
333/// Result of checking a batch of declarations.
334#[derive(Debug, Clone)]
335pub struct BatchCheckResult {
336    /// Number of declarations successfully checked.
337    pub num_ok: usize,
338    /// Number of declarations that failed.
339    pub num_failed: usize,
340    /// Errors encountered (name, error description).
341    pub errors: Vec<(String, String)>,
342}
343impl BatchCheckResult {
344    /// Returns `true` if all declarations passed.
345    pub fn all_ok(&self) -> bool {
346        self.num_failed == 0
347    }
348    /// Returns the total number of declarations processed.
349    pub fn total(&self) -> usize {
350        self.num_ok + self.num_failed
351    }
352    /// Returns an iterator over error messages.
353    pub fn error_messages(&self) -> impl Iterator<Item = String> + '_ {
354        self.errors
355            .iter()
356            .map(|(name, err)| format!("{}: {}", name, err))
357    }
358}
359/// A simple key-value store backed by a sorted Vec for small maps.
360#[allow(dead_code)]
361pub struct SmallMap<K: Ord + Clone, V: Clone> {
362    entries: Vec<(K, V)>,
363}
364#[allow(dead_code)]
365impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
366    /// Creates a new empty small map.
367    pub fn new() -> Self {
368        Self {
369            entries: Vec::new(),
370        }
371    }
372    /// Inserts or replaces the value for `key`.
373    pub fn insert(&mut self, key: K, val: V) {
374        match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
375            Ok(i) => self.entries[i].1 = val,
376            Err(i) => self.entries.insert(i, (key, val)),
377        }
378    }
379    /// Returns the value for `key`, or `None`.
380    pub fn get(&self, key: &K) -> Option<&V> {
381        self.entries
382            .binary_search_by_key(&key, |(k, _)| k)
383            .ok()
384            .map(|i| &self.entries[i].1)
385    }
386    /// Returns the number of entries.
387    pub fn len(&self) -> usize {
388        self.entries.len()
389    }
390    /// Returns `true` if empty.
391    pub fn is_empty(&self) -> bool {
392        self.entries.is_empty()
393    }
394    /// Returns all keys.
395    pub fn keys(&self) -> Vec<&K> {
396        self.entries.iter().map(|(k, _)| k).collect()
397    }
398    /// Returns all values.
399    pub fn values(&self) -> Vec<&V> {
400        self.entries.iter().map(|(_, v)| v).collect()
401    }
402}
403/// A summary of information about a declaration, useful for diagnostics.
404#[derive(Debug, Clone)]
405pub struct DeclSummary {
406    /// The name of the declaration.
407    pub name: String,
408    /// The kind of declaration.
409    pub kind: DeclKind,
410    /// Whether the declaration has a body/proof.
411    pub has_body: bool,
412    /// Number of universe parameters.
413    pub num_univ_params: usize,
414}
415/// A type-erased function pointer with arity tracking.
416#[allow(dead_code)]
417pub struct RawFnPtr {
418    /// The raw function pointer (stored as usize for type erasure).
419    ptr: usize,
420    arity: usize,
421    name: String,
422}
423#[allow(dead_code)]
424impl RawFnPtr {
425    /// Creates a new raw function pointer descriptor.
426    pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
427        Self {
428            ptr,
429            arity,
430            name: name.into(),
431        }
432    }
433    /// Returns the arity.
434    pub fn arity(&self) -> usize {
435        self.arity
436    }
437    /// Returns the name.
438    pub fn name(&self) -> &str {
439        &self.name
440    }
441    /// Returns the raw pointer value.
442    pub fn raw(&self) -> usize {
443        self.ptr
444    }
445}
446/// A token bucket rate limiter.
447#[allow(dead_code)]
448pub struct TokenBucket {
449    capacity: u64,
450    tokens: u64,
451    refill_per_ms: u64,
452    last_refill: std::time::Instant,
453}
454#[allow(dead_code)]
455impl TokenBucket {
456    /// Creates a new token bucket.
457    pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
458        Self {
459            capacity,
460            tokens: capacity,
461            refill_per_ms,
462            last_refill: std::time::Instant::now(),
463        }
464    }
465    /// Attempts to consume `n` tokens.  Returns `true` on success.
466    pub fn try_consume(&mut self, n: u64) -> bool {
467        self.refill();
468        if self.tokens >= n {
469            self.tokens -= n;
470            true
471        } else {
472            false
473        }
474    }
475    fn refill(&mut self) {
476        let now = std::time::Instant::now();
477        let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
478        if elapsed_ms > 0 {
479            let new_tokens = elapsed_ms * self.refill_per_ms;
480            self.tokens = (self.tokens + new_tokens).min(self.capacity);
481            self.last_refill = now;
482        }
483    }
484    /// Returns the number of currently available tokens.
485    pub fn available(&self) -> u64 {
486        self.tokens
487    }
488    /// Returns the bucket capacity.
489    pub fn capacity(&self) -> u64 {
490        self.capacity
491    }
492}
493/// A label set for a graph node.
494#[allow(dead_code)]
495pub struct LabelSet {
496    labels: Vec<String>,
497}
498#[allow(dead_code)]
499impl LabelSet {
500    /// Creates a new empty label set.
501    pub fn new() -> Self {
502        Self { labels: Vec::new() }
503    }
504    /// Adds a label (deduplicates).
505    pub fn add(&mut self, label: impl Into<String>) {
506        let s = label.into();
507        if !self.labels.contains(&s) {
508            self.labels.push(s);
509        }
510    }
511    /// Returns `true` if `label` is present.
512    pub fn has(&self, label: &str) -> bool {
513        self.labels.iter().any(|l| l == label)
514    }
515    /// Returns the count of labels.
516    pub fn count(&self) -> usize {
517        self.labels.len()
518    }
519    /// Returns all labels.
520    pub fn all(&self) -> &[String] {
521        &self.labels
522    }
523}
524/// A sparse vector: stores only non-default elements.
525#[allow(dead_code)]
526pub struct SparseVec<T: Default + Clone + PartialEq> {
527    entries: std::collections::HashMap<usize, T>,
528    default_: T,
529    logical_len: usize,
530}
531#[allow(dead_code)]
532impl<T: Default + Clone + PartialEq> SparseVec<T> {
533    /// Creates a new sparse vector with logical length `len`.
534    pub fn new(len: usize) -> Self {
535        Self {
536            entries: std::collections::HashMap::new(),
537            default_: T::default(),
538            logical_len: len,
539        }
540    }
541    /// Sets element at `idx`.
542    pub fn set(&mut self, idx: usize, val: T) {
543        if val == self.default_ {
544            self.entries.remove(&idx);
545        } else {
546            self.entries.insert(idx, val);
547        }
548    }
549    /// Gets element at `idx`.
550    pub fn get(&self, idx: usize) -> &T {
551        self.entries.get(&idx).unwrap_or(&self.default_)
552    }
553    /// Returns the logical length.
554    pub fn len(&self) -> usize {
555        self.logical_len
556    }
557    /// Returns whether the collection is empty.
558    pub fn is_empty(&self) -> bool {
559        self.len() == 0
560    }
561    /// Returns the number of non-default elements.
562    pub fn nnz(&self) -> usize {
563        self.entries.len()
564    }
565}
566/// A dependency closure builder (transitive closure via BFS).
567#[allow(dead_code)]
568pub struct TransitiveClosure {
569    adj: Vec<Vec<usize>>,
570    n: usize,
571}
572#[allow(dead_code)]
573impl TransitiveClosure {
574    /// Creates a transitive closure builder for `n` nodes.
575    pub fn new(n: usize) -> Self {
576        Self {
577            adj: vec![Vec::new(); n],
578            n,
579        }
580    }
581    /// Adds a direct edge.
582    pub fn add_edge(&mut self, from: usize, to: usize) {
583        if from < self.n {
584            self.adj[from].push(to);
585        }
586    }
587    /// Computes all nodes reachable from `start` (including `start`).
588    pub fn reachable_from(&self, start: usize) -> Vec<usize> {
589        let mut visited = vec![false; self.n];
590        let mut queue = std::collections::VecDeque::new();
591        queue.push_back(start);
592        while let Some(node) = queue.pop_front() {
593            if node >= self.n || visited[node] {
594                continue;
595            }
596            visited[node] = true;
597            for &next in &self.adj[node] {
598                queue.push_back(next);
599            }
600        }
601        (0..self.n).filter(|&i| visited[i]).collect()
602    }
603    /// Returns `true` if `from` can transitively reach `to`.
604    pub fn can_reach(&self, from: usize, to: usize) -> bool {
605        self.reachable_from(from).contains(&to)
606    }
607}
608/// A generic counter that tracks min/max/sum for statistical summaries.
609#[allow(dead_code)]
610pub struct StatSummary {
611    count: u64,
612    sum: f64,
613    min: f64,
614    max: f64,
615}
616#[allow(dead_code)]
617impl StatSummary {
618    /// Creates an empty summary.
619    pub fn new() -> Self {
620        Self {
621            count: 0,
622            sum: 0.0,
623            min: f64::INFINITY,
624            max: f64::NEG_INFINITY,
625        }
626    }
627    /// Records a sample.
628    pub fn record(&mut self, val: f64) {
629        self.count += 1;
630        self.sum += val;
631        if val < self.min {
632            self.min = val;
633        }
634        if val > self.max {
635            self.max = val;
636        }
637    }
638    /// Returns the mean, or `None` if no samples.
639    pub fn mean(&self) -> Option<f64> {
640        if self.count == 0 {
641            None
642        } else {
643            Some(self.sum / self.count as f64)
644        }
645    }
646    /// Returns the minimum, or `None` if no samples.
647    pub fn min(&self) -> Option<f64> {
648        if self.count == 0 {
649            None
650        } else {
651            Some(self.min)
652        }
653    }
654    /// Returns the maximum, or `None` if no samples.
655    pub fn max(&self) -> Option<f64> {
656        if self.count == 0 {
657            None
658        } else {
659            Some(self.max)
660        }
661    }
662    /// Returns the count of recorded samples.
663    pub fn count(&self) -> u64 {
664        self.count
665    }
666}
667/// A counter that can measure elapsed time between snapshots.
668#[allow(dead_code)]
669pub struct Stopwatch {
670    start: std::time::Instant,
671    splits: Vec<f64>,
672}
673#[allow(dead_code)]
674impl Stopwatch {
675    /// Creates and starts a new stopwatch.
676    pub fn start() -> Self {
677        Self {
678            start: std::time::Instant::now(),
679            splits: Vec::new(),
680        }
681    }
682    /// Records a split time (elapsed since start).
683    pub fn split(&mut self) {
684        self.splits.push(self.elapsed_ms());
685    }
686    /// Returns total elapsed milliseconds since start.
687    pub fn elapsed_ms(&self) -> f64 {
688        self.start.elapsed().as_secs_f64() * 1000.0
689    }
690    /// Returns all recorded split times.
691    pub fn splits(&self) -> &[f64] {
692        &self.splits
693    }
694    /// Returns the number of splits.
695    pub fn num_splits(&self) -> usize {
696        self.splits.len()
697    }
698}
699/// A mutable reference stack for tracking the current "focus" in a tree traversal.
700#[allow(dead_code)]
701pub struct FocusStack<T> {
702    items: Vec<T>,
703}
704#[allow(dead_code)]
705impl<T> FocusStack<T> {
706    /// Creates an empty focus stack.
707    pub fn new() -> Self {
708        Self { items: Vec::new() }
709    }
710    /// Focuses on `item`.
711    pub fn focus(&mut self, item: T) {
712        self.items.push(item);
713    }
714    /// Blurs (pops) the current focus.
715    pub fn blur(&mut self) -> Option<T> {
716        self.items.pop()
717    }
718    /// Returns the current focus, or `None`.
719    pub fn current(&self) -> Option<&T> {
720        self.items.last()
721    }
722    /// Returns the focus depth.
723    pub fn depth(&self) -> usize {
724        self.items.len()
725    }
726    /// Returns `true` if there is no current focus.
727    pub fn is_empty(&self) -> bool {
728        self.items.is_empty()
729    }
730}
731/// Well-formedness checking result for a declaration.
732#[derive(Debug, Clone, PartialEq, Eq)]
733pub enum WellFormedResult {
734    /// The declaration is well-formed.
735    Ok,
736    /// The declaration has a type that is not a sort.
737    TypeNotSort {
738        /// Description of the type-is-not-a-sort error.
739        description: String,
740    },
741    /// The value does not have the declared type.
742    TypeMismatch {
743        /// Description of the type mismatch.
744        description: String,
745    },
746    /// The declaration contains free variables.
747    FreeVariables {
748        /// Names of the free variables found.
749        vars: Vec<String>,
750    },
751    /// The name is already declared.
752    DuplicateName {
753        /// The duplicate name.
754        name: String,
755    },
756    /// Universe level inconsistency.
757    UniverseError {
758        /// Description of the universe error.
759        description: String,
760    },
761}
762impl WellFormedResult {
763    /// Returns `true` if the result indicates a well-formed declaration.
764    pub fn is_ok(&self) -> bool {
765        matches!(self, WellFormedResult::Ok)
766    }
767    /// Returns a human-readable description of the result.
768    pub fn description(&self) -> String {
769        match self {
770            WellFormedResult::Ok => "well-formed".to_string(),
771            WellFormedResult::TypeNotSort { description } => {
772                format!("type is not a sort: {}", description)
773            }
774            WellFormedResult::TypeMismatch { description } => {
775                format!("type mismatch: {}", description)
776            }
777            WellFormedResult::FreeVariables { vars } => {
778                format!("free variables: {}", vars.join(", "))
779            }
780            WellFormedResult::DuplicateName { name } => {
781                format!("duplicate declaration: {}", name)
782            }
783            WellFormedResult::UniverseError { description } => {
784                format!("universe error: {}", description)
785            }
786        }
787    }
788}
789/// A pool of reusable string buffers.
790#[allow(dead_code)]
791pub struct StringPool {
792    free: Vec<String>,
793}
794#[allow(dead_code)]
795impl StringPool {
796    /// Creates a new empty string pool.
797    pub fn new() -> Self {
798        Self { free: Vec::new() }
799    }
800    /// Takes a string from the pool (may be empty).
801    pub fn take(&mut self) -> String {
802        self.free.pop().unwrap_or_default()
803    }
804    /// Returns a string to the pool.
805    pub fn give(&mut self, mut s: String) {
806        s.clear();
807        self.free.push(s);
808    }
809    /// Returns the number of free strings in the pool.
810    pub fn free_count(&self) -> usize {
811        self.free.len()
812    }
813}
814/// A non-empty list (at least one element guaranteed).
815#[allow(dead_code)]
816pub struct NonEmptyVec<T> {
817    head: T,
818    tail: Vec<T>,
819}
820#[allow(dead_code)]
821impl<T> NonEmptyVec<T> {
822    /// Creates a non-empty vec with a single element.
823    pub fn singleton(val: T) -> Self {
824        Self {
825            head: val,
826            tail: Vec::new(),
827        }
828    }
829    /// Pushes an element.
830    pub fn push(&mut self, val: T) {
831        self.tail.push(val);
832    }
833    /// Returns a reference to the first element.
834    pub fn first(&self) -> &T {
835        &self.head
836    }
837    /// Returns a reference to the last element.
838    pub fn last(&self) -> &T {
839        self.tail.last().unwrap_or(&self.head)
840    }
841    /// Returns the number of elements.
842    pub fn len(&self) -> usize {
843        1 + self.tail.len()
844    }
845    /// Returns whether the collection is empty.
846    pub fn is_empty(&self) -> bool {
847        self.len() == 0
848    }
849    /// Returns all elements as a Vec.
850    pub fn to_vec(&self) -> Vec<&T> {
851        let mut v = vec![&self.head];
852        v.extend(self.tail.iter());
853        v
854    }
855}
856/// A pair of `StatSummary` values tracking before/after a transformation.
857#[allow(dead_code)]
858pub struct TransformStat {
859    before: StatSummary,
860    after: StatSummary,
861}
862#[allow(dead_code)]
863impl TransformStat {
864    /// Creates a new transform stat recorder.
865    pub fn new() -> Self {
866        Self {
867            before: StatSummary::new(),
868            after: StatSummary::new(),
869        }
870    }
871    /// Records a before value.
872    pub fn record_before(&mut self, v: f64) {
873        self.before.record(v);
874    }
875    /// Records an after value.
876    pub fn record_after(&mut self, v: f64) {
877        self.after.record(v);
878    }
879    /// Returns the mean reduction ratio (after/before).
880    pub fn mean_ratio(&self) -> Option<f64> {
881        let b = self.before.mean()?;
882        let a = self.after.mean()?;
883        if b.abs() < f64::EPSILON {
884            return None;
885        }
886        Some(a / b)
887    }
888}
889/// A fixed-size sliding window that computes a running sum.
890#[allow(dead_code)]
891pub struct SlidingSum {
892    window: Vec<f64>,
893    capacity: usize,
894    pos: usize,
895    sum: f64,
896    count: usize,
897}
898#[allow(dead_code)]
899impl SlidingSum {
900    /// Creates a sliding sum with the given window size.
901    pub fn new(capacity: usize) -> Self {
902        Self {
903            window: vec![0.0; capacity],
904            capacity,
905            pos: 0,
906            sum: 0.0,
907            count: 0,
908        }
909    }
910    /// Adds a value to the window, removing the oldest if full.
911    pub fn push(&mut self, val: f64) {
912        let oldest = self.window[self.pos];
913        self.sum -= oldest;
914        self.sum += val;
915        self.window[self.pos] = val;
916        self.pos = (self.pos + 1) % self.capacity;
917        if self.count < self.capacity {
918            self.count += 1;
919        }
920    }
921    /// Returns the current window sum.
922    pub fn sum(&self) -> f64 {
923        self.sum
924    }
925    /// Returns the window mean, or `None` if empty.
926    pub fn mean(&self) -> Option<f64> {
927        if self.count == 0 {
928            None
929        } else {
930            Some(self.sum / self.count as f64)
931        }
932    }
933    /// Returns the current window size (number of valid elements).
934    pub fn count(&self) -> usize {
935        self.count
936    }
937}
938/// Represents a rewrite rule `lhs → rhs`.
939#[allow(dead_code)]
940#[allow(missing_docs)]
941pub struct RewriteRule {
942    /// The name of the rule.
943    pub name: String,
944    /// A string representation of the LHS pattern.
945    pub lhs: String,
946    /// A string representation of the RHS.
947    pub rhs: String,
948    /// Whether this is a conditional rule (has side conditions).
949    pub conditional: bool,
950}
951#[allow(dead_code)]
952impl RewriteRule {
953    /// Creates an unconditional rewrite rule.
954    pub fn unconditional(
955        name: impl Into<String>,
956        lhs: impl Into<String>,
957        rhs: impl Into<String>,
958    ) -> Self {
959        Self {
960            name: name.into(),
961            lhs: lhs.into(),
962            rhs: rhs.into(),
963            conditional: false,
964        }
965    }
966    /// Creates a conditional rewrite rule.
967    pub fn conditional(
968        name: impl Into<String>,
969        lhs: impl Into<String>,
970        rhs: impl Into<String>,
971    ) -> Self {
972        Self {
973            name: name.into(),
974            lhs: lhs.into(),
975            rhs: rhs.into(),
976            conditional: true,
977        }
978    }
979    /// Returns a textual representation.
980    pub fn display(&self) -> String {
981        format!("{}: {} → {}", self.name, self.lhs, self.rhs)
982    }
983}
984/// A write-once cell.
985#[allow(dead_code)]
986pub struct WriteOnce<T> {
987    value: std::cell::Cell<Option<T>>,
988}
989#[allow(dead_code)]
990impl<T: Copy> WriteOnce<T> {
991    /// Creates an empty write-once cell.
992    pub fn new() -> Self {
993        Self {
994            value: std::cell::Cell::new(None),
995        }
996    }
997    /// Writes a value.  Returns `false` if already written.
998    pub fn write(&self, val: T) -> bool {
999        if self.value.get().is_some() {
1000            return false;
1001        }
1002        self.value.set(Some(val));
1003        true
1004    }
1005    /// Returns the value if written.
1006    pub fn read(&self) -> Option<T> {
1007        self.value.get()
1008    }
1009    /// Returns `true` if the value has been written.
1010    pub fn is_written(&self) -> bool {
1011        self.value.get().is_some()
1012    }
1013}
1014/// A builder that accumulates declarations and checks them together.
1015///
1016/// Useful for constructing a consistent environment from a sequence of
1017/// declarations, with error recovery.
1018#[derive(Default)]
1019pub struct EnvBuilder {
1020    env: Environment,
1021    stats: CheckStats,
1022    errors: Vec<(String, String)>,
1023}
1024impl EnvBuilder {
1025    /// Create a new empty builder.
1026    pub fn new() -> Self {
1027        Self::default()
1028    }
1029    /// Add a declaration to the builder, checking it against the current environment.
1030    pub fn add(&mut self, decl: Declaration) -> bool {
1031        let name = format!("{}", decl.name());
1032        let kind = summarize_declaration(&decl).kind;
1033        match check_declaration(&mut self.env, decl) {
1034            Ok(()) => {
1035                match kind {
1036                    DeclKind::Axiom => self.stats.num_axioms += 1,
1037                    DeclKind::Definition => self.stats.num_definitions += 1,
1038                    DeclKind::Theorem => self.stats.num_theorems += 1,
1039                    DeclKind::Opaque => self.stats.num_opaques += 1,
1040                }
1041                true
1042            }
1043            Err(e) => {
1044                self.stats.num_failures += 1;
1045                self.errors.push((name, format!("{:?}", e)));
1046                false
1047            }
1048        }
1049    }
1050    /// Add multiple declarations.
1051    pub fn add_all(&mut self, decls: Vec<Declaration>) -> usize {
1052        decls.into_iter().filter(|d| self.add(d.clone())).count()
1053    }
1054    /// Return the built environment (consuming the builder).
1055    pub fn build(self) -> (Environment, CheckStats, Vec<(String, String)>) {
1056        (self.env, self.stats, self.errors)
1057    }
1058    /// Return a reference to the current environment.
1059    pub fn env(&self) -> &Environment {
1060        &self.env
1061    }
1062    /// Return a reference to the current statistics.
1063    pub fn stats(&self) -> &CheckStats {
1064        &self.stats
1065    }
1066    /// Return a reference to the current errors.
1067    pub fn errors(&self) -> &[(String, String)] {
1068        &self.errors
1069    }
1070    /// Returns `true` if no errors have been encountered.
1071    pub fn is_clean(&self) -> bool {
1072        self.errors.is_empty()
1073    }
1074}
1075/// A flat list of substitution pairs `(from, to)`.
1076#[allow(dead_code)]
1077pub struct FlatSubstitution {
1078    pairs: Vec<(String, String)>,
1079}
1080#[allow(dead_code)]
1081impl FlatSubstitution {
1082    /// Creates an empty substitution.
1083    pub fn new() -> Self {
1084        Self { pairs: Vec::new() }
1085    }
1086    /// Adds a pair.
1087    pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
1088        self.pairs.push((from.into(), to.into()));
1089    }
1090    /// Applies all substitutions to `s` (leftmost-first order).
1091    pub fn apply(&self, s: &str) -> String {
1092        let mut result = s.to_string();
1093        for (from, to) in &self.pairs {
1094            result = result.replace(from.as_str(), to.as_str());
1095        }
1096        result
1097    }
1098    /// Returns the number of pairs.
1099    pub fn len(&self) -> usize {
1100        self.pairs.len()
1101    }
1102    /// Returns `true` if empty.
1103    pub fn is_empty(&self) -> bool {
1104        self.pairs.is_empty()
1105    }
1106}
1107/// A hierarchical configuration tree.
1108#[allow(dead_code)]
1109pub struct ConfigNode {
1110    key: String,
1111    value: Option<String>,
1112    children: Vec<ConfigNode>,
1113}
1114#[allow(dead_code)]
1115impl ConfigNode {
1116    /// Creates a leaf config node with a value.
1117    pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
1118        Self {
1119            key: key.into(),
1120            value: Some(value.into()),
1121            children: Vec::new(),
1122        }
1123    }
1124    /// Creates a section node with children.
1125    pub fn section(key: impl Into<String>) -> Self {
1126        Self {
1127            key: key.into(),
1128            value: None,
1129            children: Vec::new(),
1130        }
1131    }
1132    /// Adds a child node.
1133    pub fn add_child(&mut self, child: ConfigNode) {
1134        self.children.push(child);
1135    }
1136    /// Returns the key.
1137    pub fn key(&self) -> &str {
1138        &self.key
1139    }
1140    /// Returns the value, or `None` for section nodes.
1141    pub fn value(&self) -> Option<&str> {
1142        self.value.as_deref()
1143    }
1144    /// Returns the number of children.
1145    pub fn num_children(&self) -> usize {
1146        self.children.len()
1147    }
1148    /// Looks up a dot-separated path.
1149    pub fn lookup(&self, path: &str) -> Option<&str> {
1150        let mut parts = path.splitn(2, '.');
1151        let head = parts.next()?;
1152        let tail = parts.next();
1153        if head != self.key {
1154            return None;
1155        }
1156        match tail {
1157            None => self.value.as_deref(),
1158            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1159        }
1160    }
1161    fn lookup_relative(&self, path: &str) -> Option<&str> {
1162        let mut parts = path.splitn(2, '.');
1163        let head = parts.next()?;
1164        let tail = parts.next();
1165        if head != self.key {
1166            return None;
1167        }
1168        match tail {
1169            None => self.value.as_deref(),
1170            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1171        }
1172    }
1173}
1174/// A simple stack-based calculator for arithmetic expressions.
1175#[allow(dead_code)]
1176pub struct StackCalc {
1177    stack: Vec<i64>,
1178}
1179#[allow(dead_code)]
1180impl StackCalc {
1181    /// Creates a new empty calculator.
1182    pub fn new() -> Self {
1183        Self { stack: Vec::new() }
1184    }
1185    /// Pushes an integer literal.
1186    pub fn push(&mut self, n: i64) {
1187        self.stack.push(n);
1188    }
1189    /// Adds the top two values.  Panics if fewer than two values.
1190    pub fn add(&mut self) {
1191        let b = self
1192            .stack
1193            .pop()
1194            .expect("stack must have at least two values for add");
1195        let a = self
1196            .stack
1197            .pop()
1198            .expect("stack must have at least two values for add");
1199        self.stack.push(a + b);
1200    }
1201    /// Subtracts top from second.
1202    pub fn sub(&mut self) {
1203        let b = self
1204            .stack
1205            .pop()
1206            .expect("stack must have at least two values for sub");
1207        let a = self
1208            .stack
1209            .pop()
1210            .expect("stack must have at least two values for sub");
1211        self.stack.push(a - b);
1212    }
1213    /// Multiplies the top two values.
1214    pub fn mul(&mut self) {
1215        let b = self
1216            .stack
1217            .pop()
1218            .expect("stack must have at least two values for mul");
1219        let a = self
1220            .stack
1221            .pop()
1222            .expect("stack must have at least two values for mul");
1223        self.stack.push(a * b);
1224    }
1225    /// Peeks the top value.
1226    pub fn peek(&self) -> Option<i64> {
1227        self.stack.last().copied()
1228    }
1229    /// Returns the stack depth.
1230    pub fn depth(&self) -> usize {
1231        self.stack.len()
1232    }
1233}
1234/// A simple directed acyclic graph.
1235#[allow(dead_code)]
1236pub struct SimpleDag {
1237    /// `edges[i]` is the list of direct successors of node `i`.
1238    edges: Vec<Vec<usize>>,
1239}
1240#[allow(dead_code)]
1241impl SimpleDag {
1242    /// Creates a DAG with `n` nodes and no edges.
1243    pub fn new(n: usize) -> Self {
1244        Self {
1245            edges: vec![Vec::new(); n],
1246        }
1247    }
1248    /// Adds an edge from `from` to `to`.
1249    pub fn add_edge(&mut self, from: usize, to: usize) {
1250        if from < self.edges.len() {
1251            self.edges[from].push(to);
1252        }
1253    }
1254    /// Returns the successors of `node`.
1255    pub fn successors(&self, node: usize) -> &[usize] {
1256        self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1257    }
1258    /// Returns `true` if `from` can reach `to` via DFS.
1259    pub fn can_reach(&self, from: usize, to: usize) -> bool {
1260        let mut visited = vec![false; self.edges.len()];
1261        self.dfs(from, to, &mut visited)
1262    }
1263    fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
1264        if cur == target {
1265            return true;
1266        }
1267        if cur >= visited.len() || visited[cur] {
1268            return false;
1269        }
1270        visited[cur] = true;
1271        for &next in self.successors(cur) {
1272            if self.dfs(next, target, visited) {
1273                return true;
1274            }
1275        }
1276        false
1277    }
1278    /// Returns the topological order of nodes, or `None` if a cycle is detected.
1279    pub fn topological_sort(&self) -> Option<Vec<usize>> {
1280        let n = self.edges.len();
1281        let mut in_degree = vec![0usize; n];
1282        for succs in &self.edges {
1283            for &s in succs {
1284                if s < n {
1285                    in_degree[s] += 1;
1286                }
1287            }
1288        }
1289        let mut queue: std::collections::VecDeque<usize> =
1290            (0..n).filter(|&i| in_degree[i] == 0).collect();
1291        let mut order = Vec::new();
1292        while let Some(node) = queue.pop_front() {
1293            order.push(node);
1294            for &s in self.successors(node) {
1295                if s < n {
1296                    in_degree[s] -= 1;
1297                    if in_degree[s] == 0 {
1298                        queue.push_back(s);
1299                    }
1300                }
1301            }
1302        }
1303        if order.len() == n {
1304            Some(order)
1305        } else {
1306            None
1307        }
1308    }
1309    /// Returns the number of nodes.
1310    pub fn num_nodes(&self) -> usize {
1311        self.edges.len()
1312    }
1313}
1314/// A versioned record that stores a history of values.
1315#[allow(dead_code)]
1316pub struct VersionedRecord<T: Clone> {
1317    history: Vec<T>,
1318}
1319#[allow(dead_code)]
1320impl<T: Clone> VersionedRecord<T> {
1321    /// Creates a new record with an initial value.
1322    pub fn new(initial: T) -> Self {
1323        Self {
1324            history: vec![initial],
1325        }
1326    }
1327    /// Updates the record with a new version.
1328    pub fn update(&mut self, val: T) {
1329        self.history.push(val);
1330    }
1331    /// Returns the current (latest) value.
1332    pub fn current(&self) -> &T {
1333        self.history
1334            .last()
1335            .expect("VersionedRecord history is always non-empty after construction")
1336    }
1337    /// Returns the value at version `n` (0-indexed), or `None`.
1338    pub fn at_version(&self, n: usize) -> Option<&T> {
1339        self.history.get(n)
1340    }
1341    /// Returns the version number of the current value.
1342    pub fn version(&self) -> usize {
1343        self.history.len() - 1
1344    }
1345    /// Returns `true` if more than one version exists.
1346    pub fn has_history(&self) -> bool {
1347        self.history.len() > 1
1348    }
1349}