summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Haug <mhaug@live.de>2021-11-04 19:36:32 +0100
committerMartin Haug <mhaug@live.de>2021-11-05 13:46:41 +0100
commit5c952d56d0d602a1dbcf85210ae30fa402219fca (patch)
tree1845c5c90e5f39c2dbc6ae7c8e9e7fa66cbff604 /src
parentf0c9635db5efd0c66e01bef1be0a8f140fdbdd84 (diff)
New error handling
Diffstat (limited to 'src')
-rw-r--r--src/parse/mod.rs518
-rw-r--r--src/parse/parser.rs228
-rw-r--r--src/syntax/ast.rs12
-rw-r--r--src/syntax/mod.rs7
4 files changed, 326 insertions, 439 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index 30e20c0d..92220eaa 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<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);
-
- // 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;
- }
+ expr_with(p, atomic, prec)?;
- 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 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 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");
}
- 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);
-
- 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;
- }
-
- body(p);
-
- if !p.may_end_abort(NodeKind::ForExpr) {
- p.end(NodeKind::ForExpr);
+fn for_expr(p: &mut Parser) -> ParseResult {
+ p.perform(NodeKind::ForExpr, |p| {
+ p.eat_assert(&NodeKind::For);
+
+ for_pattern(p)?;
+ if p.eat_expect(&NodeKind::In) {
+ expr(p)?;
+ body(p)?;
+ Ok(())
+ } else {
+ Err(())
}
- } 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 5ecb6e9d..bc028876 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<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())
}
}
diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs
index 9ad04be5..b6f64c67 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 112fc220..db3b0c9a 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",