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 | |
| parent | 4875633acf4701705b9b3b014eb7d94268b897c2 (diff) | |
Less owning, more iterating
Diffstat (limited to 'src/syntax')
| -rw-r--r-- | src/syntax/expr.rs | 173 | ||||
| -rw-r--r-- | src/syntax/ident.rs | 11 | ||||
| -rw-r--r-- | src/syntax/markup.rs | 104 | ||||
| -rw-r--r-- | src/syntax/mod.rs | 241 | ||||
| -rw-r--r-- | src/syntax/pretty.rs | 41 |
5 files changed, 282 insertions, 288 deletions
diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs index d0d0c62f..8562a3a4 100644 --- a/src/syntax/expr.rs +++ b/src/syntax/expr.rs @@ -1,4 +1,4 @@ -use super::{Ident, Markup, NodeKind, RedNode, RedTicket, Span, TypedNode}; +use super::{Ident, Markup, NodeKind, RedNode, RedRef, Span, TypedNode}; use crate::geom::{AngularUnit, LengthUnit}; use crate::node; use crate::util::EcoString; @@ -85,7 +85,7 @@ impl Expr { } impl TypedNode for Expr { - fn cast_from(node: RedTicket) -> Option<Self> { + fn cast_from(node: RedRef) -> Option<Self> { match node.kind() { NodeKind::Ident(_) => Some(Self::Ident(Ident::cast_from(node).unwrap())), NodeKind::Array => Some(Self::Array(ArrayExpr::cast_from(node).unwrap())), @@ -146,18 +146,18 @@ pub enum Lit { } impl TypedNode for Lit { - fn cast_from(node: RedTicket) -> Option<Self> { + fn cast_from(node: RedRef) -> Option<Self> { match node.kind() { - NodeKind::None => Some(Self::None(node.own().span())), - NodeKind::Auto => Some(Self::Auto(node.own().span())), - NodeKind::Bool(b) => Some(Self::Bool(node.own().span(), *b)), - NodeKind::Int(i) => Some(Self::Int(node.own().span(), *i)), - NodeKind::Float(f) => Some(Self::Float(node.own().span(), *f)), - NodeKind::Length(f, unit) => Some(Self::Length(node.own().span(), *f, *unit)), - NodeKind::Angle(f, unit) => Some(Self::Angle(node.own().span(), *f, *unit)), - NodeKind::Percentage(f) => Some(Self::Percent(node.own().span(), *f)), - NodeKind::Fraction(f) => Some(Self::Fractional(node.own().span(), *f)), - NodeKind::Str(s) => Some(Self::Str(node.own().span(), s.string.clone())), + NodeKind::None => Some(Self::None(node.span())), + NodeKind::Auto => Some(Self::Auto(node.span())), + NodeKind::Bool(b) => Some(Self::Bool(node.span(), *b)), + NodeKind::Int(i) => Some(Self::Int(node.span(), *i)), + NodeKind::Float(f) => Some(Self::Float(node.span(), *f)), + NodeKind::Length(f, unit) => Some(Self::Length(node.span(), *f, *unit)), + NodeKind::Angle(f, unit) => Some(Self::Angle(node.span(), *f, *unit)), + NodeKind::Percentage(f) => Some(Self::Percent(node.span(), *f)), + NodeKind::Fraction(f) => Some(Self::Fractional(node.span(), *f)), + NodeKind::Str(s) => Some(Self::Str(node.span(), s.string.clone())), _ => None, } } @@ -180,34 +180,34 @@ impl Lit { } } -node!( +node! { /// An array expression: `(1, "hi", 12cm)`. Array => ArrayExpr -); +} impl ArrayExpr { /// The array items. - pub fn items(&self) -> Vec<Expr> { - self.0.children().filter_map(RedTicket::cast).collect() + pub fn items<'a>(&'a self) -> impl Iterator<Item = Expr> + 'a { + self.0.children().filter_map(RedRef::cast) } } -node!( +node! { /// A dictionary expression: `(thickness: 3pt, pattern: dashed)`. Dict => DictExpr -); +} impl DictExpr { /// The named dictionary items. - pub fn items(&self) -> Vec<Named> { - self.0.children().filter_map(RedTicket::cast).collect() + pub fn items<'a>(&'a self) -> impl Iterator<Item = Named> + 'a { + self.0.children().filter_map(RedRef::cast) } } -node!( +node! { /// A pair of a name and an expression: `pattern: dashed`. Named -); +} impl Named { /// The name: `pattern`. @@ -219,16 +219,16 @@ impl Named { pub fn expr(&self) -> Expr { self.0 .children() - .filter_map(RedTicket::cast) + .filter_map(RedRef::cast) .nth(1) .expect("named pair is missing expression") } } -node!( +node! { /// A template expression: `[*Hi* there!]`. Template => TemplateExpr -); +} impl TemplateExpr { /// The contents of the template. @@ -239,10 +239,10 @@ impl TemplateExpr { } } -node!( +node! { /// A grouped expression: `(1 + 2)`. Group => GroupExpr -); +} impl GroupExpr { /// The wrapped expression. @@ -253,22 +253,22 @@ impl GroupExpr { } } -node!( +node! { /// A block expression: `{ let x = 1; x + 2 }`. Block => BlockExpr -); +} impl BlockExpr { /// The list of expressions contained in the block. - pub fn exprs(&self) -> Vec<Expr> { - self.0.children().filter_map(RedTicket::cast).collect() + pub fn exprs<'a>(&'a self) -> impl Iterator<Item = Expr> + 'a { + self.0.children().filter_map(RedRef::cast) } } -node!( +node! { /// A unary operation: `-x`. Unary => UnaryExpr -); +} impl UnaryExpr { /// The operator: `-`. @@ -298,7 +298,7 @@ pub enum UnOp { } impl TypedNode for UnOp { - fn cast_from(node: RedTicket) -> Option<Self> { + fn cast_from(node: RedRef) -> Option<Self> { Self::from_token(node.kind()) } } @@ -332,10 +332,10 @@ impl UnOp { } } -node!( +node! { /// A binary operation: `a + b`. Binary => BinaryExpr -); +} impl BinaryExpr { /// The binary operator: `+`. @@ -356,7 +356,7 @@ impl BinaryExpr { pub fn rhs(&self) -> Expr { self.0 .children() - .filter_map(RedTicket::cast) + .filter_map(RedRef::cast) .nth(1) .expect("binary expression is missing right-hand side") } @@ -402,7 +402,7 @@ pub enum BinOp { } impl TypedNode for BinOp { - fn cast_from(node: RedTicket) -> Option<Self> { + fn cast_from(node: RedRef) -> Option<Self> { Self::from_token(node.kind()) } } @@ -504,10 +504,10 @@ pub enum Associativity { Right, } -node!( +node! { /// An invocation of a function: `foo(...)`. Call => CallExpr -); +} impl CallExpr { /// The function to call. @@ -523,15 +523,15 @@ impl CallExpr { } } -node!( +node! { /// The arguments to a function: `12, draw: false`. CallArgs -); +} impl CallArgs { /// The positional and named arguments. - pub fn items(&self) -> Vec<CallArg> { - self.0.children().filter_map(RedTicket::cast).collect() + pub fn items<'a>(&'a self) -> impl Iterator<Item = CallArg> + 'a { + self.0.children().filter_map(RedRef::cast) } } @@ -547,14 +547,13 @@ pub enum CallArg { } impl TypedNode for CallArg { - fn cast_from(node: RedTicket) -> Option<Self> { + fn cast_from(node: RedRef) -> Option<Self> { match node.kind() { NodeKind::Named => Some(CallArg::Named( node.cast().expect("named call argument is missing name"), )), NodeKind::ParameterSink => Some(CallArg::Spread( - node.own() - .cast_first_child() + node.cast_first_child() .expect("call argument sink is missing expression"), )), _ => Some(CallArg::Pos(node.cast()?)), @@ -573,10 +572,10 @@ impl CallArg { } } -node!( +node! { /// A closure expression: `(x, y) => z`. Closure => ClosureExpr -); +} impl ClosureExpr { /// The name of the closure. @@ -589,15 +588,13 @@ impl ClosureExpr { } /// The parameter bindings. - pub fn params(&self) -> Vec<ClosureParam> { + pub fn params<'a>(&'a self) -> impl Iterator<Item = ClosureParam> + 'a { self.0 .children() .find(|x| x.kind() == &NodeKind::ClosureParams) .expect("closure is missing parameter list") - .own() .children() - .filter_map(RedTicket::cast) - .collect() + .filter_map(RedRef::cast) } /// The body of the closure. @@ -607,8 +604,8 @@ impl ClosureExpr { self.0.cast_last_child().expect("closure is missing body") } - /// The ticket of the body of the closure. - pub fn body_ticket(&self) -> RedTicket { + /// The red node reference of the body of the closure. + pub fn body_ref(&self) -> RedRef { self.0 .children() .filter(|x| x.cast::<Expr>().is_some()) @@ -629,17 +626,16 @@ pub enum ClosureParam { } impl TypedNode for ClosureParam { - fn cast_from(node: RedTicket) -> Option<Self> { + fn cast_from(node: RedRef) -> Option<Self> { match node.kind() { NodeKind::Ident(i) => { - Some(ClosureParam::Pos(Ident::new(i, node.own().span()).unwrap())) + Some(ClosureParam::Pos(Ident::new(i, node.span()).unwrap())) } NodeKind::Named => Some(ClosureParam::Named( node.cast().expect("named closure parameter is missing name"), )), NodeKind::ParameterSink => Some(ClosureParam::Sink( - node.own() - .cast_first_child() + node.cast_first_child() .expect("closure parameter sink is missing identifier"), )), _ => Some(ClosureParam::Pos(node.cast()?)), @@ -647,10 +643,10 @@ impl TypedNode for ClosureParam { } } -node!( +node! { /// A with expression: `f with (x, y: 1)`. WithExpr -); +} impl WithExpr { /// The function to apply the arguments to. @@ -668,10 +664,10 @@ impl WithExpr { } } -node!( +node! { /// A let expression: `let x = 1`. LetExpr -); +} impl LetExpr { /// The binding to assign to. @@ -693,7 +689,7 @@ impl LetExpr { /// The expression the binding is initialized with. pub fn init(&self) -> Option<Expr> { if self.0.cast_first_child::<Ident>().is_some() { - self.0.children().filter_map(RedTicket::cast).nth(1) + self.0.children().filter_map(RedRef::cast).nth(1) } else { Some( self.0 @@ -703,8 +699,9 @@ impl LetExpr { } } - /// The ticket for the expression the binding is initialized with. - pub fn init_ticket(&self) -> RedTicket { + /// The red node reference for the expression the binding is initialized + /// with. + pub fn init_ref(&self) -> RedRef { if self.0.cast_first_child::<Ident>().is_some() { self.0.children().filter(|x| x.cast::<Expr>().is_some()).nth(1) } else { @@ -714,10 +711,10 @@ impl LetExpr { } } -node!( +node! { /// An import expression: `import a, b, c from "utils.typ"`. ImportExpr -); +} impl ImportExpr { /// The items to be imported. @@ -745,11 +742,11 @@ pub enum Imports { } impl TypedNode for Imports { - fn cast_from(node: RedTicket) -> Option<Self> { + fn cast_from(node: RedRef) -> Option<Self> { match node.kind() { NodeKind::Star => Some(Imports::Wildcard), NodeKind::ImportItems => { - let idents = node.own().children().filter_map(RedTicket::cast).collect(); + let idents = node.children().filter_map(RedRef::cast).collect(); Some(Imports::Idents(idents)) } _ => None, @@ -757,10 +754,10 @@ impl TypedNode for Imports { } } -node!( +node! { /// An include expression: `include "chapter1.typ"`. IncludeExpr -); +} impl IncludeExpr { /// The location of the file to be included. @@ -771,10 +768,10 @@ impl IncludeExpr { } } -node!( +node! { /// An if-else expression: `if x { y } else { z }`. IfExpr -); +} impl IfExpr { /// The condition which selects the body to evaluate. @@ -788,21 +785,21 @@ impl IfExpr { pub fn if_body(&self) -> Expr { self.0 .children() - .filter_map(RedTicket::cast) + .filter_map(RedRef::cast) .nth(1) .expect("if expression is missing if body") } /// The expression to evaluate if the condition is false. pub fn else_body(&self) -> Option<Expr> { - self.0.children().filter_map(RedTicket::cast).nth(2) + self.0.children().filter_map(RedRef::cast).nth(2) } } -node!( +node! { /// A while loop expression: `while x { y }`. WhileExpr -); +} impl WhileExpr { /// The condition which selects whether to evaluate the body. @@ -816,16 +813,16 @@ impl WhileExpr { pub fn body(&self) -> Expr { self.0 .children() - .filter_map(RedTicket::cast) + .filter_map(RedRef::cast) .nth(1) .expect("while loop expression is missing body") } } -node!( +node! { /// A for loop expression: `for x in y { z }`. ForExpr -); +} impl ForExpr { /// The pattern to assign to. @@ -846,13 +843,13 @@ impl ForExpr { pub fn body(&self) -> Expr { self.0 .children() - .filter_map(RedTicket::cast) + .filter_map(RedRef::cast) .last() .expect("for loop expression is missing body") } - /// The ticket for the expression to evaluate for each iteration. - pub fn body_ticket(&self) -> RedTicket { + /// The red node reference for the expression to evaluate for each iteration. + pub fn body_ref(&self) -> RedRef { self.0 .children() .filter(|x| x.cast::<Expr>().is_some()) @@ -861,14 +858,14 @@ impl ForExpr { } } -node!( +node! { /// A for-in loop expression: `for x in y { z }`. ForPattern -); +} impl ForPattern { pub fn key(&self) -> Option<Ident> { - let mut items: Vec<_> = self.0.children().filter_map(RedTicket::cast).collect(); + let mut items: Vec<_> = self.0.children().filter_map(RedRef::cast).collect(); if items.len() > 1 { Some(items.remove(0)) } else { None } } diff --git a/src/syntax/ident.rs b/src/syntax/ident.rs index 2c61329d..f5cc6330 100644 --- a/src/syntax/ident.rs +++ b/src/syntax/ident.rs @@ -3,7 +3,7 @@ use std::ops::Deref; use unicode_xid::UnicodeXID; -use super::{NodeKind, RedTicket, Span, TypedNode}; +use super::{NodeKind, RedRef, Span, TypedNode}; use crate::util::EcoString; /// An unicode identifier with a few extra permissible characters. @@ -67,11 +67,10 @@ impl From<&Ident> for EcoString { } impl TypedNode for Ident { - fn cast_from(node: RedTicket) -> Option<Self> { - if let NodeKind::Ident(i) = node.kind() { - Some(Ident::new(i, node.own().span()).unwrap()) - } else { - None + fn cast_from(node: RedRef) -> Option<Self> { + match node.kind() { + NodeKind::Ident(i) => Some(Ident::new(i, node.span()).unwrap()), + _ => None, } } } diff --git a/src/syntax/markup.rs b/src/syntax/markup.rs index c12c0e81..de547f76 100644 --- a/src/syntax/markup.rs +++ b/src/syntax/markup.rs @@ -1,4 +1,4 @@ -use super::{Expr, Ident, NodeKind, RedNode, RedTicket, Span, TypedNode}; +use super::{Expr, Ident, NodeKind, RedNode, RedRef, Span, TypedNode}; use crate::node; use crate::util::EcoString; use std::fmt::Write; @@ -7,12 +7,12 @@ use std::fmt::Write; pub type Markup = Vec<MarkupNode>; impl TypedNode for Markup { - fn cast_from(node: RedTicket) -> Option<Self> { + fn cast_from(node: RedRef) -> Option<Self> { if node.kind() != &NodeKind::Markup { return None; } - let children = node.own().children().filter_map(TypedNode::cast_from).collect(); + let children = node.children().filter_map(TypedNode::cast_from).collect(); Some(children) } } @@ -45,7 +45,7 @@ pub enum MarkupNode { } impl TypedNode for MarkupNode { - fn cast_from(node: RedTicket) -> Option<Self> { + fn cast_from(node: RedRef) -> Option<Self> { match node.kind() { NodeKind::Space(_) => Some(MarkupNode::Space), NodeKind::Linebreak => Some(MarkupNode::Linebreak), @@ -53,15 +53,14 @@ impl TypedNode for MarkupNode { NodeKind::Strong => Some(MarkupNode::Strong), NodeKind::Emph => Some(MarkupNode::Emph), NodeKind::Text(s) => Some(MarkupNode::Text(s.clone())), - NodeKind::UnicodeEscape(u) => { - Some(MarkupNode::Text(if let Some(s) = u.character { - s.into() - } else { + NodeKind::UnicodeEscape(u) => Some(MarkupNode::Text(match u.character { + Some(c) => c.into(), + None => { let mut eco = EcoString::with_capacity(u.sequence.len() + 4); write!(&mut eco, "\\u{{{}}}", u.sequence).unwrap(); eco - })) - } + } + })), NodeKind::EnDash => Some(MarkupNode::Text(EcoString::from("\u{2013}"))), NodeKind::EmDash => Some(MarkupNode::Text(EcoString::from("\u{2014}"))), NodeKind::NonBreakingSpace => { @@ -93,28 +92,29 @@ pub struct RawNode { } impl TypedNode for RawNode { - fn cast_from(node: RedTicket) -> Option<Self> { - if let NodeKind::Raw(raw) = node.kind() { - let span = node.own().span(); - let start = span.start + raw.backticks as usize; - Some(Self { - block: raw.block, - lang: raw.lang.as_ref().and_then(|x| { - let span = Span::new(span.source, start, start + x.len()); - Ident::new(x, span) - }), - text: raw.text.clone(), - }) - } else { - None + fn cast_from(node: RedRef) -> Option<Self> { + match node.kind() { + NodeKind::Raw(raw) => { + let span = node.span(); + let start = span.start + raw.backticks as usize; + Some(Self { + block: raw.block, + lang: raw.lang.as_ref().and_then(|x| { + let span = Span::new(span.source, start, start + x.len()); + Ident::new(x, span) + }), + text: raw.text.clone(), + }) + } + _ => None, } } } -node!( +node! { /// A section heading: `= Introduction`. Heading => HeadingNode -); +} impl HeadingNode { /// The contents of the heading. @@ -125,30 +125,21 @@ impl HeadingNode { } /// The section depth (numer of equals signs). - pub fn level(&self) -> HeadingLevel { + pub fn level(&self) -> u8 { self.0 - .cast_first_child() + .children() + .find_map(|node| match node.kind() { + NodeKind::HeadingLevel(heading) => Some(*heading), + _ => None, + }) .expect("heading node is missing heading level") } } -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub struct HeadingLevel(pub usize); - -impl TypedNode for HeadingLevel { - fn cast_from(node: RedTicket) -> Option<Self> { - if let NodeKind::HeadingLevel(l) = node.kind() { - Some(Self((*l).into())) - } else { - None - } - } -} - -node!( +node! { /// An item in an unordered list: `- ...`. List => ListNode -); +} impl ListNode { /// The contents of the list item. @@ -157,10 +148,10 @@ impl ListNode { } } -node!( +node! { /// An item in an enumeration (ordered list): `1. ...`. Enum => EnumNode -); +} impl EnumNode { /// The contents of the list item. @@ -169,20 +160,13 @@ impl EnumNode { } /// The number, if any. - pub fn number(&self) -> EnumNumber { - self.0.cast_first_child().expect("enumeration node is missing number") - } -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub struct EnumNumber(pub Option<usize>); - -impl TypedNode for EnumNumber { - fn cast_from(node: RedTicket) -> Option<Self> { - if let NodeKind::EnumNumbering(x) = node.kind() { - Some(Self(*x)) - } else { - None - } + pub fn number(&self) -> Option<usize> { + self.0 + .children() + .find_map(|node| match node.kind() { + NodeKind::EnumNumbering(num) => Some(num.clone()), + _ => None, + }) + .expect("enumeration node is missing number") } } 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() } } }; diff --git a/src/syntax/pretty.rs b/src/syntax/pretty.rs index b1c7e02b..db364eaa 100644 --- a/src/syntax/pretty.rs +++ b/src/syntax/pretty.rs @@ -46,20 +46,25 @@ impl Printer { Write::write_fmt(self, fmt) } - /// Write a list of items joined by a joiner. - pub fn join<T, I, F>(&mut self, items: I, joiner: &str, mut write_item: F) + /// Write a list of items joined by a joiner and return how many there were. + pub fn join<T, I, F>(&mut self, items: I, joiner: &str, mut write_item: F) -> usize where I: IntoIterator<Item = T>, F: FnMut(T, &mut Self), { + let mut count = 0; let mut iter = items.into_iter(); if let Some(first) = iter.next() { write_item(first, self); + count += 1; } for item in iter { self.push_str(joiner); write_item(item, self); + count += 1; } + + count } /// Finish pretty printing and return the underlying buffer. @@ -165,7 +170,7 @@ impl Pretty for RawNode { impl Pretty for HeadingNode { fn pretty(&self, p: &mut Printer) { - for _ in 0 .. self.level().0 { + for _ in 0 .. self.level() { p.push('='); } p.push(' '); @@ -182,7 +187,7 @@ impl Pretty for ListNode { impl Pretty for EnumNode { fn pretty(&self, p: &mut Printer) { - if let Some(number) = self.number().0 { + if let Some(number) = self.number() { write!(p, "{}", number).unwrap(); } p.push_str(". "); @@ -237,8 +242,8 @@ impl Pretty for ArrayExpr { p.push('('); let items = self.items(); - p.join(&items, ", ", |item, p| item.pretty(p)); - if items.len() == 1 { + let len = p.join(items, ", ", |item, p| item.pretty(p)); + if len == 1 { p.push(','); } p.push(')'); @@ -249,11 +254,11 @@ impl Pretty for DictExpr { fn pretty(&self, p: &mut Printer) { p.push('('); - let items = self.items(); - if items.is_empty() { + let mut items = self.items().peekable(); + if items.peek().is_none() { p.push(':'); } else { - p.join(&items, ", ", |named, p| named.pretty(p)); + p.join(items, ", ", |named, p| named.pretty(p)); } p.push(')'); } @@ -287,7 +292,7 @@ impl Pretty for BlockExpr { fn pretty(&self, p: &mut Printer) { p.push('{'); - let exprs = self.exprs(); + let exprs: Vec<_> = self.exprs().collect(); if exprs.len() > 1 { p.push(' '); } @@ -342,8 +347,7 @@ impl Pretty for CallExpr { p.push(')'); }; - let arg_list = self.args(); - let args = arg_list.items(); + let args: Vec<_> = self.args().items().collect(); if let Some(Expr::Template(template)) = args .last() @@ -361,7 +365,7 @@ impl Pretty for CallExpr { impl Pretty for CallArgs { fn pretty(&self, p: &mut Printer) { - p.join(&self.items(), ", ", |item, p| item.pretty(p)); + p.join(self.items(), ", ", |item, p| item.pretty(p)); } } @@ -380,11 +384,12 @@ impl Pretty for CallArg { impl Pretty for ClosureExpr { fn pretty(&self, p: &mut Printer) { - if let [param] = self.params().as_slice() { + let params: Vec<_> = self.params().collect(); + if let [param] = params.as_slice() { param.pretty(p); } else { p.push('('); - p.join(self.params().iter(), ", ", |item, p| item.pretty(p)); + p.join(params.iter(), ", ", |item, p| item.pretty(p)); p.push(')'); } p.push_str(" => "); @@ -420,7 +425,7 @@ impl Pretty for LetExpr { self.binding().pretty(p); if let Some(Expr::Closure(closure)) = &self.init() { p.push('('); - p.join(closure.params().iter(), ", ", |item, p| item.pretty(p)); + p.join(closure.params(), ", ", |item, p| item.pretty(p)); p.push_str(") = "); closure.body().pretty(p); } else if let Some(init) = &self.init() { @@ -487,7 +492,9 @@ impl Pretty for Imports { fn pretty(&self, p: &mut Printer) { match self { Self::Wildcard => p.push('*'), - Self::Idents(idents) => p.join(idents, ", ", |item, p| item.pretty(p)), + Self::Idents(idents) => { + p.join(idents, ", ", |item, p| item.pretty(p)); + } } } } |
