1use 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
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.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#[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) {
355 self.vals[idx] = val;
358 self.order.retain(|&x| x != idx);
361 self.order.insert(0, idx);
362 return;
363 }
364 match self.order.last() {
365 Some(&evict_idx) if self.keys.len() >= self.capacity => {
369 let map_key = key.clone();
374 let removed = self.map.remove_entry(&self.keys[evict_idx]);
375 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 self.map.insert(map_key, evict_idx);
384 drop((removed, old_key, old_val));
385 }
386 _ => {
389 let map_key = key.clone();
390 let idx = self.keys.len();
391 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 pub fn get(&mut self, key: &K) -> Option<&V> {
406 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 pub fn len(&self) -> usize {
415 self.keys.len()
416 }
417 pub fn is_empty(&self) -> bool {
419 self.keys.is_empty()
420 }
421}
422#[allow(dead_code)]
424#[derive(Clone, Debug)]
425pub enum PrettyDoc {
426 Text(String),
428 Newline,
430 Indent(Box<PrettyDoc>),
432 Concat(Box<PrettyDoc>, Box<PrettyDoc>),
434 Group(Box<PrettyDoc>),
436 Empty,
438}
439#[allow(dead_code)]
440impl PrettyDoc {
441 pub fn text(s: impl Into<String>) -> Self {
443 PrettyDoc::Text(s.into())
444 }
445 pub fn concat(a: PrettyDoc, b: PrettyDoc) -> Self {
447 PrettyDoc::Concat(Box::new(a), Box::new(b))
448 }
449 pub fn indent(inner: PrettyDoc) -> Self {
451 PrettyDoc::Indent(Box::new(inner))
452 }
453 pub fn group(inner: PrettyDoc) -> Self {
455 PrettyDoc::Group(Box::new(inner))
456 }
457 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#[allow(dead_code)]
487pub struct TokenPrinter {
488 config: PrettyConfig,
489 scheme: ColorScheme,
490}
491#[allow(dead_code)]
492impl TokenPrinter {
493 pub fn new(config: PrettyConfig) -> Self {
495 Self {
496 config,
497 scheme: ColorScheme::MONO,
498 }
499 }
500 pub fn with_colors(mut self, scheme: ColorScheme) -> Self {
502 self.scheme = scheme;
503 self
504 }
505 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 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#[allow(dead_code)]
540pub struct FmtWidth;
541#[allow(dead_code)]
542impl FmtWidth {
543 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 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 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 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#[allow(dead_code)]
583#[derive(Clone, Debug)]
584pub enum Doc {
585 Empty,
587 Text(String),
589 Concat(Box<Doc>, Box<Doc>),
591 Line,
593 Nest(usize, Box<Doc>),
595 Union(Box<Doc>, Box<Doc>),
597}
598#[allow(dead_code)]
599impl Doc {
600 pub fn text(s: impl Into<String>) -> Self {
602 Doc::Text(s.into())
603 }
604 pub fn concat(self, other: Doc) -> Self {
606 Doc::Concat(Box::new(self), Box::new(other))
607 }
608 pub fn line() -> Self {
610 Doc::Line
611 }
612 pub fn nest(n: usize, doc: Doc) -> Self {
614 Doc::Nest(n, Box::new(doc))
615 }
616 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#[allow(dead_code)]
647pub struct PrettyTable {
648 headers: Vec<String>,
649 rows: Vec<Vec<String>>,
650}
651#[allow(dead_code)]
652impl PrettyTable {
653 pub fn new(headers: Vec<String>) -> Self {
655 Self {
656 headers,
657 rows: Vec::new(),
658 }
659 }
660 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 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#[allow(dead_code)]
714pub struct WorkQueue<T> {
715 items: std::collections::VecDeque<T>,
716}
717#[allow(dead_code)]
718impl<T> WorkQueue<T> {
719 pub fn new() -> Self {
721 Self {
722 items: std::collections::VecDeque::new(),
723 }
724 }
725 pub fn enqueue(&mut self, item: T) {
727 self.items.push_back(item);
728 }
729 pub fn dequeue(&mut self) -> Option<T> {
731 self.items.pop_front()
732 }
733 pub fn is_empty(&self) -> bool {
735 self.items.is_empty()
736 }
737 pub fn len(&self) -> usize {
739 self.items.len()
740 }
741}
742#[allow(dead_code)]
744pub struct DiagMeta {
745 pub(super) entries: Vec<(String, String)>,
746}
747#[allow(dead_code)]
748impl DiagMeta {
749 pub fn new() -> Self {
751 Self {
752 entries: Vec::new(),
753 }
754 }
755 pub fn add(&mut self, key: impl Into<String>, val: impl Into<String>) {
757 self.entries.push((key.into(), val.into()));
758 }
759 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 pub fn len(&self) -> usize {
768 self.entries.len()
769 }
770 pub fn is_empty(&self) -> bool {
772 self.entries.is_empty()
773 }
774}
775#[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 pub const fn new(id: u32) -> Self {
786 Self {
787 id,
788 _phantom: std::marker::PhantomData,
789 }
790 }
791 pub fn raw(&self) -> u32 {
793 self.id
794 }
795}
796#[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 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 pub fn write(&mut self, s: &str) {
819 self.output.push_str(s);
820 self.col += s.len();
821 }
822 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 pub fn push_indent(&mut self) {
831 self.indent_depth += 1;
832 }
833 pub fn pop_indent(&mut self) {
835 if self.indent_depth > 0 {
836 self.indent_depth -= 1;
837 }
838 }
839 pub fn over_width(&self) -> bool {
841 self.col > self.max_width
842 }
843 pub fn finish(self) -> String {
845 self.output
846 }
847}
848#[allow(dead_code)]
850pub struct IntervalSet {
851 intervals: Vec<(i64, i64)>,
852}
853#[allow(dead_code)]
854impl IntervalSet {
855 pub fn new() -> Self {
857 Self {
858 intervals: Vec::new(),
859 }
860 }
861 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 pub fn contains(&self, x: i64) -> bool {
886 self.intervals.iter().any(|&(lo, hi)| x >= lo && x <= hi)
887 }
888 pub fn num_intervals(&self) -> usize {
890 self.intervals.len()
891 }
892 pub fn cardinality(&self) -> i64 {
894 self.intervals.iter().map(|&(lo, hi)| hi - lo + 1).sum()
895 }
896}
897#[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 pub fn new() -> Self {
907 Self {
908 next: 0,
909 _phantom: std::marker::PhantomData,
910 }
911 }
912 #[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 pub fn count(&self) -> u32 {
921 self.next
922 }
923}
924#[allow(dead_code)]
926pub struct AnnotationTable {
927 map: std::collections::HashMap<String, Vec<String>>,
928}
929#[allow(dead_code)]
930impl AnnotationTable {
931 pub fn new() -> Self {
933 Self {
934 map: std::collections::HashMap::new(),
935 }
936 }
937 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 pub fn get_all(&self, key: &str) -> &[String] {
943 self.map.get(key).map(|v| v.as_slice()).unwrap_or(&[])
944 }
945 pub fn num_keys(&self) -> usize {
947 self.map.len()
948 }
949 pub fn has(&self, key: &str) -> bool {
951 self.map.contains_key(key)
952 }
953}
954#[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 pub fn new() -> Self {
963 Self {
964 counts: std::collections::HashMap::new(),
965 }
966 }
967 pub fn record(&mut self, item: T) {
969 *self.counts.entry(item).or_insert(0) += 1;
970 }
971 pub fn freq(&self, item: &T) -> u64 {
973 self.counts.get(item).copied().unwrap_or(0)
974 }
975 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 pub fn total(&self) -> u64 {
984 self.counts.values().sum()
985 }
986 pub fn distinct(&self) -> usize {
988 self.counts.len()
989 }
990}
991#[allow(dead_code)]
993pub struct DocBuilder {
994 doc: PrettyDoc,
995}
996#[allow(dead_code)]
997impl DocBuilder {
998 pub fn from(doc: PrettyDoc) -> Self {
1000 Self { doc }
1001 }
1002 pub fn text(s: impl Into<String>) -> Self {
1004 Self {
1005 doc: PrettyDoc::text(s),
1006 }
1007 }
1008 pub fn empty() -> Self {
1010 Self {
1011 doc: PrettyDoc::Empty,
1012 }
1013 }
1014 pub fn then(self, other: PrettyDoc) -> Self {
1016 Self {
1017 doc: PrettyDoc::concat(self.doc, other),
1018 }
1019 }
1020 pub fn then_text(self, s: impl Into<String>) -> Self {
1022 self.then(PrettyDoc::text(s))
1023 }
1024 pub fn then_newline(self) -> Self {
1026 self.then(PrettyDoc::Newline)
1027 }
1028 pub fn indented(self) -> Self {
1030 Self {
1031 doc: PrettyDoc::indent(self.doc),
1032 }
1033 }
1034 pub fn build(self) -> PrettyDoc {
1036 self.doc
1037 }
1038}
1039#[allow(dead_code)]
1041pub struct WorkStack<T> {
1042 items: Vec<T>,
1043}
1044#[allow(dead_code)]
1045impl<T> WorkStack<T> {
1046 pub fn new() -> Self {
1048 Self { items: Vec::new() }
1049 }
1050 pub fn push(&mut self, item: T) {
1052 self.items.push(item);
1053 }
1054 pub fn pop(&mut self) -> Option<T> {
1056 self.items.pop()
1057 }
1058 pub fn is_empty(&self) -> bool {
1060 self.items.is_empty()
1061 }
1062 pub fn len(&self) -> usize {
1064 self.items.len()
1065 }
1066}
1067#[allow(dead_code)]
1069pub struct MemoSlot<T: Clone> {
1070 cached: Option<T>,
1071}
1072#[allow(dead_code)]
1073impl<T: Clone> MemoSlot<T> {
1074 pub fn new() -> Self {
1076 Self { cached: None }
1077 }
1078 pub fn get_or_compute(&mut self, f: impl FnOnce() -> T) -> &T {
1080 self.cached.get_or_insert_with(f)
1081 }
1082 pub fn invalidate(&mut self) {
1084 self.cached = None;
1085 }
1086 pub fn is_cached(&self) -> bool {
1088 self.cached.is_some()
1089 }
1090}
1091#[allow(dead_code)]
1093#[allow(missing_docs)]
1094pub struct StatCache<K: std::hash::Hash + Eq + Clone, V: Clone> {
1095 pub inner: SimpleLruCache<K, V>,
1097 pub hits: u64,
1099 pub misses: u64,
1101}
1102#[allow(dead_code)]
1103impl<K: std::hash::Hash + Eq + Clone, V: Clone> StatCache<K, V> {
1104 pub fn new(capacity: usize) -> Self {
1106 Self {
1107 inner: SimpleLruCache::new(capacity),
1108 hits: 0,
1109 misses: 0,
1110 }
1111 }
1112 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 pub fn put(&mut self, key: K, val: V) {
1124 self.inner.put(key, val);
1125 }
1126 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#[allow(dead_code)]
1137pub struct EscapeHelper;
1138#[allow(dead_code)]
1139impl EscapeHelper {
1140 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 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#[allow(dead_code)]
1187pub struct EventCounter {
1188 counts: std::collections::HashMap<String, u64>,
1189}
1190#[allow(dead_code)]
1191impl EventCounter {
1192 pub fn new() -> Self {
1194 Self {
1195 counts: std::collections::HashMap::new(),
1196 }
1197 }
1198 pub fn inc(&mut self, event: &str) {
1200 *self.counts.entry(event.to_string()).or_insert(0) += 1;
1201 }
1202 pub fn add(&mut self, event: &str, n: u64) {
1204 *self.counts.entry(event.to_string()).or_insert(0) += n;
1205 }
1206 pub fn get(&self, event: &str) -> u64 {
1208 self.counts.get(event).copied().unwrap_or(0)
1209 }
1210 pub fn total(&self) -> u64 {
1212 self.counts.values().sum()
1213 }
1214 pub fn reset(&mut self) {
1216 self.counts.clear();
1217 }
1218 pub fn event_names(&self) -> Vec<&str> {
1220 self.counts.keys().map(|s| s.as_str()).collect()
1221 }
1222}
1223#[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 pub fn new() -> Self {
1233 Self {
1234 forward: std::collections::HashMap::new(),
1235 backward: std::collections::HashMap::new(),
1236 }
1237 }
1238 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 pub fn get_b(&self, a: &A) -> Option<&B> {
1245 self.forward.get(a)
1246 }
1247 pub fn get_a(&self, b: &B) -> Option<&A> {
1249 self.backward.get(b)
1250 }
1251 pub fn len(&self) -> usize {
1253 self.forward.len()
1254 }
1255 pub fn is_empty(&self) -> bool {
1257 self.forward.is_empty()
1258 }
1259}
1260#[allow(dead_code)]
1262pub struct Slot<T> {
1263 inner: Option<T>,
1264}
1265#[allow(dead_code)]
1266impl<T> Slot<T> {
1267 pub fn empty() -> Self {
1269 Self { inner: None }
1270 }
1271 pub fn fill(&mut self, val: T) {
1273 assert!(self.inner.is_none(), "Slot: already filled");
1274 self.inner = Some(val);
1275 }
1276 pub fn get(&self) -> Option<&T> {
1278 self.inner.as_ref()
1279 }
1280 pub fn is_filled(&self) -> bool {
1282 self.inner.is_some()
1283 }
1284 pub fn take(&mut self) -> Option<T> {
1286 self.inner.take()
1287 }
1288 pub fn get_or_fill_with(&mut self, f: impl FnOnce() -> T) -> &T {
1290 self.inner.get_or_insert_with(f)
1291 }
1292}
1293#[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 pub fn new() -> Self {
1303 Self {
1304 strings: Vec::new(),
1305 map: std::collections::HashMap::new(),
1306 }
1307 }
1308 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 pub fn get(&self, id: u32) -> Option<&str> {
1320 self.strings.get(id as usize).map(|s| s.as_str())
1321 }
1322 pub fn len(&self) -> usize {
1324 self.strings.len()
1325 }
1326 pub fn is_empty(&self) -> bool {
1328 self.strings.is_empty()
1329 }
1330}
1331#[allow(dead_code)]
1333pub struct BoxedPrinter {
1334 width: usize,
1335}
1336#[allow(dead_code)]
1337impl BoxedPrinter {
1338 pub fn new(width: usize) -> Self {
1340 Self { width }
1341 }
1342 pub fn render(&self, doc: &PrettyDoc) -> String {
1344 doc.render(self.width, IndentStyle::Spaces(2))
1345 }
1346}
1347#[derive(Debug, Clone)]
1349pub struct PrintConfig {
1350 pub unicode: bool,
1352 pub show_implicit: bool,
1354 pub show_universes: bool,
1356 pub max_width: usize,
1358 pub show_binder_info: bool,
1360 pub show_indices: bool,
1362}
1363impl PrintConfig {
1364 pub fn ascii() -> Self {
1366 Self {
1367 unicode: false,
1368 ..Default::default()
1369 }
1370 }
1371 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#[allow(dead_code)]
1384#[allow(missing_docs)]
1385pub struct PrettyConfig {
1386 pub width: usize,
1388 pub indent: IndentStyle,
1390 pub colored: bool,
1392}
1393#[allow(dead_code)]
1394impl PrettyConfig {
1395 pub fn default_config() -> Self {
1397 Self {
1398 width: 80,
1399 indent: IndentStyle::Spaces(2),
1400 colored: false,
1401 }
1402 }
1403 pub fn compact() -> Self {
1405 Self {
1406 width: usize::MAX,
1407 indent: IndentStyle::Spaces(0),
1408 colored: false,
1409 }
1410 }
1411}
1412#[allow(dead_code)]
1414pub struct SparseBitSet {
1415 words: Vec<u64>,
1416}
1417#[allow(dead_code)]
1418impl SparseBitSet {
1419 pub fn new(capacity: usize) -> Self {
1421 let words = capacity.div_ceil(64);
1422 Self {
1423 words: vec![0u64; words],
1424 }
1425 }
1426 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 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 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 pub fn count_ones(&self) -> u32 {
1450 self.words.iter().map(|w| w.count_ones()).sum()
1451 }
1452 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#[allow(dead_code)]
1469pub struct ScopeStack {
1470 names: Vec<String>,
1471}
1472#[allow(dead_code)]
1473impl ScopeStack {
1474 pub fn new() -> Self {
1476 Self { names: Vec::new() }
1477 }
1478 pub fn push(&mut self, name: impl Into<String>) {
1480 self.names.push(name.into());
1481 }
1482 pub fn pop(&mut self) -> Option<String> {
1484 self.names.pop()
1485 }
1486 pub fn current(&self) -> Option<&str> {
1488 self.names.last().map(|s| s.as_str())
1489 }
1490 pub fn depth(&self) -> usize {
1492 self.names.len()
1493 }
1494 pub fn is_empty(&self) -> bool {
1496 self.names.is_empty()
1497 }
1498 pub fn path(&self) -> String {
1500 self.names.join(".")
1501 }
1502}
1503#[allow(dead_code)]
1505#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
1506pub struct Timestamp(u64);
1507#[allow(dead_code)]
1508impl Timestamp {
1509 pub const fn from_us(us: u64) -> Self {
1511 Self(us)
1512 }
1513 pub fn as_us(self) -> u64 {
1515 self.0
1516 }
1517 pub fn elapsed_since(self, earlier: Timestamp) -> u64 {
1519 self.0.saturating_sub(earlier.0)
1520 }
1521}
1522#[allow(dead_code)]
1524pub struct LoopClock {
1525 start: crate::wall_clock::Instant,
1526 iters: u64,
1527}
1528#[allow(dead_code)]
1529impl LoopClock {
1530 pub fn start() -> Self {
1532 Self {
1533 start: crate::wall_clock::Instant::now(),
1534 iters: 0,
1535 }
1536 }
1537 pub fn tick(&mut self) {
1539 self.iters += 1;
1540 }
1541 pub fn elapsed_us(&self) -> f64 {
1543 self.start.elapsed().as_secs_f64() * 1e6
1544 }
1545 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 pub fn iters(&self) -> u64 {
1554 self.iters
1555 }
1556}
1557#[allow(dead_code)]
1559#[derive(Clone, Debug)]
1560pub enum PrettyToken {
1561 Keyword(String),
1563 Ident(String),
1565 Literal(String),
1567 Operator(String),
1569 Space,
1571 LineBreak,
1573}
1574#[allow(dead_code)]
1575impl PrettyToken {
1576 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 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#[allow(dead_code)]
1601#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1602pub enum IndentStyle {
1603 Spaces(usize),
1605 Tabs,
1607}
1608#[allow(dead_code)]
1609impl IndentStyle {
1610 pub fn one_level(self) -> String {
1612 match self {
1613 IndentStyle::Spaces(n) => " ".repeat(n),
1614 IndentStyle::Tabs => "\t".to_string(),
1615 }
1616 }
1617 pub fn for_depth(self, depth: usize) -> String {
1619 self.one_level().repeat(depth)
1620 }
1621}
1622#[allow(dead_code)]
1624pub struct ColorScheme {
1625 pub keyword: &'static str,
1627 pub ident: &'static str,
1629 pub literal: &'static str,
1631 pub operator: &'static str,
1633 pub reset: &'static str,
1635}
1636#[allow(dead_code)]
1637impl ColorScheme {
1638 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 pub const MONO: ColorScheme = ColorScheme {
1648 keyword: "",
1649 ident: "",
1650 literal: "",
1651 operator: "",
1652 reset: "",
1653 };
1654 pub fn is_colored(&self) -> bool {
1656 !self.keyword.is_empty()
1657 }
1658}