1use std::collections::{HashMap, VecDeque};
6use std::fmt;
7use std::fmt::Write as FmtWrite;
8
9use super::functions::*;
10use crate::{BinderInfo, Expr, Level, Name};
11
12pub struct ExprPrinter {
14 buffer: String,
16 pub(super) config: PrintConfig,
18}
19impl ExprPrinter {
20 pub fn new() -> Self {
22 Self {
23 buffer: String::new(),
24 config: PrintConfig::default(),
25 }
26 }
27 pub fn with_config(config: PrintConfig) -> Self {
29 Self {
30 buffer: String::new(),
31 config,
32 }
33 }
34 pub fn with_unicode(mut self, unicode: bool) -> Self {
36 self.config.unicode = unicode;
37 self
38 }
39 pub fn output(self) -> String {
41 self.buffer
42 }
43 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 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 fn print_sort(&mut self, level: &Level) -> fmt::Result {
230 match level {
231 Level::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 {
248 Level::Zero => write!(self.buffer, "0"),
249 Level::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 Level::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 Level::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 Level::Param(name) => self.print_name(name),
279 Level::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#[allow(dead_code)]
288pub struct SExprPrinter {
289 indent: usize,
290}
291#[allow(dead_code)]
292impl SExprPrinter {
293 pub fn new() -> Self {
295 Self { indent: 0 }
296 }
297 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 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 pub fn list(&self, items: &[String]) -> String {
319 format!("[{}]", items.join(", "))
320 }
321}
322#[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 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 pub fn put(&mut self, key: K, val: V) {
346 if let Some(&idx) = self.map.get(&key) {
347 self.vals[idx] = val;
348 self.order.retain(|&x| x != idx);
349 self.order.insert(0, idx);
350 return;
351 }
352 if self.keys.len() >= self.capacity {
353 let evict_idx = *self
354 .order
355 .last()
356 .expect("order list must be non-empty before eviction");
357 self.map.remove(&self.keys[evict_idx]);
358 self.order.pop();
359 self.keys[evict_idx] = key.clone();
360 self.vals[evict_idx] = val;
361 self.map.insert(key, evict_idx);
362 self.order.insert(0, evict_idx);
363 } else {
364 let idx = self.keys.len();
365 self.keys.push(key.clone());
366 self.vals.push(val);
367 self.map.insert(key, idx);
368 self.order.insert(0, idx);
369 }
370 }
371 pub fn get(&mut self, key: &K) -> Option<&V> {
373 let idx = *self.map.get(key)?;
374 self.order.retain(|&x| x != idx);
375 self.order.insert(0, idx);
376 Some(&self.vals[idx])
377 }
378 pub fn len(&self) -> usize {
380 self.keys.len()
381 }
382 pub fn is_empty(&self) -> bool {
384 self.keys.is_empty()
385 }
386}
387#[allow(dead_code)]
389#[derive(Clone, Debug)]
390pub enum PrettyDoc {
391 Text(String),
393 Newline,
395 Indent(Box<PrettyDoc>),
397 Concat(Box<PrettyDoc>, Box<PrettyDoc>),
399 Group(Box<PrettyDoc>),
401 Empty,
403}
404#[allow(dead_code)]
405impl PrettyDoc {
406 pub fn text(s: impl Into<String>) -> Self {
408 PrettyDoc::Text(s.into())
409 }
410 pub fn concat(a: PrettyDoc, b: PrettyDoc) -> Self {
412 PrettyDoc::Concat(Box::new(a), Box::new(b))
413 }
414 pub fn indent(inner: PrettyDoc) -> Self {
416 PrettyDoc::Indent(Box::new(inner))
417 }
418 pub fn group(inner: PrettyDoc) -> Self {
420 PrettyDoc::Group(Box::new(inner))
421 }
422 pub fn render(&self, _width: usize, style: IndentStyle) -> String {
424 let mut out = String::new();
425 let mut depth = 0usize;
426 self.render_inner(&mut out, &mut depth, &style);
427 out
428 }
429 fn render_inner(&self, out: &mut String, depth: &mut usize, style: &IndentStyle) {
430 match self {
431 PrettyDoc::Text(s) => out.push_str(s),
432 PrettyDoc::Newline => {
433 out.push('\n');
434 out.push_str(&style.for_depth(*depth));
435 }
436 PrettyDoc::Indent(inner) => {
437 *depth += 1;
438 inner.render_inner(out, depth, style);
439 *depth -= 1;
440 }
441 PrettyDoc::Concat(a, b) => {
442 a.render_inner(out, depth, style);
443 b.render_inner(out, depth, style);
444 }
445 PrettyDoc::Group(inner) => inner.render_inner(out, depth, style),
446 PrettyDoc::Empty => {}
447 }
448 }
449}
450#[allow(dead_code)]
452pub struct TokenPrinter {
453 config: PrettyConfig,
454 scheme: ColorScheme,
455}
456#[allow(dead_code)]
457impl TokenPrinter {
458 pub fn new(config: PrettyConfig) -> Self {
460 Self {
461 config,
462 scheme: ColorScheme::MONO,
463 }
464 }
465 pub fn with_colors(mut self, scheme: ColorScheme) -> Self {
467 self.scheme = scheme;
468 self
469 }
470 pub fn render(&self, tokens: &[PrettyToken]) -> String {
472 let mut out = String::new();
473 for tok in tokens {
474 if self.config.colored {
475 out.push_str(&tok.colored_text(&self.scheme));
476 } else {
477 out.push_str(tok.raw_text());
478 }
479 }
480 out
481 }
482 pub fn render_wrapped(&self, tokens: &[PrettyToken]) -> String {
484 let mut out = String::new();
485 let mut col = 0usize;
486 for tok in tokens {
487 let text = tok.raw_text();
488 if matches!(tok, PrettyToken::LineBreak) {
489 out.push('\n');
490 col = 0;
491 continue;
492 }
493 if col + text.len() > self.config.width && col > 0 {
494 out.push('\n');
495 col = 0;
496 }
497 out.push_str(text);
498 col += text.len();
499 }
500 out
501 }
502}
503#[allow(dead_code)]
505pub struct FmtWidth;
506#[allow(dead_code)]
507impl FmtWidth {
508 pub fn decimal_width(n: usize) -> usize {
510 if n == 0 {
511 return 1;
512 }
513 let mut w = 0;
514 let mut v = n;
515 while v > 0 {
516 v /= 10;
517 w += 1;
518 }
519 w
520 }
521 pub fn pad_right(s: &str, width: usize) -> String {
523 if s.len() >= width {
524 return s.to_string();
525 }
526 format!("{}{}", s, " ".repeat(width - s.len()))
527 }
528 pub fn pad_left(s: &str, width: usize) -> String {
530 if s.len() >= width {
531 return s.to_string();
532 }
533 format!("{}{}", " ".repeat(width - s.len()), s)
534 }
535 pub fn center(s: &str, width: usize) -> String {
537 if s.len() >= width {
538 return s.to_string();
539 }
540 let pad = width - s.len();
541 let left = pad / 2;
542 let right = pad - left;
543 format!("{}{}{}", " ".repeat(left), s, " ".repeat(right))
544 }
545}
546#[allow(dead_code)]
548#[derive(Clone, Debug)]
549pub enum Doc {
550 Empty,
552 Text(String),
554 Concat(Box<Doc>, Box<Doc>),
556 Line,
558 Nest(usize, Box<Doc>),
560 Union(Box<Doc>, Box<Doc>),
562}
563#[allow(dead_code)]
564impl Doc {
565 pub fn text(s: impl Into<String>) -> Self {
567 Doc::Text(s.into())
568 }
569 pub fn concat(self, other: Doc) -> Self {
571 Doc::Concat(Box::new(self), Box::new(other))
572 }
573 pub fn line() -> Self {
575 Doc::Line
576 }
577 pub fn nest(n: usize, doc: Doc) -> Self {
579 Doc::Nest(n, Box::new(doc))
580 }
581 pub fn render(&self, width: usize) -> String {
583 let mut out = String::new();
584 self.render_impl(0, &mut out, width);
585 out
586 }
587 fn render_impl(&self, indent: usize, out: &mut String, _width: usize) {
588 match self {
589 Doc::Empty => {}
590 Doc::Text(s) => out.push_str(s),
591 Doc::Concat(a, b) => {
592 a.render_impl(indent, out, _width);
593 b.render_impl(indent, out, _width);
594 }
595 Doc::Line => {
596 out.push('\n');
597 for _ in 0..indent {
598 out.push(' ');
599 }
600 }
601 Doc::Nest(n, doc) => {
602 doc.render_impl(indent + n, out, _width);
603 }
604 Doc::Union(a, _b) => {
605 a.render_impl(indent, out, _width);
606 }
607 }
608 }
609}
610#[allow(dead_code)]
612pub struct PrettyTable {
613 headers: Vec<String>,
614 rows: Vec<Vec<String>>,
615}
616#[allow(dead_code)]
617impl PrettyTable {
618 pub fn new(headers: Vec<String>) -> Self {
620 Self {
621 headers,
622 rows: Vec::new(),
623 }
624 }
625 pub fn add_row(&mut self, row: Vec<String>) {
627 let n = self.headers.len();
628 let mut r = row;
629 r.resize(n, String::new());
630 self.rows.push(r);
631 }
632 pub fn render(&self) -> String {
634 let n = self.headers.len();
635 let mut widths: Vec<usize> = self.headers.iter().map(|h| h.len()).collect();
636 for row in &self.rows {
637 for (i, cell) in row.iter().enumerate() {
638 if i < n {
639 widths[i] = widths[i].max(cell.len());
640 }
641 }
642 }
643 let sep: String = widths
644 .iter()
645 .map(|&w| "-".repeat(w + 2))
646 .collect::<Vec<_>>()
647 .join("+");
648 let sep = format!("+{}+", sep);
649 let mut out = String::new();
650 out.push_str(&sep);
651 out.push('\n');
652 let header_line: String = self
653 .headers
654 .iter()
655 .enumerate()
656 .map(|(i, h)| FmtWidth::pad_right(h, widths[i]))
657 .collect::<Vec<_>>()
658 .join(" | ");
659 out.push_str(&format!("| {} |", header_line));
660 out.push('\n');
661 out.push_str(&sep);
662 out.push('\n');
663 for row in &self.rows {
664 let line: String = (0..n)
665 .map(|i| {
666 FmtWidth::pad_right(row.get(i).map(|s| s.as_str()).unwrap_or(""), widths[i])
667 })
668 .collect::<Vec<_>>()
669 .join(" | ");
670 out.push_str(&format!("| {} |", line));
671 out.push('\n');
672 }
673 out.push_str(&sep);
674 out
675 }
676}
677#[allow(dead_code)]
679pub struct WorkQueue<T> {
680 items: std::collections::VecDeque<T>,
681}
682#[allow(dead_code)]
683impl<T> WorkQueue<T> {
684 pub fn new() -> Self {
686 Self {
687 items: std::collections::VecDeque::new(),
688 }
689 }
690 pub fn enqueue(&mut self, item: T) {
692 self.items.push_back(item);
693 }
694 pub fn dequeue(&mut self) -> Option<T> {
696 self.items.pop_front()
697 }
698 pub fn is_empty(&self) -> bool {
700 self.items.is_empty()
701 }
702 pub fn len(&self) -> usize {
704 self.items.len()
705 }
706}
707#[allow(dead_code)]
709pub struct DiagMeta {
710 pub(super) entries: Vec<(String, String)>,
711}
712#[allow(dead_code)]
713impl DiagMeta {
714 pub fn new() -> Self {
716 Self {
717 entries: Vec::new(),
718 }
719 }
720 pub fn add(&mut self, key: impl Into<String>, val: impl Into<String>) {
722 self.entries.push((key.into(), val.into()));
723 }
724 pub fn get(&self, key: &str) -> Option<&str> {
726 self.entries
727 .iter()
728 .find(|(k, _)| k == key)
729 .map(|(_, v)| v.as_str())
730 }
731 pub fn len(&self) -> usize {
733 self.entries.len()
734 }
735 pub fn is_empty(&self) -> bool {
737 self.entries.is_empty()
738 }
739}
740#[allow(dead_code)]
742#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
743pub struct TypedId<T> {
744 pub(super) id: u32,
745 _phantom: std::marker::PhantomData<T>,
746}
747#[allow(dead_code)]
748impl<T> TypedId<T> {
749 pub const fn new(id: u32) -> Self {
751 Self {
752 id,
753 _phantom: std::marker::PhantomData,
754 }
755 }
756 pub fn raw(&self) -> u32 {
758 self.id
759 }
760}
761#[allow(dead_code)]
763pub struct PrettyPrinterState {
764 output: String,
765 indent_depth: usize,
766 indent_str: String,
767 pub(crate) col: usize,
768 max_width: usize,
769}
770#[allow(dead_code)]
771impl PrettyPrinterState {
772 pub fn new(max_width: usize, indent: IndentStyle) -> Self {
774 Self {
775 output: String::new(),
776 indent_depth: 0,
777 indent_str: indent.one_level(),
778 col: 0,
779 max_width,
780 }
781 }
782 pub fn write(&mut self, s: &str) {
784 self.output.push_str(s);
785 self.col += s.len();
786 }
787 pub fn newline(&mut self) {
789 self.output.push('\n');
790 let indent = self.indent_str.repeat(self.indent_depth);
791 self.output.push_str(&indent);
792 self.col = indent.len();
793 }
794 pub fn push_indent(&mut self) {
796 self.indent_depth += 1;
797 }
798 pub fn pop_indent(&mut self) {
800 if self.indent_depth > 0 {
801 self.indent_depth -= 1;
802 }
803 }
804 pub fn over_width(&self) -> bool {
806 self.col > self.max_width
807 }
808 pub fn finish(self) -> String {
810 self.output
811 }
812}
813#[allow(dead_code)]
815pub struct IntervalSet {
816 intervals: Vec<(i64, i64)>,
817}
818#[allow(dead_code)]
819impl IntervalSet {
820 pub fn new() -> Self {
822 Self {
823 intervals: Vec::new(),
824 }
825 }
826 pub fn add(&mut self, lo: i64, hi: i64) {
828 if lo > hi {
829 return;
830 }
831 let mut new_lo = lo;
832 let mut new_hi = hi;
833 let mut i = 0;
834 while i < self.intervals.len() {
835 let (il, ih) = self.intervals[i];
836 if ih < new_lo - 1 {
837 i += 1;
838 continue;
839 }
840 if il > new_hi + 1 {
841 break;
842 }
843 new_lo = new_lo.min(il);
844 new_hi = new_hi.max(ih);
845 self.intervals.remove(i);
846 }
847 self.intervals.insert(i, (new_lo, new_hi));
848 }
849 pub fn contains(&self, x: i64) -> bool {
851 self.intervals.iter().any(|&(lo, hi)| x >= lo && x <= hi)
852 }
853 pub fn num_intervals(&self) -> usize {
855 self.intervals.len()
856 }
857 pub fn cardinality(&self) -> i64 {
859 self.intervals.iter().map(|&(lo, hi)| hi - lo + 1).sum()
860 }
861}
862#[allow(dead_code)]
864pub struct IdDispenser<T> {
865 next: u32,
866 _phantom: std::marker::PhantomData<T>,
867}
868#[allow(dead_code)]
869impl<T> IdDispenser<T> {
870 pub fn new() -> Self {
872 Self {
873 next: 0,
874 _phantom: std::marker::PhantomData,
875 }
876 }
877 #[allow(clippy::should_implement_trait)]
879 pub fn next(&mut self) -> TypedId<T> {
880 let id = TypedId::new(self.next);
881 self.next += 1;
882 id
883 }
884 pub fn count(&self) -> u32 {
886 self.next
887 }
888}
889#[allow(dead_code)]
891pub struct AnnotationTable {
892 map: std::collections::HashMap<String, Vec<String>>,
893}
894#[allow(dead_code)]
895impl AnnotationTable {
896 pub fn new() -> Self {
898 Self {
899 map: std::collections::HashMap::new(),
900 }
901 }
902 pub fn annotate(&mut self, key: impl Into<String>, val: impl Into<String>) {
904 self.map.entry(key.into()).or_default().push(val.into());
905 }
906 pub fn get_all(&self, key: &str) -> &[String] {
908 self.map.get(key).map(|v| v.as_slice()).unwrap_or(&[])
909 }
910 pub fn num_keys(&self) -> usize {
912 self.map.len()
913 }
914 pub fn has(&self, key: &str) -> bool {
916 self.map.contains_key(key)
917 }
918}
919#[allow(dead_code)]
921pub struct FrequencyTable<T: std::hash::Hash + Eq + Clone> {
922 counts: std::collections::HashMap<T, u64>,
923}
924#[allow(dead_code)]
925impl<T: std::hash::Hash + Eq + Clone> FrequencyTable<T> {
926 pub fn new() -> Self {
928 Self {
929 counts: std::collections::HashMap::new(),
930 }
931 }
932 pub fn record(&mut self, item: T) {
934 *self.counts.entry(item).or_insert(0) += 1;
935 }
936 pub fn freq(&self, item: &T) -> u64 {
938 self.counts.get(item).copied().unwrap_or(0)
939 }
940 pub fn most_frequent(&self) -> Option<(&T, u64)> {
942 self.counts
943 .iter()
944 .max_by_key(|(_, &v)| v)
945 .map(|(k, &v)| (k, v))
946 }
947 pub fn total(&self) -> u64 {
949 self.counts.values().sum()
950 }
951 pub fn distinct(&self) -> usize {
953 self.counts.len()
954 }
955}
956#[allow(dead_code)]
958pub struct DocBuilder {
959 doc: PrettyDoc,
960}
961#[allow(dead_code)]
962impl DocBuilder {
963 pub fn from(doc: PrettyDoc) -> Self {
965 Self { doc }
966 }
967 pub fn text(s: impl Into<String>) -> Self {
969 Self {
970 doc: PrettyDoc::text(s),
971 }
972 }
973 pub fn empty() -> Self {
975 Self {
976 doc: PrettyDoc::Empty,
977 }
978 }
979 pub fn then(self, other: PrettyDoc) -> Self {
981 Self {
982 doc: PrettyDoc::concat(self.doc, other),
983 }
984 }
985 pub fn then_text(self, s: impl Into<String>) -> Self {
987 self.then(PrettyDoc::text(s))
988 }
989 pub fn then_newline(self) -> Self {
991 self.then(PrettyDoc::Newline)
992 }
993 pub fn indented(self) -> Self {
995 Self {
996 doc: PrettyDoc::indent(self.doc),
997 }
998 }
999 pub fn build(self) -> PrettyDoc {
1001 self.doc
1002 }
1003}
1004#[allow(dead_code)]
1006pub struct WorkStack<T> {
1007 items: Vec<T>,
1008}
1009#[allow(dead_code)]
1010impl<T> WorkStack<T> {
1011 pub fn new() -> Self {
1013 Self { items: Vec::new() }
1014 }
1015 pub fn push(&mut self, item: T) {
1017 self.items.push(item);
1018 }
1019 pub fn pop(&mut self) -> Option<T> {
1021 self.items.pop()
1022 }
1023 pub fn is_empty(&self) -> bool {
1025 self.items.is_empty()
1026 }
1027 pub fn len(&self) -> usize {
1029 self.items.len()
1030 }
1031}
1032#[allow(dead_code)]
1034pub struct MemoSlot<T: Clone> {
1035 cached: Option<T>,
1036}
1037#[allow(dead_code)]
1038impl<T: Clone> MemoSlot<T> {
1039 pub fn new() -> Self {
1041 Self { cached: None }
1042 }
1043 pub fn get_or_compute(&mut self, f: impl FnOnce() -> T) -> &T {
1045 if self.cached.is_none() {
1046 self.cached = Some(f());
1047 }
1048 self.cached
1049 .as_ref()
1050 .expect("cached value must be initialized before access")
1051 }
1052 pub fn invalidate(&mut self) {
1054 self.cached = None;
1055 }
1056 pub fn is_cached(&self) -> bool {
1058 self.cached.is_some()
1059 }
1060}
1061#[allow(dead_code)]
1063#[allow(missing_docs)]
1064pub struct StatCache<K: std::hash::Hash + Eq + Clone, V: Clone> {
1065 pub inner: SimpleLruCache<K, V>,
1067 pub hits: u64,
1069 pub misses: u64,
1071}
1072#[allow(dead_code)]
1073impl<K: std::hash::Hash + Eq + Clone, V: Clone> StatCache<K, V> {
1074 pub fn new(capacity: usize) -> Self {
1076 Self {
1077 inner: SimpleLruCache::new(capacity),
1078 hits: 0,
1079 misses: 0,
1080 }
1081 }
1082 pub fn get(&mut self, key: &K) -> Option<&V> {
1084 let result = self.inner.get(key);
1085 if result.is_some() {
1086 self.hits += 1;
1087 } else {
1088 self.misses += 1;
1089 }
1090 None
1091 }
1092 pub fn put(&mut self, key: K, val: V) {
1094 self.inner.put(key, val);
1095 }
1096 pub fn hit_rate(&self) -> f64 {
1098 let total = self.hits + self.misses;
1099 if total == 0 {
1100 return 0.0;
1101 }
1102 self.hits as f64 / total as f64
1103 }
1104}
1105#[allow(dead_code)]
1107pub struct EscapeHelper;
1108#[allow(dead_code)]
1109impl EscapeHelper {
1110 pub fn escape_str(s: &str) -> String {
1112 let mut out = String::with_capacity(s.len() + 2);
1113 out.push('"');
1114 for c in s.chars() {
1115 match c {
1116 '"' => out.push_str("\\\""),
1117 '\\' => out.push_str("\\\\"),
1118 '\n' => out.push_str("\\n"),
1119 '\t' => out.push_str("\\t"),
1120 _ => out.push(c),
1121 }
1122 }
1123 out.push('"');
1124 out
1125 }
1126 pub fn unescape_str(s: &str) -> String {
1128 let s = if s.starts_with('"') && s.ends_with('"') && s.len() >= 2 {
1129 &s[1..s.len() - 1]
1130 } else {
1131 s
1132 };
1133 let mut out = String::new();
1134 let mut chars = s.chars().peekable();
1135 while let Some(c) = chars.next() {
1136 if c == '\\' {
1137 match chars.next() {
1138 Some('n') => out.push('\n'),
1139 Some('t') => out.push('\t'),
1140 Some('\\') => out.push('\\'),
1141 Some('"') => out.push('"'),
1142 Some(x) => {
1143 out.push('\\');
1144 out.push(x);
1145 }
1146 None => out.push('\\'),
1147 }
1148 } else {
1149 out.push(c);
1150 }
1151 }
1152 out
1153 }
1154}
1155#[allow(dead_code)]
1157pub struct EventCounter {
1158 counts: std::collections::HashMap<String, u64>,
1159}
1160#[allow(dead_code)]
1161impl EventCounter {
1162 pub fn new() -> Self {
1164 Self {
1165 counts: std::collections::HashMap::new(),
1166 }
1167 }
1168 pub fn inc(&mut self, event: &str) {
1170 *self.counts.entry(event.to_string()).or_insert(0) += 1;
1171 }
1172 pub fn add(&mut self, event: &str, n: u64) {
1174 *self.counts.entry(event.to_string()).or_insert(0) += n;
1175 }
1176 pub fn get(&self, event: &str) -> u64 {
1178 self.counts.get(event).copied().unwrap_or(0)
1179 }
1180 pub fn total(&self) -> u64 {
1182 self.counts.values().sum()
1183 }
1184 pub fn reset(&mut self) {
1186 self.counts.clear();
1187 }
1188 pub fn event_names(&self) -> Vec<&str> {
1190 self.counts.keys().map(|s| s.as_str()).collect()
1191 }
1192}
1193#[allow(dead_code)]
1195pub struct BiMap<A: std::hash::Hash + Eq + Clone, B: std::hash::Hash + Eq + Clone> {
1196 forward: std::collections::HashMap<A, B>,
1197 backward: std::collections::HashMap<B, A>,
1198}
1199#[allow(dead_code)]
1200impl<A: std::hash::Hash + Eq + Clone, B: std::hash::Hash + Eq + Clone> BiMap<A, B> {
1201 pub fn new() -> Self {
1203 Self {
1204 forward: std::collections::HashMap::new(),
1205 backward: std::collections::HashMap::new(),
1206 }
1207 }
1208 pub fn insert(&mut self, a: A, b: B) {
1210 self.forward.insert(a.clone(), b.clone());
1211 self.backward.insert(b, a);
1212 }
1213 pub fn get_b(&self, a: &A) -> Option<&B> {
1215 self.forward.get(a)
1216 }
1217 pub fn get_a(&self, b: &B) -> Option<&A> {
1219 self.backward.get(b)
1220 }
1221 pub fn len(&self) -> usize {
1223 self.forward.len()
1224 }
1225 pub fn is_empty(&self) -> bool {
1227 self.forward.is_empty()
1228 }
1229}
1230#[allow(dead_code)]
1232pub struct Slot<T> {
1233 inner: Option<T>,
1234}
1235#[allow(dead_code)]
1236impl<T> Slot<T> {
1237 pub fn empty() -> Self {
1239 Self { inner: None }
1240 }
1241 pub fn fill(&mut self, val: T) {
1243 assert!(self.inner.is_none(), "Slot: already filled");
1244 self.inner = Some(val);
1245 }
1246 pub fn get(&self) -> Option<&T> {
1248 self.inner.as_ref()
1249 }
1250 pub fn is_filled(&self) -> bool {
1252 self.inner.is_some()
1253 }
1254 pub fn take(&mut self) -> Option<T> {
1256 self.inner.take()
1257 }
1258 pub fn get_or_fill_with(&mut self, f: impl FnOnce() -> T) -> &T {
1260 if self.inner.is_none() {
1261 self.inner = Some(f());
1262 }
1263 self.inner
1264 .as_ref()
1265 .expect("inner value must be initialized before access")
1266 }
1267}
1268#[allow(dead_code)]
1270pub struct StringInterner {
1271 strings: Vec<String>,
1272 map: std::collections::HashMap<String, u32>,
1273}
1274#[allow(dead_code)]
1275impl StringInterner {
1276 pub fn new() -> Self {
1278 Self {
1279 strings: Vec::new(),
1280 map: std::collections::HashMap::new(),
1281 }
1282 }
1283 pub fn intern(&mut self, s: &str) -> u32 {
1285 if let Some(&id) = self.map.get(s) {
1286 return id;
1287 }
1288 let id = self.strings.len() as u32;
1289 self.strings.push(s.to_string());
1290 self.map.insert(s.to_string(), id);
1291 id
1292 }
1293 pub fn get(&self, id: u32) -> Option<&str> {
1295 self.strings.get(id as usize).map(|s| s.as_str())
1296 }
1297 pub fn len(&self) -> usize {
1299 self.strings.len()
1300 }
1301 pub fn is_empty(&self) -> bool {
1303 self.strings.is_empty()
1304 }
1305}
1306#[allow(dead_code)]
1308pub struct BoxedPrinter {
1309 width: usize,
1310}
1311#[allow(dead_code)]
1312impl BoxedPrinter {
1313 pub fn new(width: usize) -> Self {
1315 Self { width }
1316 }
1317 pub fn render(&self, doc: &PrettyDoc) -> String {
1319 doc.render(self.width, IndentStyle::Spaces(2))
1320 }
1321}
1322#[derive(Debug, Clone)]
1324pub struct PrintConfig {
1325 pub unicode: bool,
1327 pub show_implicit: bool,
1329 pub show_universes: bool,
1331 pub max_width: usize,
1333 pub show_binder_info: bool,
1335 pub show_indices: bool,
1337}
1338impl PrintConfig {
1339 pub fn ascii() -> Self {
1341 Self {
1342 unicode: false,
1343 ..Default::default()
1344 }
1345 }
1346 pub fn verbose() -> Self {
1348 Self {
1349 show_implicit: true,
1350 show_universes: true,
1351 show_binder_info: true,
1352 show_indices: true,
1353 ..Default::default()
1354 }
1355 }
1356}
1357#[allow(dead_code)]
1359#[allow(missing_docs)]
1360pub struct PrettyConfig {
1361 pub width: usize,
1363 pub indent: IndentStyle,
1365 pub colored: bool,
1367}
1368#[allow(dead_code)]
1369impl PrettyConfig {
1370 pub fn default_config() -> Self {
1372 Self {
1373 width: 80,
1374 indent: IndentStyle::Spaces(2),
1375 colored: false,
1376 }
1377 }
1378 pub fn compact() -> Self {
1380 Self {
1381 width: usize::MAX,
1382 indent: IndentStyle::Spaces(0),
1383 colored: false,
1384 }
1385 }
1386}
1387#[allow(dead_code)]
1389pub struct SparseBitSet {
1390 words: Vec<u64>,
1391}
1392#[allow(dead_code)]
1393impl SparseBitSet {
1394 pub fn new(capacity: usize) -> Self {
1396 let words = (capacity + 63) / 64;
1397 Self {
1398 words: vec![0u64; words],
1399 }
1400 }
1401 pub fn set(&mut self, i: usize) {
1403 let word = i / 64;
1404 let bit = i % 64;
1405 if word < self.words.len() {
1406 self.words[word] |= 1u64 << bit;
1407 }
1408 }
1409 pub fn clear(&mut self, i: usize) {
1411 let word = i / 64;
1412 let bit = i % 64;
1413 if word < self.words.len() {
1414 self.words[word] &= !(1u64 << bit);
1415 }
1416 }
1417 pub fn get(&self, i: usize) -> bool {
1419 let word = i / 64;
1420 let bit = i % 64;
1421 self.words.get(word).is_some_and(|w| w & (1u64 << bit) != 0)
1422 }
1423 pub fn count_ones(&self) -> u32 {
1425 self.words.iter().map(|w| w.count_ones()).sum()
1426 }
1427 pub fn union(&self, other: &SparseBitSet) -> SparseBitSet {
1429 let len = self.words.len().max(other.words.len());
1430 let mut result = SparseBitSet {
1431 words: vec![0u64; len],
1432 };
1433 for i in 0..self.words.len() {
1434 result.words[i] |= self.words[i];
1435 }
1436 for i in 0..other.words.len() {
1437 result.words[i] |= other.words[i];
1438 }
1439 result
1440 }
1441}
1442#[allow(dead_code)]
1444pub struct ScopeStack {
1445 names: Vec<String>,
1446}
1447#[allow(dead_code)]
1448impl ScopeStack {
1449 pub fn new() -> Self {
1451 Self { names: Vec::new() }
1452 }
1453 pub fn push(&mut self, name: impl Into<String>) {
1455 self.names.push(name.into());
1456 }
1457 pub fn pop(&mut self) -> Option<String> {
1459 self.names.pop()
1460 }
1461 pub fn current(&self) -> Option<&str> {
1463 self.names.last().map(|s| s.as_str())
1464 }
1465 pub fn depth(&self) -> usize {
1467 self.names.len()
1468 }
1469 pub fn is_empty(&self) -> bool {
1471 self.names.is_empty()
1472 }
1473 pub fn path(&self) -> String {
1475 self.names.join(".")
1476 }
1477}
1478#[allow(dead_code)]
1480#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
1481pub struct Timestamp(u64);
1482#[allow(dead_code)]
1483impl Timestamp {
1484 pub const fn from_us(us: u64) -> Self {
1486 Self(us)
1487 }
1488 pub fn as_us(self) -> u64 {
1490 self.0
1491 }
1492 pub fn elapsed_since(self, earlier: Timestamp) -> u64 {
1494 self.0.saturating_sub(earlier.0)
1495 }
1496}
1497#[allow(dead_code)]
1499pub struct LoopClock {
1500 start: std::time::Instant,
1501 iters: u64,
1502}
1503#[allow(dead_code)]
1504impl LoopClock {
1505 pub fn start() -> Self {
1507 Self {
1508 start: std::time::Instant::now(),
1509 iters: 0,
1510 }
1511 }
1512 pub fn tick(&mut self) {
1514 self.iters += 1;
1515 }
1516 pub fn elapsed_us(&self) -> f64 {
1518 self.start.elapsed().as_secs_f64() * 1e6
1519 }
1520 pub fn avg_us_per_iter(&self) -> f64 {
1522 if self.iters == 0 {
1523 return 0.0;
1524 }
1525 self.elapsed_us() / self.iters as f64
1526 }
1527 pub fn iters(&self) -> u64 {
1529 self.iters
1530 }
1531}
1532#[allow(dead_code)]
1534#[derive(Clone, Debug)]
1535pub enum PrettyToken {
1536 Keyword(String),
1538 Ident(String),
1540 Literal(String),
1542 Operator(String),
1544 Space,
1546 LineBreak,
1548}
1549#[allow(dead_code)]
1550impl PrettyToken {
1551 pub fn raw_text(&self) -> &str {
1553 match self {
1554 PrettyToken::Keyword(s) => s.as_str(),
1555 PrettyToken::Ident(s) => s.as_str(),
1556 PrettyToken::Literal(s) => s.as_str(),
1557 PrettyToken::Operator(s) => s.as_str(),
1558 PrettyToken::Space => " ",
1559 PrettyToken::LineBreak => "\n",
1560 }
1561 }
1562 pub fn colored_text(&self, cs: &ColorScheme) -> String {
1564 match self {
1565 PrettyToken::Keyword(s) => format!("{}{}{}", cs.keyword, s, cs.reset),
1566 PrettyToken::Ident(s) => format!("{}{}{}", cs.ident, s, cs.reset),
1567 PrettyToken::Literal(s) => format!("{}{}{}", cs.literal, s, cs.reset),
1568 PrettyToken::Operator(s) => format!("{}{}{}", cs.operator, s, cs.reset),
1569 PrettyToken::Space => " ".to_string(),
1570 PrettyToken::LineBreak => "\n".to_string(),
1571 }
1572 }
1573}
1574#[allow(dead_code)]
1576#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1577pub enum IndentStyle {
1578 Spaces(usize),
1580 Tabs,
1582}
1583#[allow(dead_code)]
1584impl IndentStyle {
1585 pub fn one_level(self) -> String {
1587 match self {
1588 IndentStyle::Spaces(n) => " ".repeat(n),
1589 IndentStyle::Tabs => "\t".to_string(),
1590 }
1591 }
1592 pub fn for_depth(self, depth: usize) -> String {
1594 self.one_level().repeat(depth)
1595 }
1596}
1597#[allow(dead_code)]
1599pub struct ColorScheme {
1600 pub keyword: &'static str,
1602 pub ident: &'static str,
1604 pub literal: &'static str,
1606 pub operator: &'static str,
1608 pub reset: &'static str,
1610}
1611#[allow(dead_code)]
1612impl ColorScheme {
1613 pub const DEFAULT: ColorScheme = ColorScheme {
1615 keyword: "\x1b[34m",
1616 ident: "\x1b[0m",
1617 literal: "\x1b[32m",
1618 operator: "\x1b[33m",
1619 reset: "\x1b[0m",
1620 };
1621 pub const MONO: ColorScheme = ColorScheme {
1623 keyword: "",
1624 ident: "",
1625 literal: "",
1626 operator: "",
1627 reset: "",
1628 };
1629 pub fn is_colored(&self) -> bool {
1631 !self.keyword.is_empty()
1632 }
1633}