diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 30e20c0db..92220eaab 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -16,6 +16,8 @@ use crate::syntax::ast::{Associativity, BinOp, UnOp}; use crate::syntax::{ErrorPosition, GreenNode, NodeKind}; use crate::util::EcoString; +type ParseResult = Result<(), ()>; + /// Parse a source file. pub fn parse(source: &str) -> Rc { let mut p = Parser::new(source); @@ -53,24 +55,16 @@ where p.start(); while !p.eof() && f(p) { markup_node(p, &mut at_start); - // NOTE: Just do this at the end of markup_node. Maybe even gives a - // speed boost. Wasn't possible in old parser due to use of ?. - if let Some(node) = p.last_child() { - at_start &= matches!(node.kind(), - &NodeKind::Space(_) | &NodeKind::Parbreak | - &NodeKind::LineComment | &NodeKind::BlockComment - ); - } } p.end(NodeKind::Markup); } /// Parse a markup node. -fn markup_node(p: &mut Parser, at_start: &mut bool) { +fn markup_node(p: &mut Parser, at_start: &mut bool) -> ParseResult { let token = match p.peek() { Some(t) => t, - None => return, + None => return Ok(()), }; match token { @@ -83,6 +77,7 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) { } else { p.convert(NodeKind::Parbreak); } + return Ok(()); } // Text and markup. @@ -94,7 +89,10 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) { | NodeKind::Strong | NodeKind::Linebreak | NodeKind::Raw(_) - | NodeKind::UnicodeEscape(_) => p.eat(), + | NodeKind::UnicodeEscape(_) => { + p.eat(); + Ok(()) + } NodeKind::Eq if *at_start => heading(p), NodeKind::ListBullet if *at_start => list_node(p), @@ -102,7 +100,8 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) { // 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.convert(NodeKind::Text(p.peek_src().into())); + Ok(()) } // Hashtag + keyword / identifier. @@ -117,12 +116,11 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) { let group = if stmt { Group::Stmt } else { Group::Expr }; p.start_group(group, TokenMode::Code); - // NOTE: Return success from expr_with? - expr_with(p, true, 0); - if stmt && p.success() && !p.eof() { + let res = expr_with(p, true, 0); + if stmt && res.is_ok() && !p.eof() { p.expected_at("semicolon or line break"); } - p.end_group(); + p.end_group() } // Block and template. @@ -130,19 +128,28 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) { NodeKind::LeftBracket => template(p), // Comments. - NodeKind::LineComment | NodeKind::BlockComment | NodeKind::Error(_, _) => p.eat(), + NodeKind::LineComment | NodeKind::BlockComment => { + p.eat(); + return Ok(()); + } + + NodeKind::Error(_, _) => { + p.eat(); + Ok(()) + } _ => { - *at_start = false; p.unexpected(); + Err(()) } - }; + }?; + + *at_start = false; + Ok(()) } /// Parse a heading. -fn heading(p: &mut Parser) { - // NOTE: Remove HeadingLevel kind and simply count Eq children in AST. - p.start(); +fn heading(p: &mut Parser) -> ParseResult { p.start(); p.eat_assert(&NodeKind::Eq); @@ -153,36 +160,37 @@ fn heading(p: &mut Parser) { } if level > 6 { - p.lift(); p.end(NodeKind::Text(EcoString::from('=').repeat(level))); } else { - p.end(NodeKind::HeadingLevel(level as u8)); let column = p.column(p.prev_end()); markup_indented(p, column); p.end(NodeKind::Heading); } + Ok(()) } /// Parse a single list item. -fn list_node(p: &mut Parser) { +fn list_node(p: &mut Parser) -> ParseResult { p.start(); p.eat_assert(&NodeKind::ListBullet); let column = p.column(p.prev_end()); markup_indented(p, column); p.end(NodeKind::List); + Ok(()) } /// Parse a single enum item. -fn enum_node(p: &mut Parser) { +fn enum_node(p: &mut Parser) -> ParseResult { p.start(); p.eat(); let column = p.column(p.prev_end()); markup_indented(p, column); p.end(NodeKind::Enum); + Ok(()) } /// Parse an expression. -fn expr(p: &mut Parser) { +fn expr(p: &mut Parser) -> ParseResult { expr_with(p, false, 0) } @@ -193,28 +201,19 @@ fn expr(p: &mut Parser) { /// in markup. /// /// Stops parsing at operations with lower precedence than `min_prec`, -fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) { - p.start(); - let mut offset = p.child_count(); +fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult { + let marker = p.marker(); + // Start the unary expression. match p.eat_map(|x| UnOp::from_token(&x)) { Some(op) => { let prec = op.precedence(); - expr_with(p, atomic, prec); + expr_with(p, atomic, prec)?; - // NOTE: Lifting not needed if we don't start in the first place. - // Then we could simply do expr_with(p, atomic, prec)?; - if p.may_lift_abort() { - return; - } - - p.end_and_start_with(NodeKind::Unary); + marker.end(p, NodeKind::Unary); } None => { - primary(p, atomic); - if p.may_lift_abort() { - return; - } + primary(p, atomic)?; } }; @@ -225,35 +224,28 @@ fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) { p.peek_direct(), Some(NodeKind::LeftParen | NodeKind::LeftBracket) ) { - call(p, p.child_count() - offset); + call(p, &marker); continue; } - if p.peek() == Some(&NodeKind::With) { - with_expr(p, p.child_count() - offset); - - if p.may_lift_abort() { - return; - } + if atomic { + break Ok(()); } - if atomic { - p.lift(); - break; + if p.peek() == Some(&NodeKind::With) { + with_expr(p, &marker)?; } let op = match p.peek().and_then(BinOp::from_token) { Some(binop) => binop, None => { - p.lift(); - break; + break Ok(()); } }; let mut prec = op.precedence(); if prec < min_prec { - p.lift(); - break; + break Ok(()); } p.eat(); @@ -263,44 +255,38 @@ fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) { Associativity::Right => {} } - expr_with(p, atomic, prec); - - if !p.success() { - p.lift(); - break; + if expr_with(p, atomic, prec).is_err() { + break Ok(()); } - // NOTE: All lifts up to here wouldn't be needed. - // Only here we then need to do - // marker.end(p, NodeKind::Binary); - - offset = p.end_and_start_with(NodeKind::Binary).0; + marker.end(p, NodeKind::Binary); } } /// Parse a primary expression. -fn primary(p: &mut Parser, atomic: bool) { - if literal(p) { - return; +fn primary(p: &mut Parser, atomic: bool) -> ParseResult { + let lit = literal(p); + if lit.is_ok() { + return lit; } match p.peek() { // Things that start with an identifier. Some(NodeKind::Ident(_)) => { // Start closure params. - p.start(); + let marker = p.marker(); p.eat(); // Arrow means this is a closure's lone parameter. if !atomic && p.peek() == Some(&NodeKind::Arrow) { - p.end_and_start_with(NodeKind::ClosureParams); + marker.end(p, NodeKind::ClosureParams); p.eat(); - expr(p); - - p.end_or_abort(NodeKind::Closure); + let e = expr(p); + marker.end(p, NodeKind::Closure); + e } else { - p.lift(); + Ok(()) } } @@ -319,18 +305,19 @@ fn primary(p: &mut Parser, atomic: bool) { Some(NodeKind::Error(_, _)) => { p.eat(); + Ok(()) } // Nothing. _ => { p.expected("expression"); - p.unsuccessful(); + Err(()) } } } /// Parse a literal. -fn literal(p: &mut Parser) -> bool { +fn literal(p: &mut Parser) -> ParseResult { match p.peek() { // Basic values. Some( @@ -346,10 +333,10 @@ fn literal(p: &mut Parser) -> bool { | NodeKind::Str(_), ) => { p.eat(); - true + Ok(()) } - _ => false, + _ => Err(()), } } @@ -358,47 +345,39 @@ fn literal(p: &mut Parser) -> bool { /// - Dictionary literal /// - Parenthesized expression /// - Parameter list of closure expression -fn parenthesized(p: &mut Parser) { - let offset = p.child_count(); - p.start(); +fn parenthesized(p: &mut Parser) -> ParseResult { + let marker = p.marker(); p.start_group(Group::Paren, TokenMode::Code); let colon = p.eat_if(&NodeKind::Colon); let kind = collection(p).0; p.end_group(); - let token_count = p.child_count() - offset; // Leading colon makes this a (empty) dictionary. if colon { - p.lift(); - dict(p, token_count); - return; + return dict(p, &marker); } // Arrow means this is a closure's parameter list. if p.peek() == Some(&NodeKind::Arrow) { - p.start_with(token_count); - params(p, 0, true); - p.end(NodeKind::ClosureParams); + params(p, &marker, true); + marker.end(p, NodeKind::ClosureParams); p.eat_assert(&NodeKind::Arrow); - expr(p); + let r = expr(p); - p.end_or_abort(NodeKind::Closure); - return; + marker.end(p, NodeKind::Closure); + return r; } // Find out which kind of collection this is. match kind { - CollectionKind::Group => p.end(NodeKind::Group), - CollectionKind::Positional => { - p.lift(); - array(p, token_count); - } - CollectionKind::Named => { - p.lift(); - dict(p, token_count); + CollectionKind::Group => { + marker.end(p, NodeKind::Group); + Ok(()) } + CollectionKind::Positional => array(p, &marker), + CollectionKind::Named => dict(p, &marker), } } @@ -422,23 +401,22 @@ fn collection(p: &mut Parser) -> (CollectionKind, usize) { let mut items = 0; let mut kind = CollectionKind::Positional; let mut has_comma = false; - let mut missing_coma = None; + let mut missing_coma: Option = None; while !p.eof() { - let item_kind = item(p); - if p.success() { + if let Ok(item_kind) = item(p) { if items == 0 && item_kind == NodeKind::Named { kind = CollectionKind::Named; } - if item_kind == NodeKind::ParameterSink { + if item_kind == NodeKind::Spread { has_comma = true; } items += 1; - if let Some(pos) = missing_coma.take() { - p.expected_at_child(pos, "comma"); + if let Some(marker) = missing_coma.take() { + marker.expected_at(p, "comma"); } if p.eof() { @@ -448,7 +426,7 @@ fn collection(p: &mut Parser) -> (CollectionKind, usize) { if p.eat_if(&NodeKind::Comma) { has_comma = true; } else { - missing_coma = Some(p.child_count()); + missing_coma = Some(p.marker()); } } } @@ -461,52 +439,49 @@ fn collection(p: &mut Parser) -> (CollectionKind, usize) { } /// Parse an expression or a named pair. Returns if this is a named pair. -fn item(p: &mut Parser) -> NodeKind { - p.start(); +fn item(p: &mut Parser) -> Result { + let marker = p.marker(); if p.eat_if(&NodeKind::Dots) { - expr(p); + let r = expr(p); - // NOTE: Should be called `Spread`. - p.end_or_abort(NodeKind::ParameterSink); - return NodeKind::ParameterSink; + marker.end(p, NodeKind::Spread); + return r.map(|_| NodeKind::Spread); } - expr(p); - - if p.may_lift_abort() { - return NodeKind::None; + let ident_marker = p.marker(); + if expr(p).is_err() { + return Err(()); } - if p.eat_if(&NodeKind::Colon) { - let child = p.child(1).unwrap(); - if matches!(child.kind(), &NodeKind::Ident(_)) { - expr(p); - p.end_or_abort(NodeKind::Named); + if p.peek() == Some(&NodeKind::Colon) { + let r = if matches!(p.child(0).unwrap().kind(), &NodeKind::Ident(_)) { + p.eat(); + expr(p) } else { - p.wrap( - 1, + ident_marker.end( + p, NodeKind::Error(ErrorPosition::Full, "expected identifier".into()), ); + p.eat(); expr(p); - p.end(NodeKind::Named); - p.unsuccessful(); - } + Err(()) + }; - NodeKind::Named + marker.end(p, NodeKind::Named); + r.map(|_| NodeKind::Named) } else { - p.lift(); - p.last_child().unwrap().kind().clone() + Ok(p.last_child().unwrap().kind().clone()) } } /// Convert a collection into an array, producing errors for anything other than /// expressions. -fn array(p: &mut Parser, items: usize) { - p.filter_children( - p.child_count() - items, +fn array(p: &mut Parser, marker: &Marker) -> ParseResult { + marker.filter_children( + p, |x| match x.kind() { - NodeKind::Named | NodeKind::ParameterSink => false, + NodeKind::Named | NodeKind::Spread => false, _ => true, }, |kind| match kind { @@ -514,21 +489,22 @@ fn array(p: &mut Parser, items: usize) { ErrorPosition::Full, "expected expression, found named pair".into(), ), - NodeKind::ParameterSink => { + NodeKind::Spread => { (ErrorPosition::Full, "spreading is not allowed here".into()) } _ => unreachable!(), }, ); - p.convert_with(items, NodeKind::Array); + marker.end(p, NodeKind::Array); + Ok(()) } /// Convert a collection into a dictionary, producing errors for anything other /// than named pairs. -fn dict(p: &mut Parser, items: usize) { - p.filter_children( - p.child_count() - items, +fn dict(p: &mut Parser, marker: &Marker) -> ParseResult { + marker.filter_children( + p, |x| { x.kind() == &NodeKind::Named || x.kind().is_paren() @@ -536,7 +512,7 @@ fn dict(p: &mut Parser, items: usize) { || x.kind() == &NodeKind::Colon }, |kind| match kind { - NodeKind::ParameterSink => { + NodeKind::Spread => { (ErrorPosition::Full, "spreading is not allowed here".into()) } _ => ( @@ -545,17 +521,19 @@ fn dict(p: &mut Parser, items: usize) { ), }, ); - p.convert_with(items, NodeKind::Dict); + + marker.end(p, NodeKind::Dict); + Ok(()) } /// Convert a collection into a list of parameters, producing errors for /// anything other than identifiers, spread operations and named pairs. -fn params(p: &mut Parser, count: usize, allow_parens: bool) { - p.filter_children( - count, +fn params(p: &mut Parser, marker: &Marker, allow_parens: bool) { + marker.filter_children( + p, |x| match x.kind() { NodeKind::Named | NodeKind::Comma | NodeKind::Ident(_) => true, - NodeKind::ParameterSink => matches!( + NodeKind::Spread => matches!( x.children().last().map(|x| x.kind()), Some(&NodeKind::Ident(_)) ), @@ -567,22 +545,22 @@ fn params(p: &mut Parser, count: usize, allow_parens: bool) { } // Parse a template block: `[...]`. -fn template(p: &mut Parser) { +fn template(p: &mut Parser) -> ParseResult { p.start(); p.start_group(Group::Bracket, TokenMode::Markup); markup(p); p.end_group(); p.end(NodeKind::Template); + Ok(()) } /// Parse a code block: `{...}`. -fn block(p: &mut Parser) { +fn block(p: &mut Parser) -> ParseResult { p.start(); p.start_group(Group::Brace, TokenMode::Code); while !p.eof() { p.start_group(Group::Stmt, TokenMode::Code); - expr(p); - if p.success() { + if expr(p).is_ok() { if !p.eof() { p.expected_at("semicolon or line break"); } @@ -594,25 +572,25 @@ fn block(p: &mut Parser) { } p.end_group(); p.end(NodeKind::Block); + Ok(()) } /// Parse a function call. -fn call(p: &mut Parser, callee: usize) { - p.start_with(callee); - match p.peek_direct() { +fn call(p: &mut Parser, callee: &Marker) -> ParseResult { + let res = match p.peek_direct() { Some(NodeKind::LeftParen) | Some(NodeKind::LeftBracket) => args(p, true), _ => { p.expected_at("argument list"); - p.may_end_abort(NodeKind::Call); - return; + Err(()) } }; - p.end(NodeKind::Call); + callee.end(p, NodeKind::Call); + res } /// Parse the arguments to a function call. -fn args(p: &mut Parser, allow_template: bool) { +fn args(p: &mut Parser, allow_template: bool) -> ParseResult { p.start(); if !allow_template || p.peek_direct() == Some(&NodeKind::LeftParen) { p.start_group(Group::Paren, TokenMode::Code); @@ -625,167 +603,126 @@ fn args(p: &mut Parser, allow_template: bool) { } p.end(NodeKind::CallArgs); + Ok(()) } /// Parse a with expression. -fn with_expr(p: &mut Parser, preserve: usize) { - p.start_with(preserve); +fn with_expr(p: &mut Parser, marker: &Marker) -> ParseResult { p.eat_assert(&NodeKind::With); - if p.peek() == Some(&NodeKind::LeftParen) { - args(p, false); - p.end(NodeKind::WithExpr); + let res = if p.peek() == Some(&NodeKind::LeftParen) { + args(p, false) } else { p.expected("argument list"); - p.may_end_abort(NodeKind::WithExpr); - } + Err(()) + }; + + marker.end(p, NodeKind::WithExpr); + res } /// Parse a let expression. -fn let_expr(p: &mut Parser) { - p.start(); - p.eat_assert(&NodeKind::Let); +fn let_expr(p: &mut Parser) -> ParseResult { + p.perform(NodeKind::LetExpr, |p| { + p.eat_assert(&NodeKind::Let); - let offset = p.child_count(); - ident(p); - if p.may_end_abort(NodeKind::LetExpr) { - return; - } + let marker = p.marker(); + ident(p)?; - if p.peek() == Some(&NodeKind::With) { - with_expr(p, p.child_count() - offset); - } else { - // If a parenthesis follows, this is a function definition. - let has_params = if p.peek_direct() == Some(&NodeKind::LeftParen) { - p.start(); - p.start_group(Group::Paren, TokenMode::Code); - let offset = p.child_count(); - collection(p); - params(p, offset, true); - p.end_group(); - p.end(NodeKind::ClosureParams); - true + if p.peek() == Some(&NodeKind::With) { + with_expr(p, &marker); } else { - false - }; + // If a parenthesis follows, this is a function definition. + let has_params = if p.peek_direct() == Some(&NodeKind::LeftParen) { + p.start(); + p.start_group(Group::Paren, TokenMode::Code); + let marker = p.marker(); + collection(p); + params(p, &marker, true); + p.end_group(); + p.end(NodeKind::ClosureParams); + true + } else { + false + }; - if p.eat_if(&NodeKind::Eq) { - expr(p); - } else if has_params { - // Function definitions must have a body. - p.expected_at("body"); - } - - // Rewrite into a closure expression if it's a function definition. - if has_params { - if p.may_end_abort(NodeKind::LetExpr) { - return; + if p.eat_if(&NodeKind::Eq) { + expr(p)?; + } else if has_params { + // Function definitions must have a body. + p.expected_at("body"); } - p.convert_with(p.child_count() - offset, NodeKind::Closure); + // Rewrite into a closure expression if it's a function definition. + if has_params { + marker.end(p, NodeKind::Closure); + } } - } - p.end(NodeKind::LetExpr); + Ok(()) + }) } /// Parse an if expresion. -fn if_expr(p: &mut Parser) { - p.start(); - p.eat_assert(&NodeKind::If); +fn if_expr(p: &mut Parser) -> ParseResult { + p.perform(NodeKind::IfExpr, |p| { + p.eat_assert(&NodeKind::If); - expr(p); - if p.may_end_abort(NodeKind::IfExpr) { - return; - } + expr(p)?; + body(p)?; - body(p); - if p.may_end_abort(NodeKind::IfExpr) { - // Expected function body. - return; - } - - if p.eat_if(&NodeKind::Else) { - if p.peek() == Some(&NodeKind::If) { - if_expr(p); - } else { - body(p); + if p.eat_if(&NodeKind::Else) { + if p.peek() == Some(&NodeKind::If) { + if_expr(p)?; + } else { + body(p)?; + } } - } - p.end(NodeKind::IfExpr); + Ok(()) + }) } /// Parse a while expresion. -fn while_expr(p: &mut Parser) { - p.start(); - p.eat_assert(&NodeKind::While); - - expr(p); - - if p.may_end_abort(NodeKind::WhileExpr) { - return; - } - - body(p); - if !p.may_end_abort(NodeKind::WhileExpr) { - p.end(NodeKind::WhileExpr); - } +fn while_expr(p: &mut Parser) -> ParseResult { + p.perform(NodeKind::WhileExpr, |p| { + p.eat_assert(&NodeKind::While); + expr(p)?; + body(p)?; + Ok(()) + }) } /// Parse a for expression. -fn for_expr(p: &mut Parser) { - p.start(); - p.eat_assert(&NodeKind::For); +fn for_expr(p: &mut Parser) -> ParseResult { + p.perform(NodeKind::ForExpr, |p| { + p.eat_assert(&NodeKind::For); - for_pattern(p); - - if p.may_end_abort(NodeKind::ForExpr) { - return; - } - - if p.eat_expect(&NodeKind::In) { - expr(p); - - if p.may_end_abort(NodeKind::ForExpr) { - return; + for_pattern(p)?; + if p.eat_expect(&NodeKind::In) { + expr(p)?; + body(p)?; + Ok(()) + } else { + Err(()) } - - body(p); - - if !p.may_end_abort(NodeKind::ForExpr) { - p.end(NodeKind::ForExpr); - } - } else { - p.unsuccessful(); - p.may_end_abort(NodeKind::ForExpr); - } + }) } /// Parse a for loop pattern. -fn for_pattern(p: &mut Parser) { - p.start(); - ident(p); - - if p.may_end_abort(NodeKind::ForPattern) { - return; - } - - if p.peek() == Some(&NodeKind::Comma) { - p.eat(); - - ident(p); - - if p.may_end_abort(NodeKind::ForPattern) { - return; +fn for_pattern(p: &mut Parser) -> ParseResult { + p.perform(NodeKind::ForPattern, |p| { + ident(p)?; + if p.peek() == Some(&NodeKind::Comma) { + p.eat(); + ident(p)?; } - } - - p.end(NodeKind::ForPattern); + Ok(()) + }) } /// Parse an import expression. -fn import_expr(p: &mut Parser) { +fn import_expr(p: &mut Parser) -> ParseResult { p.start(); p.eat_assert(&NodeKind::Import); @@ -793,15 +730,15 @@ fn import_expr(p: &mut Parser) { // This is the list of identifiers scenario. p.start(); p.start_group(Group::Imports, TokenMode::Code); - let offset = p.child_count(); + let marker = p.marker(); let items = collection(p).1; if items == 0 { p.expected_at("import items"); } p.end_group(); - p.filter_children( - offset, + marker.filter_children( + p, |n| matches!(n.kind(), NodeKind::Ident(_) | NodeKind::Comma), |_| (ErrorPosition::Full, "expected identifier".into()), ); @@ -813,36 +750,41 @@ fn import_expr(p: &mut Parser) { } p.end(NodeKind::ImportExpr); + Ok(()) } /// Parse an include expression. -fn include_expr(p: &mut Parser) { +fn include_expr(p: &mut Parser) -> ParseResult { p.start(); p.eat_assert(&NodeKind::Include); expr(p); p.end(NodeKind::IncludeExpr); + Ok(()) } /// Parse an identifier. -fn ident(p: &mut Parser) { +fn ident(p: &mut Parser) -> ParseResult { match p.peek() { - Some(NodeKind::Ident(_)) => p.eat(), + Some(NodeKind::Ident(_)) => { + p.eat(); + Ok(()) + } _ => { p.expected("identifier"); - p.unsuccessful(); + Err(()) } } } /// Parse a control flow body. -fn body(p: &mut Parser) { +fn body(p: &mut Parser) -> ParseResult { match p.peek() { Some(NodeKind::LeftBracket) => template(p), Some(NodeKind::LeftBrace) => block(p), _ => { p.expected_at("body"); - p.unsuccessful(); + Err(()) } } } diff --git a/src/parse/parser.rs b/src/parse/parser.rs index 5ecb6e9dc..bc028876c 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -1,7 +1,7 @@ use std::ops::Range; use std::rc::Rc; -use super::{TokenMode, Tokens}; +use super::{ParseResult, TokenMode, Tokens}; use crate::syntax::{ErrorPosition, Green, GreenData, GreenNode, NodeKind}; use crate::util::EcoString; @@ -26,8 +26,6 @@ pub struct Parser<'s> { stack: Vec>, /// The children of the currently built node. children: Vec, - /// Whether the last parsing step was successful. - success: bool, } /// A logical group of tokens, e.g. `[...]`. @@ -58,6 +56,49 @@ pub enum Group { Imports, } +/// A marker that indicates where a child may start. +pub struct Marker(usize); + +impl Marker { + /// Wraps all children in front of the marker. + pub fn end(&self, p: &mut Parser, kind: NodeKind) { + if p.children.len() != self.0 { + let stop_nl = p.stop_at_newline(); + let end = (self.0 .. p.children.len()) + .rev() + .find(|&i| !Parser::skip_type_ext(p.children[i].kind(), stop_nl)) + .unwrap_or(self.0) + + 1; + + let children: Vec<_> = p.children.drain(self.0 .. end).collect(); + let len = children.iter().map(Green::len).sum(); + p.children + .insert(self.0, GreenNode::with_children(kind, len, children).into()); + } + } + + /// Wrap all children that do not fulfill the predicate in error nodes. + pub fn filter_children(&self, p: &mut Parser, f: F, error: G) + where + F: Fn(&Green) -> bool, + G: Fn(&NodeKind) -> (ErrorPosition, EcoString), + { + p.filter_children(self, f, error) + } + + /// Insert an error message that `what` was expected at the marker position. + pub fn expected_at(&self, p: &mut Parser, what: &str) { + p.children.insert( + self.0, + GreenData::new( + NodeKind::Error(ErrorPosition::Full, format!("expected {}", what).into()), + 0, + ) + .into(), + ); + } +} + impl<'s> Parser<'s> { /// Create a new parser for the source string. pub fn new(src: &'s str) -> Self { @@ -73,7 +114,6 @@ impl<'s> Parser<'s> { next_start: 0, stack: vec![], children: vec![], - success: true, } } @@ -85,19 +125,13 @@ impl<'s> Parser<'s> { self.stack.push(std::mem::take(&mut self.children)); } - /// Start a nested node, preserving a number of the current children. - pub fn start_with(&mut self, preserve: usize) { - let preserved = self.children.drain(self.children.len() - preserve ..).collect(); - self.stack.push(std::mem::replace(&mut self.children, preserved)); - } - /// Filter the last children using the given predicate. - pub fn filter_children(&mut self, count: usize, f: F, error: G) + fn filter_children(&mut self, count: &Marker, f: F, error: G) where F: Fn(&Green) -> bool, G: Fn(&NodeKind) -> (ErrorPosition, EcoString), { - for child in &mut self.children[count ..] { + for child in &mut self.children[count.0 ..] { if !((self.tokens.mode() != TokenMode::Code || Self::skip_type_ext(child.kind(), false)) || child.kind().is_error() @@ -161,46 +195,22 @@ impl<'s> Parser<'s> { self.children .push(GreenNode::with_children(kind, len, children).into()); self.children.extend(remains); - self.success = true; } - /// End the current node as a node of given `kind`, and start a new node - /// with the ended node as a first child. The function returns how many - /// children the stack frame had before and how many were appended (accounts - /// for trivia). - pub fn end_and_start_with(&mut self, kind: NodeKind) -> (usize, usize) { - let stack_offset = self.stack.last().unwrap().len(); + pub fn perform(&mut self, kind: NodeKind, f: F) -> ParseResult + where + F: FnOnce(&mut Self) -> ParseResult, + { + self.start(); + let success = f(self); self.end(kind); - let diff = self.children.len() - stack_offset; - self.start_with(diff); - (stack_offset, diff) - } - - /// Wrap a specified node in the current stack frame (indexed from the back, - /// not including trivia). - pub fn wrap(&mut self, index: usize, kind: NodeKind) { - let index = self.node_index_from_back(index).unwrap(); - let child = std::mem::take(&mut self.children[index]); - let item = GreenNode::with_child(kind, child.len(), child); - self.children[index] = item.into(); + success } /// Eat and wrap the next token. pub fn convert(&mut self, kind: NodeKind) { self.eat(); self.children.last_mut().unwrap().set_kind(kind); - self.success = true; - } - - /// Wrap the last `amount` children in the current stack frame with a new - /// node. - pub fn convert_with(&mut self, amount: usize, kind: NodeKind) { - let preserved: Vec<_> = - self.children.drain(self.children.len() - amount ..).collect(); - let len = preserved.iter().map(|c| c.len()).sum(); - self.children - .push(GreenNode::with_children(kind, len, preserved).into()); - self.success = true; } /// End the current node and undo its existence, inling all accumulated @@ -209,50 +219,14 @@ impl<'s> Parser<'s> { let outer = self.stack.pop().unwrap(); let children = std::mem::replace(&mut self.children, outer); self.children.extend(children); - self.success = true; } - /// End the current node and undo its existence, deleting all accumulated - /// children. - pub fn abort(&mut self, msg: impl Into) { - self.end(NodeKind::Error(ErrorPosition::Full, msg.into().into())); - self.success = false; - } - - /// This function [`Self::lift`]s if the last operation was unsuccessful and - /// returns whether it did. - pub fn may_lift_abort(&mut self) -> bool { - if !self.success { - self.lift(); - self.success = false; - true - } else { - false - } - } - - /// This function [`Self::end`]s if the last operation was unsuccessful and - /// returns whether it did. - pub fn may_end_abort(&mut self, kind: NodeKind) -> bool { - if !self.success { - self.end(kind); - self.success = false; - true - } else { - false - } - } - - /// End the current node as a node of given `kind` if the last parse was - /// successful, otherwise, abort. - pub fn end_or_abort(&mut self, kind: NodeKind) -> bool { - if self.success { - self.end(kind); - true - } else { - self.may_end_abort(kind); - false - } + /// Add an error to the current children list. + fn push_error(&mut self, msg: impl Into) { + self.children.push( + GreenData::new(NodeKind::Error(ErrorPosition::Full, msg.into().into()), 0) + .into(), + ); } /// End the parsing process and return the last child. @@ -268,14 +242,6 @@ impl<'s> Parser<'s> { self.peek().is_none() } - /// Consume the next token and return its kind. - // NOTE: This isn't great. - 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 { if self.peek() == Some(t) { @@ -311,9 +277,9 @@ impl<'s> Parser<'s> { /// Consume the next token, debug-asserting that it is one of the given ones. pub fn eat_assert(&mut self, t: &NodeKind) { - // NOTE: assert with peek(), then eat() - let next = self.eat_peeked(); - debug_assert_eq!(next.as_ref(), Some(t)); + let next = self.peek(); + debug_assert_eq!(next, Some(t)); + self.eat(); } /// Consume tokens while the condition is true. @@ -402,9 +368,10 @@ impl<'s> Parser<'s> { /// End the parsing of a group. /// /// This panics if no group was started. - pub fn end_group(&mut self) { + pub fn end_group(&mut self) -> ParseResult { let prev_mode = self.tokens.mode(); let group = self.groups.pop().expect("no started group"); + let mut success = true; self.tokens.set_mode(group.prev_mode); self.repeek(); @@ -424,8 +391,8 @@ impl<'s> Parser<'s> { self.eat(); rescan = false; } else if required { - self.start(); - self.abort(format!("expected {}", end)); + self.push_error(format!("expected {}", end)); + success = false; } } @@ -448,6 +415,8 @@ impl<'s> Parser<'s> { self.next = self.tokens.next(); self.repeek(); } + + if success { Ok(()) } else { Err(()) } } /// Add an error that `what` was expected at the given span. @@ -460,39 +429,36 @@ impl<'s> Parser<'s> { found = i; } - self.expected_at_child(found, what); - } - - /// Add an error that `what` was expected at the given child index. - pub fn expected_at_child(&mut self, index: usize, what: &str) { - self.children.insert( - index, - GreenData::new( - NodeKind::Error(ErrorPosition::Full, format!("expected {}", what).into()), - 0, - ) - .into(), - ); + Marker(found).expected_at(self, what); } /// Eat the next token and add an error that it is not the expected `thing`. pub fn expected(&mut self, what: &str) { - self.start(); - match self.eat_peeked() { - Some(found) => self.abort(format!("expected {}, found {}", what, found)), - None => { - self.lift(); - self.expected_at(what); + match self.peek().cloned() { + Some(found) => { + self.start(); + self.eat(); + self.end(NodeKind::Error( + ErrorPosition::Full, + format!("expected {}, found {}", what, found).into(), + )); } + None => self.expected_at(what), } } /// Eat the next token and add an error that it is unexpected. pub fn unexpected(&mut self) { - self.start(); - match self.eat_peeked() { - Some(found) => self.abort(format!("unexpected {}", found)), - None => self.abort("unexpected end of file"), + match self.peek().cloned() { + Some(found) => { + self.start(); + self.eat(); + self.end(NodeKind::Error( + ErrorPosition::Full, + format!("unexpected {}", found).into(), + )); + } + None => self.push_error("unexpected end of file"), } } @@ -584,20 +550,8 @@ impl<'s> Parser<'s> { self.children.last() } - /// Whether the last operation was successful. - pub fn success(&mut self) -> bool { - let s = self.success; - self.success = true; - s - } - - /// Declare the last operation as unsuccessful. - pub fn unsuccessful(&mut self) { - self.success = false; - } - - /// Amount of children in the current stack frame. - pub fn child_count(&self) -> usize { - self.children.len() + /// Create a new marker. + pub fn marker(&mut self) -> Marker { + Marker(self.children.len()) } } diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs index 9ad04be58..b6f64c677 100644 --- a/src/syntax/ast.rs +++ b/src/syntax/ast.rs @@ -156,13 +156,7 @@ impl HeadingNode { /// The section depth (numer of equals signs). pub fn level(&self) -> u8 { - self.0 - .children() - .find_map(|node| match node.kind() { - NodeKind::HeadingLevel(heading) => Some(*heading), - _ => None, - }) - .expect("heading node is missing heading level") + self.0.children().filter(|n| n.kind() == &NodeKind::Eq).count() as u8 } } @@ -743,7 +737,7 @@ impl TypedNode for CallArg { NodeKind::Named => Some(CallArg::Named( node.cast().expect("named call argument is missing name"), )), - NodeKind::ParameterSink => Some(CallArg::Spread( + NodeKind::Spread => Some(CallArg::Spread( node.cast_first_child() .expect("call argument sink is missing expression"), )), @@ -825,7 +819,7 @@ impl TypedNode for ClosureParam { NodeKind::Named => Some(ClosureParam::Named( node.cast().expect("named closure parameter is missing name"), )), - NodeKind::ParameterSink => Some(ClosureParam::Sink( + NodeKind::Spread => Some(ClosureParam::Sink( node.cast_first_child() .expect("closure parameter sink is missing identifier"), )), diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index 112fc220f..db3b0c9ab 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -487,8 +487,6 @@ pub enum NodeKind { Emph, /// A section heading: `= Introduction`. Heading, - /// A heading's level: `=`, `==`, `===`, etc. - HeadingLevel(u8), /// An item in an enumeration (ordered list): `1. ...`. Enum, /// A numbering: `23.`. @@ -546,7 +544,7 @@ pub enum NodeKind { /// A closure's parameters: `(x, y)`. ClosureParams, /// A parameter sink: `..x`. - ParameterSink, + Spread, /// A template expression: `[*Hi* there!]`. Template, /// A block expression: `{ let x = 1; x + 2 }`. @@ -709,7 +707,6 @@ impl NodeKind { Self::Strong => "strong", Self::Emph => "emphasis", Self::Heading => "heading", - Self::HeadingLevel(_) => "heading level", Self::Enum => "enumeration item", Self::EnumNumbering(_) => "enumeration item numbering", Self::List => "list item", @@ -735,7 +732,7 @@ impl NodeKind { Self::CallArgs => "call arguments", Self::Closure => "closure", Self::ClosureParams => "closure parameters", - Self::ParameterSink => "parameter sink", + Self::Spread => "parameter sink", Self::Template => "template", Self::Block => "block", Self::ForExpr => "for-loop expression", diff --git a/tests/typ/code/let.typ b/tests/typ/code/let.typ index 3f3f9d357..cd7531b76 100644 --- a/tests/typ/code/let.typ +++ b/tests/typ/code/let.typ @@ -56,7 +56,7 @@ Three #let v4 = 4 Four // Terminated by semicolon even though we are in a paren group. -// Error: 19 expected expression +// Error: 18 expected expression // Error: 19 expected closing paren #let v5 = (1, 2 + ; Five