New error handling
This commit is contained in:
parent
f0c9635db5
commit
5c952d56d0
514
src/parse/mod.rs
514
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);
|
||||
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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
@ -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"),
|
||||
)),
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user