New error handling

This commit is contained in:
Martin Haug 2021-11-04 19:36:32 +01:00
parent f0c9635db5
commit 5c952d56d0
5 changed files with 325 additions and 438 deletions

View File

@ -16,6 +16,8 @@ use crate::syntax::ast::{Associativity, BinOp, UnOp};
use crate::syntax::{ErrorPosition, GreenNode, NodeKind}; use crate::syntax::{ErrorPosition, GreenNode, NodeKind};
use crate::util::EcoString; use crate::util::EcoString;
type ParseResult = Result<(), ()>;
/// Parse a source file. /// Parse a source file.
pub fn parse(source: &str) -> Rc<GreenNode> { pub fn parse(source: &str) -> Rc<GreenNode> {
let mut p = Parser::new(source); let mut p = Parser::new(source);
@ -53,24 +55,16 @@ where
p.start(); p.start();
while !p.eof() && f(p) { while !p.eof() && f(p) {
markup_node(p, &mut at_start); 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); p.end(NodeKind::Markup);
} }
/// Parse a markup node. /// 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() { let token = match p.peek() {
Some(t) => t, Some(t) => t,
None => return, None => return Ok(()),
}; };
match token { match token {
@ -83,6 +77,7 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) {
} else { } else {
p.convert(NodeKind::Parbreak); p.convert(NodeKind::Parbreak);
} }
return Ok(());
} }
// Text and markup. // Text and markup.
@ -94,7 +89,10 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) {
| NodeKind::Strong | NodeKind::Strong
| NodeKind::Linebreak | NodeKind::Linebreak
| NodeKind::Raw(_) | NodeKind::Raw(_)
| NodeKind::UnicodeEscape(_) => p.eat(), | NodeKind::UnicodeEscape(_) => {
p.eat();
Ok(())
}
NodeKind::Eq if *at_start => heading(p), NodeKind::Eq if *at_start => heading(p),
NodeKind::ListBullet if *at_start => list_node(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. // Line-based markup that is not currently at the start of the line.
NodeKind::Eq | NodeKind::ListBullet | NodeKind::EnumNumbering(_) => { 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. // 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 }; let group = if stmt { Group::Stmt } else { Group::Expr };
p.start_group(group, TokenMode::Code); p.start_group(group, TokenMode::Code);
// NOTE: Return success from expr_with? let res = expr_with(p, true, 0);
expr_with(p, true, 0); if stmt && res.is_ok() && !p.eof() {
if stmt && p.success() && !p.eof() {
p.expected_at("semicolon or line break"); p.expected_at("semicolon or line break");
} }
p.end_group(); p.end_group()
} }
// Block and template. // Block and template.
@ -130,19 +128,28 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) {
NodeKind::LeftBracket => template(p), NodeKind::LeftBracket => template(p),
// Comments. // 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(); p.unexpected();
Err(())
} }
}; }?;
*at_start = false;
Ok(())
} }
/// Parse a heading. /// Parse a heading.
fn heading(p: &mut Parser) { fn heading(p: &mut Parser) -> ParseResult {
// NOTE: Remove HeadingLevel kind and simply count Eq children in AST.
p.start();
p.start(); p.start();
p.eat_assert(&NodeKind::Eq); p.eat_assert(&NodeKind::Eq);
@ -153,36 +160,37 @@ fn heading(p: &mut Parser) {
} }
if level > 6 { if level > 6 {
p.lift();
p.end(NodeKind::Text(EcoString::from('=').repeat(level))); p.end(NodeKind::Text(EcoString::from('=').repeat(level)));
} else { } else {
p.end(NodeKind::HeadingLevel(level as u8));
let column = p.column(p.prev_end()); let column = p.column(p.prev_end());
markup_indented(p, column); markup_indented(p, column);
p.end(NodeKind::Heading); p.end(NodeKind::Heading);
} }
Ok(())
} }
/// Parse a single list item. /// Parse a single list item.
fn list_node(p: &mut Parser) { fn list_node(p: &mut Parser) -> ParseResult {
p.start(); p.start();
p.eat_assert(&NodeKind::ListBullet); p.eat_assert(&NodeKind::ListBullet);
let column = p.column(p.prev_end()); let column = p.column(p.prev_end());
markup_indented(p, column); markup_indented(p, column);
p.end(NodeKind::List); p.end(NodeKind::List);
Ok(())
} }
/// Parse a single enum item. /// Parse a single enum item.
fn enum_node(p: &mut Parser) { fn enum_node(p: &mut Parser) -> ParseResult {
p.start(); p.start();
p.eat(); p.eat();
let column = p.column(p.prev_end()); let column = p.column(p.prev_end());
markup_indented(p, column); markup_indented(p, column);
p.end(NodeKind::Enum); p.end(NodeKind::Enum);
Ok(())
} }
/// Parse an expression. /// Parse an expression.
fn expr(p: &mut Parser) { fn expr(p: &mut Parser) -> ParseResult {
expr_with(p, false, 0) expr_with(p, false, 0)
} }
@ -193,28 +201,19 @@ fn expr(p: &mut Parser) {
/// in markup. /// in markup.
/// ///
/// Stops parsing at operations with lower precedence than `min_prec`, /// Stops parsing at operations with lower precedence than `min_prec`,
fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) { fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult {
p.start(); let marker = p.marker();
let mut offset = p.child_count();
// Start the unary expression. // Start the unary expression.
match p.eat_map(|x| UnOp::from_token(&x)) { match p.eat_map(|x| UnOp::from_token(&x)) {
Some(op) => { Some(op) => {
let prec = op.precedence(); 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. marker.end(p, NodeKind::Unary);
// Then we could simply do expr_with(p, atomic, prec)?;
if p.may_lift_abort() {
return;
}
p.end_and_start_with(NodeKind::Unary);
} }
None => { None => {
primary(p, atomic); primary(p, atomic)?;
if p.may_lift_abort() {
return;
}
} }
}; };
@ -225,35 +224,28 @@ fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) {
p.peek_direct(), p.peek_direct(),
Some(NodeKind::LeftParen | NodeKind::LeftBracket) Some(NodeKind::LeftParen | NodeKind::LeftBracket)
) { ) {
call(p, p.child_count() - offset); call(p, &marker);
continue; continue;
} }
if p.peek() == Some(&NodeKind::With) {
with_expr(p, p.child_count() - offset);
if p.may_lift_abort() {
return;
}
}
if atomic { if atomic {
p.lift(); break Ok(());
break; }
if p.peek() == Some(&NodeKind::With) {
with_expr(p, &marker)?;
} }
let op = match p.peek().and_then(BinOp::from_token) { let op = match p.peek().and_then(BinOp::from_token) {
Some(binop) => binop, Some(binop) => binop,
None => { None => {
p.lift(); break Ok(());
break;
} }
}; };
let mut prec = op.precedence(); let mut prec = op.precedence();
if prec < min_prec { if prec < min_prec {
p.lift(); break Ok(());
break;
} }
p.eat(); p.eat();
@ -263,44 +255,38 @@ fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) {
Associativity::Right => {} Associativity::Right => {}
} }
expr_with(p, atomic, prec); if expr_with(p, atomic, prec).is_err() {
break Ok(());
if !p.success() {
p.lift();
break;
} }
// NOTE: All lifts up to here wouldn't be needed. marker.end(p, NodeKind::Binary);
// Only here we then need to do
// marker.end(p, NodeKind::Binary);
offset = p.end_and_start_with(NodeKind::Binary).0;
} }
} }
/// Parse a primary expression. /// Parse a primary expression.
fn primary(p: &mut Parser, atomic: bool) { fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
if literal(p) { let lit = literal(p);
return; if lit.is_ok() {
return lit;
} }
match p.peek() { match p.peek() {
// Things that start with an identifier. // Things that start with an identifier.
Some(NodeKind::Ident(_)) => { Some(NodeKind::Ident(_)) => {
// Start closure params. // Start closure params.
p.start(); let marker = p.marker();
p.eat(); p.eat();
// Arrow means this is a closure's lone parameter. // 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); marker.end(p, NodeKind::ClosureParams);
p.eat(); p.eat();
expr(p); let e = expr(p);
marker.end(p, NodeKind::Closure);
p.end_or_abort(NodeKind::Closure); e
} else { } else {
p.lift(); Ok(())
} }
} }
@ -319,18 +305,19 @@ fn primary(p: &mut Parser, atomic: bool) {
Some(NodeKind::Error(_, _)) => { Some(NodeKind::Error(_, _)) => {
p.eat(); p.eat();
Ok(())
} }
// Nothing. // Nothing.
_ => { _ => {
p.expected("expression"); p.expected("expression");
p.unsuccessful(); Err(())
} }
} }
} }
/// Parse a literal. /// Parse a literal.
fn literal(p: &mut Parser) -> bool { fn literal(p: &mut Parser) -> ParseResult {
match p.peek() { match p.peek() {
// Basic values. // Basic values.
Some( Some(
@ -346,10 +333,10 @@ fn literal(p: &mut Parser) -> bool {
| NodeKind::Str(_), | NodeKind::Str(_),
) => { ) => {
p.eat(); p.eat();
true Ok(())
} }
_ => false, _ => Err(()),
} }
} }
@ -358,47 +345,39 @@ fn literal(p: &mut Parser) -> bool {
/// - Dictionary literal /// - Dictionary literal
/// - Parenthesized expression /// - Parenthesized expression
/// - Parameter list of closure expression /// - Parameter list of closure expression
fn parenthesized(p: &mut Parser) { fn parenthesized(p: &mut Parser) -> ParseResult {
let offset = p.child_count(); let marker = p.marker();
p.start();
p.start_group(Group::Paren, TokenMode::Code); 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; let kind = collection(p).0;
p.end_group(); p.end_group();
let token_count = p.child_count() - offset;
// Leading colon makes this a (empty) dictionary. // Leading colon makes this a (empty) dictionary.
if colon { if colon {
p.lift(); return dict(p, &marker);
dict(p, token_count);
return;
} }
// Arrow means this is a closure's parameter list. // 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, &marker, true);
params(p, 0, true); marker.end(p, NodeKind::ClosureParams);
p.end(NodeKind::ClosureParams);
p.eat_assert(&NodeKind::Arrow); p.eat_assert(&NodeKind::Arrow);
expr(p); let r = expr(p);
p.end_or_abort(NodeKind::Closure); marker.end(p, NodeKind::Closure);
return; return r;
} }
// Find out which kind of collection this is. // Find out which kind of collection this is.
match kind { match kind {
CollectionKind::Group => p.end(NodeKind::Group), CollectionKind::Group => {
CollectionKind::Positional => { marker.end(p, NodeKind::Group);
p.lift(); Ok(())
array(p, token_count);
}
CollectionKind::Named => {
p.lift();
dict(p, token_count);
} }
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 items = 0;
let mut kind = CollectionKind::Positional; let mut kind = CollectionKind::Positional;
let mut has_comma = false; let mut has_comma = false;
let mut missing_coma = None; let mut missing_coma: Option<Marker> = None;
while !p.eof() { while !p.eof() {
let item_kind = item(p); if let Ok(item_kind) = item(p) {
if p.success() {
if items == 0 && item_kind == NodeKind::Named { if items == 0 && item_kind == NodeKind::Named {
kind = CollectionKind::Named; kind = CollectionKind::Named;
} }
if item_kind == NodeKind::ParameterSink { if item_kind == NodeKind::Spread {
has_comma = true; has_comma = true;
} }
items += 1; items += 1;
if let Some(pos) = missing_coma.take() { if let Some(marker) = missing_coma.take() {
p.expected_at_child(pos, "comma"); marker.expected_at(p, "comma");
} }
if p.eof() { if p.eof() {
@ -448,7 +426,7 @@ fn collection(p: &mut Parser) -> (CollectionKind, usize) {
if p.eat_if(&NodeKind::Comma) { if p.eat_if(&NodeKind::Comma) {
has_comma = true; has_comma = true;
} else { } 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. /// Parse an expression or a named pair. Returns if this is a named pair.
fn item(p: &mut Parser) -> NodeKind { fn item(p: &mut Parser) -> Result<NodeKind, ()> {
p.start(); let marker = p.marker();
if p.eat_if(&NodeKind::Dots) { if p.eat_if(&NodeKind::Dots) {
expr(p); let r = expr(p);
// NOTE: Should be called `Spread`. marker.end(p, NodeKind::Spread);
p.end_or_abort(NodeKind::ParameterSink); return r.map(|_| NodeKind::Spread);
return NodeKind::ParameterSink;
} }
expr(p); let ident_marker = p.marker();
if expr(p).is_err() {
if p.may_lift_abort() { return Err(());
return NodeKind::None;
} }
if p.eat_if(&NodeKind::Colon) { if p.peek() == Some(&NodeKind::Colon) {
let child = p.child(1).unwrap(); let r = if matches!(p.child(0).unwrap().kind(), &NodeKind::Ident(_)) {
if matches!(child.kind(), &NodeKind::Ident(_)) { p.eat();
expr(p); expr(p)
p.end_or_abort(NodeKind::Named);
} else { } else {
p.wrap( ident_marker.end(
1, p,
NodeKind::Error(ErrorPosition::Full, "expected identifier".into()), NodeKind::Error(ErrorPosition::Full, "expected identifier".into()),
); );
p.eat();
expr(p); expr(p);
p.end(NodeKind::Named); Err(())
p.unsuccessful(); };
}
NodeKind::Named marker.end(p, NodeKind::Named);
r.map(|_| NodeKind::Named)
} else { } else {
p.lift(); Ok(p.last_child().unwrap().kind().clone())
p.last_child().unwrap().kind().clone()
} }
} }
/// Convert a collection into an array, producing errors for anything other than /// Convert a collection into an array, producing errors for anything other than
/// expressions. /// expressions.
fn array(p: &mut Parser, items: usize) { fn array(p: &mut Parser, marker: &Marker) -> ParseResult {
p.filter_children( marker.filter_children(
p.child_count() - items, p,
|x| match x.kind() { |x| match x.kind() {
NodeKind::Named | NodeKind::ParameterSink => false, NodeKind::Named | NodeKind::Spread => false,
_ => true, _ => true,
}, },
|kind| match kind { |kind| match kind {
@ -514,21 +489,22 @@ fn array(p: &mut Parser, items: usize) {
ErrorPosition::Full, ErrorPosition::Full,
"expected expression, found named pair".into(), "expected expression, found named pair".into(),
), ),
NodeKind::ParameterSink => { NodeKind::Spread => {
(ErrorPosition::Full, "spreading is not allowed here".into()) (ErrorPosition::Full, "spreading is not allowed here".into())
} }
_ => unreachable!(), _ => unreachable!(),
}, },
); );
p.convert_with(items, NodeKind::Array); marker.end(p, NodeKind::Array);
Ok(())
} }
/// Convert a collection into a dictionary, producing errors for anything other /// Convert a collection into a dictionary, producing errors for anything other
/// than named pairs. /// than named pairs.
fn dict(p: &mut Parser, items: usize) { fn dict(p: &mut Parser, marker: &Marker) -> ParseResult {
p.filter_children( marker.filter_children(
p.child_count() - items, p,
|x| { |x| {
x.kind() == &NodeKind::Named x.kind() == &NodeKind::Named
|| x.kind().is_paren() || x.kind().is_paren()
@ -536,7 +512,7 @@ fn dict(p: &mut Parser, items: usize) {
|| x.kind() == &NodeKind::Colon || x.kind() == &NodeKind::Colon
}, },
|kind| match kind { |kind| match kind {
NodeKind::ParameterSink => { NodeKind::Spread => {
(ErrorPosition::Full, "spreading is not allowed here".into()) (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 /// Convert a collection into a list of parameters, producing errors for
/// anything other than identifiers, spread operations and named pairs. /// anything other than identifiers, spread operations and named pairs.
fn params(p: &mut Parser, count: usize, allow_parens: bool) { fn params(p: &mut Parser, marker: &Marker, allow_parens: bool) {
p.filter_children( marker.filter_children(
count, p,
|x| match x.kind() { |x| match x.kind() {
NodeKind::Named | NodeKind::Comma | NodeKind::Ident(_) => true, NodeKind::Named | NodeKind::Comma | NodeKind::Ident(_) => true,
NodeKind::ParameterSink => matches!( NodeKind::Spread => matches!(
x.children().last().map(|x| x.kind()), x.children().last().map(|x| x.kind()),
Some(&NodeKind::Ident(_)) Some(&NodeKind::Ident(_))
), ),
@ -567,22 +545,22 @@ fn params(p: &mut Parser, count: usize, allow_parens: bool) {
} }
// Parse a template block: `[...]`. // Parse a template block: `[...]`.
fn template(p: &mut Parser) { fn template(p: &mut Parser) -> ParseResult {
p.start(); p.start();
p.start_group(Group::Bracket, TokenMode::Markup); p.start_group(Group::Bracket, TokenMode::Markup);
markup(p); markup(p);
p.end_group(); p.end_group();
p.end(NodeKind::Template); p.end(NodeKind::Template);
Ok(())
} }
/// Parse a code block: `{...}`. /// Parse a code block: `{...}`.
fn block(p: &mut Parser) { fn block(p: &mut Parser) -> ParseResult {
p.start(); p.start();
p.start_group(Group::Brace, TokenMode::Code); p.start_group(Group::Brace, TokenMode::Code);
while !p.eof() { while !p.eof() {
p.start_group(Group::Stmt, TokenMode::Code); p.start_group(Group::Stmt, TokenMode::Code);
expr(p); if expr(p).is_ok() {
if p.success() {
if !p.eof() { if !p.eof() {
p.expected_at("semicolon or line break"); p.expected_at("semicolon or line break");
} }
@ -594,25 +572,25 @@ fn block(p: &mut Parser) {
} }
p.end_group(); p.end_group();
p.end(NodeKind::Block); p.end(NodeKind::Block);
Ok(())
} }
/// Parse a function call. /// Parse a function call.
fn call(p: &mut Parser, callee: usize) { fn call(p: &mut Parser, callee: &Marker) -> ParseResult {
p.start_with(callee); let res = match p.peek_direct() {
match p.peek_direct() {
Some(NodeKind::LeftParen) | Some(NodeKind::LeftBracket) => args(p, true), Some(NodeKind::LeftParen) | Some(NodeKind::LeftBracket) => args(p, true),
_ => { _ => {
p.expected_at("argument list"); p.expected_at("argument list");
p.may_end_abort(NodeKind::Call); Err(())
return;
} }
}; };
p.end(NodeKind::Call); callee.end(p, NodeKind::Call);
res
} }
/// Parse the arguments to a function call. /// 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(); p.start();
if !allow_template || p.peek_direct() == Some(&NodeKind::LeftParen) { if !allow_template || p.peek_direct() == Some(&NodeKind::LeftParen) {
p.start_group(Group::Paren, TokenMode::Code); p.start_group(Group::Paren, TokenMode::Code);
@ -625,43 +603,42 @@ fn args(p: &mut Parser, allow_template: bool) {
} }
p.end(NodeKind::CallArgs); p.end(NodeKind::CallArgs);
Ok(())
} }
/// Parse a with expression. /// Parse a with expression.
fn with_expr(p: &mut Parser, preserve: usize) { fn with_expr(p: &mut Parser, marker: &Marker) -> ParseResult {
p.start_with(preserve);
p.eat_assert(&NodeKind::With); p.eat_assert(&NodeKind::With);
if p.peek() == Some(&NodeKind::LeftParen) { let res = if p.peek() == Some(&NodeKind::LeftParen) {
args(p, false); args(p, false)
p.end(NodeKind::WithExpr);
} else { } else {
p.expected("argument list"); p.expected("argument list");
p.may_end_abort(NodeKind::WithExpr); Err(())
} };
marker.end(p, NodeKind::WithExpr);
res
} }
/// Parse a let expression. /// Parse a let expression.
fn let_expr(p: &mut Parser) { fn let_expr(p: &mut Parser) -> ParseResult {
p.start(); p.perform(NodeKind::LetExpr, |p| {
p.eat_assert(&NodeKind::Let); p.eat_assert(&NodeKind::Let);
let offset = p.child_count(); let marker = p.marker();
ident(p); ident(p)?;
if p.may_end_abort(NodeKind::LetExpr) {
return;
}
if p.peek() == Some(&NodeKind::With) { if p.peek() == Some(&NodeKind::With) {
with_expr(p, p.child_count() - offset); with_expr(p, &marker);
} else { } else {
// If a parenthesis follows, this is a function definition. // If a parenthesis follows, this is a function definition.
let has_params = if p.peek_direct() == Some(&NodeKind::LeftParen) { let has_params = if p.peek_direct() == Some(&NodeKind::LeftParen) {
p.start(); p.start();
p.start_group(Group::Paren, TokenMode::Code); p.start_group(Group::Paren, TokenMode::Code);
let offset = p.child_count(); let marker = p.marker();
collection(p); collection(p);
params(p, offset, true); params(p, &marker, true);
p.end_group(); p.end_group();
p.end(NodeKind::ClosureParams); p.end(NodeKind::ClosureParams);
true true
@ -670,7 +647,7 @@ fn let_expr(p: &mut Parser) {
}; };
if p.eat_if(&NodeKind::Eq) { if p.eat_if(&NodeKind::Eq) {
expr(p); expr(p)?;
} else if has_params { } else if has_params {
// Function definitions must have a body. // Function definitions must have a body.
p.expected_at("body"); p.expected_at("body");
@ -678,114 +655,74 @@ fn let_expr(p: &mut Parser) {
// Rewrite into a closure expression if it's a function definition. // Rewrite into a closure expression if it's a function definition.
if has_params { if has_params {
if p.may_end_abort(NodeKind::LetExpr) { marker.end(p, NodeKind::Closure);
return;
}
p.convert_with(p.child_count() - offset, NodeKind::Closure);
} }
} }
p.end(NodeKind::LetExpr); Ok(())
})
} }
/// Parse an if expresion. /// Parse an if expresion.
fn if_expr(p: &mut Parser) { fn if_expr(p: &mut Parser) -> ParseResult {
p.start(); p.perform(NodeKind::IfExpr, |p| {
p.eat_assert(&NodeKind::If); p.eat_assert(&NodeKind::If);
expr(p); expr(p)?;
if p.may_end_abort(NodeKind::IfExpr) { body(p)?;
return;
}
body(p);
if p.may_end_abort(NodeKind::IfExpr) {
// Expected function body.
return;
}
if p.eat_if(&NodeKind::Else) { if p.eat_if(&NodeKind::Else) {
if p.peek() == Some(&NodeKind::If) { if p.peek() == Some(&NodeKind::If) {
if_expr(p); if_expr(p)?;
} else { } else {
body(p); body(p)?;
} }
} }
p.end(NodeKind::IfExpr); Ok(())
})
} }
/// Parse a while expresion. /// Parse a while expresion.
fn while_expr(p: &mut Parser) { fn while_expr(p: &mut Parser) -> ParseResult {
p.start(); p.perform(NodeKind::WhileExpr, |p| {
p.eat_assert(&NodeKind::While); p.eat_assert(&NodeKind::While);
expr(p)?;
expr(p); body(p)?;
Ok(())
if p.may_end_abort(NodeKind::WhileExpr) { })
return;
}
body(p);
if !p.may_end_abort(NodeKind::WhileExpr) {
p.end(NodeKind::WhileExpr);
}
} }
/// Parse a for expression. /// Parse a for expression.
fn for_expr(p: &mut Parser) { fn for_expr(p: &mut Parser) -> ParseResult {
p.start(); p.perform(NodeKind::ForExpr, |p| {
p.eat_assert(&NodeKind::For); p.eat_assert(&NodeKind::For);
for_pattern(p); for_pattern(p)?;
if p.may_end_abort(NodeKind::ForExpr) {
return;
}
if p.eat_expect(&NodeKind::In) { if p.eat_expect(&NodeKind::In) {
expr(p); expr(p)?;
body(p)?;
if p.may_end_abort(NodeKind::ForExpr) { Ok(())
return;
}
body(p);
if !p.may_end_abort(NodeKind::ForExpr) {
p.end(NodeKind::ForExpr);
}
} else { } else {
p.unsuccessful(); Err(())
p.may_end_abort(NodeKind::ForExpr);
} }
})
} }
/// Parse a for loop pattern. /// Parse a for loop pattern.
fn for_pattern(p: &mut Parser) { fn for_pattern(p: &mut Parser) -> ParseResult {
p.start(); p.perform(NodeKind::ForPattern, |p| {
ident(p); ident(p)?;
if p.may_end_abort(NodeKind::ForPattern) {
return;
}
if p.peek() == Some(&NodeKind::Comma) { if p.peek() == Some(&NodeKind::Comma) {
p.eat(); p.eat();
ident(p)?;
ident(p);
if p.may_end_abort(NodeKind::ForPattern) {
return;
} }
} Ok(())
})
p.end(NodeKind::ForPattern);
} }
/// Parse an import expression. /// Parse an import expression.
fn import_expr(p: &mut Parser) { fn import_expr(p: &mut Parser) -> ParseResult {
p.start(); p.start();
p.eat_assert(&NodeKind::Import); p.eat_assert(&NodeKind::Import);
@ -793,15 +730,15 @@ fn import_expr(p: &mut Parser) {
// This is the list of identifiers scenario. // This is the list of identifiers scenario.
p.start(); p.start();
p.start_group(Group::Imports, TokenMode::Code); p.start_group(Group::Imports, TokenMode::Code);
let offset = p.child_count(); let marker = p.marker();
let items = collection(p).1; let items = collection(p).1;
if items == 0 { if items == 0 {
p.expected_at("import items"); p.expected_at("import items");
} }
p.end_group(); p.end_group();
p.filter_children( marker.filter_children(
offset, p,
|n| matches!(n.kind(), NodeKind::Ident(_) | NodeKind::Comma), |n| matches!(n.kind(), NodeKind::Ident(_) | NodeKind::Comma),
|_| (ErrorPosition::Full, "expected identifier".into()), |_| (ErrorPosition::Full, "expected identifier".into()),
); );
@ -813,36 +750,41 @@ fn import_expr(p: &mut Parser) {
} }
p.end(NodeKind::ImportExpr); p.end(NodeKind::ImportExpr);
Ok(())
} }
/// Parse an include expression. /// Parse an include expression.
fn include_expr(p: &mut Parser) { fn include_expr(p: &mut Parser) -> ParseResult {
p.start(); p.start();
p.eat_assert(&NodeKind::Include); p.eat_assert(&NodeKind::Include);
expr(p); expr(p);
p.end(NodeKind::IncludeExpr); p.end(NodeKind::IncludeExpr);
Ok(())
} }
/// Parse an identifier. /// Parse an identifier.
fn ident(p: &mut Parser) { fn ident(p: &mut Parser) -> ParseResult {
match p.peek() { match p.peek() {
Some(NodeKind::Ident(_)) => p.eat(), Some(NodeKind::Ident(_)) => {
p.eat();
Ok(())
}
_ => { _ => {
p.expected("identifier"); p.expected("identifier");
p.unsuccessful(); Err(())
} }
} }
} }
/// Parse a control flow body. /// Parse a control flow body.
fn body(p: &mut Parser) { fn body(p: &mut Parser) -> ParseResult {
match p.peek() { match p.peek() {
Some(NodeKind::LeftBracket) => template(p), Some(NodeKind::LeftBracket) => template(p),
Some(NodeKind::LeftBrace) => block(p), Some(NodeKind::LeftBrace) => block(p),
_ => { _ => {
p.expected_at("body"); p.expected_at("body");
p.unsuccessful(); Err(())
} }
} }
} }

View File

@ -1,7 +1,7 @@
use std::ops::Range; use std::ops::Range;
use std::rc::Rc; use std::rc::Rc;
use super::{TokenMode, Tokens}; use super::{ParseResult, TokenMode, Tokens};
use crate::syntax::{ErrorPosition, Green, GreenData, GreenNode, NodeKind}; use crate::syntax::{ErrorPosition, Green, GreenData, GreenNode, NodeKind};
use crate::util::EcoString; use crate::util::EcoString;
@ -26,8 +26,6 @@ pub struct Parser<'s> {
stack: Vec<Vec<Green>>, stack: Vec<Vec<Green>>,
/// The children of the currently built node. /// The children of the currently built node.
children: Vec<Green>, children: Vec<Green>,
/// Whether the last parsing step was successful.
success: bool,
} }
/// A logical group of tokens, e.g. `[...]`. /// A logical group of tokens, e.g. `[...]`.
@ -58,6 +56,49 @@ pub enum Group {
Imports, 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<F, G>(&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> { impl<'s> Parser<'s> {
/// Create a new parser for the source string. /// Create a new parser for the source string.
pub fn new(src: &'s str) -> Self { pub fn new(src: &'s str) -> Self {
@ -73,7 +114,6 @@ impl<'s> Parser<'s> {
next_start: 0, next_start: 0,
stack: vec![], stack: vec![],
children: vec![], children: vec![],
success: true,
} }
} }
@ -85,19 +125,13 @@ impl<'s> Parser<'s> {
self.stack.push(std::mem::take(&mut self.children)); 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. /// Filter the last children using the given predicate.
pub fn filter_children<F, G>(&mut self, count: usize, f: F, error: G) fn filter_children<F, G>(&mut self, count: &Marker, f: F, error: G)
where where
F: Fn(&Green) -> bool, F: Fn(&Green) -> bool,
G: Fn(&NodeKind) -> (ErrorPosition, EcoString), 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 if !((self.tokens.mode() != TokenMode::Code
|| Self::skip_type_ext(child.kind(), false)) || Self::skip_type_ext(child.kind(), false))
|| child.kind().is_error() || child.kind().is_error()
@ -161,46 +195,22 @@ impl<'s> Parser<'s> {
self.children self.children
.push(GreenNode::with_children(kind, len, children).into()); .push(GreenNode::with_children(kind, len, children).into());
self.children.extend(remains); self.children.extend(remains);
self.success = true;
} }
/// End the current node as a node of given `kind`, and start a new node pub fn perform<F>(&mut self, kind: NodeKind, f: F) -> ParseResult
/// with the ended node as a first child. The function returns how many where
/// children the stack frame had before and how many were appended (accounts F: FnOnce(&mut Self) -> ParseResult,
/// for trivia). {
pub fn end_and_start_with(&mut self, kind: NodeKind) -> (usize, usize) { self.start();
let stack_offset = self.stack.last().unwrap().len(); let success = f(self);
self.end(kind); self.end(kind);
let diff = self.children.len() - stack_offset; success
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();
} }
/// Eat and wrap the next token. /// Eat and wrap the next token.
pub fn convert(&mut self, kind: NodeKind) { pub fn convert(&mut self, kind: NodeKind) {
self.eat(); self.eat();
self.children.last_mut().unwrap().set_kind(kind); 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 /// 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 outer = self.stack.pop().unwrap();
let children = std::mem::replace(&mut self.children, outer); let children = std::mem::replace(&mut self.children, outer);
self.children.extend(children); self.children.extend(children);
self.success = true;
} }
/// End the current node and undo its existence, deleting all accumulated /// Add an error to the current children list.
/// children. fn push_error(&mut self, msg: impl Into<String>) {
pub fn abort(&mut self, msg: impl Into<String>) { self.children.push(
self.end(NodeKind::Error(ErrorPosition::Full, msg.into().into())); GreenData::new(NodeKind::Error(ErrorPosition::Full, msg.into().into()), 0)
self.success = false; .into(),
} );
/// 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
}
} }
/// End the parsing process and return the last child. /// End the parsing process and return the last child.
@ -268,14 +242,6 @@ impl<'s> Parser<'s> {
self.peek().is_none() self.peek().is_none()
} }
/// Consume the next token and return its kind.
// NOTE: This isn't great.
fn eat_peeked(&mut self) -> Option<NodeKind> {
let token = self.peek()?.clone();
self.eat();
Some(token)
}
/// Consume the next token if it is the given one. /// 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) { 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. /// Consume the next token, debug-asserting that it is one of the given ones.
pub fn eat_assert(&mut self, t: &NodeKind) { pub fn eat_assert(&mut self, t: &NodeKind) {
// NOTE: assert with peek(), then eat() let next = self.peek();
let next = self.eat_peeked(); debug_assert_eq!(next, Some(t));
debug_assert_eq!(next.as_ref(), Some(t)); self.eat();
} }
/// Consume tokens while the condition is true. /// Consume tokens while the condition is true.
@ -402,9 +368,10 @@ impl<'s> Parser<'s> {
/// End the parsing of a group. /// End the parsing of a group.
/// ///
/// This panics if no group was started. /// 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 prev_mode = self.tokens.mode();
let group = self.groups.pop().expect("no started group"); let group = self.groups.pop().expect("no started group");
let mut success = true;
self.tokens.set_mode(group.prev_mode); self.tokens.set_mode(group.prev_mode);
self.repeek(); self.repeek();
@ -424,8 +391,8 @@ impl<'s> Parser<'s> {
self.eat(); self.eat();
rescan = false; rescan = false;
} else if required { } else if required {
self.start(); self.push_error(format!("expected {}", end));
self.abort(format!("expected {}", end)); success = false;
} }
} }
@ -448,6 +415,8 @@ impl<'s> Parser<'s> {
self.next = self.tokens.next(); self.next = self.tokens.next();
self.repeek(); self.repeek();
} }
if success { Ok(()) } else { Err(()) }
} }
/// Add an error that `what` was expected at the given span. /// Add an error that `what` was expected at the given span.
@ -460,39 +429,36 @@ impl<'s> Parser<'s> {
found = i; found = i;
} }
self.expected_at_child(found, what); Marker(found).expected_at(self, 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(),
);
} }
/// Eat the next token and add an error that it is not the expected `thing`. /// Eat the next token and add an error that it is not the expected `thing`.
pub fn expected(&mut self, what: &str) { pub fn expected(&mut self, what: &str) {
match self.peek().cloned() {
Some(found) => {
self.start(); self.start();
match self.eat_peeked() { self.eat();
Some(found) => self.abort(format!("expected {}, found {}", what, found)), self.end(NodeKind::Error(
None => { ErrorPosition::Full,
self.lift(); format!("expected {}, found {}", what, found).into(),
self.expected_at(what); ));
} }
None => self.expected_at(what),
} }
} }
/// Eat the next token and add an error that it is unexpected. /// Eat the next token and add an error that it is unexpected.
pub fn unexpected(&mut self) { pub fn unexpected(&mut self) {
match self.peek().cloned() {
Some(found) => {
self.start(); self.start();
match self.eat_peeked() { self.eat();
Some(found) => self.abort(format!("unexpected {}", found)), self.end(NodeKind::Error(
None => self.abort("unexpected end of file"), 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() self.children.last()
} }
/// Whether the last operation was successful. /// Create a new marker.
pub fn success(&mut self) -> bool { pub fn marker(&mut self) -> Marker {
let s = self.success; Marker(self.children.len())
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()
} }
} }

View File

@ -156,13 +156,7 @@ impl HeadingNode {
/// The section depth (numer of equals signs). /// The section depth (numer of equals signs).
pub fn level(&self) -> u8 { pub fn level(&self) -> u8 {
self.0 self.0.children().filter(|n| n.kind() == &NodeKind::Eq).count() as u8
.children()
.find_map(|node| match node.kind() {
NodeKind::HeadingLevel(heading) => Some(*heading),
_ => None,
})
.expect("heading node is missing heading level")
} }
} }
@ -743,7 +737,7 @@ impl TypedNode for CallArg {
NodeKind::Named => Some(CallArg::Named( NodeKind::Named => Some(CallArg::Named(
node.cast().expect("named call argument is missing name"), node.cast().expect("named call argument is missing name"),
)), )),
NodeKind::ParameterSink => Some(CallArg::Spread( NodeKind::Spread => Some(CallArg::Spread(
node.cast_first_child() node.cast_first_child()
.expect("call argument sink is missing expression"), .expect("call argument sink is missing expression"),
)), )),
@ -825,7 +819,7 @@ impl TypedNode for ClosureParam {
NodeKind::Named => Some(ClosureParam::Named( NodeKind::Named => Some(ClosureParam::Named(
node.cast().expect("named closure parameter is missing name"), node.cast().expect("named closure parameter is missing name"),
)), )),
NodeKind::ParameterSink => Some(ClosureParam::Sink( NodeKind::Spread => Some(ClosureParam::Sink(
node.cast_first_child() node.cast_first_child()
.expect("closure parameter sink is missing identifier"), .expect("closure parameter sink is missing identifier"),
)), )),

View File

@ -487,8 +487,6 @@ pub enum NodeKind {
Emph, Emph,
/// A section heading: `= Introduction`. /// A section heading: `= Introduction`.
Heading, Heading,
/// A heading's level: `=`, `==`, `===`, etc.
HeadingLevel(u8),
/// An item in an enumeration (ordered list): `1. ...`. /// An item in an enumeration (ordered list): `1. ...`.
Enum, Enum,
/// A numbering: `23.`. /// A numbering: `23.`.
@ -546,7 +544,7 @@ pub enum NodeKind {
/// A closure's parameters: `(x, y)`. /// A closure's parameters: `(x, y)`.
ClosureParams, ClosureParams,
/// A parameter sink: `..x`. /// A parameter sink: `..x`.
ParameterSink, Spread,
/// A template expression: `[*Hi* there!]`. /// A template expression: `[*Hi* there!]`.
Template, Template,
/// A block expression: `{ let x = 1; x + 2 }`. /// A block expression: `{ let x = 1; x + 2 }`.
@ -709,7 +707,6 @@ impl NodeKind {
Self::Strong => "strong", Self::Strong => "strong",
Self::Emph => "emphasis", Self::Emph => "emphasis",
Self::Heading => "heading", Self::Heading => "heading",
Self::HeadingLevel(_) => "heading level",
Self::Enum => "enumeration item", Self::Enum => "enumeration item",
Self::EnumNumbering(_) => "enumeration item numbering", Self::EnumNumbering(_) => "enumeration item numbering",
Self::List => "list item", Self::List => "list item",
@ -735,7 +732,7 @@ impl NodeKind {
Self::CallArgs => "call arguments", Self::CallArgs => "call arguments",
Self::Closure => "closure", Self::Closure => "closure",
Self::ClosureParams => "closure parameters", Self::ClosureParams => "closure parameters",
Self::ParameterSink => "parameter sink", Self::Spread => "parameter sink",
Self::Template => "template", Self::Template => "template",
Self::Block => "block", Self::Block => "block",
Self::ForExpr => "for-loop expression", Self::ForExpr => "for-loop expression",

View File

@ -56,7 +56,7 @@ Three
#let v4 = 4 Four #let v4 = 4 Four
// Terminated by semicolon even though we are in a paren group. // Terminated by semicolon even though we are in a paren group.
// Error: 19 expected expression // Error: 18 expected expression
// Error: 19 expected closing paren // Error: 19 expected closing paren
#let v5 = (1, 2 + ; Five #let v5 = (1, 2 + ; Five