1use oxilean_kernel::{BinderInfo, Declaration, Expr, Level, Literal, Name};
6
7use super::functions::*;
8use std::fmt;
9
10#[allow(dead_code)]
12pub struct DiagnosticDisplay {
13 pub message: String,
15 pub location: Option<String>,
17 pub severity: u8,
19 pub snippet: Option<String>,
21}
22impl DiagnosticDisplay {
23 pub fn new(message: impl Into<String>, severity: u8) -> Self {
25 DiagnosticDisplay {
26 message: message.into(),
27 location: None,
28 severity,
29 snippet: None,
30 }
31 }
32 pub fn with_location(mut self, loc: impl Into<String>) -> Self {
34 self.location = Some(loc.into());
35 self
36 }
37 pub fn with_snippet(mut self, snip: impl Into<String>) -> Self {
39 self.snippet = Some(snip.into());
40 self
41 }
42 pub fn render(&self) -> String {
44 let prefix = match self.severity {
45 0 => "note",
46 1 => "warning",
47 _ => "error",
48 };
49 let loc = self
50 .location
51 .as_deref()
52 .map(|l| format!(" [{}]", l))
53 .unwrap_or_default();
54 let snip = self
55 .snippet
56 .as_deref()
57 .map(|s| format!("\n | {}", s))
58 .unwrap_or_default();
59 format!("{}{}: {}{}", prefix, loc, self.message, snip)
60 }
61}
62#[derive(Clone, Copy, Debug, PartialEq, Eq)]
64pub enum ShowMode {
65 Short,
67 Full,
69 Debug,
71}
72impl ShowMode {
73 pub fn to_config(self) -> ShowConfig {
75 match self {
76 ShowMode::Short => ShowConfig::compact(),
77 ShowMode::Full => ShowConfig::wide(),
78 ShowMode::Debug => ShowConfig::default().with_implicit().with_levels(),
79 }
80 }
81}
82#[allow(clippy::type_complexity)]
84pub struct ShowRegistry {
85 formatters: Vec<(String, Box<dyn Fn(&Expr) -> String + Send + Sync>)>,
86}
87impl ShowRegistry {
88 pub fn new() -> Self {
90 ShowRegistry {
91 formatters: Vec::new(),
92 }
93 }
94 pub fn register<F>(&mut self, name: &str, f: F)
96 where
97 F: Fn(&Expr) -> String + Send + Sync + 'static,
98 {
99 self.formatters.push((name.to_string(), Box::new(f)));
100 }
101 pub fn format_all(&self, expr: &Expr) -> Vec<(String, String)> {
103 self.formatters
104 .iter()
105 .map(|(n, f)| (n.clone(), f(expr)))
106 .collect()
107 }
108 pub fn len(&self) -> usize {
110 self.formatters.len()
111 }
112 pub fn is_empty(&self) -> bool {
114 self.formatters.is_empty()
115 }
116}
117#[allow(dead_code)]
119pub struct FormattedOutput {
120 pub rendered: String,
122 pub formatter: String,
124 pub truncated: bool,
126 pub char_count: usize,
128}
129impl FormattedOutput {
130 pub fn new(rendered: impl Into<String>, formatter: impl Into<String>, truncated: bool) -> Self {
132 let r = rendered.into();
133 let cc = r.chars().count();
134 FormattedOutput {
135 rendered: r,
136 formatter: formatter.into(),
137 truncated,
138 char_count: cc,
139 }
140 }
141 pub fn from_show<T: Show>(
143 value: &T,
144 formatter: impl Into<String>,
145 max_len: Option<usize>,
146 ) -> Self {
147 let s = value.show();
148 let (rendered, truncated) = match max_len {
149 Some(n) if s.chars().count() > n => (truncate_show(&s, n), true),
150 _ => (s, false),
151 };
152 FormattedOutput::new(rendered, formatter, truncated)
153 }
154}
155#[allow(dead_code)]
158pub struct ShowS {
159 pub label: String,
161 pub prefix: String,
163}
164impl ShowS {
165 pub fn new(label: impl Into<String>, prefix: impl Into<String>) -> Self {
167 ShowS {
168 label: label.into(),
169 prefix: prefix.into(),
170 }
171 }
172 pub fn apply(&self, rest: &str) -> String {
174 format!("{}{}", self.prefix, rest)
175 }
176 pub fn compose(&self, other: &ShowS) -> ShowS {
178 ShowS {
179 label: format!("{}.{}", self.label, other.label),
180 prefix: format!("{}{}", self.prefix, other.prefix),
181 }
182 }
183 pub fn identity() -> ShowS {
185 ShowS {
186 label: "id".to_string(),
187 prefix: String::new(),
188 }
189 }
190}
191#[derive(Clone, Debug)]
193pub struct ShowConfig {
194 pub compact: bool,
196 pub ascii_only: bool,
198 pub max_depth: Option<usize>,
200 pub show_implicit: bool,
202 pub show_levels: bool,
204 pub show_binder_types: bool,
206 pub indent_step: usize,
208}
209impl ShowConfig {
210 pub fn compact() -> Self {
212 Self {
213 compact: true,
214 ..Self::default()
215 }
216 }
217 pub fn wide() -> Self {
219 Self {
220 compact: false,
221 ..Self::default()
222 }
223 }
224 pub fn ascii() -> Self {
226 Self {
227 ascii_only: true,
228 ..Self::default()
229 }
230 }
231 pub fn with_depth(self, d: usize) -> Self {
233 Self {
234 max_depth: Some(d),
235 ..self
236 }
237 }
238 pub fn unlimited(self) -> Self {
240 Self {
241 max_depth: None,
242 ..self
243 }
244 }
245 pub fn with_implicit(self) -> Self {
247 Self {
248 show_implicit: true,
249 ..self
250 }
251 }
252 pub fn with_levels(self) -> Self {
254 Self {
255 show_levels: true,
256 ..self
257 }
258 }
259 pub fn arrow(&self) -> &'static str {
261 if self.ascii_only {
262 "->"
263 } else {
264 "→"
265 }
266 }
267 pub fn lambda(&self) -> &'static str {
269 "fun"
270 }
271 pub fn forall_kw(&self) -> &'static str {
273 if self.ascii_only {
274 "forall"
275 } else {
276 "∀"
277 }
278 }
279}
280#[derive(Clone, Debug, Default)]
282pub struct ShowStats {
283 pub exprs_shown: u64,
285 pub depth_truncations: u64,
287 pub chars_produced: u64,
289}
290impl ShowStats {
291 pub fn new() -> Self {
293 Self::default()
294 }
295 pub fn record(&mut self, output_len: usize, truncated: bool) {
297 self.exprs_shown += 1;
298 self.chars_produced += output_len as u64;
299 if truncated {
300 self.depth_truncations += 1;
301 }
302 }
303}
304pub struct Showable<T: Show>(pub T);
306#[allow(dead_code)]
308pub struct PrettyDoc {
309 pub text: String,
311 pub width: usize,
313 pub indent: usize,
315}
316impl PrettyDoc {
317 pub fn text(s: impl Into<String>) -> Self {
319 let t = s.into();
320 let w = t.len();
321 PrettyDoc {
322 text: t,
323 width: w,
324 indent: 0,
325 }
326 }
327 pub fn concat(a: &PrettyDoc, b: &PrettyDoc) -> PrettyDoc {
329 PrettyDoc {
330 text: format!("{}{}", a.text, b.text),
331 width: a.width + b.width,
332 indent: a.indent,
333 }
334 }
335 pub fn nest(d: &PrettyDoc, extra: usize) -> PrettyDoc {
337 PrettyDoc {
338 text: d.text.clone(),
339 width: d.width,
340 indent: d.indent + extra,
341 }
342 }
343 pub fn render(&self) -> String {
345 self.text.clone()
346 }
347}
348#[allow(dead_code)]
350pub struct ShowRegistryExt<T> {
351 pub type_name: String,
353 _phantom: std::marker::PhantomData<T>,
355 pub formatter_names: Vec<String>,
357}
358impl<T> ShowRegistryExt<T> {
359 pub fn new(type_name: impl Into<String>) -> Self {
361 ShowRegistryExt {
362 type_name: type_name.into(),
363 _phantom: std::marker::PhantomData,
364 formatter_names: Vec::new(),
365 }
366 }
367 pub fn register_name(&mut self, name: impl Into<String>) {
369 self.formatter_names.push(name.into());
370 }
371 pub fn count(&self) -> usize {
373 self.formatter_names.len()
374 }
375}
376#[derive(Clone, Debug, Default)]
378pub struct ShowBuffer {
379 pub(super) buf: String,
381 pub(super) indent: usize,
383 pub(super) step: usize,
385}
386impl ShowBuffer {
387 pub fn new(step: usize) -> Self {
389 Self {
390 buf: String::new(),
391 indent: 0,
392 step,
393 }
394 }
395 pub fn push(&mut self, s: &str) {
397 self.buf.push_str(s);
398 }
399 pub fn push_char(&mut self, c: char) {
401 self.buf.push(c);
402 }
403 pub fn newline(&mut self) {
405 self.buf.push('\n');
406 for _ in 0..self.indent * self.step {
407 self.buf.push(' ');
408 }
409 }
410 pub fn indent(&mut self) {
412 self.indent += 1;
413 }
414 pub fn dedent(&mut self) {
416 self.indent = self.indent.saturating_sub(1);
417 }
418 pub fn finish(self) -> String {
420 self.buf
421 }
422 pub fn len(&self) -> usize {
424 self.buf.len()
425 }
426 pub fn is_empty(&self) -> bool {
428 self.buf.is_empty()
429 }
430 pub fn with_indent<F: FnOnce(&mut ShowBuffer)>(&mut self, f: F) {
432 self.indent();
433 f(self);
434 self.dedent();
435 }
436}