diff options
| author | Martin Haug <mhaug@live.de> | 2021-10-31 11:46:12 +0100 |
|---|---|---|
| committer | Martin Haug <mhaug@live.de> | 2021-11-05 13:44:49 +0100 |
| commit | 84d35efee38d137a77e368c50421ac24327371c6 (patch) | |
| tree | c2fa9f669743d35cbb79892770427dd843202894 /src/syntax/mod.rs | |
| parent | 4875633acf4701705b9b3b014eb7d94268b897c2 (diff) | |
Less owning, more iterating
Diffstat (limited to 'src/syntax/mod.rs')
| -rw-r--r-- | src/syntax/mod.rs | 241 |
1 files changed, 124 insertions, 117 deletions
diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index 88757f8e..8e04a569 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -160,8 +160,6 @@ pub enum NodeKind { /// /// The comment can contain nested block comments. BlockComment, - /// A node that should never appear in a finished tree. - Never, /// Tokens that appear in the wrong place. Error(ErrorPosition, EcoString), /// Template markup. @@ -246,7 +244,41 @@ pub enum ErrorPosition { impl Display for NodeKind { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.pad(match self { + f.pad(self.as_str()) + } +} + +impl NodeKind { + pub fn is_parenthesis(&self) -> bool { + match self { + Self::LeftParen => true, + Self::RightParen => true, + _ => false, + } + } + + pub fn is_bracket(&self) -> bool { + match self { + Self::LeftBracket => true, + Self::RightBracket => true, + _ => false, + } + } + + pub fn is_brace(&self) -> bool { + match self { + Self::LeftBrace => true, + Self::RightBrace => true, + _ => false, + } + } + + pub fn is_error(&self) -> bool { + matches!(self, NodeKind::Error(_, _)) + } + + pub fn as_str(&self) -> &'static str { + match self { Self::LeftBracket => "opening bracket", Self::RightBracket => "closing bracket", Self::LeftBrace => "opening brace", @@ -296,7 +328,6 @@ impl Display for NodeKind { Self::Math(_) => "math formula", Self::EnumNumbering(_) => "numbering", Self::Str(_) => "string", - Self::Never => "a node that should not be here", Self::LineComment => "line comment", Self::BlockComment => "block comment", Self::Markup => "markup", @@ -348,45 +379,15 @@ impl Display for NodeKind { "*/" => "end of block comment", _ => "invalid token", }, - }) - } -} - -impl NodeKind { - pub fn is_parenthesis(&self) -> bool { - match self { - Self::LeftParen => true, - Self::RightParen => true, - _ => false, - } - } - - pub fn is_bracket(&self) -> bool { - match self { - Self::LeftBracket => true, - Self::RightBracket => true, - _ => false, - } - } - - pub fn is_brace(&self) -> bool { - match self { - Self::LeftBrace => true, - Self::RightBrace => true, - _ => false, } } - - pub fn is_error(&self) -> bool { - matches!(self, NodeKind::Never | NodeKind::Error(_, _)) - } } /// A syntactical node. #[derive(Clone, PartialEq)] pub struct GreenNode { /// Node metadata. - meta: GreenData, + data: GreenData, /// This node's children, losslessly make up this node. children: Vec<Green>, } @@ -400,12 +401,12 @@ pub struct GreenData { /// The byte length of the node in the source. len: usize, /// Whether this node or any of its children are erroneous. - has_error: bool, + erroneous: bool, } impl GreenData { pub fn new(kind: NodeKind, len: usize) -> Self { - Self { len, has_error: kind.is_error(), kind } + Self { len, erroneous: kind.is_error(), kind } } pub fn kind(&self) -> &NodeKind { @@ -416,8 +417,8 @@ impl GreenData { self.len } - pub fn has_error(&self) -> bool { - self.has_error + pub fn erroneous(&self) -> bool { + self.erroneous } } @@ -437,23 +438,23 @@ pub enum Green { } impl Green { - fn meta(&self) -> &GreenData { + fn data(&self) -> &GreenData { match self { Green::Token(t) => &t, - Green::Node(n) => &n.meta, + Green::Node(n) => &n.data, } } pub fn kind(&self) -> &NodeKind { - self.meta().kind() + self.data().kind() } pub fn len(&self) -> usize { - self.meta().len() + self.data().len() } - pub fn has_error(&self) -> bool { - self.meta().has_error() + pub fn erroneous(&self) -> bool { + self.data().erroneous() } pub fn children(&self) -> &[Green] { @@ -467,29 +468,19 @@ impl Green { impl GreenNode { pub fn new(kind: NodeKind, len: usize) -> Self { Self { - meta: GreenData::new(kind, len), + data: GreenData::new(kind, len), children: Vec::new(), } } - pub fn with_children( - kind: NodeKind, - len: usize, - children: impl Iterator<Item = impl Into<Green>>, - ) -> Self { + pub fn with_children(kind: NodeKind, len: usize, children: Vec<Green>) -> Self { let mut meta = GreenData::new(kind, len); - let children = children - .map(|x| { - let x = x.into(); - meta.has_error |= x.has_error(); - x - }) - .collect(); - Self { meta, children } + meta.erroneous |= children.iter().any(|c| c.erroneous()); + Self { data: meta, children } } pub fn with_child(kind: NodeKind, len: usize, child: impl Into<Green>) -> Self { - Self::with_children(kind, len, std::iter::once(child.into())) + Self::with_children(kind, len, vec![child.into()]) } pub fn children(&self) -> &[Green] { @@ -511,7 +502,7 @@ impl From<Rc<GreenNode>> for Green { impl Default for Green { fn default() -> Self { - Self::Token(GreenData::new(NodeKind::Never, 0)) + Self::Token(GreenData::new(NodeKind::None, 0)) } } @@ -530,13 +521,13 @@ impl Debug for Green { } #[derive(Copy, Clone, PartialEq)] -pub struct RedTicket<'a> { +pub struct RedRef<'a> { id: SourceId, offset: usize, green: &'a Green, } -impl<'a> RedTicket<'a> { +impl<'a> RedRef<'a> { pub fn own(self) -> RedNode { RedNode { id: self.id, @@ -549,6 +540,9 @@ impl<'a> RedTicket<'a> { self.green.kind() } + pub fn span(&self) -> Span { + Span::new(self.id, self.offset, self.offset + self.green.len()) + } pub fn cast<T>(self) -> Option<T> where @@ -556,6 +550,37 @@ impl<'a> RedTicket<'a> { { T::cast_from(self) } + + pub fn erroneous(&self) -> bool { + self.green.erroneous() + } + + pub fn children(self) -> impl Iterator<Item = RedRef<'a>> + Clone { + let children = match &self.green { + Green::Node(node) => node.children(), + Green::Token(_) => &[], + }; + + let mut offset = self.offset; + children.iter().map(move |green| { + let child_offset = offset; + offset += green.len(); + RedRef { id: self.id, offset: child_offset, green } + }) + } + + pub(crate) fn typed_child(&self, kind: &NodeKind) -> Option<RedRef> { + self.children() + .find(|x| mem::discriminant(x.kind()) == mem::discriminant(kind)) + } + + pub(crate) fn cast_first_child<T: TypedNode>(&self) -> Option<T> { + self.children().find_map(RedRef::cast) + } + + pub(crate) fn cast_last_child<T: TypedNode>(&self) -> Option<T> { + self.children().filter_map(RedRef::cast).last() + } } #[derive(Clone, PartialEq)] @@ -571,7 +596,7 @@ impl RedNode { } pub fn span(&self) -> Span { - Span::new(self.id, self.offset, self.offset + self.green.len()) + self.as_ref().span() } pub fn len(&self) -> usize { @@ -582,53 +607,36 @@ impl RedNode { self.green.kind() } - pub fn children<'a>(&'a self) -> impl Iterator<Item = RedTicket<'a>> + Clone + 'a { - let children = match &self.green { - Green::Node(node) => node.children(), - Green::Token(_) => &[], - }; - - let mut offset = self.offset; - children.iter().map(move |green_child| { - let child_offset = offset; - offset += green_child.len(); - RedTicket { - id: self.id, - offset: child_offset, - green: &green_child, - } - }) - } - - pub fn has_error(&self) -> bool { - self.green.has_error() + pub fn children<'a>(&'a self) -> impl Iterator<Item = RedRef<'a>> + Clone { + self.as_ref().children() } pub fn errors(&self) -> Vec<(Span, EcoString)> { - if !self.green.has_error() { + if !self.green.erroneous() { return vec![]; } - if let NodeKind::Error(pos, msg) = self.kind() { - let span = match pos { - ErrorPosition::Start => self.span().at_start(), - ErrorPosition::Full => self.span(), - ErrorPosition::End => self.span().at_end(), - }; - - vec![(span, msg.clone())] - } else if let NodeKind::Never = self.kind() { - vec![(self.span(), "found a never node".into())] - } else { - self.children() - .filter(|ticket| ticket.green.has_error()) - .flat_map(|ticket| ticket.own().errors()) - .collect() + match self.kind() { + NodeKind::Error(pos, msg) => { + let span = match pos { + ErrorPosition::Start => self.span().at_start(), + ErrorPosition::Full => self.span(), + ErrorPosition::End => self.span().at_end(), + }; + + vec![(span, msg.clone())] + } + _ => self + .as_ref() + .children() + .filter(|red| red.green.erroneous()) + .flat_map(|red| red.own().errors()) + .collect(), } } - pub fn ticket<'a>(&'a self) -> RedTicket<'a> { - RedTicket { + pub fn as_ref<'a>(&'a self) -> RedRef<'a> { + RedRef { id: self.id, offset: self.offset, green: &self.green, @@ -636,28 +644,26 @@ impl RedNode { } pub(crate) fn typed_child(&self, kind: &NodeKind) -> Option<RedNode> { - self.children() - .find(|x| mem::discriminant(x.kind()) == mem::discriminant(kind)) - .map(RedTicket::own) + self.as_ref().typed_child(kind).map(RedRef::own) } pub(crate) fn cast_first_child<T: TypedNode>(&self) -> Option<T> { - self.children().find_map(RedTicket::cast) + self.as_ref().cast_first_child() } pub(crate) fn cast_last_child<T: TypedNode>(&self) -> Option<T> { - self.children().filter_map(RedTicket::cast).last() + self.as_ref().cast_last_child() } } impl Debug for RedNode { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{:?}: {:?}", self.kind(), self.span())?; - let children = self.children().collect::<Vec<_>>(); + let children = self.as_ref().children().collect::<Vec<_>>(); if !children.is_empty() { f.write_str(" ")?; f.debug_list() - .entries(children.into_iter().map(RedTicket::own)) + .entries(children.into_iter().map(RedRef::own)) .finish()?; } Ok(()) @@ -666,21 +672,22 @@ impl Debug for RedNode { pub trait TypedNode: Sized { /// Performs the conversion. - fn cast_from(value: RedTicket) -> Option<Self>; + fn cast_from(value: RedRef) -> Option<Self>; } #[macro_export] macro_rules! node { - (#[doc = $doc:expr] $name:ident) => { - node!(#[doc = $doc] $name => $name); + ($(#[$attr:meta])* $name:ident) => { + node!{$(#[$attr])* $name => $name} }; - (#[doc = $doc:expr] $variant:ident => $name:ident) => { - #[doc = $doc] + ($(#[$attr:meta])* $variant:ident => $name:ident) => { #[derive(Debug, Clone, PartialEq)] + #[repr(transparent)] + $(#[$attr])* pub struct $name(RedNode); impl TypedNode for $name { - fn cast_from(node: RedTicket) -> Option<Self> { + fn cast_from(node: RedRef) -> Option<Self> { if node.kind() != &NodeKind::$variant { return None; } @@ -694,8 +701,8 @@ macro_rules! node { self.0.span() } - pub fn underlying(&self) -> RedTicket { - self.0.ticket() + pub fn underlying(&self) -> RedRef { + self.0.as_ref() } } }; |
