use crate::lang::label::Label;
use crate::value::span::Span;
#[derive(Clone, PartialEq)]
pub(crate) enum Node {
Space(Span),
Comma(Span),
Tag(Span, Vec<u8>),
Bytes(Span, Vec<u8>),
Label(Span, Label),
List(Span, Vec<Node>),
Map(Span, Vec<Node>),
Pipe(Span, Vec<Node>),
Paren(Span, Vec<Node>),
Bracket(Span, Vec<Node>),
And(Span, Vec<Node>),
Or(Span, Vec<Node>),
Thunk(Span, Vec<Node>),
Semicolon(Span, Vec<Node>),
}
impl Default for Node {
fn default() -> Self {
Node::Bytes(Span::default(), Vec::default())
}
}
impl core::fmt::Debug for Node {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let u8l = |n| String::from_utf8_lossy(n).into_owned();
match self {
Node::Space(s) => write!(f, "Node::Space({s:?})"),
Node::Comma(s) => write!(f, "Node::Comma({s:?})"),
Node::Tag(s, n) => write!(f, "Node::Tag({s:?}, {:?})", u8l(n)),
Node::Bytes(s, n) => write!(f, "Node::Bytes({s:?}, {:?})", u8l(n)),
Node::Label(s, n) => write!(f, "Node::Label({s:?}, \"{n:?}\")"),
Node::List(s, n) => write!(f, "Node::List({s:?}, {n:?})"),
Node::Map(s, n) => write!(f, "Node::Map({s:?}, {n:?})"),
Node::Pipe(s, n) => write!(f, "Node::Pipe({s:?}, {n:?})"),
Node::Paren(s, n) => write!(f, "Node::Paren({s:?}, {n:?})"),
Node::Bracket(s, n) => write!(f, "Node::Bracket({s:?}, {n:?})"),
Node::And(s, n) => write!(f, "Node::And({s:?}, {n:?})"),
Node::Or(s, n) => write!(f, "Node::Or({s:?}, {n:?})"),
Node::Semicolon(s, n) => write!(f, "Node::Semicolon({s:?}, {n:?})"),
Node::Thunk(s, n) => write!(f, "Node::Thunk({s:?}, {n:?})"),
}
}
}
impl From<&Node> for Span {
fn from(value: &Node) -> Self {
match value {
Node::Space(s) => *s,
Node::Comma(s) => *s,
Node::Tag(s, _) => *s,
Node::Bytes(s, _) => *s,
Node::Label(s, _) => *s,
Node::List(s, _) => *s,
Node::Map(s, _) => *s,
Node::Pipe(s, _) => *s,
Node::Paren(s, _) => *s,
Node::Bracket(s, _) => *s,
Node::And(s, _) => *s,
Node::Or(s, _) => *s,
Node::Thunk(s, _) => *s,
Node::Semicolon(s, _) => *s,
}
}
}
impl Node {
pub(crate) fn is_pipe(&self) -> bool {
matches!(
self,
Node::Pipe(..) | Node::And(..) | Node::Or(..) | Node::Semicolon(..)
)
}
pub(crate) fn list(&self) -> &[Self] {
match self {
Node::Space(..) => &[],
Node::Comma(..) => &[],
Node::Tag(..) => &[],
Node::Bytes(..) => &[],
Node::Label(..) => &[],
Node::List(_, n) => n,
Node::Map(_, n) => n,
Node::Pipe(_, n) => n,
Node::Paren(_, n) => n,
Node::Bracket(_, n) => n,
Node::And(_, n) => n,
Node::Or(_, n) => n,
Node::Semicolon(_, n) => n,
Node::Thunk(_, n) => n,
}
}
pub(crate) fn list_mut(&mut self) -> Option<&mut Vec<Self>> {
match self {
Node::Space(..) => None,
Node::Comma(..) => None,
Node::Tag(..) => None,
Node::Bytes(..) => None,
Node::Label(..) => None,
Node::List(_, n) => Some(n),
Node::Map(_, n) => Some(n),
Node::Pipe(_, n) => Some(n),
Node::Paren(_, n) => Some(n),
Node::Bracket(_, n) => Some(n),
Node::And(_, n) => Some(n),
Node::Or(_, n) => Some(n),
Node::Semicolon(_, n) => Some(n),
Node::Thunk(_, n) => Some(n),
}
}
pub(crate) fn into_list(self) -> Option<Vec<Self>> {
match self {
Node::Space(..) => None,
Node::Comma(..) => None,
Node::Tag(..) => None,
Node::Bytes(..) => None,
Node::Label(..) => None,
Node::List(_, n) => Some(n),
Node::Map(_, n) => Some(n),
Node::Pipe(_, n) => Some(n),
Node::Paren(_, n) => Some(n),
Node::Bracket(_, n) => Some(n),
Node::And(_, n) => Some(n),
Node::Or(_, n) => Some(n),
Node::Semicolon(_, n) => Some(n),
Node::Thunk(_, n) => Some(n),
}
}
pub(crate) fn as_label(&self) -> Option<&Label> {
match self {
Node::Label(_, label) => Some(label),
_ => None,
}
}
pub(crate) fn try_remove(&mut self, index: usize) -> Option<Node> {
self.list_mut()
.filter(|l| l.get(index).is_some())
.map(|l| l.remove(index))
}
}
pub(crate) fn pipe_from_nodes(mut nodes: Vec<Node>) -> Node {
if nodes.len() != 1 {
return Node::Pipe(span_from_nodes(&nodes), nodes);
}
match nodes.pop() {
Some(node) if node.is_pipe() => node,
Some(node) => Node::Pipe(span_from_nodes(&nodes), vec![node]),
_ => Node::Pipe(span_from_nodes(&nodes), Vec::default()),
}
}
fn span_from_nodes(nodes: &[Node]) -> Span {
nodes
.first()
.map(Span::from)
.zip(nodes.last().map(Span::from))
.map(|(s0, s1)| Span::new(s0.lo(), s1.hi()))
.unwrap_or_default()
}