diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-11-07 22:05:48 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-11-08 01:37:49 +0100 |
| commit | 95866d5fc9ae89a23c5754193c7de5d4fe4873b1 (patch) | |
| tree | ae408006c29ba31aa62dab7e48e9326316f89fed /src/syntax | |
| parent | 8117ca9950a2027efae133f811a26a4a7bf86a8e (diff) | |
Tidy up AST
Diffstat (limited to 'src/syntax')
| -rw-r--r-- | src/syntax/ast.rs | 350 | ||||
| -rw-r--r-- | src/syntax/mod.rs | 249 | ||||
| -rw-r--r-- | src/syntax/pretty.rs | 6 |
3 files changed, 242 insertions, 363 deletions
diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs index 1198d6b1..dc71e229 100644 --- a/src/syntax/ast.rs +++ b/src/syntax/ast.rs @@ -1,10 +1,7 @@ //! A typed layer over the red-green tree. -use std::ops::Deref; - use super::{NodeKind, RedNode, RedRef, Span}; use crate::geom::{AngularUnit, LengthUnit}; -use crate::parse::is_ident; use crate::util::EcoString; /// A typed AST node. @@ -40,7 +37,7 @@ macro_rules! node { } /// The underlying red node. - pub fn underlying(&self) -> RedRef { + pub fn as_red(&self) -> RedRef { self.0.as_ref() } } @@ -112,7 +109,7 @@ impl TypedNode for MarkupNode { #[derive(Debug, Clone, PartialEq)] pub struct RawNode { /// An optional identifier specifying the language to syntax-highlight in. - pub lang: Option<Ident>, + pub lang: Option<EcoString>, /// The raw text, determined as the raw string between the backticks trimmed /// according to the above rules. pub text: EcoString, @@ -124,18 +121,11 @@ pub struct RawNode { impl TypedNode for RawNode { fn from_red(node: RedRef) -> Option<Self> { match node.kind() { - NodeKind::Raw(raw) => { - let full = node.span(); - let start = full.start + raw.backticks as usize; - Some(Self { - block: raw.block, - lang: raw.lang.as_ref().and_then(|lang| { - let span = Span::new(full.source, start, start + lang.len()); - Ident::new(lang, span) - }), - text: raw.text.clone(), - }) - } + NodeKind::Raw(raw) => Some(Self { + block: raw.block, + lang: raw.lang.clone(), + text: raw.text.clone(), + }), _ => None, } } @@ -149,9 +139,7 @@ node! { impl HeadingNode { /// The contents of the heading. pub fn body(&self) -> Markup { - self.0 - .cast_first_child() - .expect("heading node is missing markup body") + self.0.cast_first_child().expect("heading is missing markup body") } /// The section depth (numer of equals signs). @@ -184,7 +172,7 @@ node! { impl EnumNode { /// The contents of the list item. pub fn body(&self) -> Markup { - self.0.cast_first_child().expect("enumeration node is missing body") + self.0.cast_first_child().expect("enum node is missing body") } /// The number, if any. @@ -195,7 +183,7 @@ impl EnumNode { NodeKind::EnumNumbering(num) => Some(num.clone()), _ => None, }) - .expect("enumeration node is missing number") + .expect("enum node is missing number") } } @@ -240,6 +228,31 @@ pub enum Expr { Include(IncludeExpr), } +impl TypedNode for Expr { + fn from_red(node: RedRef) -> Option<Self> { + match node.kind() { + NodeKind::Ident(_) => node.cast().map(Self::Ident), + NodeKind::Array => node.cast().map(Self::Array), + NodeKind::Dict => node.cast().map(Self::Dict), + NodeKind::Template => node.cast().map(Self::Template), + NodeKind::Group => node.cast().map(Self::Group), + NodeKind::Block => node.cast().map(Self::Block), + NodeKind::Unary => node.cast().map(Self::Unary), + NodeKind::Binary => node.cast().map(Self::Binary), + NodeKind::Call => node.cast().map(Self::Call), + NodeKind::Closure => node.cast().map(Self::Closure), + NodeKind::WithExpr => node.cast().map(Self::With), + NodeKind::LetExpr => node.cast().map(Self::Let), + NodeKind::IfExpr => node.cast().map(Self::If), + NodeKind::WhileExpr => node.cast().map(Self::While), + NodeKind::ForExpr => node.cast().map(Self::For), + NodeKind::ImportExpr => node.cast().map(Self::Import), + NodeKind::IncludeExpr => node.cast().map(Self::Include), + _ => node.cast().map(Self::Lit), + } + } +} + impl Expr { /// Whether the expression can be shortened in markup with a hashtag. pub fn has_short_form(&self) -> bool { @@ -280,31 +293,6 @@ impl Expr { } } -impl TypedNode for Expr { - fn from_red(node: RedRef) -> Option<Self> { - match node.kind() { - NodeKind::Ident(_) => node.cast().map(Self::Ident), - NodeKind::Array => node.cast().map(Self::Array), - NodeKind::Dict => node.cast().map(Self::Dict), - NodeKind::Template => node.cast().map(Self::Template), - NodeKind::Group => node.cast().map(Self::Group), - NodeKind::Block => node.cast().map(Self::Block), - NodeKind::Unary => node.cast().map(Self::Unary), - NodeKind::Binary => node.cast().map(Self::Binary), - NodeKind::Call => node.cast().map(Self::Call), - NodeKind::Closure => node.cast().map(Self::Closure), - NodeKind::WithExpr => node.cast().map(Self::With), - NodeKind::LetExpr => node.cast().map(Self::Let), - NodeKind::IfExpr => node.cast().map(Self::If), - NodeKind::WhileExpr => node.cast().map(Self::While), - NodeKind::ForExpr => node.cast().map(Self::For), - NodeKind::ImportExpr => node.cast().map(Self::Import), - NodeKind::IncludeExpr => node.cast().map(Self::Include), - _ => node.cast().map(Self::Lit), - } - } -} - /// A literal: `1`, `true`, ... #[derive(Debug, Clone, PartialEq)] pub enum Lit { @@ -335,17 +323,17 @@ pub enum Lit { impl TypedNode for Lit { fn from_red(node: RedRef) -> Option<Self> { - match node.kind() { + match *node.kind() { 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.clone())), + NodeKind::Bool(v) => Some(Self::Bool(node.span(), v)), + NodeKind::Int(v) => Some(Self::Int(node.span(), v)), + NodeKind::Float(v) => Some(Self::Float(node.span(), v)), + NodeKind::Length(v, unit) => Some(Self::Length(node.span(), v, unit)), + NodeKind::Angle(v, unit) => Some(Self::Angle(node.span(), v, unit)), + NodeKind::Percentage(v) => Some(Self::Percent(node.span(), v)), + NodeKind::Fraction(v) => Some(Self::Fractional(node.span(), v)), + NodeKind::Str(ref v) => Some(Self::Str(node.span(), v.clone())), _ => None, } } @@ -354,17 +342,17 @@ impl TypedNode for Lit { impl Lit { /// The source code location. pub fn span(&self) -> Span { - match self { - Self::None(span) => *span, - Self::Auto(span) => *span, - Self::Bool(span, _) => *span, - Self::Int(span, _) => *span, - Self::Float(span, _) => *span, - Self::Length(span, _, _) => *span, - Self::Angle(span, _, _) => *span, - Self::Percent(span, _) => *span, - Self::Fractional(span, _) => *span, - Self::Str(span, _) => *span, + match *self { + Self::None(span) => span, + Self::Auto(span) => span, + Self::Bool(span, _) => span, + Self::Int(span, _) => span, + Self::Float(span, _) => span, + Self::Length(span, _, _) => span, + Self::Angle(span, _, _) => span, + Self::Percent(span, _) => span, + Self::Fractional(span, _) => span, + Self::Str(span, _) => span, } } } @@ -401,16 +389,12 @@ node! { impl Named { /// The name: `pattern`. pub fn name(&self) -> Ident { - self.0.cast_first_child().expect("named pair is missing name ident") + self.0.cast_first_child().expect("named pair is missing name") } /// The right-hand side of the pair: `dashed`. pub fn expr(&self) -> Expr { - self.0 - .children() - .filter_map(RedRef::cast) - .nth(1) - .expect("named pair is missing expression") + self.0.cast_last_child().expect("named pair is missing expression") } } @@ -422,9 +406,7 @@ node! { impl TemplateExpr { /// The contents of the template. pub fn body(&self) -> Markup { - self.0 - .cast_first_child() - .expect("template expression is missing body") + self.0.cast_first_child().expect("template is missing body") } } @@ -436,9 +418,7 @@ node! { impl GroupExpr { /// The wrapped expression. pub fn expr(&self) -> Expr { - self.0 - .cast_first_child() - .expect("group expression is missing expression") + self.0.cast_first_child().expect("group is missing expression") } } @@ -469,9 +449,7 @@ impl UnaryExpr { /// The expression to operator on: `x`. pub fn expr(&self) -> Expr { - self.0 - .cast_first_child() - .expect("unary expression is missing expression") + self.0.cast_last_child().expect("unary expression is missing child") } } @@ -506,7 +484,7 @@ impl UnOp { /// The precedence of this operator. pub fn precedence(self) -> usize { match self { - Self::Pos | Self::Neg => 8, + Self::Pos | Self::Neg => 7, Self::Not => 4, } } @@ -544,9 +522,7 @@ impl BinaryExpr { /// The right-hand side of the operation: `b`. pub fn rhs(&self) -> Expr { self.0 - .children() - .filter_map(RedRef::cast) - .nth(1) + .cast_last_child() .expect("binary expression is missing right-hand side") } } @@ -701,14 +677,12 @@ node! { impl CallExpr { /// The function to call. pub fn callee(&self) -> Expr { - self.0.cast_first_child().expect("call expression is missing callee") + self.0.cast_first_child().expect("call is missing callee") } /// The arguments to the function. pub fn args(&self) -> CallArgs { - self.0 - .cast_first_child() - .expect("call expression is missing argument list") + self.0.cast_last_child().expect("call is missing argument list") } } @@ -738,14 +712,9 @@ pub enum CallArg { impl TypedNode for CallArg { fn from_red(node: RedRef) -> Option<Self> { match node.kind() { - NodeKind::Named => Some(CallArg::Named( - node.cast().expect("named call argument is missing name"), - )), - NodeKind::Spread => Some(CallArg::Spread( - node.cast_first_child() - .expect("call argument sink is missing expression"), - )), - _ => Some(CallArg::Pos(node.cast()?)), + NodeKind::Named => node.cast().map(CallArg::Named), + NodeKind::Spread => node.cast_first_child().map(CallArg::Spread), + _ => node.cast().map(CallArg::Pos), } } } @@ -754,8 +723,8 @@ impl CallArg { /// The name of this argument. pub fn span(&self) -> Span { match self { - Self::Named(named) => named.span(), Self::Pos(expr) => expr.span(), + Self::Named(named) => named.span(), Self::Spread(expr) => expr.span(), } } @@ -771,8 +740,6 @@ impl ClosureExpr { /// /// This only exists if you use the function syntax sugar: `let f(x) = y`. pub fn name(&self) -> Option<Ident> { - // `first_convert_child` does not work here because of the Option in the - // Result. self.0.cast_first_child() } @@ -788,22 +755,11 @@ impl ClosureExpr { /// The body of the closure. pub fn body(&self) -> Expr { - // The filtering for the NodeKind is necessary here because otherwise, - // `first_convert_child` will use the Ident if present. self.0.cast_last_child().expect("closure is missing body") } - - /// 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()) - .last() - .unwrap() - } } -/// An parameter to a closure. +/// A parameter to a closure. #[derive(Debug, Clone, PartialEq)] pub enum ClosureParam { /// A positional parameter: `x`. @@ -817,17 +773,10 @@ pub enum ClosureParam { impl TypedNode for ClosureParam { fn from_red(node: RedRef) -> Option<Self> { match node.kind() { - NodeKind::Ident(id) => { - Some(ClosureParam::Pos(Ident::new_unchecked(id, node.span()))) - } - NodeKind::Named => Some(ClosureParam::Named( - node.cast().expect("named closure parameter is missing name"), - )), - NodeKind::Spread => Some(ClosureParam::Sink( - node.cast_first_child() - .expect("closure parameter sink is missing identifier"), - )), - _ => Some(ClosureParam::Pos(node.cast()?)), + NodeKind::Ident(_) => node.cast().map(ClosureParam::Pos), + NodeKind::Named => node.cast().map(ClosureParam::Named), + NodeKind::Spread => node.cast_first_child().map(ClosureParam::Sink), + _ => None, } } } @@ -840,9 +789,7 @@ node! { impl WithExpr { /// The function to apply the arguments to. pub fn callee(&self) -> Expr { - self.0 - .cast_first_child() - .expect("with expression is missing callee expression") + self.0.cast_first_child().expect("with expression is missing callee") } /// The arguments to apply to the function. @@ -861,17 +808,16 @@ node! { impl LetExpr { /// The binding to assign to. pub fn binding(&self) -> Ident { - if let Some(c) = self.0.cast_first_child() { - c - } else if let Some(w) = self.0.typed_child(&NodeKind::WithExpr) { - // Can't do an `first_convert_child` here because the WithExpr's - // callee has to be an identifier. - w.cast_first_child() - .expect("with expression is missing an identifier callee") - } else if let Some(Expr::Closure(c)) = self.0.cast_last_child() { - c.name().expect("closure is missing an identifier name") - } else { - panic!("let expression is missing either an identifier or a with expression") + match self.0.cast_first_child() { + Some(Expr::Ident(binding)) => binding, + Some(Expr::With(with)) => match with.callee() { + Expr::Ident(binding) => binding, + _ => panic!("let .. with callee must be identifier"), + }, + Some(Expr::Closure(closure)) => { + closure.name().expect("let-bound closure is missing name") + } + _ => panic!("let expression is missing binding"), } } @@ -880,23 +826,9 @@ impl LetExpr { if self.0.cast_first_child::<Ident>().is_some() { self.0.children().filter_map(RedRef::cast).nth(1) } else { - Some( - self.0 - .cast_first_child() - .expect("let expression is missing a with expression"), - ) - } - } - - /// 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 { - self.0.children().find(|x| x.cast::<Expr>().is_some()) + // This is a let .. with expression. + self.0.cast_first_child() } - .unwrap() } } @@ -908,16 +840,12 @@ node! { impl ImportExpr { /// The items to be imported. pub fn imports(&self) -> Imports { - self.0 - .cast_first_child() - .expect("import expression is missing import list") + self.0.cast_first_child().expect("import is missing items") } /// The location of the importable file. pub fn path(&self) -> Expr { - self.0 - .cast_first_child() - .expect("import expression is missing path expression") + self.0.cast_last_child().expect("import is missing path") } } @@ -926,8 +854,8 @@ impl ImportExpr { pub enum Imports { /// All items in the scope of the file should be imported. Wildcard, - /// The specified identifiers from the file should be imported. - Idents(Vec<Ident>), + /// The specified items from the file should be imported. + Items(Vec<Ident>), } impl TypedNode for Imports { @@ -935,8 +863,8 @@ impl TypedNode for Imports { match node.kind() { NodeKind::Star => Some(Imports::Wildcard), NodeKind::ImportItems => { - let idents = node.children().filter_map(RedRef::cast).collect(); - Some(Imports::Idents(idents)) + let items = node.children().filter_map(RedRef::cast).collect(); + Some(Imports::Items(items)) } _ => None, } @@ -951,9 +879,7 @@ node! { impl IncludeExpr { /// The location of the file to be included. pub fn path(&self) -> Expr { - self.0 - .cast_first_child() - .expect("include expression is missing path expression") + self.0.cast_last_child().expect("include is missing path") } } @@ -965,9 +891,7 @@ node! { impl IfExpr { /// The condition which selects the body to evaluate. pub fn condition(&self) -> Expr { - self.0 - .cast_first_child() - .expect("if expression is missing condition expression") + self.0.cast_first_child().expect("if expression is missing condition") } /// The expression to evaluate if the condition is true. @@ -976,7 +900,7 @@ impl IfExpr { .children() .filter_map(RedRef::cast) .nth(1) - .expect("if expression is missing if body") + .expect("if expression is missing body") } /// The expression to evaluate if the condition is false. @@ -993,18 +917,12 @@ node! { impl WhileExpr { /// The condition which selects whether to evaluate the body. pub fn condition(&self) -> Expr { - self.0 - .cast_first_child() - .expect("while loop expression is missing condition expression") + self.0.cast_first_child().expect("while loop is missing condition") } /// The expression to evaluate while the condition is true. pub fn body(&self) -> Expr { - self.0 - .children() - .filter_map(RedRef::cast) - .nth(1) - .expect("while loop expression is missing body") + self.0.cast_last_child().expect("while loop is missing body") } } @@ -1016,34 +934,17 @@ node! { impl ForExpr { /// The pattern to assign to. pub fn pattern(&self) -> ForPattern { - self.0 - .cast_first_child() - .expect("for loop expression is missing pattern") + self.0.cast_first_child().expect("for loop is missing pattern") } /// The expression to iterate over. pub fn iter(&self) -> Expr { - self.0 - .cast_first_child() - .expect("for loop expression is missing iterable expression") + self.0.cast_first_child().expect("for loop is missing iterable") } /// The expression to evaluate for each iteration. pub fn body(&self) -> Expr { - self.0 - .children() - .filter_map(RedRef::cast) - .last() - .expect("for loop expression is missing body") - } - - /// 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()) - .last() - .unwrap() + self.0.cast_last_child().expect("for loop is missing body") } } @@ -1062,19 +963,11 @@ impl ForPattern { /// The value part of the pattern. pub fn value(&self) -> Ident { - self.0 - .cast_last_child() - .expect("for-in loop pattern is missing value") + self.0.cast_last_child().expect("for loop pattern is missing value") } } -/// An unicode identifier with a few extra permissible characters. -/// -/// In addition to what is specified in the [Unicode Standard][uax31], we allow: -/// - `_` as a starting character, -/// - `_` and `-` as continuing characters. -/// -/// [uax31]: http://www.unicode.org/reports/tr31/ +/// An identifier. #[derive(Debug, Clone, PartialEq)] pub struct Ident { /// The source code location. @@ -1083,44 +976,13 @@ pub struct Ident { pub string: EcoString, } -impl Ident { - /// Create a new identifier from a string checking that it is a valid. - pub fn new( - string: impl AsRef<str> + Into<EcoString>, - span: impl Into<Span>, - ) -> Option<Self> { - is_ident(string.as_ref()) - .then(|| Self { span: span.into(), string: string.into() }) - } - - /// Create a new identifier from a string and a span. - /// - /// The `string` must be a valid identifier. - #[track_caller] - pub fn new_unchecked(string: impl Into<EcoString>, span: Span) -> Self { - let string = string.into(); - debug_assert!(is_ident(&string), "`{}` is not a valid identifier", string); - Self { span, string } - } - - /// Return a reference to the underlying string. - pub fn as_str(&self) -> &str { - &self.string - } -} - -impl Deref for Ident { - type Target = str; - - fn deref(&self) -> &Self::Target { - self.as_str() - } -} - impl TypedNode for Ident { fn from_red(node: RedRef) -> Option<Self> { match node.kind() { - NodeKind::Ident(string) => Some(Ident::new_unchecked(string, node.span())), + NodeKind::Ident(string) => Some(Ident { + span: node.span(), + string: string.clone(), + }), _ => None, } } diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index 022b51de..fc05ad50 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -5,7 +5,6 @@ mod pretty; mod span; use std::fmt::{self, Debug, Display, Formatter}; -use std::mem; use std::rc::Rc; pub use pretty::*; @@ -40,14 +39,6 @@ impl Green { self.data().kind() } - /// Set the type of the node. - pub fn set_kind(&mut self, kind: NodeKind) { - match self { - Self::Node(node) => Rc::make_mut(node).data.set_kind(kind), - Self::Token(data) => data.set_kind(kind), - } - } - /// The length of the node. pub fn len(&self) -> usize { self.data().len() @@ -68,6 +59,18 @@ impl Green { Green::Token(_) => &[], } } + + /// Change the type of the node. + pub fn convert(&mut self, kind: NodeKind) { + match self { + Self::Node(node) => { + let node = Rc::make_mut(node); + node.erroneous |= kind.is_error(); + node.data.kind = kind; + } + Self::Token(data) => data.kind = kind, + } + } } impl Default for Green { @@ -161,11 +164,6 @@ impl GreenData { &self.kind } - /// Set the type of the node. - pub fn set_kind(&mut self, kind: NodeKind) { - self.kind = kind; - } - /// The length of the node. pub fn len(&self) -> usize { self.len @@ -178,7 +176,82 @@ impl From<GreenData> for Green { } } -/// A borrowed wrapper for a [`GreenNode`] with span information. +/// A owned wrapper for a green node with span information. +/// +/// Owned variant of [`RedRef`]. Can be [cast](Self::cast) to an AST nodes. +#[derive(Clone, PartialEq)] +pub struct RedNode { + id: SourceId, + offset: usize, + green: Green, +} + +impl RedNode { + /// Create a new root node from a [`GreenNode`]. + pub fn new_root(root: Rc<GreenNode>, id: SourceId) -> Self { + Self { id, offset: 0, green: root.into() } + } + + /// Convert to a borrowed representation. + pub fn as_ref(&self) -> RedRef<'_> { + RedRef { + id: self.id, + offset: self.offset, + green: &self.green, + } + } + + /// The type of the node. + pub fn kind(&self) -> &NodeKind { + self.as_ref().kind() + } + + /// The length of the node. + pub fn len(&self) -> usize { + self.as_ref().len() + } + + /// The span of the node. + pub fn span(&self) -> Span { + self.as_ref().span() + } + + /// The error messages for this node and its descendants. + pub fn errors(&self) -> Vec<Error> { + self.as_ref().errors() + } + + /// Convert the node to a typed AST node. + pub fn cast<T>(self) -> Option<T> + where + T: TypedNode, + { + self.as_ref().cast() + } + + /// The children of the node. + pub fn children(&self) -> Children<'_> { + self.as_ref().children() + } + + /// Get the first child that can cast to some AST type. + pub fn cast_first_child<T: TypedNode>(&self) -> Option<T> { + self.as_ref().cast_first_child() + } + + /// Get the last child that can cast to some AST type. + pub fn cast_last_child<T: TypedNode>(&self) -> Option<T> { + self.as_ref().cast_last_child() + } +} + +impl Debug for RedNode { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + self.as_ref().fmt(f) + } +} + +/// A borrowed wrapper for a green node with span information. /// /// Borrowed variant of [`RedNode`]. Can be [cast](Self::cast) to an AST node. #[derive(Copy, Clone, PartialEq)] @@ -213,30 +286,25 @@ impl<'a> RedRef<'a> { Span::new(self.id, self.offset, self.offset + self.green.len()) } - /// Whether the node or its children contain an error. - pub fn erroneous(self) -> bool { - self.green.erroneous() - } - /// The error messages for this node and its descendants. pub fn errors(self) -> Vec<Error> { - if !self.erroneous() { + if !self.green.erroneous() { return vec![]; } 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(), + ErrorPos::Start => self.span().at_start(), + ErrorPos::Full => self.span(), + ErrorPos::End => self.span().at_end(), }; vec![Error::new(span, msg.to_string())] } _ => self .children() - .filter(|red| red.erroneous()) + .filter(|red| red.green.erroneous()) .flat_map(|red| red.errors()) .collect(), } @@ -251,34 +319,28 @@ impl<'a> RedRef<'a> { } /// The node's children. - pub fn children(self) -> impl Iterator<Item = RedRef<'a>> { + pub fn children(self) -> Children<'a> { let children = match &self.green { Green::Node(node) => node.children(), Green::Token(_) => &[], }; - let mut cursor = self.offset; - children.iter().map(move |green| { - let offset = cursor; - cursor += green.len(); - RedRef { id: self.id, offset, green } - }) - } - - /// Get the first child of some type. - pub(crate) fn typed_child(self, kind: &NodeKind) -> Option<RedRef<'a>> { - self.children() - .find(|x| mem::discriminant(x.kind()) == mem::discriminant(kind)) + Children { + id: self.id, + iter: children.iter(), + front: self.offset, + back: self.offset + self.len(), + } } /// Get the first child that can cast to some AST type. - pub(crate) fn cast_first_child<T: TypedNode>(self) -> Option<T> { + pub fn cast_first_child<T: TypedNode>(self) -> Option<T> { self.children().find_map(RedRef::cast) } /// Get the last child that can cast to some AST type. - pub(crate) fn cast_last_child<T: TypedNode>(self) -> Option<T> { - self.children().filter_map(RedRef::cast).last() + pub fn cast_last_child<T: TypedNode>(self) -> Option<T> { + self.children().rev().find_map(RedRef::cast) } } @@ -294,86 +356,41 @@ impl Debug for RedRef<'_> { } } -/// A owned wrapper for a [`GreenNode`] with span information. -/// -/// Owned variant of [`RedRef`]. Can be [cast](Self::cast) to an AST nodes. -#[derive(Clone, PartialEq)] -pub struct RedNode { +/// An iterator over the children of a red node. +pub struct Children<'a> { id: SourceId, - offset: usize, - green: Green, + iter: std::slice::Iter<'a, Green>, + front: usize, + back: usize, } -impl RedNode { - /// Create a new root node from a [`GreenNode`]. - pub fn new_root(root: Rc<GreenNode>, id: SourceId) -> Self { - Self { id, offset: 0, green: root.into() } - } - - /// Convert to a borrowed representation. - pub fn as_ref(&self) -> RedRef<'_> { - RedRef { - id: self.id, - offset: self.offset, - green: &self.green, - } - } - - /// The type of the node. - pub fn kind(&self) -> &NodeKind { - self.as_ref().kind() - } - - /// The length of the node. - pub fn len(&self) -> usize { - self.as_ref().len() - } - - /// The span of the node. - pub fn span(&self) -> Span { - self.as_ref().span() - } - - /// The error messages for this node and its descendants. - pub fn errors(&self) -> Vec<Error> { - self.as_ref().errors() - } +impl<'a> Iterator for Children<'a> { + type Item = RedRef<'a>; - /// Convert the node to a typed AST node. - pub fn cast<T>(self) -> Option<T> - where - T: TypedNode, - { - self.as_ref().cast() - } - - /// The children of the node. - pub fn children(&self) -> impl Iterator<Item = RedRef<'_>> { - self.as_ref().children() - } - - /// Get the first child of some type. - pub(crate) fn typed_child(&self, kind: &NodeKind) -> Option<RedNode> { - self.as_ref().typed_child(kind).map(RedRef::own) - } - - /// Get the first child that can cast to some AST type. - pub(crate) fn cast_first_child<T: TypedNode>(&self) -> Option<T> { - self.as_ref().cast_first_child() + fn next(&mut self) -> Option<Self::Item> { + self.iter.next().map(|green| { + let offset = self.front; + self.front += green.len(); + RedRef { id: self.id, offset, green } + }) } - /// Get the last child that can cast to some AST type. - pub(crate) fn cast_last_child<T: TypedNode>(&self) -> Option<T> { - self.as_ref().cast_last_child() + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() } } -impl Debug for RedNode { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - self.as_ref().fmt(f) +impl DoubleEndedIterator for Children<'_> { + fn next_back(&mut self) -> Option<Self::Item> { + self.iter.next_back().map(|green| { + self.back -= green.len(); + RedRef { id: self.id, offset: self.back, green } + }) } } +impl ExactSizeIterator for Children<'_> {} + /// All syntactical building blocks that can be part of a Typst document. /// /// Can be emitted as a token by the tokenizer or as part of a green node by @@ -533,7 +550,7 @@ pub enum NodeKind { Array, /// A dictionary expression: `(thickness: 3pt, pattern: dashed)`. Dict, - /// A named argument: `thickness: 3pt`. + /// A named pair: `thickness: 3pt`. Named, /// A grouped expression: `(1 + 2)`. Group, @@ -582,12 +599,12 @@ pub enum NodeKind { /// The comment can contain nested block comments. BlockComment, /// Tokens that appear in the wrong place. - Error(ErrorPosition, EcoString), + Error(ErrorPos, EcoString), /// Unknown character sequences. Unknown(EcoString), } -/// Payload of a raw block: `` `...` ``. +/// Payload of a raw block node. #[derive(Debug, Clone, PartialEq)] pub struct RawData { /// The raw text in the block. @@ -600,19 +617,19 @@ pub struct RawData { pub block: bool, } -/// Payload of a math formula: `$2pi + x$` or `$[f'(x) = x^2]$`. +/// Payload of a math formula node. #[derive(Debug, Clone, PartialEq)] pub struct MathData { - /// The formula between the dollars. + /// The formula between the dollars / brackets. pub formula: EcoString, /// Whether the formula is display-level, that is, it is surrounded by - /// `$[..]`. + /// `$[..]$`. pub display: bool, } /// Where in a node an error should be annotated. #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum ErrorPosition { +pub enum ErrorPos { /// At the start of the node. Start, /// Over the full width of the node. diff --git a/src/syntax/pretty.rs b/src/syntax/pretty.rs index b396a39c..fa423e94 100644 --- a/src/syntax/pretty.rs +++ b/src/syntax/pretty.rs @@ -141,7 +141,7 @@ impl Pretty for RawNode { // Language tag. if let Some(lang) = &self.lang { - lang.pretty(p); + p.push_str(lang); } // Start untrimming. @@ -492,7 +492,7 @@ impl Pretty for Imports { fn pretty(&self, p: &mut Printer) { match self { Self::Wildcard => p.push('*'), - Self::Idents(idents) => { + Self::Items(idents) => { p.join(idents, ", ", |item, p| item.pretty(p)); } } @@ -508,7 +508,7 @@ impl Pretty for IncludeExpr { impl Pretty for Ident { fn pretty(&self, p: &mut Printer) { - p.push_str(self.as_str()); + p.push_str(&self.string); } } |
