summaryrefslogtreecommitdiff
path: root/src/syntax
diff options
context:
space:
mode:
authorMartin Haug <mhaug@live.de>2021-10-31 11:46:12 +0100
committerMartin Haug <mhaug@live.de>2021-11-05 13:44:49 +0100
commit84d35efee38d137a77e368c50421ac24327371c6 (patch)
treec2fa9f669743d35cbb79892770427dd843202894 /src/syntax
parent4875633acf4701705b9b3b014eb7d94268b897c2 (diff)
Less owning, more iterating
Diffstat (limited to 'src/syntax')
-rw-r--r--src/syntax/expr.rs173
-rw-r--r--src/syntax/ident.rs11
-rw-r--r--src/syntax/markup.rs104
-rw-r--r--src/syntax/mod.rs241
-rw-r--r--src/syntax/pretty.rs41
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));
+ }
}
}
}