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::util::EcoString;
type ParseResult = Result<(), ()>;
/// Parse a source file.
pub fn parse(source: &str) -> Rc<GreenNode> {
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<Marker> = 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<NodeKind, ()> {
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(())
}
}
}

View File

@ -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<Vec<Green>>,
/// The children of the currently built node.
children: Vec<Green>,
/// 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<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> {
/// 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<F, G>(&mut self, count: usize, f: F, error: G)
fn filter_children<F, G>(&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<F>(&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<String>) {
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<String>) {
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<NodeKind> {
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())
}
}

View File

@ -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"),
)),

View File

@ -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",

View File

@ -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