use std::fmt;
use crate::position::{LexerPosition, NodeSpan};
pub trait NodeContent: fmt::Debug + Clone + PartialEq + Sized {
fn into_node<T>(self) -> Node<T>
where
T: From<Self> + NodeContent,
{
Node::new(self.into(), None)
}
fn spanned(self, start: LexerPosition, end: LexerPosition) -> Node<Self> {
assert_eq!(start.source_id, end.source_id);
Node {
content: self,
span: Some(NodeSpan::from_lexer(start, end)),
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(rserde::Serialize, rserde::Deserialize))]
#[cfg_attr(feature = "serde", serde(crate = "rserde"))]
pub struct Node<T: NodeContent> {
pub content: T,
pub span: Option<NodeSpan>,
}
impl<T: NodeContent> Node<T> {
pub fn new(content: T, span: Option<NodeSpan>) -> Self {
Self { content, span }
}
pub fn into_inner(self) -> T {
self.content
}
pub fn map<U: NodeContent>(self, f: impl FnOnce(T) -> U) -> Node<U> {
Node {
content: f(self.content),
span: self.span,
}
}
pub fn map_spanned<U: NodeContent>(self, f: impl FnOnce(Self) -> U) -> Node<U> {
let span = self.span;
Node {
content: f(self),
span,
}
}
}
impl<T: NodeContent> std::ops::Deref for Node<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.content
}
}
impl<T: NodeContent> std::ops::DerefMut for Node<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.content
}
}
impl<T: NodeContent + Copy> Copy for Node<T> {}
impl<T: NodeContent + fmt::Display> fmt::Display for Node<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<T as fmt::Display>::fmt(&self.content, f)
}
}
impl<T: NodeContent> From<T> for Node<T> {
fn from(inner: T) -> Self {
Node::new(inner, None)
}
}
impl NodeContent for &'static str {}
impl<U, T: NodeContent + AsRef<U>> AsRef<U> for Node<T> {
fn as_ref(&self) -> &U {
self.content.as_ref()
}
}
impl<T: NodeContent + PartialEq> PartialEq for Node<T> {
fn eq(&self, other: &Self) -> bool {
self.content.eq(&other.content)
}
}
impl<T: NodeContent + Eq> Eq for Node<T> {}
impl<T: NodeContent + PartialOrd> PartialOrd for Node<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.content.partial_cmp(&other.content)
}
}
impl<T: NodeContent + Ord> Ord for Node<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.content.cmp(&other.content)
}
}
impl<T: NodeContent + std::hash::Hash> std::hash::Hash for Node<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.content.hash(state)
}
}