summaryrefslogtreecommitdiff
path: root/src/syntax
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-11-07 22:05:48 +0100
committerLaurenz <laurmaedje@gmail.com>2021-11-08 01:37:49 +0100
commit95866d5fc9ae89a23c5754193c7de5d4fe4873b1 (patch)
treeae408006c29ba31aa62dab7e48e9326316f89fed /src/syntax
parent8117ca9950a2027efae133f811a26a4a7bf86a8e (diff)
Tidy up AST
Diffstat (limited to 'src/syntax')
-rw-r--r--src/syntax/ast.rs350
-rw-r--r--src/syntax/mod.rs249
-rw-r--r--src/syntax/pretty.rs6
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);
}
}