Skip to main content

oxilean_kernel/prettyprint/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use std::collections::{HashMap, VecDeque};
6use std::fmt;
7use std::fmt::Write as FmtWrite;
8
9use super::functions::*;
10use crate::{BinderInfo, Expr, Level, LevelView, Name};
11
12/// Pretty printer for kernel expressions.
13pub struct ExprPrinter {
14    /// Output buffer
15    buffer: String,
16    /// Print configuration
17    pub(super) config: PrintConfig,
18}
19impl ExprPrinter {
20    /// Create a new expression printer with default config.
21    pub fn new() -> Self {
22        Self {
23            buffer: String::new(),
24            config: PrintConfig::default(),
25        }
26    }
27    /// Create a printer with a specific configuration.
28    pub fn with_config(config: PrintConfig) -> Self {
29        Self {
30            buffer: String::new(),
31            config,
32        }
33    }
34    /// Set whether to use unicode symbols.
35    pub fn with_unicode(mut self, unicode: bool) -> Self {
36        self.config.unicode = unicode;
37        self
38    }
39    /// Get the output.
40    pub fn output(self) -> String {
41        self.buffer
42    }
43    /// Print an expression.
44    pub fn print(&mut self, expr: &Expr) -> fmt::Result {
45        self.print_expr(expr, 0)
46    }
47    fn print_expr(&mut self, expr: &Expr, prec: u32) -> fmt::Result {
48        match expr {
49            Expr::Sort(level) => self.print_sort(level),
50            Expr::BVar(idx) => {
51                if self.config.show_indices {
52                    write!(self.buffer, "#{}", idx)
53                } else {
54                    write!(self.buffer, "_")
55                }
56            }
57            Expr::FVar(fvar) => write!(self.buffer, "@{}", fvar.0),
58            Expr::Const(name, levels) => {
59                self.print_name(name)?;
60                if self.config.show_universes && !levels.is_empty() {
61                    write!(self.buffer, ".{{")?;
62                    for (i, level) in levels.iter().enumerate() {
63                        if i > 0 {
64                            write!(self.buffer, ", ")?;
65                        }
66                        self.print_level(level)?;
67                    }
68                    write!(self.buffer, "}}")?;
69                }
70                Ok(())
71            }
72            Expr::App(fun, arg) => {
73                let (head, args) = collect_app_args(expr);
74                if args.len() > 1 {
75                    if prec > 10 {
76                        write!(self.buffer, "(")?;
77                    }
78                    self.print_expr(head, 10)?;
79                    for a in &args {
80                        write!(self.buffer, " ")?;
81                        self.print_expr(a, 11)?;
82                    }
83                    if prec > 10 {
84                        write!(self.buffer, ")")?;
85                    }
86                    Ok(())
87                } else {
88                    if prec > 10 {
89                        write!(self.buffer, "(")?;
90                    }
91                    self.print_expr(fun, 10)?;
92                    write!(self.buffer, " ")?;
93                    self.print_expr(arg, 11)?;
94                    if prec > 10 {
95                        write!(self.buffer, ")")?;
96                    }
97                    Ok(())
98                }
99            }
100            Expr::Lam(bi, name, ty, body) => {
101                if prec > 0 {
102                    write!(self.buffer, "(")?;
103                }
104                if self.config.unicode {
105                    write!(self.buffer, "λ ")?;
106                } else {
107                    write!(self.buffer, "fun ")?;
108                }
109                self.print_binder(*bi, name, ty)?;
110                let mut current_body = body.as_ref();
111                while let Expr::Lam(bi2, name2, ty2, body2) = current_body {
112                    write!(self.buffer, " ")?;
113                    self.print_binder(*bi2, name2, ty2)?;
114                    current_body = body2;
115                }
116                if self.config.unicode {
117                    write!(self.buffer, ", ")?;
118                } else {
119                    write!(self.buffer, " => ")?;
120                }
121                self.print_expr(current_body, 0)?;
122                if prec > 0 {
123                    write!(self.buffer, ")")?;
124                }
125                Ok(())
126            }
127            Expr::Pi(bi, name, ty, body) => {
128                if prec > 0 {
129                    write!(self.buffer, "(")?;
130                }
131                if name.is_anonymous() || *name == Name::str("_") {
132                    self.print_expr(ty, 25)?;
133                    if self.config.unicode {
134                        write!(self.buffer, " → ")?;
135                    } else {
136                        write!(self.buffer, " -> ")?;
137                    }
138                    self.print_expr(body, 24)?;
139                } else {
140                    if self.config.unicode {
141                        write!(self.buffer, "∀ ")?;
142                    } else {
143                        write!(self.buffer, "forall ")?;
144                    }
145                    self.print_binder(*bi, name, ty)?;
146                    let mut current_body = body.as_ref();
147                    while let Expr::Pi(bi2, name2, ty2, body2) = current_body {
148                        if !name2.is_anonymous() && *name2 != Name::str("_") {
149                            write!(self.buffer, " ")?;
150                            self.print_binder(*bi2, name2, ty2)?;
151                            current_body = body2;
152                        } else {
153                            break;
154                        }
155                    }
156                    write!(self.buffer, ", ")?;
157                    self.print_expr(current_body, 0)?;
158                }
159                if prec > 0 {
160                    write!(self.buffer, ")")?;
161                }
162                Ok(())
163            }
164            Expr::Let(name, ty, val, body) => {
165                write!(self.buffer, "let ")?;
166                self.print_name(name)?;
167                write!(self.buffer, " : ")?;
168                self.print_expr(ty, 0)?;
169                write!(self.buffer, " := ")?;
170                self.print_expr(val, 0)?;
171                write!(self.buffer, " in ")?;
172                self.print_expr(body, 0)
173            }
174            Expr::Lit(lit) => write!(self.buffer, "{}", lit),
175            Expr::Proj(name, idx, expr) => {
176                self.print_expr(expr, 11)?;
177                write!(self.buffer, ".{}.{}", name, idx)
178            }
179        }
180    }
181    /// Print a binder with its info.
182    fn print_binder(&mut self, bi: BinderInfo, name: &Name, ty: &Expr) -> fmt::Result {
183        if self.config.show_binder_info {
184            match bi {
185                BinderInfo::Default => {
186                    write!(self.buffer, "(")?;
187                    self.print_name(name)?;
188                    write!(self.buffer, " : ")?;
189                    self.print_expr(ty, 0)?;
190                    write!(self.buffer, ")")
191                }
192                BinderInfo::Implicit => {
193                    write!(self.buffer, "{{")?;
194                    self.print_name(name)?;
195                    write!(self.buffer, " : ")?;
196                    self.print_expr(ty, 0)?;
197                    write!(self.buffer, "}}")
198                }
199                BinderInfo::StrictImplicit => {
200                    if self.config.unicode {
201                        write!(self.buffer, "\u{2983}")?;
202                    } else {
203                        write!(self.buffer, "{{{{")?;
204                    }
205                    self.print_name(name)?;
206                    write!(self.buffer, " : ")?;
207                    self.print_expr(ty, 0)?;
208                    if self.config.unicode {
209                        write!(self.buffer, "\u{2984}")
210                    } else {
211                        write!(self.buffer, "}}}}")
212                    }
213                }
214                BinderInfo::InstImplicit => {
215                    write!(self.buffer, "[")?;
216                    self.print_name(name)?;
217                    write!(self.buffer, " : ")?;
218                    self.print_expr(ty, 0)?;
219                    write!(self.buffer, "]")
220                }
221            }
222        } else {
223            self.print_name(name)?;
224            write!(self.buffer, " : ")?;
225            self.print_expr(ty, 0)
226        }
227    }
228    /// Print a sort expression with smart level display.
229    fn print_sort(&mut self, level: &Level) -> fmt::Result {
230        match level.view() {
231            LevelView::Zero => write!(self.buffer, "Prop"),
232            _ => {
233                if let Some(n) = level_to_nat(level) {
234                    if n == 1 {
235                        write!(self.buffer, "Type")
236                    } else {
237                        write!(self.buffer, "Type {}", n - 1)
238                    }
239                } else {
240                    write!(self.buffer, "Sort ")?;
241                    self.print_level(level)
242                }
243            }
244        }
245    }
246    pub(super) fn print_level(&mut self, level: &Level) -> fmt::Result {
247        match level.view() {
248            LevelView::Zero => write!(self.buffer, "0"),
249            LevelView::Succ(_) => {
250                if let Some(n) = level_to_nat(level) {
251                    write!(self.buffer, "{}", n)
252                } else {
253                    let (base, offset) = level_to_offset(level);
254                    if offset > 0 {
255                        self.print_level(base)?;
256                        write!(self.buffer, "+{}", offset)
257                    } else {
258                        write!(self.buffer, "(")?;
259                        self.print_level(level)?;
260                        write!(self.buffer, ")")
261                    }
262                }
263            }
264            LevelView::Max(l1, l2) => {
265                write!(self.buffer, "max(")?;
266                self.print_level(l1)?;
267                write!(self.buffer, ", ")?;
268                self.print_level(l2)?;
269                write!(self.buffer, ")")
270            }
271            LevelView::IMax(l1, l2) => {
272                write!(self.buffer, "imax(")?;
273                self.print_level(l1)?;
274                write!(self.buffer, ", ")?;
275                self.print_level(l2)?;
276                write!(self.buffer, ")")
277            }
278            LevelView::Param(name) => self.print_name(name),
279            LevelView::MVar(id) => write!(self.buffer, "?u_{}", id.0),
280        }
281    }
282    fn print_name(&mut self, name: &Name) -> fmt::Result {
283        write!(self.buffer, "{}", name)
284    }
285}
286/// Prints an expression as an S-expression.
287#[allow(dead_code)]
288pub struct SExprPrinter {
289    indent: usize,
290}
291#[allow(dead_code)]
292impl SExprPrinter {
293    /// Creates a new S-expression printer.
294    pub fn new() -> Self {
295        Self { indent: 0 }
296    }
297    /// Renders a name applied to arguments as `(name arg1 arg2 ...)`.
298    pub fn app(&self, name: &str, args: &[&str]) -> String {
299        if args.is_empty() {
300            return name.to_string();
301        }
302        format!("({} {})", name, args.join(" "))
303    }
304    /// Renders a nested S-expression with indentation.
305    pub fn nested_app(&self, name: &str, args: &[String]) -> String {
306        if args.is_empty() {
307            return name.to_string();
308        }
309        let pad = " ".repeat(self.indent + 2);
310        let inner = args
311            .iter()
312            .map(|a| format!("{}{}", pad, a))
313            .collect::<Vec<_>>()
314            .join("\n");
315        format!("({}\n{})", name, inner)
316    }
317    /// Renders a list.
318    pub fn list(&self, items: &[String]) -> String {
319        format!("[{}]", items.join(", "))
320    }
321}
322/// A simple LRU cache backed by a linked list + hash map.
323#[allow(dead_code)]
324pub struct SimpleLruCache<K: std::hash::Hash + Eq + Clone, V: Clone> {
325    capacity: usize,
326    map: std::collections::HashMap<K, usize>,
327    keys: Vec<K>,
328    vals: Vec<V>,
329    order: Vec<usize>,
330}
331#[allow(dead_code)]
332impl<K: std::hash::Hash + Eq + Clone, V: Clone> SimpleLruCache<K, V> {
333    /// Creates a new LRU cache with the given capacity.
334    pub fn new(capacity: usize) -> Self {
335        assert!(capacity > 0);
336        Self {
337            capacity,
338            map: std::collections::HashMap::new(),
339            keys: Vec::new(),
340            vals: Vec::new(),
341            order: Vec::new(),
342        }
343    }
344    /// Inserts or updates a key-value pair.
345    pub fn put(&mut self, key: K, val: V) {
346        // `keys`, `vals` and `order` keep one length, with `order` holding
347        // each slot index once (most recently used first) and the length at
348        // most `capacity`, also when a call unwinds out of user code (`Clone`,
349        // `Hash` or `Eq` of `K`, the drop of a `K` or a `V`): `new` starts
350        // them empty, and every change below to a length or to `order` is a
351        // step that runs no user code and cannot fail, with its branch's user
352        // code (and the `reserve`s, which may panic) before the first such
353        // step or after the last. Every index in `map` is a slot index.
354        if let Some(&idx) = self.map.get(&key) {
355            // `map.get` ran `Hash` / `Eq` before any change. The old value's
356            // drop runs in this assignment and changes no length.
357            self.vals[idx] = val;
358            // `idx` is in `order` once, so `retain` removes one index and
359            // `insert` puts it back without growing the buffer.
360            self.order.retain(|&x| x != idx);
361            self.order.insert(0, idx);
362            return;
363        }
364        match self.order.last() {
365            // A full cache has `order.len() == keys.len() >= capacity > 0`
366            // (`new` asserts `capacity > 0`), so its least recently used slot
367            // is `order.last()`.
368            Some(&evict_idx) if self.keys.len() >= self.capacity => {
369                // The user code that comes before any change: the clone that
370                // goes into the map, and `Hash` / `Eq` in removing the evicted
371                // key from the map (a panic there leaves the map as it was).
372                // The removed key is held and dropped at the end.
373                let map_key = key.clone();
374                let removed = self.map.remove_entry(&self.keys[evict_idx]);
375                // Moves that run no user code: the slot takes the new key and
376                // value, and `rotate_right` takes the evicted index from the
377                // back of `order` to the front. No length changes.
378                let old_key = std::mem::replace(&mut self.keys[evict_idx], key);
379                let old_val = std::mem::replace(&mut self.vals[evict_idx], val);
380                self.order.rotate_right(1);
381                // The user code that comes after: `Hash` / `Eq` in the map's
382                // insertion, then the drops of the evicted key and value.
383                self.map.insert(map_key, evict_idx);
384                drop((removed, old_key, old_val));
385            }
386            // Not full: a new slot. (With the lengths equal, `order` is never
387            // empty while `keys.len() >= capacity`.)
388            _ => {
389                let map_key = key.clone();
390                let idx = self.keys.len();
391                // Reserving first, the three appends below allocate nothing
392                // and cannot fail, so the lists grow together; `Hash` / `Eq`
393                // in the map's insertion run after them.
394                self.keys.reserve(1);
395                self.vals.reserve(1);
396                self.order.reserve(1);
397                self.keys.push(key);
398                self.vals.push(val);
399                self.order.insert(0, idx);
400                self.map.insert(map_key, idx);
401            }
402        }
403    }
404    /// Returns a reference to the value for `key`, promoting it.
405    pub fn get(&mut self, key: &K) -> Option<&V> {
406        // `map.get` runs `Hash` / `Eq` before any change; `idx` is in `order`
407        // once (see `put`), so `retain` and `insert` change no length.
408        let idx = *self.map.get(key)?;
409        self.order.retain(|&x| x != idx);
410        self.order.insert(0, idx);
411        Some(&self.vals[idx])
412    }
413    /// Returns the number of entries.
414    pub fn len(&self) -> usize {
415        self.keys.len()
416    }
417    /// Returns `true` if empty.
418    pub fn is_empty(&self) -> bool {
419        self.keys.is_empty()
420    }
421}
422/// An abstract pretty-print document.
423#[allow(dead_code)]
424#[derive(Clone, Debug)]
425pub enum PrettyDoc {
426    /// A literal text string.
427    Text(String),
428    /// A newline followed by indentation.
429    Newline,
430    /// Increase indentation for nested content.
431    Indent(Box<PrettyDoc>),
432    /// Concatenation of two documents.
433    Concat(Box<PrettyDoc>, Box<PrettyDoc>),
434    /// A group: try to fit on one line, break if too long.
435    Group(Box<PrettyDoc>),
436    /// An empty document.
437    Empty,
438}
439#[allow(dead_code)]
440impl PrettyDoc {
441    /// Creates a `Text` document.
442    pub fn text(s: impl Into<String>) -> Self {
443        PrettyDoc::Text(s.into())
444    }
445    /// Creates a `Concat` document.
446    pub fn concat(a: PrettyDoc, b: PrettyDoc) -> Self {
447        PrettyDoc::Concat(Box::new(a), Box::new(b))
448    }
449    /// Creates an `Indent` document.
450    pub fn indent(inner: PrettyDoc) -> Self {
451        PrettyDoc::Indent(Box::new(inner))
452    }
453    /// Creates a `Group` document.
454    pub fn group(inner: PrettyDoc) -> Self {
455        PrettyDoc::Group(Box::new(inner))
456    }
457    /// Renders the document to a `String` using the given line width and indent style.
458    pub fn render(&self, _width: usize, style: IndentStyle) -> String {
459        let mut out = String::new();
460        let mut depth = 0usize;
461        self.render_inner(&mut out, &mut depth, &style);
462        out
463    }
464    fn render_inner(&self, out: &mut String, depth: &mut usize, style: &IndentStyle) {
465        match self {
466            PrettyDoc::Text(s) => out.push_str(s),
467            PrettyDoc::Newline => {
468                out.push('\n');
469                out.push_str(&style.for_depth(*depth));
470            }
471            PrettyDoc::Indent(inner) => {
472                *depth += 1;
473                inner.render_inner(out, depth, style);
474                *depth -= 1;
475            }
476            PrettyDoc::Concat(a, b) => {
477                a.render_inner(out, depth, style);
478                b.render_inner(out, depth, style);
479            }
480            PrettyDoc::Group(inner) => inner.render_inner(out, depth, style),
481            PrettyDoc::Empty => {}
482        }
483    }
484}
485/// A pretty printer that works with `PrettyToken` streams.
486#[allow(dead_code)]
487pub struct TokenPrinter {
488    config: PrettyConfig,
489    scheme: ColorScheme,
490}
491#[allow(dead_code)]
492impl TokenPrinter {
493    /// Creates a new token printer.
494    pub fn new(config: PrettyConfig) -> Self {
495        Self {
496            config,
497            scheme: ColorScheme::MONO,
498        }
499    }
500    /// Sets the color scheme.
501    pub fn with_colors(mut self, scheme: ColorScheme) -> Self {
502        self.scheme = scheme;
503        self
504    }
505    /// Renders a slice of tokens to a `String`.
506    pub fn render(&self, tokens: &[PrettyToken]) -> String {
507        let mut out = String::new();
508        for tok in tokens {
509            if self.config.colored {
510                out.push_str(&tok.colored_text(&self.scheme));
511            } else {
512                out.push_str(tok.raw_text());
513            }
514        }
515        out
516    }
517    /// Renders with line wrapping at `config.width`.
518    pub fn render_wrapped(&self, tokens: &[PrettyToken]) -> String {
519        let mut out = String::new();
520        let mut col = 0usize;
521        for tok in tokens {
522            let text = tok.raw_text();
523            if matches!(tok, PrettyToken::LineBreak) {
524                out.push('\n');
525                col = 0;
526                continue;
527            }
528            if col + text.len() > self.config.width && col > 0 {
529                out.push('\n');
530                col = 0;
531            }
532            out.push_str(text);
533            col += text.len();
534        }
535        out
536    }
537}
538/// Utilities for computing display widths.
539#[allow(dead_code)]
540pub struct FmtWidth;
541#[allow(dead_code)]
542impl FmtWidth {
543    /// Returns the display width of a `usize` in decimal.
544    pub fn decimal_width(n: usize) -> usize {
545        if n == 0 {
546            return 1;
547        }
548        let mut w = 0;
549        let mut v = n;
550        while v > 0 {
551            v /= 10;
552            w += 1;
553        }
554        w
555    }
556    /// Pads `s` on the right with spaces to `width` total chars.
557    pub fn pad_right(s: &str, width: usize) -> String {
558        if s.len() >= width {
559            return s.to_string();
560        }
561        format!("{}{}", s, " ".repeat(width - s.len()))
562    }
563    /// Pads `s` on the left with spaces to `width` total chars.
564    pub fn pad_left(s: &str, width: usize) -> String {
565        if s.len() >= width {
566            return s.to_string();
567        }
568        format!("{}{}", " ".repeat(width - s.len()), s)
569    }
570    /// Centers `s` within `width` chars.
571    pub fn center(s: &str, width: usize) -> String {
572        if s.len() >= width {
573            return s.to_string();
574        }
575        let pad = width - s.len();
576        let left = pad / 2;
577        let right = pad - left;
578        format!("{}{}{}", " ".repeat(left), s, " ".repeat(right))
579    }
580}
581/// An indented document for pretty-printing with line wrapping.
582#[allow(dead_code)]
583#[derive(Clone, Debug)]
584pub enum Doc {
585    /// Empty document.
586    Empty,
587    /// A text fragment.
588    Text(String),
589    /// Append two documents.
590    Concat(Box<Doc>, Box<Doc>),
591    /// A line break; collapses to a space when flattened.
592    Line,
593    /// Indented document.
594    Nest(usize, Box<Doc>),
595    /// Choose between two layouts.
596    Union(Box<Doc>, Box<Doc>),
597}
598#[allow(dead_code)]
599impl Doc {
600    /// Create a text document.
601    pub fn text(s: impl Into<String>) -> Self {
602        Doc::Text(s.into())
603    }
604    /// Append two documents.
605    pub fn concat(self, other: Doc) -> Self {
606        Doc::Concat(Box::new(self), Box::new(other))
607    }
608    /// Add a line break.
609    pub fn line() -> Self {
610        Doc::Line
611    }
612    /// Indent a document by `n` spaces.
613    pub fn nest(n: usize, doc: Doc) -> Self {
614        Doc::Nest(n, Box::new(doc))
615    }
616    /// Render to a string with the given page width.
617    pub fn render(&self, width: usize) -> String {
618        let mut out = String::new();
619        self.render_impl(0, &mut out, width);
620        out
621    }
622    fn render_impl(&self, indent: usize, out: &mut String, _width: usize) {
623        match self {
624            Doc::Empty => {}
625            Doc::Text(s) => out.push_str(s),
626            Doc::Concat(a, b) => {
627                a.render_impl(indent, out, _width);
628                b.render_impl(indent, out, _width);
629            }
630            Doc::Line => {
631                out.push('\n');
632                for _ in 0..indent {
633                    out.push(' ');
634                }
635            }
636            Doc::Nest(n, doc) => {
637                doc.render_impl(indent + n, out, _width);
638            }
639            Doc::Union(a, _b) => {
640                a.render_impl(indent, out, _width);
641            }
642        }
643    }
644}
645/// A simple ASCII table formatter.
646#[allow(dead_code)]
647pub struct PrettyTable {
648    headers: Vec<String>,
649    rows: Vec<Vec<String>>,
650}
651#[allow(dead_code)]
652impl PrettyTable {
653    /// Creates a new table with the given headers.
654    pub fn new(headers: Vec<String>) -> Self {
655        Self {
656            headers,
657            rows: Vec::new(),
658        }
659    }
660    /// Adds a row.  Pads or truncates to match the number of columns.
661    pub fn add_row(&mut self, row: Vec<String>) {
662        let n = self.headers.len();
663        let mut r = row;
664        r.resize(n, String::new());
665        self.rows.push(r);
666    }
667    /// Renders the table as an ASCII grid.
668    pub fn render(&self) -> String {
669        let n = self.headers.len();
670        let mut widths: Vec<usize> = self.headers.iter().map(|h| h.len()).collect();
671        for row in &self.rows {
672            for (i, cell) in row.iter().enumerate() {
673                if i < n {
674                    widths[i] = widths[i].max(cell.len());
675                }
676            }
677        }
678        let sep: String = widths
679            .iter()
680            .map(|&w| "-".repeat(w + 2))
681            .collect::<Vec<_>>()
682            .join("+");
683        let sep = format!("+{}+", sep);
684        let mut out = String::new();
685        out.push_str(&sep);
686        out.push('\n');
687        let header_line: String = self
688            .headers
689            .iter()
690            .enumerate()
691            .map(|(i, h)| FmtWidth::pad_right(h, widths[i]))
692            .collect::<Vec<_>>()
693            .join(" | ");
694        out.push_str(&format!("| {} |", header_line));
695        out.push('\n');
696        out.push_str(&sep);
697        out.push('\n');
698        for row in &self.rows {
699            let line: String = (0..n)
700                .map(|i| {
701                    FmtWidth::pad_right(row.get(i).map(|s| s.as_str()).unwrap_or(""), widths[i])
702                })
703                .collect::<Vec<_>>()
704                .join(" | ");
705            out.push_str(&format!("| {} |", line));
706            out.push('\n');
707        }
708        out.push_str(&sep);
709        out
710    }
711}
712/// A FIFO work queue.
713#[allow(dead_code)]
714pub struct WorkQueue<T> {
715    items: std::collections::VecDeque<T>,
716}
717#[allow(dead_code)]
718impl<T> WorkQueue<T> {
719    /// Creates a new empty queue.
720    pub fn new() -> Self {
721        Self {
722            items: std::collections::VecDeque::new(),
723        }
724    }
725    /// Enqueues a work item.
726    pub fn enqueue(&mut self, item: T) {
727        self.items.push_back(item);
728    }
729    /// Dequeues the next work item.
730    pub fn dequeue(&mut self) -> Option<T> {
731        self.items.pop_front()
732    }
733    /// Returns `true` if empty.
734    pub fn is_empty(&self) -> bool {
735        self.items.is_empty()
736    }
737    /// Returns the number of pending items.
738    pub fn len(&self) -> usize {
739        self.items.len()
740    }
741}
742/// A key-value store for diagnostic metadata.
743#[allow(dead_code)]
744pub struct DiagMeta {
745    pub(super) entries: Vec<(String, String)>,
746}
747#[allow(dead_code)]
748impl DiagMeta {
749    /// Creates an empty metadata store.
750    pub fn new() -> Self {
751        Self {
752            entries: Vec::new(),
753        }
754    }
755    /// Adds a key-value pair.
756    pub fn add(&mut self, key: impl Into<String>, val: impl Into<String>) {
757        self.entries.push((key.into(), val.into()));
758    }
759    /// Returns the value for `key`, or `None`.
760    pub fn get(&self, key: &str) -> Option<&str> {
761        self.entries
762            .iter()
763            .find(|(k, _)| k == key)
764            .map(|(_, v)| v.as_str())
765    }
766    /// Returns the number of entries.
767    pub fn len(&self) -> usize {
768        self.entries.len()
769    }
770    /// Returns `true` if empty.
771    pub fn is_empty(&self) -> bool {
772        self.entries.is_empty()
773    }
774}
775/// A type-safe wrapper around a `u32` identifier.
776#[allow(dead_code)]
777#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
778pub struct TypedId<T> {
779    pub(super) id: u32,
780    _phantom: std::marker::PhantomData<T>,
781}
782#[allow(dead_code)]
783impl<T> TypedId<T> {
784    /// Creates a new typed ID.
785    pub const fn new(id: u32) -> Self {
786        Self {
787            id,
788            _phantom: std::marker::PhantomData,
789        }
790    }
791    /// Returns the raw `u32` ID.
792    pub fn raw(&self) -> u32 {
793        self.id
794    }
795}
796/// Mutable state threaded through a recursive pretty printer.
797#[allow(dead_code)]
798pub struct PrettyPrinterState {
799    output: String,
800    indent_depth: usize,
801    indent_str: String,
802    pub(crate) col: usize,
803    max_width: usize,
804}
805#[allow(dead_code)]
806impl PrettyPrinterState {
807    /// Creates a new printer state.
808    pub fn new(max_width: usize, indent: IndentStyle) -> Self {
809        Self {
810            output: String::new(),
811            indent_depth: 0,
812            indent_str: indent.one_level(),
813            col: 0,
814            max_width,
815        }
816    }
817    /// Writes a string token.
818    pub fn write(&mut self, s: &str) {
819        self.output.push_str(s);
820        self.col += s.len();
821    }
822    /// Writes a newline and current indentation.
823    pub fn newline(&mut self) {
824        self.output.push('\n');
825        let indent = self.indent_str.repeat(self.indent_depth);
826        self.output.push_str(&indent);
827        self.col = indent.len();
828    }
829    /// Increases indentation depth.
830    pub fn push_indent(&mut self) {
831        self.indent_depth += 1;
832    }
833    /// Decreases indentation depth.
834    pub fn pop_indent(&mut self) {
835        if self.indent_depth > 0 {
836            self.indent_depth -= 1;
837        }
838    }
839    /// Returns `true` if the current line is past `max_width`.
840    pub fn over_width(&self) -> bool {
841        self.col > self.max_width
842    }
843    /// Returns the accumulated output.
844    pub fn finish(self) -> String {
845        self.output
846    }
847}
848/// A set of non-overlapping integer intervals.
849#[allow(dead_code)]
850pub struct IntervalSet {
851    intervals: Vec<(i64, i64)>,
852}
853#[allow(dead_code)]
854impl IntervalSet {
855    /// Creates an empty interval set.
856    pub fn new() -> Self {
857        Self {
858            intervals: Vec::new(),
859        }
860    }
861    /// Adds the interval `[lo, hi]` to the set.
862    pub fn add(&mut self, lo: i64, hi: i64) {
863        if lo > hi {
864            return;
865        }
866        let mut new_lo = lo;
867        let mut new_hi = hi;
868        let mut i = 0;
869        while i < self.intervals.len() {
870            let (il, ih) = self.intervals[i];
871            if ih < new_lo - 1 {
872                i += 1;
873                continue;
874            }
875            if il > new_hi + 1 {
876                break;
877            }
878            new_lo = new_lo.min(il);
879            new_hi = new_hi.max(ih);
880            self.intervals.remove(i);
881        }
882        self.intervals.insert(i, (new_lo, new_hi));
883    }
884    /// Returns `true` if `x` is in the set.
885    pub fn contains(&self, x: i64) -> bool {
886        self.intervals.iter().any(|&(lo, hi)| x >= lo && x <= hi)
887    }
888    /// Returns the number of intervals.
889    pub fn num_intervals(&self) -> usize {
890        self.intervals.len()
891    }
892    /// Returns the total count of integers covered.
893    pub fn cardinality(&self) -> i64 {
894        self.intervals.iter().map(|&(lo, hi)| hi - lo + 1).sum()
895    }
896}
897/// A counter that dispenses monotonically increasing `TypedId` values.
898#[allow(dead_code)]
899pub struct IdDispenser<T> {
900    next: u32,
901    _phantom: std::marker::PhantomData<T>,
902}
903#[allow(dead_code)]
904impl<T> IdDispenser<T> {
905    /// Creates a new dispenser starting from zero.
906    pub fn new() -> Self {
907        Self {
908            next: 0,
909            _phantom: std::marker::PhantomData,
910        }
911    }
912    /// Dispenses the next ID.
913    #[allow(clippy::should_implement_trait)]
914    pub fn next(&mut self) -> TypedId<T> {
915        let id = TypedId::new(self.next);
916        self.next += 1;
917        id
918    }
919    /// Returns the number of IDs dispensed.
920    pub fn count(&self) -> u32 {
921        self.next
922    }
923}
924/// A key-value annotation table for arbitrary metadata.
925#[allow(dead_code)]
926pub struct AnnotationTable {
927    map: std::collections::HashMap<String, Vec<String>>,
928}
929#[allow(dead_code)]
930impl AnnotationTable {
931    /// Creates an empty annotation table.
932    pub fn new() -> Self {
933        Self {
934            map: std::collections::HashMap::new(),
935        }
936    }
937    /// Adds an annotation value for the given key.
938    pub fn annotate(&mut self, key: impl Into<String>, val: impl Into<String>) {
939        self.map.entry(key.into()).or_default().push(val.into());
940    }
941    /// Returns all annotations for `key`.
942    pub fn get_all(&self, key: &str) -> &[String] {
943        self.map.get(key).map(|v| v.as_slice()).unwrap_or(&[])
944    }
945    /// Returns the number of distinct annotation keys.
946    pub fn num_keys(&self) -> usize {
947        self.map.len()
948    }
949    /// Returns `true` if the table has any annotations for `key`.
950    pub fn has(&self, key: &str) -> bool {
951        self.map.contains_key(key)
952    }
953}
954/// Tracks the frequency of items.
955#[allow(dead_code)]
956pub struct FrequencyTable<T: std::hash::Hash + Eq + Clone> {
957    counts: std::collections::HashMap<T, u64>,
958}
959#[allow(dead_code)]
960impl<T: std::hash::Hash + Eq + Clone> FrequencyTable<T> {
961    /// Creates a new empty frequency table.
962    pub fn new() -> Self {
963        Self {
964            counts: std::collections::HashMap::new(),
965        }
966    }
967    /// Records one occurrence of `item`.
968    pub fn record(&mut self, item: T) {
969        *self.counts.entry(item).or_insert(0) += 1;
970    }
971    /// Returns the frequency of `item`.
972    pub fn freq(&self, item: &T) -> u64 {
973        self.counts.get(item).copied().unwrap_or(0)
974    }
975    /// Returns the item with the highest frequency.
976    pub fn most_frequent(&self) -> Option<(&T, u64)> {
977        self.counts
978            .iter()
979            .max_by_key(|(_, &v)| v)
980            .map(|(k, &v)| (k, v))
981    }
982    /// Returns the total number of recordings.
983    pub fn total(&self) -> u64 {
984        self.counts.values().sum()
985    }
986    /// Returns the number of distinct items.
987    pub fn distinct(&self) -> usize {
988        self.counts.len()
989    }
990}
991/// A builder for `PrettyDoc` values with a fluent API.
992#[allow(dead_code)]
993pub struct DocBuilder {
994    doc: PrettyDoc,
995}
996#[allow(dead_code)]
997impl DocBuilder {
998    /// Creates a builder from an existing doc.
999    pub fn from(doc: PrettyDoc) -> Self {
1000        Self { doc }
1001    }
1002    /// Creates a text builder.
1003    pub fn text(s: impl Into<String>) -> Self {
1004        Self {
1005            doc: PrettyDoc::text(s),
1006        }
1007    }
1008    /// Creates an empty builder.
1009    pub fn empty() -> Self {
1010        Self {
1011            doc: PrettyDoc::Empty,
1012        }
1013    }
1014    /// Appends another document.
1015    pub fn then(self, other: PrettyDoc) -> Self {
1016        Self {
1017            doc: PrettyDoc::concat(self.doc, other),
1018        }
1019    }
1020    /// Appends a text string.
1021    pub fn then_text(self, s: impl Into<String>) -> Self {
1022        self.then(PrettyDoc::text(s))
1023    }
1024    /// Appends a newline.
1025    pub fn then_newline(self) -> Self {
1026        self.then(PrettyDoc::Newline)
1027    }
1028    /// Wraps in an indent.
1029    pub fn indented(self) -> Self {
1030        Self {
1031            doc: PrettyDoc::indent(self.doc),
1032        }
1033    }
1034    /// Returns the built document.
1035    pub fn build(self) -> PrettyDoc {
1036        self.doc
1037    }
1038}
1039/// A simple LIFO work queue.
1040#[allow(dead_code)]
1041pub struct WorkStack<T> {
1042    items: Vec<T>,
1043}
1044#[allow(dead_code)]
1045impl<T> WorkStack<T> {
1046    /// Creates a new empty stack.
1047    pub fn new() -> Self {
1048        Self { items: Vec::new() }
1049    }
1050    /// Pushes a work item.
1051    pub fn push(&mut self, item: T) {
1052        self.items.push(item);
1053    }
1054    /// Pops the next work item.
1055    pub fn pop(&mut self) -> Option<T> {
1056        self.items.pop()
1057    }
1058    /// Returns `true` if empty.
1059    pub fn is_empty(&self) -> bool {
1060        self.items.is_empty()
1061    }
1062    /// Returns the number of pending work items.
1063    pub fn len(&self) -> usize {
1064        self.items.len()
1065    }
1066}
1067/// A memoized computation slot that stores a cached value.
1068#[allow(dead_code)]
1069pub struct MemoSlot<T: Clone> {
1070    cached: Option<T>,
1071}
1072#[allow(dead_code)]
1073impl<T: Clone> MemoSlot<T> {
1074    /// Creates an uncomputed memo slot.
1075    pub fn new() -> Self {
1076        Self { cached: None }
1077    }
1078    /// Returns the cached value, computing it with `f` if absent.
1079    pub fn get_or_compute(&mut self, f: impl FnOnce() -> T) -> &T {
1080        self.cached.get_or_insert_with(f)
1081    }
1082    /// Invalidates the cached value.
1083    pub fn invalidate(&mut self) {
1084        self.cached = None;
1085    }
1086    /// Returns `true` if the value has been computed.
1087    pub fn is_cached(&self) -> bool {
1088        self.cached.is_some()
1089    }
1090}
1091/// A counted-access cache that tracks hit and miss statistics.
1092#[allow(dead_code)]
1093#[allow(missing_docs)]
1094pub struct StatCache<K: std::hash::Hash + Eq + Clone, V: Clone> {
1095    /// The inner LRU cache.
1096    pub inner: SimpleLruCache<K, V>,
1097    /// Number of cache hits.
1098    pub hits: u64,
1099    /// Number of cache misses.
1100    pub misses: u64,
1101}
1102#[allow(dead_code)]
1103impl<K: std::hash::Hash + Eq + Clone, V: Clone> StatCache<K, V> {
1104    /// Creates a new stat cache with the given capacity.
1105    pub fn new(capacity: usize) -> Self {
1106        Self {
1107            inner: SimpleLruCache::new(capacity),
1108            hits: 0,
1109            misses: 0,
1110        }
1111    }
1112    /// Performs a lookup, tracking hit/miss.
1113    pub fn get(&mut self, key: &K) -> Option<&V> {
1114        let result = self.inner.get(key);
1115        if result.is_some() {
1116            self.hits += 1;
1117        } else {
1118            self.misses += 1;
1119        }
1120        None
1121    }
1122    /// Inserts a key-value pair.
1123    pub fn put(&mut self, key: K, val: V) {
1124        self.inner.put(key, val);
1125    }
1126    /// Returns the hit rate.
1127    pub fn hit_rate(&self) -> f64 {
1128        let total = self.hits + self.misses;
1129        if total == 0 {
1130            return 0.0;
1131        }
1132        self.hits as f64 / total as f64
1133    }
1134}
1135/// Helpers for string escaping in pretty output.
1136#[allow(dead_code)]
1137pub struct EscapeHelper;
1138#[allow(dead_code)]
1139impl EscapeHelper {
1140    /// Escapes `\n`, `\t`, `\\`, and `"` in `s`.
1141    pub fn escape_str(s: &str) -> String {
1142        let mut out = String::with_capacity(s.len() + 2);
1143        out.push('"');
1144        for c in s.chars() {
1145            match c {
1146                '"' => out.push_str("\\\""),
1147                '\\' => out.push_str("\\\\"),
1148                '\n' => out.push_str("\\n"),
1149                '\t' => out.push_str("\\t"),
1150                _ => out.push(c),
1151            }
1152        }
1153        out.push('"');
1154        out
1155    }
1156    /// Unescapes a string that may contain `\\n`, `\\t`, `\\\\`, `\\"`.
1157    pub fn unescape_str(s: &str) -> String {
1158        let s = if s.starts_with('"') && s.ends_with('"') && s.len() >= 2 {
1159            &s[1..s.len() - 1]
1160        } else {
1161            s
1162        };
1163        let mut out = String::new();
1164        let mut chars = s.chars().peekable();
1165        while let Some(c) = chars.next() {
1166            if c == '\\' {
1167                match chars.next() {
1168                    Some('n') => out.push('\n'),
1169                    Some('t') => out.push('\t'),
1170                    Some('\\') => out.push('\\'),
1171                    Some('"') => out.push('"'),
1172                    Some(x) => {
1173                        out.push('\\');
1174                        out.push(x);
1175                    }
1176                    None => out.push('\\'),
1177                }
1178            } else {
1179                out.push(c);
1180            }
1181        }
1182        out
1183    }
1184}
1185/// A simple event counter with named events.
1186#[allow(dead_code)]
1187pub struct EventCounter {
1188    counts: std::collections::HashMap<String, u64>,
1189}
1190#[allow(dead_code)]
1191impl EventCounter {
1192    /// Creates a new empty counter.
1193    pub fn new() -> Self {
1194        Self {
1195            counts: std::collections::HashMap::new(),
1196        }
1197    }
1198    /// Increments the counter for `event`.
1199    pub fn inc(&mut self, event: &str) {
1200        *self.counts.entry(event.to_string()).or_insert(0) += 1;
1201    }
1202    /// Adds `n` to the counter for `event`.
1203    pub fn add(&mut self, event: &str, n: u64) {
1204        *self.counts.entry(event.to_string()).or_insert(0) += n;
1205    }
1206    /// Returns the count for `event`.
1207    pub fn get(&self, event: &str) -> u64 {
1208        self.counts.get(event).copied().unwrap_or(0)
1209    }
1210    /// Returns the total count across all events.
1211    pub fn total(&self) -> u64 {
1212        self.counts.values().sum()
1213    }
1214    /// Resets all counters.
1215    pub fn reset(&mut self) {
1216        self.counts.clear();
1217    }
1218    /// Returns all event names.
1219    pub fn event_names(&self) -> Vec<&str> {
1220        self.counts.keys().map(|s| s.as_str()).collect()
1221    }
1222}
1223/// A bidirectional map between two types.
1224#[allow(dead_code)]
1225pub struct BiMap<A: std::hash::Hash + Eq + Clone, B: std::hash::Hash + Eq + Clone> {
1226    forward: std::collections::HashMap<A, B>,
1227    backward: std::collections::HashMap<B, A>,
1228}
1229#[allow(dead_code)]
1230impl<A: std::hash::Hash + Eq + Clone, B: std::hash::Hash + Eq + Clone> BiMap<A, B> {
1231    /// Creates an empty bidirectional map.
1232    pub fn new() -> Self {
1233        Self {
1234            forward: std::collections::HashMap::new(),
1235            backward: std::collections::HashMap::new(),
1236        }
1237    }
1238    /// Inserts a pair `(a, b)`.
1239    pub fn insert(&mut self, a: A, b: B) {
1240        self.forward.insert(a.clone(), b.clone());
1241        self.backward.insert(b, a);
1242    }
1243    /// Looks up `b` for a given `a`.
1244    pub fn get_b(&self, a: &A) -> Option<&B> {
1245        self.forward.get(a)
1246    }
1247    /// Looks up `a` for a given `b`.
1248    pub fn get_a(&self, b: &B) -> Option<&A> {
1249        self.backward.get(b)
1250    }
1251    /// Returns the number of pairs.
1252    pub fn len(&self) -> usize {
1253        self.forward.len()
1254    }
1255    /// Returns `true` if empty.
1256    pub fn is_empty(&self) -> bool {
1257        self.forward.is_empty()
1258    }
1259}
1260/// A slot that can hold a value, with lazy initialization.
1261#[allow(dead_code)]
1262pub struct Slot<T> {
1263    inner: Option<T>,
1264}
1265#[allow(dead_code)]
1266impl<T> Slot<T> {
1267    /// Creates an empty slot.
1268    pub fn empty() -> Self {
1269        Self { inner: None }
1270    }
1271    /// Fills the slot with `val`.  Panics if already filled.
1272    pub fn fill(&mut self, val: T) {
1273        assert!(self.inner.is_none(), "Slot: already filled");
1274        self.inner = Some(val);
1275    }
1276    /// Returns the slot's value, or `None`.
1277    pub fn get(&self) -> Option<&T> {
1278        self.inner.as_ref()
1279    }
1280    /// Returns `true` if the slot is filled.
1281    pub fn is_filled(&self) -> bool {
1282        self.inner.is_some()
1283    }
1284    /// Takes the value out of the slot.
1285    pub fn take(&mut self) -> Option<T> {
1286        self.inner.take()
1287    }
1288    /// Fills the slot if empty, returning a reference to the value.
1289    pub fn get_or_fill_with(&mut self, f: impl FnOnce() -> T) -> &T {
1290        self.inner.get_or_insert_with(f)
1291    }
1292}
1293/// Interns strings to save memory (each unique string stored once).
1294#[allow(dead_code)]
1295pub struct StringInterner {
1296    strings: Vec<String>,
1297    map: std::collections::HashMap<String, u32>,
1298}
1299#[allow(dead_code)]
1300impl StringInterner {
1301    /// Creates a new string interner.
1302    pub fn new() -> Self {
1303        Self {
1304            strings: Vec::new(),
1305            map: std::collections::HashMap::new(),
1306        }
1307    }
1308    /// Interns `s` and returns its ID.
1309    pub fn intern(&mut self, s: &str) -> u32 {
1310        if let Some(&id) = self.map.get(s) {
1311            return id;
1312        }
1313        let id = self.strings.len() as u32;
1314        self.strings.push(s.to_string());
1315        self.map.insert(s.to_string(), id);
1316        id
1317    }
1318    /// Returns the string for `id`.
1319    pub fn get(&self, id: u32) -> Option<&str> {
1320        self.strings.get(id as usize).map(|s| s.as_str())
1321    }
1322    /// Returns the total number of interned strings.
1323    pub fn len(&self) -> usize {
1324        self.strings.len()
1325    }
1326    /// Returns `true` if empty.
1327    pub fn is_empty(&self) -> bool {
1328        self.strings.is_empty()
1329    }
1330}
1331/// Implements Wadler/Lindig-style pretty printing using a box model.
1332#[allow(dead_code)]
1333pub struct BoxedPrinter {
1334    width: usize,
1335}
1336#[allow(dead_code)]
1337impl BoxedPrinter {
1338    /// Creates a printer with the given line width.
1339    pub fn new(width: usize) -> Self {
1340        Self { width }
1341    }
1342    /// Renders a `PrettyDoc` to a `String`.
1343    pub fn render(&self, doc: &PrettyDoc) -> String {
1344        doc.render(self.width, IndentStyle::Spaces(2))
1345    }
1346}
1347/// Configuration for pretty printing.
1348#[derive(Debug, Clone)]
1349pub struct PrintConfig {
1350    /// Use unicode symbols (λ, ∀, →)
1351    pub unicode: bool,
1352    /// Show implicit arguments
1353    pub show_implicit: bool,
1354    /// Show universe levels
1355    pub show_universes: bool,
1356    /// Maximum line width for wrapping
1357    pub max_width: usize,
1358    /// Show binder info (default, implicit, etc.)
1359    pub show_binder_info: bool,
1360    /// Show de Bruijn indices
1361    pub show_indices: bool,
1362}
1363impl PrintConfig {
1364    /// ASCII-only configuration.
1365    pub fn ascii() -> Self {
1366        Self {
1367            unicode: false,
1368            ..Default::default()
1369        }
1370    }
1371    /// Verbose configuration showing everything.
1372    pub fn verbose() -> Self {
1373        Self {
1374            show_implicit: true,
1375            show_universes: true,
1376            show_binder_info: true,
1377            show_indices: true,
1378            ..Default::default()
1379        }
1380    }
1381}
1382/// Configuration for the pretty printer.
1383#[allow(dead_code)]
1384#[allow(missing_docs)]
1385pub struct PrettyConfig {
1386    /// Maximum line width.
1387    pub width: usize,
1388    /// Indentation style.
1389    pub indent: IndentStyle,
1390    /// Whether to use color.
1391    pub colored: bool,
1392}
1393#[allow(dead_code)]
1394impl PrettyConfig {
1395    /// Default config: 80 columns, 2-space indent, no color.
1396    pub fn default_config() -> Self {
1397        Self {
1398            width: 80,
1399            indent: IndentStyle::Spaces(2),
1400            colored: false,
1401        }
1402    }
1403    /// Creates a compact single-line config (no newlines honoured).
1404    pub fn compact() -> Self {
1405        Self {
1406            width: usize::MAX,
1407            indent: IndentStyle::Spaces(0),
1408            colored: false,
1409        }
1410    }
1411}
1412/// A simple sparse bit set.
1413#[allow(dead_code)]
1414pub struct SparseBitSet {
1415    words: Vec<u64>,
1416}
1417#[allow(dead_code)]
1418impl SparseBitSet {
1419    /// Creates a new bit set that can hold at least `capacity` bits.
1420    pub fn new(capacity: usize) -> Self {
1421        let words = capacity.div_ceil(64);
1422        Self {
1423            words: vec![0u64; words],
1424        }
1425    }
1426    /// Sets bit `i`.
1427    pub fn set(&mut self, i: usize) {
1428        let word = i / 64;
1429        let bit = i % 64;
1430        if word < self.words.len() {
1431            self.words[word] |= 1u64 << bit;
1432        }
1433    }
1434    /// Clears bit `i`.
1435    pub fn clear(&mut self, i: usize) {
1436        let word = i / 64;
1437        let bit = i % 64;
1438        if word < self.words.len() {
1439            self.words[word] &= !(1u64 << bit);
1440        }
1441    }
1442    /// Returns `true` if bit `i` is set.
1443    pub fn get(&self, i: usize) -> bool {
1444        let word = i / 64;
1445        let bit = i % 64;
1446        self.words.get(word).is_some_and(|w| w & (1u64 << bit) != 0)
1447    }
1448    /// Returns the number of set bits.
1449    pub fn count_ones(&self) -> u32 {
1450        self.words.iter().map(|w| w.count_ones()).sum()
1451    }
1452    /// Returns the union with another bit set.
1453    pub fn union(&self, other: &SparseBitSet) -> SparseBitSet {
1454        let len = self.words.len().max(other.words.len());
1455        let mut result = SparseBitSet {
1456            words: vec![0u64; len],
1457        };
1458        for i in 0..self.words.len() {
1459            result.words[i] |= self.words[i];
1460        }
1461        for i in 0..other.words.len() {
1462            result.words[i] |= other.words[i];
1463        }
1464        result
1465    }
1466}
1467/// A simple stack-based scope tracker.
1468#[allow(dead_code)]
1469pub struct ScopeStack {
1470    names: Vec<String>,
1471}
1472#[allow(dead_code)]
1473impl ScopeStack {
1474    /// Creates a new empty scope stack.
1475    pub fn new() -> Self {
1476        Self { names: Vec::new() }
1477    }
1478    /// Pushes a scope name.
1479    pub fn push(&mut self, name: impl Into<String>) {
1480        self.names.push(name.into());
1481    }
1482    /// Pops the current scope.
1483    pub fn pop(&mut self) -> Option<String> {
1484        self.names.pop()
1485    }
1486    /// Returns the current (innermost) scope name, or `None`.
1487    pub fn current(&self) -> Option<&str> {
1488        self.names.last().map(|s| s.as_str())
1489    }
1490    /// Returns the depth of the scope stack.
1491    pub fn depth(&self) -> usize {
1492        self.names.len()
1493    }
1494    /// Returns `true` if the stack is empty.
1495    pub fn is_empty(&self) -> bool {
1496        self.names.is_empty()
1497    }
1498    /// Returns the full path as a dot-separated string.
1499    pub fn path(&self) -> String {
1500        self.names.join(".")
1501    }
1502}
1503/// A monotonic timestamp in microseconds.
1504#[allow(dead_code)]
1505#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
1506pub struct Timestamp(u64);
1507#[allow(dead_code)]
1508impl Timestamp {
1509    /// Creates a timestamp from microseconds.
1510    pub const fn from_us(us: u64) -> Self {
1511        Self(us)
1512    }
1513    /// Returns the timestamp in microseconds.
1514    pub fn as_us(self) -> u64 {
1515        self.0
1516    }
1517    /// Returns the duration between two timestamps.
1518    pub fn elapsed_since(self, earlier: Timestamp) -> u64 {
1519        self.0.saturating_sub(earlier.0)
1520    }
1521}
1522/// A clock that measures elapsed time in a loop.
1523#[allow(dead_code)]
1524pub struct LoopClock {
1525    start: crate::wall_clock::Instant,
1526    iters: u64,
1527}
1528#[allow(dead_code)]
1529impl LoopClock {
1530    /// Starts the clock.
1531    pub fn start() -> Self {
1532        Self {
1533            start: crate::wall_clock::Instant::now(),
1534            iters: 0,
1535        }
1536    }
1537    /// Records one iteration.
1538    pub fn tick(&mut self) {
1539        self.iters += 1;
1540    }
1541    /// Returns the elapsed time in microseconds.
1542    pub fn elapsed_us(&self) -> f64 {
1543        self.start.elapsed().as_secs_f64() * 1e6
1544    }
1545    /// Returns the average microseconds per iteration.
1546    pub fn avg_us_per_iter(&self) -> f64 {
1547        if self.iters == 0 {
1548            return 0.0;
1549        }
1550        self.elapsed_us() / self.iters as f64
1551    }
1552    /// Returns the number of iterations.
1553    pub fn iters(&self) -> u64 {
1554        self.iters
1555    }
1556}
1557/// A stream of pretty-printable tokens.
1558#[allow(dead_code)]
1559#[derive(Clone, Debug)]
1560pub enum PrettyToken {
1561    /// A keyword.
1562    Keyword(String),
1563    /// An identifier.
1564    Ident(String),
1565    /// A literal (number, string, etc.).
1566    Literal(String),
1567    /// An operator or punctuation.
1568    Operator(String),
1569    /// Whitespace.
1570    Space,
1571    /// A line break.
1572    LineBreak,
1573}
1574#[allow(dead_code)]
1575impl PrettyToken {
1576    /// Returns the raw text of the token (no color).
1577    pub fn raw_text(&self) -> &str {
1578        match self {
1579            PrettyToken::Keyword(s) => s.as_str(),
1580            PrettyToken::Ident(s) => s.as_str(),
1581            PrettyToken::Literal(s) => s.as_str(),
1582            PrettyToken::Operator(s) => s.as_str(),
1583            PrettyToken::Space => " ",
1584            PrettyToken::LineBreak => "\n",
1585        }
1586    }
1587    /// Returns colored text using the given color scheme.
1588    pub fn colored_text(&self, cs: &ColorScheme) -> String {
1589        match self {
1590            PrettyToken::Keyword(s) => format!("{}{}{}", cs.keyword, s, cs.reset),
1591            PrettyToken::Ident(s) => format!("{}{}{}", cs.ident, s, cs.reset),
1592            PrettyToken::Literal(s) => format!("{}{}{}", cs.literal, s, cs.reset),
1593            PrettyToken::Operator(s) => format!("{}{}{}", cs.operator, s, cs.reset),
1594            PrettyToken::Space => " ".to_string(),
1595            PrettyToken::LineBreak => "\n".to_string(),
1596        }
1597    }
1598}
1599/// Describes the indentation style used by the pretty printer.
1600#[allow(dead_code)]
1601#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1602pub enum IndentStyle {
1603    /// Indent using `n` space characters.
1604    Spaces(usize),
1605    /// Indent using a single tab character.
1606    Tabs,
1607}
1608#[allow(dead_code)]
1609impl IndentStyle {
1610    /// Returns the indentation string for one level.
1611    pub fn one_level(self) -> String {
1612        match self {
1613            IndentStyle::Spaces(n) => " ".repeat(n),
1614            IndentStyle::Tabs => "\t".to_string(),
1615        }
1616    }
1617    /// Returns the indentation string for `depth` levels.
1618    pub fn for_depth(self, depth: usize) -> String {
1619        self.one_level().repeat(depth)
1620    }
1621}
1622/// A set of ANSI color codes for syntax-highlighted pretty printing.
1623#[allow(dead_code)]
1624pub struct ColorScheme {
1625    /// Color for keywords.
1626    pub keyword: &'static str,
1627    /// Color for identifiers.
1628    pub ident: &'static str,
1629    /// Color for literals.
1630    pub literal: &'static str,
1631    /// Color for operators.
1632    pub operator: &'static str,
1633    /// Reset color.
1634    pub reset: &'static str,
1635}
1636#[allow(dead_code)]
1637impl ColorScheme {
1638    /// The default ANSI color scheme.
1639    pub const DEFAULT: ColorScheme = ColorScheme {
1640        keyword: "\x1b[34m",
1641        ident: "\x1b[0m",
1642        literal: "\x1b[32m",
1643        operator: "\x1b[33m",
1644        reset: "\x1b[0m",
1645    };
1646    /// A monochrome (no color) scheme.
1647    pub const MONO: ColorScheme = ColorScheme {
1648        keyword: "",
1649        ident: "",
1650        literal: "",
1651        operator: "",
1652        reset: "",
1653    };
1654    /// Returns `true` if this is a colored scheme.
1655    pub fn is_colored(&self) -> bool {
1656        !self.keyword.is_empty()
1657    }
1658}