diff --git a/src/eval/capture.rs b/src/eval/capture.rs index baf597472..b71e1ac18 100644 --- a/src/eval/capture.rs +++ b/src/eval/capture.rs @@ -1,7 +1,7 @@ use std::rc::Rc; use super::{Scope, Scopes, Value}; -use crate::syntax::{ClosureParam, Expr, Imports, RedTicket}; +use crate::syntax::{ClosureParam, Expr, Imports, RedRef}; /// A visitor that captures variable slots. pub struct CapturesVisitor<'a> { @@ -20,12 +20,12 @@ impl<'a> CapturesVisitor<'a> { } } - pub fn visit(&mut self, node: RedTicket) { + pub fn visit(&mut self, node: RedRef) { let expr: Option = node.cast(); match expr.as_ref() { Some(Expr::Let(expr)) => { - self.visit(expr.init_ticket()); + self.visit(expr.init_ref()); let ident = expr.binding(); self.internal.def_mut(ident.as_str(), Value::None); } @@ -40,7 +40,7 @@ impl<'a> CapturesVisitor<'a> { } } } - self.visit(closure.body_ticket()); + self.visit(closure.body_ref()); } Some(Expr::For(forloop)) => { let pattern = forloop.pattern(); @@ -49,7 +49,7 @@ impl<'a> CapturesVisitor<'a> { if let Some(key) = pattern.key() { self.internal.def_mut(key.as_str(), Value::None); } - self.visit(forloop.body_ticket()); + self.visit(forloop.body_ref()); } Some(Expr::Import(import)) => { if let Imports::Idents(idents) = import.imports() { @@ -73,7 +73,7 @@ impl<'a> CapturesVisitor<'a> { Some(Expr::Block(_)) => { self.internal.enter(); - for child in node.own().children() { + for child in node.children() { self.visit(child); } self.internal.exit(); @@ -81,14 +81,14 @@ impl<'a> CapturesVisitor<'a> { Some(Expr::Template(_)) => { self.internal.enter(); - for child in node.own().children() { + for child in node.children() { self.visit(child); } self.internal.exit(); } _ => { - for child in node.own().children() { + for child in node.children() { self.visit(child); } } diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 296e33808..8d31c1774 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -230,7 +230,7 @@ impl Eval for ArrayExpr { type Output = Array; fn eval(&self, ctx: &mut EvalContext) -> TypResult { - self.items().iter().map(|expr| expr.eval(ctx)).collect() + self.items().map(|expr| expr.eval(ctx)).collect() } } @@ -239,7 +239,6 @@ impl Eval for DictExpr { fn eval(&self, ctx: &mut EvalContext) -> TypResult { self.items() - .iter() .map(|x| Ok(((&x.name().string).into(), x.expr().eval(ctx)?))) .collect() } @@ -268,7 +267,7 @@ impl Eval for BlockExpr { ctx.scopes.enter(); let mut output = Value::None; - for expr in &self.exprs() { + for expr in self.exprs() { let value = expr.eval(ctx)?; output = ops::join(output, value).at(expr.span())?; } @@ -387,9 +386,9 @@ impl Eval for CallArgs { type Output = Args; fn eval(&self, ctx: &mut EvalContext) -> TypResult { - let mut items = Vec::with_capacity(self.items().len()); + let mut items = Vec::new(); - for arg in &self.items() { + for arg in self.items() { let span = arg.span(); match arg { CallArg::Pos(expr) => { @@ -454,11 +453,10 @@ impl Eval for ClosureExpr { }; let mut sink = None; - let params_src = self.params(); - let mut params = Vec::with_capacity(params_src.len()); + let mut params = Vec::new(); // Collect parameters and an optional sink parameter. - for param in ¶ms_src { + for param in self.params() { match param { ClosureParam::Pos(name) => { params.push((name.string.clone(), None)); diff --git a/src/eval/walk.rs b/src/eval/walk.rs index e4d7f61a1..b28f4fde7 100644 --- a/src/eval/walk.rs +++ b/src/eval/walk.rs @@ -69,7 +69,7 @@ impl Walk for RawNode { impl Walk for HeadingNode { fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { - let level = self.level().0; + let level = self.level(); let body = self.body().eval(ctx)?; ctx.template.parbreak(); @@ -99,7 +99,7 @@ impl Walk for ListNode { impl Walk for EnumNode { fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> { let body = self.body().eval(ctx)?; - let label = format_str!("{}.", self.number().0.unwrap_or(1)); + let label = format_str!("{}.", self.number().unwrap_or(1)); walk_item(ctx, label, body); Ok(()) } diff --git a/src/parse/mod.rs b/src/parse/mod.rs index dc7691833..0425f8248 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -30,15 +30,14 @@ fn markup(p: &mut Parser) { /// Parse markup that stays right of the given column. fn markup_indented(p: &mut Parser, column: usize) { - // TODO this is broken p.eat_while(|t| match t { - NodeKind::Space(n) => n == 0, + NodeKind::Space(n) => *n == 0, NodeKind::LineComment | NodeKind::BlockComment => true, _ => false, }); markup_while(p, false, &mut |p| match p.peek() { - Some(NodeKind::Space(n)) if n >= 1 => p.column(p.next_end()) >= column, + Some(NodeKind::Space(n)) if *n >= 1 => p.column(p.next_end()) >= column, _ => true, }) } @@ -64,125 +63,119 @@ where /// Parse a markup node. fn markup_node(p: &mut Parser, at_start: &mut bool) { - if let Some(token) = p.peek() { - match token { - // Whitespace. - NodeKind::Space(newlines) => { - *at_start |= newlines > 0; + let token = match p.peek() { + Some(t) => t, + None => return, + }; - if newlines < 2 { - p.eat(); - } else { - p.convert(NodeKind::Parbreak); - } - } - - // Text. - NodeKind::UnicodeEscape(u) => { - if !u.terminated { - p.convert(NodeKind::Error( - ErrorPosition::End, - "expected closing brace".into(), - )); - p.unsuccessful(); - return; - } - - if u.character.is_none() { - let src = p.peek_src(); - p.convert(NodeKind::Error( - ErrorPosition::Full, - "invalid unicode escape sequence".into(), - )); - p.start(); - p.end(NodeKind::Text(src.into())); - return; - } + match token { + // Whitespace. + NodeKind::Space(newlines) => { + *at_start |= *newlines > 0; + if *newlines < 2 { p.eat(); + } else { + p.convert(NodeKind::Parbreak); } - NodeKind::Raw(r) => { - if !r.terminated { - p.convert(NodeKind::Error( - ErrorPosition::End, - "expected backtick(s)".into(), - )); - p.unsuccessful(); - return; - } + } - p.eat(); - } - NodeKind::Text(_) - | NodeKind::EnDash - | NodeKind::EmDash - | NodeKind::NonBreakingSpace => { - p.eat(); + // Text and markup. + NodeKind::Text(_) + | NodeKind::EnDash + | NodeKind::EmDash + | NodeKind::NonBreakingSpace + | NodeKind::Emph + | NodeKind::Strong + | NodeKind::Linebreak => p.eat(), + + NodeKind::UnicodeEscape(u) => { + if !u.terminated { + p.convert(NodeKind::Error( + ErrorPosition::End, + "expected closing brace".into(), + )); + p.unsuccessful(); + return; } - // Markup. - NodeKind::Emph | NodeKind::Strong | NodeKind::Linebreak => { - p.eat(); + if u.character.is_none() { + let src = p.peek_src(); + p.convert(NodeKind::Error( + ErrorPosition::Full, + "invalid unicode escape sequence".into(), + )); + p.start(); + p.end(NodeKind::Text(src.into())); + return; } - NodeKind::Eq if *at_start => heading(p), - NodeKind::ListBullet if *at_start => list_node(p), - NodeKind::EnumNumbering(_) if *at_start => enum_node(p), - - // Line-based markup that is not currently at the start of the line. - NodeKind::Eq | NodeKind::ListBullet | NodeKind::EnumNumbering(_) => { - p.convert(NodeKind::Text(p.peek_src().into())) + p.eat(); + } + NodeKind::Raw(r) => { + if !r.terminated { + p.convert(NodeKind::Error( + ErrorPosition::End, + "expected backtick(s)".into(), + )); + p.unsuccessful(); + return; } - // Hashtag + keyword / identifier. - NodeKind::Ident(_) - | NodeKind::Let - | NodeKind::If - | NodeKind::While - | NodeKind::For - | NodeKind::Import - | NodeKind::Include => { - let stmt = matches!(token, NodeKind::Let | NodeKind::Import); - let group = if stmt { Group::Stmt } else { Group::Expr }; + p.eat(); + } - p.start_group(group, TokenMode::Code); - expr_with(p, true, 0); - if stmt && p.success() && !p.eof() { - p.expected_at("semicolon or line break"); - } - p.end_group(); - } + NodeKind::Eq if *at_start => heading(p), + NodeKind::ListBullet if *at_start => list_node(p), + NodeKind::EnumNumbering(_) if *at_start => enum_node(p), - // Block and template. - NodeKind::LeftBrace => { - block(p); - } - NodeKind::LeftBracket => { - template(p); - } + // Line-based markup that is not currently at the start of the line. + NodeKind::Eq | NodeKind::ListBullet | NodeKind::EnumNumbering(_) => { + p.convert(NodeKind::Text(p.peek_src().into())) + } - // Comments. - NodeKind::LineComment | NodeKind::BlockComment => { - p.eat(); - } + // Hashtag + keyword / identifier. + NodeKind::Ident(_) + | NodeKind::Let + | NodeKind::If + | NodeKind::While + | NodeKind::For + | NodeKind::Import + | NodeKind::Include => { + let stmt = matches!(token, NodeKind::Let | NodeKind::Import); + let group = if stmt { Group::Stmt } else { Group::Expr }; - _ => { - *at_start = false; - p.unexpected(); + p.start_group(group, TokenMode::Code); + expr_with(p, true, 0); + if stmt && p.success() && !p.eof() { + p.expected_at("semicolon or line break"); } - }; - } + p.end_group(); + } + + // Block and template. + NodeKind::LeftBrace => block(p), + NodeKind::LeftBracket => template(p), + + // Comments. + NodeKind::LineComment | NodeKind::BlockComment => p.eat(), + + _ => { + *at_start = false; + p.unexpected(); + } + }; } /// Parse a heading. fn heading(p: &mut Parser) { p.start(); p.start(); - p.eat_assert(NodeKind::Eq); + p.eat_assert(&NodeKind::Eq); // Count depth. let mut level: usize = 1; - while p.eat_if(NodeKind::Eq) { + while p.eat_if(&NodeKind::Eq) { level += 1; } @@ -200,7 +193,7 @@ fn heading(p: &mut Parser) { /// Parse a single list item. fn list_node(p: &mut Parser) { p.start(); - p.eat_assert(NodeKind::ListBullet); + p.eat_assert(&NodeKind::ListBullet); let column = p.column(p.prev_end()); markup_indented(p, column); p.end(NodeKind::List); @@ -209,9 +202,7 @@ fn list_node(p: &mut Parser) { /// Parse a single enum item. fn enum_node(p: &mut Parser) { p.start(); - if !matches!(p.eat(), Some(NodeKind::EnumNumbering(_))) { - panic!("enum item does not start with numbering") - }; + p.eat(); let column = p.column(p.prev_end()); markup_indented(p, column); p.end(NodeKind::Enum); @@ -263,7 +254,7 @@ fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) { continue; } - if p.peek() == Some(NodeKind::With) { + if p.peek() == Some(&NodeKind::With) { with_expr(p, p.child_count() - offset); if p.may_lift_abort() { @@ -276,7 +267,7 @@ fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) { break; } - let op = match p.peek().as_ref().and_then(BinOp::from_token) { + let op = match p.peek().and_then(BinOp::from_token) { Some(binop) => binop, None => { p.lift(); @@ -286,10 +277,8 @@ fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) { let mut prec = op.precedence(); if prec < min_prec { - { - p.lift(); - break; - }; + p.lift(); + break; } p.eat(); @@ -324,7 +313,7 @@ fn primary(p: &mut Parser, atomic: bool) { p.eat(); // Arrow means this is a closure's lone parameter. - if !atomic && p.peek() == Some(NodeKind::Arrow) { + if !atomic && p.peek() == Some(&NodeKind::Arrow) { p.end_and_start_with(NodeKind::ClosureParams); p.eat(); @@ -359,10 +348,9 @@ fn primary(p: &mut Parser, atomic: bool) { /// Parse a literal. fn literal(p: &mut Parser) -> bool { - let peeked = if let Some(p) = p.peek() { - p - } else { - return false; + let peeked = match p.peek() { + Some(x) => x.clone(), + None => return false, }; match peeked { @@ -375,18 +363,14 @@ fn literal(p: &mut Parser) -> bool { | NodeKind::Fraction(_) | NodeKind::Length(_, _) | NodeKind::Angle(_, _) - | NodeKind::Percentage(_) => { - p.eat(); - } + | NodeKind::Percentage(_) => p.eat(), NodeKind::Str(s) => { p.eat(); if !s.terminated { p.expected_at("quote"); } } - _ => { - return false; - } + _ => return false, } true @@ -401,7 +385,7 @@ fn parenthesized(p: &mut Parser) { let offset = p.child_count(); p.start(); p.start_group(Group::Paren, TokenMode::Code); - let colon = p.eat_if(NodeKind::Colon); + let colon = p.eat_if(&NodeKind::Colon); let kind = collection(p).0; p.end_group(); let token_count = p.child_count() - offset; @@ -414,12 +398,12 @@ fn parenthesized(p: &mut Parser) { } // Arrow means this is a closure's parameter list. - if p.peek() == Some(NodeKind::Arrow) { + if p.peek() == Some(&NodeKind::Arrow) { p.start_with(token_count); params(p, 0, true); p.end(NodeKind::ClosureParams); - p.eat_assert(NodeKind::Arrow); + p.eat_assert(&NodeKind::Arrow); expr(p); @@ -485,7 +469,7 @@ fn collection(p: &mut Parser) -> (CollectionKind, usize) { break; } - if p.eat_if(NodeKind::Comma) { + if p.eat_if(&NodeKind::Comma) { has_comma = true; } else { missing_coma = Some(p.child_count()); @@ -518,7 +502,7 @@ enum CollectionItemKind { /// Parse an expression or a named pair. Returns if this is a named pair. fn item(p: &mut Parser) -> CollectionItemKind { p.start(); - if p.eat_if(NodeKind::Dots) { + if p.eat_if(&NodeKind::Dots) { expr(p); p.end_or_abort(NodeKind::ParameterSink); @@ -531,7 +515,7 @@ fn item(p: &mut Parser) -> CollectionItemKind { return CollectionItemKind::Unnamed; } - if p.eat_if(NodeKind::Colon) { + if p.eat_if(&NodeKind::Colon) { let child = p.child(1).unwrap(); if matches!(child.kind(), &NodeKind::Ident(_)) { expr(p); @@ -686,9 +670,9 @@ fn args(p: &mut Parser, allow_template: bool) { /// Parse a with expression. fn with_expr(p: &mut Parser, preserve: usize) { p.start_with(preserve); - p.eat_assert(NodeKind::With); + p.eat_assert(&NodeKind::With); - if p.peek() == Some(NodeKind::LeftParen) { + if p.peek() == Some(&NodeKind::LeftParen) { args(p, false); p.end(NodeKind::WithExpr); } else { @@ -700,7 +684,7 @@ fn with_expr(p: &mut Parser, preserve: usize) { /// Parse a let expression. fn let_expr(p: &mut Parser) { p.start(); - p.eat_assert(NodeKind::Let); + p.eat_assert(&NodeKind::Let); let offset = p.child_count(); ident(p); @@ -708,7 +692,7 @@ fn let_expr(p: &mut Parser) { return; } - if p.peek() == Some(NodeKind::With) { + if p.peek() == Some(&NodeKind::With) { with_expr(p, p.child_count() - offset); } else { // If a parenthesis follows, this is a function definition. @@ -725,7 +709,7 @@ fn let_expr(p: &mut Parser) { false }; - if p.eat_if(NodeKind::Eq) { + if p.eat_if(&NodeKind::Eq) { expr(p); } else if has_params { // Function definitions must have a body. @@ -749,7 +733,7 @@ fn let_expr(p: &mut Parser) { /// Parse an if expresion. fn if_expr(p: &mut Parser) { p.start(); - p.eat_assert(NodeKind::If); + p.eat_assert(&NodeKind::If); expr(p); if p.may_end_abort(NodeKind::IfExpr) { @@ -762,8 +746,8 @@ fn if_expr(p: &mut Parser) { return; } - if p.eat_if(NodeKind::Else) { - if p.peek() == Some(NodeKind::If) { + if p.eat_if(&NodeKind::Else) { + if p.peek() == Some(&NodeKind::If) { if_expr(p); } else { body(p); @@ -776,7 +760,7 @@ fn if_expr(p: &mut Parser) { /// Parse a while expresion. fn while_expr(p: &mut Parser) { p.start(); - p.eat_assert(NodeKind::While); + p.eat_assert(&NodeKind::While); expr(p); @@ -793,7 +777,7 @@ fn while_expr(p: &mut Parser) { /// Parse a for expression. fn for_expr(p: &mut Parser) { p.start(); - p.eat_assert(NodeKind::For); + p.eat_assert(&NodeKind::For); for_pattern(p); @@ -801,7 +785,7 @@ fn for_expr(p: &mut Parser) { return; } - if p.eat_expect(NodeKind::In) { + if p.eat_expect(&NodeKind::In) { expr(p); if p.may_end_abort(NodeKind::ForExpr) { @@ -828,7 +812,7 @@ fn for_pattern(p: &mut Parser) { return; } - if p.peek() == Some(NodeKind::Comma) { + if p.peek() == Some(&NodeKind::Comma) { p.eat(); ident(p); @@ -844,9 +828,9 @@ fn for_pattern(p: &mut Parser) { /// Parse an import expression. fn import_expr(p: &mut Parser) { p.start(); - p.eat_assert(NodeKind::Import); + p.eat_assert(&NodeKind::Import); - if !p.eat_if(NodeKind::Star) { + if !p.eat_if(&NodeKind::Star) { // This is the list of identifiers scenario. p.start(); p.start_group(Group::Imports, TokenMode::Code); @@ -865,7 +849,7 @@ fn import_expr(p: &mut Parser) { p.end(NodeKind::ImportItems); }; - if p.eat_expect(NodeKind::From) { + if p.eat_expect(&NodeKind::From) { expr(p); } @@ -875,7 +859,7 @@ fn import_expr(p: &mut Parser) { /// Parse an include expression. fn include_expr(p: &mut Parser) { p.start(); - p.eat_assert(NodeKind::Include); + p.eat_assert(&NodeKind::Include); expr(p); p.end(NodeKind::IncludeExpr); @@ -883,11 +867,12 @@ fn include_expr(p: &mut Parser) { /// Parse an identifier. fn ident(p: &mut Parser) { - if let Some(NodeKind::Ident(_)) = p.peek() { - p.eat(); - } else { - p.expected("identifier"); - p.unsuccessful(); + match p.peek() { + Some(NodeKind::Ident(_)) => p.eat(), + _ => { + p.expected("identifier"); + p.unsuccessful(); + } } } diff --git a/src/parse/parser.rs b/src/parse/parser.rs index f62e882af..e6fcc1aed 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -161,7 +161,7 @@ impl<'s> Parser<'s> { let len = children.iter().map(|c| c.len()).sum(); self.children - .push(GreenNode::with_children(kind, len, children.into_iter()).into()); + .push(GreenNode::with_children(kind, len, children).into()); self.children.extend(remains); self.success = true; } @@ -240,10 +240,9 @@ impl<'s> Parser<'s> { } pub fn finish(&mut self) -> Rc { - if let Green::Node(n) = self.children.pop().unwrap() { - n - } else { - panic!() + match self.children.pop().unwrap() { + Green::Node(n) => n, + _ => panic!(), } } @@ -252,16 +251,16 @@ impl<'s> Parser<'s> { self.peek().is_none() } - pub fn eat(&mut self) -> Option { - let token = self.peek()?; - self.bump(); + fn eat_peeked(&mut self) -> Option { + let token = self.peek()?.clone(); + self.eat(); Some(token) } /// Consume the next token if it is the given one. - pub fn eat_if(&mut self, t: NodeKind) -> bool { + pub fn eat_if(&mut self, t: &NodeKind) -> bool { if self.peek() == Some(t) { - self.bump(); + self.eat(); true } else { false @@ -271,36 +270,36 @@ impl<'s> Parser<'s> { /// Consume the next token if the closure maps it a to `Some`-variant. pub fn eat_map(&mut self, f: F) -> Option where - F: FnOnce(NodeKind) -> Option, + F: FnOnce(&NodeKind) -> Option, { let token = self.peek()?; let mapped = f(token); if mapped.is_some() { - self.bump(); + self.eat(); } mapped } /// Consume the next token if it is the given one and produce an error if /// not. - pub fn eat_expect(&mut self, t: NodeKind) -> bool { - let eaten = self.eat_if(t.clone()); + pub fn eat_expect(&mut self, t: &NodeKind) -> bool { + let eaten = self.eat_if(t); if !eaten { - self.expected_at(&t.to_string()); + self.expected_at(t.as_str()); } eaten } /// Consume the next token, debug-asserting that it is one of the given ones. - pub fn eat_assert(&mut self, t: NodeKind) { - let next = self.eat(); - debug_assert_eq!(next, Some(t)); + pub fn eat_assert(&mut self, t: &NodeKind) { + let next = self.eat_peeked(); + debug_assert_eq!(next.as_ref(), Some(t)); } /// Consume tokens while the condition is true. pub fn eat_while(&mut self, mut f: F) where - F: FnMut(NodeKind) -> bool, + F: FnMut(&NodeKind) -> bool, { while self.peek().map_or(false, |t| f(t)) { self.eat(); @@ -308,8 +307,8 @@ impl<'s> Parser<'s> { } /// Peek at the next token without consuming it. - pub fn peek(&self) -> Option { - self.peeked.clone() + pub fn peek(&self) -> Option<&NodeKind> { + self.peeked.as_ref() } /// Peek at the next token if it follows immediately after the last one @@ -371,9 +370,9 @@ impl<'s> Parser<'s> { self.repeek(); match kind { - Group::Paren => self.eat_assert(NodeKind::LeftParen), - Group::Bracket => self.eat_assert(NodeKind::LeftBracket), - Group::Brace => self.eat_assert(NodeKind::LeftBrace), + Group::Paren => self.eat_assert(&NodeKind::LeftParen), + Group::Bracket => self.eat_assert(&NodeKind::LeftBracket), + Group::Brace => self.eat_assert(&NodeKind::LeftBrace), Group::Stmt => {} Group::Expr => {} Group::Imports => {} @@ -402,11 +401,11 @@ impl<'s> Parser<'s> { } { if self.next == Some(end.clone()) { // Bump the delimeter and return. No need to rescan in this case. - self.bump(); + self.eat(); rescan = false; } else if required { self.start(); - self.abort(format!("expected {}", end.to_string())); + self.abort(format!("expected {}", end)); } } @@ -457,21 +456,21 @@ impl<'s> Parser<'s> { /// Eat the next token and add an error that it is not the expected `thing`. pub fn expected(&mut self, what: &str) { self.start(); - if let Some(found) = self.eat() { - self.abort(format!("expected {}, found {}", what, found.to_string())) - } else { - self.lift(); - self.expected_at(what); + match self.eat_peeked() { + Some(found) => self.abort(format!("expected {}, found {}", what, found)), + None => { + self.lift(); + self.expected_at(what); + } } } /// Eat the next token and add an error that it is unexpected. pub fn unexpected(&mut self) { self.start(); - if let Some(found) = self.eat() { - self.abort(format!("unexpected {}", found.to_string())) - } else { - self.abort("unexpected end of file") + match self.eat_peeked() { + Some(found) => self.abort(format!("unexpected {}", found)), + None => self.abort("unexpected end of file"), } } @@ -489,7 +488,7 @@ impl<'s> Parser<'s> { } /// Move to the next token. - fn bump(&mut self) { + pub fn eat(&mut self) { self.children.push( GreenData::new( self.next.clone().unwrap(), @@ -511,7 +510,7 @@ impl<'s> Parser<'s> { if self.tokens.mode() == TokenMode::Code { // Skip whitespace and comments. while self.next.as_ref().map_or(false, |x| self.skip_type(x)) { - self.bump(); + self.eat(); } } diff --git a/src/parse/resolve.rs b/src/parse/resolve.rs index c59c3bb17..1b3089a63 100644 --- a/src/parse/resolve.rs +++ b/src/parse/resolve.rs @@ -25,11 +25,9 @@ pub fn resolve_string(string: &str) -> EcoString { let sequence = s.eat_while(|c| c.is_ascii_hexdigit()); let _terminated = s.eat_if('}'); - if let Some(c) = resolve_hex(sequence) { - out.push(c); - } else { - // TODO: Feedback that unicode escape sequence is wrong. - out.push_str(s.eaten_from(start)); + match resolve_hex(sequence) { + Some(c) => out.push(c), + None => out.push_str(s.eaten_from(start)), } } diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs index 19d0d77bb..bfd9f3ed1 100644 --- a/src/parse/tokens.rs +++ b/src/parse/tokens.rs @@ -224,8 +224,8 @@ impl<'s> Tokens<'s> { } fn backslash(&mut self) -> NodeKind { - if let Some(c) = self.s.peek() { - match c { + match self.s.peek() { + Some(c) => match c { // Backslash and comments. '\\' | '/' | // Parenthesis and hashtag. @@ -247,9 +247,8 @@ impl<'s> Tokens<'s> { } c if c.is_whitespace() => NodeKind::Linebreak, _ => NodeKind::Text("\\".into()), - } - } else { - NodeKind::Linebreak + }, + None => NodeKind::Linebreak, } } @@ -257,10 +256,9 @@ impl<'s> Tokens<'s> { fn hash(&mut self) -> NodeKind { if self.s.check_or(false, is_id_start) { let read = self.s.eat_while(is_id_continue); - if let Some(keyword) = keyword(read) { - keyword - } else { - NodeKind::Ident(read.into()) + match keyword(read) { + Some(keyword) => keyword, + None => NodeKind::Ident(read.into()), } } else { NodeKind::Text("#".into()) diff --git a/src/source.rs b/src/source.rs index e33e146c0..e3803f575 100644 --- a/src/source.rs +++ b/src/source.rs @@ -148,10 +148,10 @@ impl SourceFile { } pub fn ast(&self) -> TypResult { - let res = RedNode::new_root(self.root.clone(), self.id); - let errors = res.errors(); + let red = RedNode::new_root(self.root.clone(), self.id); + let errors = red.errors(); if errors.is_empty() { - Ok(res.ticket().cast().unwrap()) + Ok(red.as_ref().cast().unwrap()) } else { Err(Box::new( errors.into_iter().map(|(span, msg)| Error::new(span, msg)).collect(), diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs index d0d0c62fe..8562a3a49 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 { + fn cast_from(node: RedRef) -> Option { 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 { + fn cast_from(node: RedRef) -> Option { 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 { - self.0.children().filter_map(RedTicket::cast).collect() + pub fn items<'a>(&'a self) -> impl Iterator + '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 { - self.0.children().filter_map(RedTicket::cast).collect() + pub fn items<'a>(&'a self) -> impl Iterator + '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 { - self.0.children().filter_map(RedTicket::cast).collect() + pub fn exprs<'a>(&'a self) -> impl Iterator + '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 { + fn cast_from(node: RedRef) -> Option { 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 { + fn cast_from(node: RedRef) -> Option { 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 { - self.0.children().filter_map(RedTicket::cast).collect() + pub fn items<'a>(&'a self) -> impl Iterator + '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 { + fn cast_from(node: RedRef) -> Option { 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 { + pub fn params<'a>(&'a self) -> impl Iterator + '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::().is_some()) @@ -629,17 +626,16 @@ pub enum ClosureParam { } impl TypedNode for ClosureParam { - fn cast_from(node: RedTicket) -> Option { + fn cast_from(node: RedRef) -> Option { 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 { if self.0.cast_first_child::().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::().is_some() { self.0.children().filter(|x| x.cast::().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 { + fn cast_from(node: RedRef) -> Option { 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 { - 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::().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 { - 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 2c61329d1..f5cc63300 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 { - if let NodeKind::Ident(i) = node.kind() { - Some(Ident::new(i, node.own().span()).unwrap()) - } else { - None + fn cast_from(node: RedRef) -> Option { + 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 c12c0e819..de547f769 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; impl TypedNode for Markup { - fn cast_from(node: RedTicket) -> Option { + fn cast_from(node: RedRef) -> Option { 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 { + fn cast_from(node: RedRef) -> Option { 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 { - 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 { + 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 { - 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); - -impl TypedNode for EnumNumber { - fn cast_from(node: RedTicket) -> Option { - if let NodeKind::EnumNumbering(x) = node.kind() { - Some(Self(*x)) - } else { - None - } + pub fn number(&self) -> Option { + 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 88757f8ea..8e04a569f 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, } @@ -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>, - ) -> Self { + pub fn with_children(kind: NodeKind, len: usize, children: Vec) -> 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) -> 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> 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(self) -> Option 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> + 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 { + self.children() + .find(|x| mem::discriminant(x.kind()) == mem::discriminant(kind)) + } + + pub(crate) fn cast_first_child(&self) -> Option { + self.children().find_map(RedRef::cast) + } + + pub(crate) fn cast_last_child(&self) -> Option { + 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> + 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> + 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(), - }; + 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())] - } 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() + 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 { - 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(&self) -> Option { - self.children().find_map(RedTicket::cast) + self.as_ref().cast_first_child() } pub(crate) fn cast_last_child(&self) -> Option { - 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::>(); + let children = self.as_ref().children().collect::>(); 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; + fn cast_from(value: RedRef) -> Option; } #[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 { + fn cast_from(node: RedRef) -> Option { 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 b1c7e02bd..db364eaa1 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(&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(&mut self, items: I, joiner: &str, mut write_item: F) -> usize where I: IntoIterator, 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)); + } } } }