#[derive(Debug, Copy, Clone)]
pub enum Symbol {
Var(usize),
Zero,
One,
Bot,
Top,
Dual,
Bang,
Quest,
Tensor,
Par,
With,
Plus,
Lollipop,
}
#[derive(Debug)]
pub struct Term {
term: Box<[Symbol]>,
}
#[derive(Debug)]
struct TermView<'a> {
tv: &'a [Symbol],
}
#[derive(Debug)]
enum SymbolView<'a> {
Var(usize),
Zero,
One,
Bot,
Top,
Dual(TermView<'a>),
Bang(TermView<'a>),
Quest(TermView<'a>),
Tensor(TermView<'a>, TermView<'a>),
Par(TermView<'a>, TermView<'a>),
With(TermView<'a>, TermView<'a>),
Plus(TermView<'a>, TermView<'a>),
Lollipop(TermView<'a>, TermView<'a>),
}
impl<'a> TermView<'a> {
fn get_subterm_split_index(&'a self) -> usize {
let mut leaves_left = 1usize;
let mut it = self.tv.iter().enumerate();
let h = it.next();
use Symbol::*;
for (i, sym) in it {
match sym {
Var(_) | Zero | One | Bot | Top => {
if leaves_left == 1 {
return i + 1;
} else {
leaves_left -= 1
}
}
Dual | Bang | Quest => {}
Tensor | Par | With | Plus | Lollipop => {
leaves_left += 1;
}
}
}
unreachable!()
}
fn get_subterm_view(&'a self) -> SymbolView<'a> {
debug_assert!(!self.tv.is_empty());
use Symbol::*;
use SymbolView as SV;
match self.tv[0] {
Var(i) => SV::Var(i),
Zero => SV::Zero,
One => SV::One,
Bot => SV::Bot,
Top => SV::Top,
Dual => SV::Dual(TermView { tv: &self.tv[1..] }),
Bang => SV::Bang(TermView { tv: &self.tv[1..] }),
Quest => SV::Quest(TermView { tv: &self.tv[1..] }),
Tensor => {
let i = self.get_subterm_split_index();
SV::Tensor(
TermView { tv: &self.tv[1..i] },
TermView { tv: &self.tv[i..] },
)
}
Par => {
let i = self.get_subterm_split_index();
SV::Par(
TermView { tv: &self.tv[1..i] },
TermView { tv: &self.tv[i..] },
)
}
With => {
let i = self.get_subterm_split_index();
SV::With(
TermView { tv: &self.tv[1..i] },
TermView { tv: &self.tv[i..] },
)
}
Plus => {
let i = self.get_subterm_split_index();
SV::Plus(
TermView { tv: &self.tv[1..i] },
TermView { tv: &self.tv[i..] },
)
}
Lollipop => {
let i = self.get_subterm_split_index();
SV::Lollipop(
TermView { tv: &self.tv[1..i] },
TermView { tv: &self.tv[i..] },
)
}
}
}
fn write_to_string<const IS_OUTER_MOST: bool>(
&'a self,
s: &'a mut String,
labels: &'a [String],
) {
use SymbolView::*;
match self.get_subterm_view() {
Var(i) => s.push_str(&labels[i]),
Zero => s.push('0'),
One => s.push('1'),
Bot => s.push('⊥'),
Top => s.push('⊤'),
Dual(t) => {
s.push('~');
t.write_to_string::<false>(s, labels);
}
Bang(t) => {
s.push('!');
t.write_to_string::<false>(s, labels);
}
Quest(t) => {
s.push('?');
t.write_to_string::<false>(s, labels);
}
Tensor(t1, t2) => {
if !IS_OUTER_MOST {
s.push('(');
}
t1.write_to_string::<false>(s, labels);
s.push_str(" ⊗ ");
t2.write_to_string::<false>(s, labels);
if !IS_OUTER_MOST {
s.push(')');
}
}
Par(t1, t2) => {
if !IS_OUTER_MOST {
s.push('(');
}
t1.write_to_string::<false>(s, labels);
s.push_str(" ⅋ ");
t2.write_to_string::<false>(s, labels);
if !IS_OUTER_MOST {
s.push(')');
}
}
With(t1, t2) => {
if !IS_OUTER_MOST {
s.push('(');
}
t1.write_to_string::<false>(s, labels);
s.push_str(" & ");
t2.write_to_string::<false>(s, labels);
if !IS_OUTER_MOST {
s.push(')');
}
}
Plus(t1, t2) => {
if !IS_OUTER_MOST {
s.push('(');
}
t1.write_to_string::<false>(s, labels);
s.push_str(" ⊕ ");
t2.write_to_string::<false>(s, labels);
if !IS_OUTER_MOST {
s.push(')');
}
}
Lollipop(t1, t2) => {
if !IS_OUTER_MOST {
s.push('(');
}
t1.write_to_string::<false>(s, labels);
s.push_str(" ⊸ ");
t2.write_to_string::<false>(s, labels);
if !IS_OUTER_MOST {
s.push(')');
}
}
}
}
}
impl<'a> Term {
pub unsafe fn new_unsafe(term: Box<[Symbol]>) -> Self {
Self { term }
}
fn into_view(&'a self) -> TermView<'a> {
TermView { tv: &self.term }
}
}
#[derive(Debug)]
pub struct Sequent {
pub left: Box<[Term]>,
pub right: Box<[Term]>,
pub labels: Box<[String]>,
}
impl std::fmt::Display for Sequent {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let mut s = String::new();
fn add_term_vec(s: &mut String, terms: &[Term], labels: &[String]) {
debug_assert!(!terms.is_empty());
let mut it = terms.iter();
it.next()
.unwrap() .into_view()
.write_to_string::<true>(s, labels);
for t in it {
s.push_str(", ");
t.into_view().write_to_string::<true>(s, labels);
}
}
if !self.left.is_empty() {
add_term_vec(&mut s, &self.left, &self.labels);
s.push(' ');
}
s.push('⊢');
if !self.right.is_empty() {
s.push(' ');
add_term_vec(&mut s, &self.right, &self.labels);
}
write!(f, "{}", s)
}
}