smt2 0.2.0

A SMT-LIB 2.6 parsing/formatting library for Rust
Documentation
use std::fmt;
use source_span::Span;
use crate::{Located, Sort};
use super::TypeRef;

pub enum Error<S: Sort> {
	Missmatch(SortMissmatch<S>),
	Ambiguity
}

impl<S: Sort> Error<S> {
	pub fn at(self, span: Span) -> Located<Error<S>> {
		Located::new(self, span)
	}
}

pub type Result<T, S> = std::result::Result<T, Located<Error<S>>>;

impl<S: Sort + fmt::Display> fmt::Display for Error<S> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		use self::Error::*;
		match self {
			Missmatch(_) => write!(f, "mismatched sorts"),
			Ambiguity => write!(f, "sort ambiguity")
		}
	}
}

impl<S: Sort + fmt::Display> crate::error::Informative for Error<S> {
	fn informations(&self, i: &mut crate::error::Infos) {
		use self::Error::*;
		match self {
			Missmatch(m) => {
				let (expected, given) = m.mismatched_sorts();
				i.set_label(format!("expected `{}`, found `{}`", expected, given));
				i.add_note(format!("\x1b[1mnote:\x1b[m expected sort `{}`\n		 found sort `{}`", Expected(&m), Given(&m)));
			},
			Ambiguity => {
				i.set_label(format!("use the `(as {} <sort>)` type coercion construct to remove the ambiguity", i.content()));
			}
		}
	}
}

pub enum SortMissmatch<S: Sort> {
	Var(usize, Span),
	Match {
		sort: S,
		parameters: Vec<SortMissmatch<S>>
	},
	Miss {
		expected_sort: S,
		expected_parameters: Vec<TypeRef<S>>,

		given_sort: S,
		given_parameters: Vec<TypeRef<S>>
	}
}

pub struct Expected<'a, S: Sort>(&'a SortMissmatch<S>);

impl<'a, S: Sort + fmt::Display> fmt::Display for Expected<'a, S> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		use SortMissmatch::*;
		match &self.0 {
			Var(_, _) => write!(f, "_"),
			Match { sort, parameters } => {
				if parameters.is_empty() {
					write!(f, "{}", sort)
				} else {
					write!(f, "({}", sort)?;
					for p in parameters {
						write!(f, " {}", Expected(p))?;
					}
					write!(f, ")")
				}
			},
			Miss { expected_sort, expected_parameters, .. } => {
				if expected_parameters.is_empty() {
					write!(f, "\x1b[1m{}\x1b[m", expected_sort)
				} else {
					write!(f, "\x1b[1m({}", expected_sort)?;
					for p in expected_parameters {
						write!(f, " {}", p)?;
					}
					write!(f, ")\x1b[m")
				}
			}
		}
	}
}

pub struct Given<'a, S: Sort>(&'a SortMissmatch<S>);

impl<'a, S: Sort + fmt::Display> fmt::Display for Given<'a, S> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		use SortMissmatch::*;
		match &self.0 {
			Var(_, _) => write!(f, "_"),
			Match { sort, parameters } => {
				if parameters.is_empty() {
					write!(f, "{}", sort)
				} else {
					write!(f, "({}", sort)?;
					for p in parameters {
						write!(f, " {}", Given(p))?;
					}
					write!(f, ")")
				}
			},
			Miss { given_sort, given_parameters, .. } => {
				if given_parameters.is_empty() {
					write!(f, "\x1b[1m{}\x1b[m", given_sort)
				} else {
					write!(f, "\x1b[1m({}", given_sort)?;
					for p in given_parameters {
						write!(f, " {}", p)?;
					}
					write!(f, ")\x1b[m")
				}
			}
		}
	}
}

impl<S: Sort> SortMissmatch<S> {
	fn find_mismatched_sorts(&self) -> Option<(&S, &S)> {
		use SortMissmatch::*;
		match self {
			Var(_, _) => None,
			Match { parameters, .. } => {
				for p in parameters {
					if let Some(m) = p.find_mismatched_sorts() {
						return Some(m)
					}
				}

				None
			},
			Miss { expected_sort, given_sort, .. } => {
				Some((expected_sort, given_sort))
			}
		}
	}

	pub fn mismatched_sorts(&self) -> (&S, &S) {
		self.find_mismatched_sorts().unwrap()
	}
}