use std::rc::Rc;
use crate::eval::lazy::Thunk;
use crate::position::{RawSpan, TermPos};
use crate::types::{TypeF, Types};
use codespan::Files;
pub mod ty_path {
use crate::{
identifier::Ident,
types::{RecordRowF, RecordRowsF, TypeF, Types},
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Elem {
Domain,
Codomain,
Field(Ident),
Array,
}
pub type Path = Vec<Elem>;
pub fn is_only_codom(p: &Path) -> bool {
p.iter().all(|elt| *elt == Elem::Codomain)
}
pub fn has_no_arrow(p: &Path) -> bool {
!p.iter()
.any(|elt| matches!(*elt, Elem::Domain | Elem::Codomain))
}
pub fn span<'a, I>(mut path_it: std::iter::Peekable<I>, mut ty: &Types) -> (usize, usize)
where
I: Iterator<Item = &'a Elem>,
I: std::clone::Clone,
{
let forall_offset = match (&ty.0, path_it.peek()) {
(_, None) => {
let repr = format!("{}", ty);
return (0, repr.len());
}
(TypeF::Forall { .. }, Some(_)) => {
let mut result = 8;
while let TypeF::Forall { var, body, .. } = &ty.0 {
result += var.to_string().len() + 1;
ty = body.as_ref();
}
result
}
_ => 0,
};
match (&ty.0, path_it.next()) {
(TypeF::Arrow(dom, codom), Some(next)) => {
let paren_offset = match dom.0 {
TypeF::Arrow(_, _) => 1,
_ => 0,
};
match next {
Elem::Domain => {
let (dom_start, dom_end) = span(path_it, dom.as_ref());
(
dom_start + paren_offset + forall_offset,
dom_end + paren_offset + forall_offset,
)
}
Elem::Codomain => {
let (_, dom_end) = span(Vec::new().iter().peekable(), dom.as_ref());
let (codom_start, codom_end) = span(path_it, codom.as_ref());
let offset = (paren_offset * 2) + 4 + dom_end + forall_offset;
(codom_start + offset, codom_end + offset)
}
_ => panic!(),
}
}
(TypeF::Record(rows), Some(Elem::Field(ident))) => {
let mut start_offset = 1;
let id_offset = 2;
let end_offset = 2;
let mut row = &rows.0;
loop {
match row {
RecordRowsF::Extend {
row: RecordRowF { id, types: ty },
tail: _,
} if id == ident => {
let (sub_start, sub_end) = span(path_it, ty);
let full_offset = start_offset + format!("{}", id).len() + id_offset;
break (full_offset + sub_start, full_offset + sub_end);
}
RecordRowsF::Extend {
row: RecordRowF { id, types: ty },
tail,
} => {
start_offset += format!("{}", id).len()
+ id_offset
+ format!("{}", ty).len()
+ end_offset;
row = &tail.0;
}
_ => panic!(),
}
}
}
(TypeF::Array(ty), Some(Elem::Array)) if *ty.as_ref() == Types(TypeF::Dyn) =>
{
panic!("span(): unexpected blame of a dyn contract inside an array")
}
(TypeF::Array(ty), Some(Elem::Array)) => {
let start_offset = 6;
let paren_offset = if ty.fmt_is_atom() { 0 } else { 1 };
let (sub_start, sub_end) = span(path_it, ty);
(
start_offset + paren_offset + sub_start,
start_offset + paren_offset + sub_end,
)
}
(ty, next) => panic!(
"label::span: unexpected type {} with path element {:?}",
Types(ty.clone()),
next
),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Label {
pub types: Rc<Types>,
pub tag: String,
pub span: RawSpan,
pub arg_thunk: Option<Thunk>,
pub arg_pos: TermPos,
pub polarity: bool,
pub path: ty_path::Path,
}
impl Label {
pub fn dummy() -> Label {
Label {
types: Rc::new(Types(TypeF::Num)),
tag: "testing".to_string(),
span: RawSpan {
src_id: Files::new().add("<test>", String::from("empty")),
start: 0.into(),
end: 1.into(),
},
arg_thunk: None,
arg_pos: TermPos::None,
polarity: true,
path: Vec::new(),
}
}
}
impl Default for Label {
fn default() -> Label {
Label {
types: Rc::new(Types(TypeF::Dyn)),
tag: "".to_string(),
span: RawSpan {
src_id: Files::new().add("<null>", String::from("")),
start: 0.into(),
end: 1.into(),
},
arg_thunk: None,
arg_pos: TermPos::None,
polarity: true,
path: Vec::new(),
}
}
}