use oxilean_kernel::{BinderInfo, Declaration, Expr, Level, Literal, Name};
use super::functions::*;
use std::fmt;
#[allow(dead_code)]
pub struct DiagnosticDisplay {
pub message: String,
pub location: Option<String>,
pub severity: u8,
pub snippet: Option<String>,
}
impl DiagnosticDisplay {
pub fn new(message: impl Into<String>, severity: u8) -> Self {
DiagnosticDisplay {
message: message.into(),
location: None,
severity,
snippet: None,
}
}
pub fn with_location(mut self, loc: impl Into<String>) -> Self {
self.location = Some(loc.into());
self
}
pub fn with_snippet(mut self, snip: impl Into<String>) -> Self {
self.snippet = Some(snip.into());
self
}
pub fn render(&self) -> String {
let prefix = match self.severity {
0 => "note",
1 => "warning",
_ => "error",
};
let loc = self
.location
.as_deref()
.map(|l| format!(" [{}]", l))
.unwrap_or_default();
let snip = self
.snippet
.as_deref()
.map(|s| format!("\n | {}", s))
.unwrap_or_default();
format!("{}{}: {}{}", prefix, loc, self.message, snip)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ShowMode {
Short,
Full,
Debug,
}
impl ShowMode {
pub fn to_config(self) -> ShowConfig {
match self {
ShowMode::Short => ShowConfig::compact(),
ShowMode::Full => ShowConfig::wide(),
ShowMode::Debug => ShowConfig::default().with_implicit().with_levels(),
}
}
}
#[allow(clippy::type_complexity)]
pub struct ShowRegistry {
formatters: Vec<(String, Box<dyn Fn(&Expr) -> String + Send + Sync>)>,
}
impl ShowRegistry {
pub fn new() -> Self {
ShowRegistry {
formatters: Vec::new(),
}
}
pub fn register<F>(&mut self, name: &str, f: F)
where
F: Fn(&Expr) -> String + Send + Sync + 'static,
{
self.formatters.push((name.to_string(), Box::new(f)));
}
pub fn format_all(&self, expr: &Expr) -> Vec<(String, String)> {
self.formatters
.iter()
.map(|(n, f)| (n.clone(), f(expr)))
.collect()
}
pub fn len(&self) -> usize {
self.formatters.len()
}
pub fn is_empty(&self) -> bool {
self.formatters.is_empty()
}
}
#[allow(dead_code)]
pub struct FormattedOutput {
pub rendered: String,
pub formatter: String,
pub truncated: bool,
pub char_count: usize,
}
impl FormattedOutput {
pub fn new(rendered: impl Into<String>, formatter: impl Into<String>, truncated: bool) -> Self {
let r = rendered.into();
let cc = r.chars().count();
FormattedOutput {
rendered: r,
formatter: formatter.into(),
truncated,
char_count: cc,
}
}
pub fn from_show<T: Show>(
value: &T,
formatter: impl Into<String>,
max_len: Option<usize>,
) -> Self {
let s = value.show();
let (rendered, truncated) = match max_len {
Some(n) if s.chars().count() > n => (truncate_show(&s, n), true),
_ => (s, false),
};
FormattedOutput::new(rendered, formatter, truncated)
}
}
#[allow(dead_code)]
pub struct ShowS {
pub label: String,
pub prefix: String,
}
impl ShowS {
pub fn new(label: impl Into<String>, prefix: impl Into<String>) -> Self {
ShowS {
label: label.into(),
prefix: prefix.into(),
}
}
pub fn apply(&self, rest: &str) -> String {
format!("{}{}", self.prefix, rest)
}
pub fn compose(&self, other: &ShowS) -> ShowS {
ShowS {
label: format!("{}.{}", self.label, other.label),
prefix: format!("{}{}", self.prefix, other.prefix),
}
}
pub fn identity() -> ShowS {
ShowS {
label: "id".to_string(),
prefix: String::new(),
}
}
}
#[derive(Clone, Debug)]
pub struct ShowConfig {
pub compact: bool,
pub ascii_only: bool,
pub max_depth: Option<usize>,
pub show_implicit: bool,
pub show_levels: bool,
pub show_binder_types: bool,
pub indent_step: usize,
}
impl ShowConfig {
pub fn compact() -> Self {
Self {
compact: true,
..Self::default()
}
}
pub fn wide() -> Self {
Self {
compact: false,
..Self::default()
}
}
pub fn ascii() -> Self {
Self {
ascii_only: true,
..Self::default()
}
}
pub fn with_depth(self, d: usize) -> Self {
Self {
max_depth: Some(d),
..self
}
}
pub fn unlimited(self) -> Self {
Self {
max_depth: None,
..self
}
}
pub fn with_implicit(self) -> Self {
Self {
show_implicit: true,
..self
}
}
pub fn with_levels(self) -> Self {
Self {
show_levels: true,
..self
}
}
pub fn arrow(&self) -> &'static str {
if self.ascii_only {
"->"
} else {
"→"
}
}
pub fn lambda(&self) -> &'static str {
"fun"
}
pub fn forall_kw(&self) -> &'static str {
if self.ascii_only {
"forall"
} else {
"∀"
}
}
}
#[derive(Clone, Debug, Default)]
pub struct ShowStats {
pub exprs_shown: u64,
pub depth_truncations: u64,
pub chars_produced: u64,
}
impl ShowStats {
pub fn new() -> Self {
Self::default()
}
pub fn record(&mut self, output_len: usize, truncated: bool) {
self.exprs_shown += 1;
self.chars_produced += output_len as u64;
if truncated {
self.depth_truncations += 1;
}
}
}
pub struct Showable<T: Show>(pub T);
#[allow(dead_code)]
pub struct PrettyDoc {
pub text: String,
pub width: usize,
pub indent: usize,
}
impl PrettyDoc {
pub fn text(s: impl Into<String>) -> Self {
let t = s.into();
let w = t.len();
PrettyDoc {
text: t,
width: w,
indent: 0,
}
}
pub fn concat(a: &PrettyDoc, b: &PrettyDoc) -> PrettyDoc {
PrettyDoc {
text: format!("{}{}", a.text, b.text),
width: a.width + b.width,
indent: a.indent,
}
}
pub fn nest(d: &PrettyDoc, extra: usize) -> PrettyDoc {
PrettyDoc {
text: d.text.clone(),
width: d.width,
indent: d.indent + extra,
}
}
pub fn render(&self) -> String {
self.text.clone()
}
}
#[allow(dead_code)]
pub struct ShowRegistryExt<T> {
pub type_name: String,
_phantom: std::marker::PhantomData<T>,
pub formatter_names: Vec<String>,
}
impl<T> ShowRegistryExt<T> {
pub fn new(type_name: impl Into<String>) -> Self {
ShowRegistryExt {
type_name: type_name.into(),
_phantom: std::marker::PhantomData,
formatter_names: Vec::new(),
}
}
pub fn register_name(&mut self, name: impl Into<String>) {
self.formatter_names.push(name.into());
}
pub fn count(&self) -> usize {
self.formatter_names.len()
}
}
#[derive(Clone, Debug, Default)]
pub struct ShowBuffer {
pub(super) buf: String,
pub(super) indent: usize,
pub(super) step: usize,
}
impl ShowBuffer {
pub fn new(step: usize) -> Self {
Self {
buf: String::new(),
indent: 0,
step,
}
}
pub fn push(&mut self, s: &str) {
self.buf.push_str(s);
}
pub fn push_char(&mut self, c: char) {
self.buf.push(c);
}
pub fn newline(&mut self) {
self.buf.push('\n');
for _ in 0..self.indent * self.step {
self.buf.push(' ');
}
}
pub fn indent(&mut self) {
self.indent += 1;
}
pub fn dedent(&mut self) {
self.indent = self.indent.saturating_sub(1);
}
pub fn finish(self) -> String {
self.buf
}
pub fn len(&self) -> usize {
self.buf.len()
}
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
pub fn with_indent<F: FnOnce(&mut ShowBuffer)>(&mut self, f: F) {
self.indent();
f(self);
self.dedent();
}
}