summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/eval/walk.rs2
-rw-r--r--src/parse/mod.rs417
-rw-r--r--src/parse/parser.rs135
-rw-r--r--src/syntax/ast.rs6
-rw-r--r--src/syntax/mod.rs15
-rw-r--r--tests/ref/markup/heading.pngbin6611 -> 6406 bytes
-rw-r--r--tests/typ/markup/heading.typ4
7 files changed, 261 insertions, 318 deletions
diff --git a/src/eval/walk.rs b/src/eval/walk.rs
index ff73f9f9..1656929b 100644
--- a/src/eval/walk.rs
+++ b/src/eval/walk.rs
@@ -76,7 +76,7 @@ impl Walk for HeadingNode {
ctx.template.save();
ctx.template.modify(move |style| {
let text = style.text_mut();
- let upscale = 1.6 - 0.1 * level as f64;
+ let upscale = (1.6 - 0.1 * level as f64).max(0.75);
text.size *= upscale;
text.strong = true;
});
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index 92220eaa..21ca303e 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -14,9 +14,8 @@ use std::rc::Rc;
use crate::syntax::ast::{Associativity, BinOp, UnOp};
use crate::syntax::{ErrorPosition, GreenNode, NodeKind};
-use crate::util::EcoString;
-type ParseResult = Result<(), ()>;
+type ParseResult<T = ()> = Result<T, ()>;
/// Parse a source file.
pub fn parse(source: &str) -> Rc<GreenNode> {
@@ -52,12 +51,11 @@ fn markup_while<F>(p: &mut Parser, mut at_start: bool, f: &mut F)
where
F: FnMut(&mut Parser) -> bool,
{
- p.start();
- while !p.eof() && f(p) {
- markup_node(p, &mut at_start);
- }
-
- p.end(NodeKind::Markup);
+ p.perform(NodeKind::Markup, |p| {
+ while !p.eof() && f(p) {
+ markup_node(p, &mut at_start).ok();
+ }
+ });
}
/// Parse a markup node.
@@ -91,7 +89,6 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) -> ParseResult {
| NodeKind::Raw(_)
| NodeKind::UnicodeEscape(_) => {
p.eat();
- Ok(())
}
NodeKind::Eq if *at_start => heading(p),
@@ -101,7 +98,6 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) -> ParseResult {
// 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()));
- Ok(())
}
// Hashtag + keyword / identifier.
@@ -120,7 +116,7 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) -> ParseResult {
if stmt && res.is_ok() && !p.eof() {
p.expected_at("semicolon or line break");
}
- p.end_group()
+ p.end_group();
}
// Block and template.
@@ -135,58 +131,46 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) -> ParseResult {
NodeKind::Error(_, _) => {
p.eat();
- Ok(())
}
_ => {
p.unexpected();
- Err(())
+ return Err(());
}
- }?;
+ };
*at_start = false;
Ok(())
}
/// Parse a heading.
-fn heading(p: &mut Parser) -> ParseResult {
- p.start();
- p.eat_assert(&NodeKind::Eq);
-
- // Count depth.
- let mut level: usize = 1;
- while p.eat_if(&NodeKind::Eq) {
- level += 1;
- }
+fn heading(p: &mut Parser) {
+ p.perform(NodeKind::Heading, |p| {
+ p.eat_assert(&NodeKind::Eq);
+
+ while p.eat_if(&NodeKind::Eq) {}
- if level > 6 {
- p.end(NodeKind::Text(EcoString::from('=').repeat(level)));
- } else {
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) -> ParseResult {
- p.start();
- p.eat_assert(&NodeKind::ListBullet);
- let column = p.column(p.prev_end());
- markup_indented(p, column);
- p.end(NodeKind::List);
- Ok(())
+fn list_node(p: &mut Parser) {
+ p.perform(NodeKind::List, |p| {
+ p.eat_assert(&NodeKind::ListBullet);
+ let column = p.column(p.prev_end());
+ markup_indented(p, column);
+ });
}
/// Parse a single enum item.
-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(())
+fn enum_node(p: &mut Parser) {
+ p.perform(NodeKind::Enum, |p| {
+ p.eat();
+ let column = p.column(p.prev_end());
+ markup_indented(p, column);
+ });
}
/// Parse an expression.
@@ -224,7 +208,7 @@ fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult {
p.peek_direct(),
Some(NodeKind::LeftParen | NodeKind::LeftBracket)
) {
- call(p, &marker);
+ call(p, &marker)?;
continue;
}
@@ -255,19 +239,14 @@ fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult {
Associativity::Right => {}
}
- if expr_with(p, atomic, prec).is_err() {
- break Ok(());
- }
-
- marker.end(p, NodeKind::Binary);
+ marker.perform(p, NodeKind::Binary, |p| expr_with(p, atomic, prec))?;
}
}
/// Parse a primary expression.
fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
- let lit = literal(p);
- if lit.is_ok() {
- return lit;
+ if literal(p) {
+ return Ok(());
}
match p.peek() {
@@ -282,9 +261,7 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
marker.end(p, NodeKind::ClosureParams);
p.eat();
- let e = expr(p);
- marker.end(p, NodeKind::Closure);
- e
+ marker.perform(p, NodeKind::Closure, expr)
} else {
Ok(())
}
@@ -292,8 +269,14 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
// Structures.
Some(NodeKind::LeftParen) => parenthesized(p),
- Some(NodeKind::LeftBracket) => template(p),
- Some(NodeKind::LeftBrace) => block(p),
+ Some(NodeKind::LeftBracket) => {
+ template(p);
+ Ok(())
+ }
+ Some(NodeKind::LeftBrace) => {
+ block(p);
+ Ok(())
+ }
// Keywords.
Some(NodeKind::Let) => let_expr(p),
@@ -317,7 +300,7 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
}
/// Parse a literal.
-fn literal(p: &mut Parser) -> ParseResult {
+fn literal(p: &mut Parser) -> bool {
match p.peek() {
// Basic values.
Some(
@@ -333,10 +316,10 @@ fn literal(p: &mut Parser) -> ParseResult {
| NodeKind::Str(_),
) => {
p.eat();
- Ok(())
+ true
}
- _ => Err(()),
+ _ => false,
}
}
@@ -364,10 +347,7 @@ fn parenthesized(p: &mut Parser) -> ParseResult {
p.eat_assert(&NodeKind::Arrow);
- let r = expr(p);
-
- marker.end(p, NodeKind::Closure);
- return r;
+ return marker.perform(p, NodeKind::Closure, expr);
}
// Find out which kind of collection this is.
@@ -439,37 +419,35 @@ 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) -> Result<NodeKind, ()> {
+fn item(p: &mut Parser) -> ParseResult<NodeKind> {
let marker = p.marker();
if p.eat_if(&NodeKind::Dots) {
- let r = expr(p);
-
- marker.end(p, NodeKind::Spread);
- return r.map(|_| NodeKind::Spread);
+ return marker
+ .perform(p, NodeKind::Spread, |p| expr(p).map(|_| NodeKind::Spread));
}
let ident_marker = p.marker();
- if expr(p).is_err() {
- return Err(());
- }
+ expr(p)?;
if p.peek() == Some(&NodeKind::Colon) {
- let r = if matches!(p.child(0).unwrap().kind(), &NodeKind::Ident(_)) {
- p.eat();
- expr(p)
- } else {
- ident_marker.end(
- p,
- NodeKind::Error(ErrorPosition::Full, "expected identifier".into()),
- );
- p.eat();
-
- expr(p);
- Err(())
- };
+ marker.perform(p, NodeKind::Named, |p| {
+ if matches!(
+ ident_marker.child_at(p).unwrap().kind(),
+ &NodeKind::Ident(_)
+ ) {
+ p.eat();
+ expr(p).map(|_| NodeKind::Named)
+ } else {
+ ident_marker.end(
+ p,
+ NodeKind::Error(ErrorPosition::Full, "expected identifier".into()),
+ );
+ p.eat();
- marker.end(p, NodeKind::Named);
- r.map(|_| NodeKind::Named)
+ expr(p).ok();
+ Err(())
+ }
+ })
} else {
Ok(p.last_child().unwrap().kind().clone())
}
@@ -478,23 +456,16 @@ fn item(p: &mut Parser) -> Result<NodeKind, ()> {
/// Convert a collection into an array, producing errors for anything other than
/// expressions.
fn array(p: &mut Parser, marker: &Marker) -> ParseResult {
- marker.filter_children(
- p,
- |x| match x.kind() {
- NodeKind::Named | NodeKind::Spread => false,
- _ => true,
- },
- |kind| match kind {
- NodeKind::Named => (
- ErrorPosition::Full,
- "expected expression, found named pair".into(),
- ),
- NodeKind::Spread => {
- (ErrorPosition::Full, "spreading is not allowed here".into())
- }
- _ => unreachable!(),
- },
- );
+ marker.filter_children(p, |x| match x.kind() {
+ NodeKind::Named => Err((
+ ErrorPosition::Full,
+ "expected expression, found named pair".into(),
+ )),
+ NodeKind::Spread => {
+ Err((ErrorPosition::Full, "spreading is not allowed here".into()))
+ }
+ _ => Ok(()),
+ });
marker.end(p, NodeKind::Array);
Ok(())
@@ -503,24 +474,17 @@ fn array(p: &mut Parser, marker: &Marker) -> ParseResult {
/// Convert a collection into a dictionary, producing errors for anything other
/// than named pairs.
fn dict(p: &mut Parser, marker: &Marker) -> ParseResult {
- marker.filter_children(
- p,
- |x| {
- x.kind() == &NodeKind::Named
- || x.kind().is_paren()
- || x.kind() == &NodeKind::Comma
- || x.kind() == &NodeKind::Colon
- },
- |kind| match kind {
- NodeKind::Spread => {
- (ErrorPosition::Full, "spreading is not allowed here".into())
- }
- _ => (
- ErrorPosition::Full,
- "expected named pair, found expression".into(),
- ),
- },
- );
+ marker.filter_children(p, |x| match x.kind() {
+ NodeKind::Named | NodeKind::Comma | NodeKind::Colon => Ok(()),
+ NodeKind::Spread => {
+ Err((ErrorPosition::Full, "spreading is not allowed here".into()))
+ }
+ _ if x.kind().is_paren() => Ok(()),
+ _ => Err((
+ ErrorPosition::Full,
+ "expected named pair, found expression".into(),
+ )),
+ });
marker.end(p, NodeKind::Dict);
Ok(())
@@ -529,96 +493,90 @@ fn dict(p: &mut Parser, marker: &Marker) -> ParseResult {
/// 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, marker: &Marker, allow_parens: bool) {
- marker.filter_children(
- p,
- |x| match x.kind() {
- NodeKind::Named | NodeKind::Comma | NodeKind::Ident(_) => true,
- NodeKind::Spread => matches!(
- x.children().last().map(|x| x.kind()),
- Some(&NodeKind::Ident(_))
- ),
- _ => false,
- }
- || (allow_parens && x.kind().is_paren()),
- |_| (ErrorPosition::Full, "expected identifier".into()),
- );
+ marker.filter_children(p, |x| match x.kind() {
+ NodeKind::Named | NodeKind::Comma | NodeKind::Ident(_) => Ok(()),
+ NodeKind::Spread
+ if matches!(
+ x.children().last().map(|x| x.kind()),
+ Some(&NodeKind::Ident(_))
+ ) =>
+ {
+ Ok(())
+ }
+ _ if allow_parens && x.kind().is_paren() => Ok(()),
+ _ => Err((ErrorPosition::Full, "expected identifier".into())),
+ });
}
// Parse a template block: `[...]`.
-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(())
+fn template(p: &mut Parser) {
+ p.perform(NodeKind::Template, |p| {
+ p.start_group(Group::Bracket, TokenMode::Markup);
+ markup(p);
+ p.end_group();
+ });
}
/// Parse a code block: `{...}`.
-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);
- if expr(p).is_ok() {
- if !p.eof() {
+fn block(p: &mut Parser) {
+ p.perform(NodeKind::Block, |p| {
+ p.start_group(Group::Brace, TokenMode::Code);
+ while !p.eof() {
+ p.start_group(Group::Stmt, TokenMode::Code);
+ if expr(p).is_ok() && !p.eof() {
p.expected_at("semicolon or line break");
}
+ p.end_group();
+
+ // Forcefully skip over newlines since the group's contents can't.
+ p.eat_while(|t| matches!(t, NodeKind::Space(_)));
}
p.end_group();
-
- // Forcefully skip over newlines since the group's contents can't.
- p.eat_while(|t| matches!(t, NodeKind::Space(_)));
- }
- p.end_group();
- p.end(NodeKind::Block);
- Ok(())
+ });
}
/// Parse a function call.
fn call(p: &mut Parser, callee: &Marker) -> ParseResult {
- let res = match p.peek_direct() {
- Some(NodeKind::LeftParen) | Some(NodeKind::LeftBracket) => args(p, true),
+ callee.perform(p, NodeKind::Call, |p| match p.peek_direct() {
+ Some(NodeKind::LeftParen) | Some(NodeKind::LeftBracket) => {
+ args(p, true);
+ Ok(())
+ }
_ => {
p.expected_at("argument list");
Err(())
}
- };
-
- callee.end(p, NodeKind::Call);
- res
+ })
}
/// Parse the arguments to a function call.
-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);
- collection(p);
- p.end_group();
- }
-
- while allow_template && p.peek_direct() == Some(&NodeKind::LeftBracket) {
- template(p);
- }
+fn args(p: &mut Parser, allow_template: bool) {
+ p.perform(NodeKind::CallArgs, |p| {
+ if !allow_template || p.peek_direct() == Some(&NodeKind::LeftParen) {
+ p.start_group(Group::Paren, TokenMode::Code);
+ collection(p);
+ p.end_group();
+ }
- p.end(NodeKind::CallArgs);
- Ok(())
+ while allow_template && p.peek_direct() == Some(&NodeKind::LeftBracket) {
+ template(p);
+ }
+ })
}
/// Parse a with expression.
fn with_expr(p: &mut Parser, marker: &Marker) -> ParseResult {
- p.eat_assert(&NodeKind::With);
-
- let res = if p.peek() == Some(&NodeKind::LeftParen) {
- args(p, false)
- } else {
- p.expected("argument list");
- Err(())
- };
+ marker.perform(p, NodeKind::WithExpr, |p| {
+ p.eat_assert(&NodeKind::With);
- marker.end(p, NodeKind::WithExpr);
- res
+ if p.peek() == Some(&NodeKind::LeftParen) {
+ args(p, false);
+ Ok(())
+ } else {
+ p.expected("argument list");
+ Err(())
+ }
+ })
}
/// Parse a let expression.
@@ -630,17 +588,17 @@ fn let_expr(p: &mut Parser) -> ParseResult {
ident(p)?;
if p.peek() == Some(&NodeKind::With) {
- with_expr(p, &marker);
+ with_expr(p, &marker)?;
} 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 marker = p.marker();
- collection(p);
- params(p, &marker, true);
- p.end_group();
- p.end(NodeKind::ClosureParams);
+ p.perform(NodeKind::ClosureParams, |p| {
+ p.start_group(Group::Paren, TokenMode::Code);
+ let marker = p.marker();
+ collection(p);
+ params(p, &marker, true);
+ p.end_group();
+ });
true
} else {
false
@@ -699,13 +657,10 @@ fn for_expr(p: &mut Parser) -> ParseResult {
p.eat_assert(&NodeKind::For);
for_pattern(p)?;
- if p.eat_expect(&NodeKind::In) {
- expr(p)?;
- body(p)?;
- Ok(())
- } else {
- Err(())
- }
+ p.eat_expect(&NodeKind::In)?;
+ expr(p)?;
+ body(p)?;
+ Ok(())
})
}
@@ -723,44 +678,42 @@ fn for_pattern(p: &mut Parser) -> ParseResult {
/// Parse an import expression.
fn import_expr(p: &mut Parser) -> ParseResult {
- p.start();
- p.eat_assert(&NodeKind::Import);
+ p.perform(NodeKind::ImportExpr, |p| {
+ p.eat_assert(&NodeKind::Import);
- if !p.eat_if(&NodeKind::Star) {
- // This is the list of identifiers scenario.
- p.start();
- p.start_group(Group::Imports, TokenMode::Code);
- let marker = p.marker();
- let items = collection(p).1;
- if items == 0 {
- p.expected_at("import items");
- }
- p.end_group();
+ if !p.eat_if(&NodeKind::Star) {
+ // This is the list of identifiers scenario.
+ p.perform(NodeKind::ImportItems, |p| {
+ p.start_group(Group::Imports, TokenMode::Code);
+ let marker = p.marker();
+ let items = collection(p).1;
+ if items == 0 {
+ p.expected_at("import items");
+ }
+ p.end_group();
- marker.filter_children(
- p,
- |n| matches!(n.kind(), NodeKind::Ident(_) | NodeKind::Comma),
- |_| (ErrorPosition::Full, "expected identifier".into()),
- );
- p.end(NodeKind::ImportItems);
- };
+ marker.filter_children(p, |n| match n.kind() {
+ NodeKind::Ident(_) | NodeKind::Comma => Ok(()),
+ _ => Err((ErrorPosition::Full, "expected identifier".into())),
+ });
+ });
+ };
- if p.eat_expect(&NodeKind::From) {
- expr(p);
- }
+ if p.eat_expect(&NodeKind::From).is_ok() {
+ expr(p)?;
+ }
- p.end(NodeKind::ImportExpr);
- Ok(())
+ Ok(())
+ })
}
/// Parse an include expression.
fn include_expr(p: &mut Parser) -> ParseResult {
- p.start();
- p.eat_assert(&NodeKind::Include);
-
- expr(p);
- p.end(NodeKind::IncludeExpr);
- Ok(())
+ p.perform(NodeKind::IncludeExpr, |p| {
+ p.eat_assert(&NodeKind::Include);
+ expr(p)?;
+ Ok(())
+ })
}
/// Parse an identifier.
@@ -784,7 +737,9 @@ fn body(p: &mut Parser) -> ParseResult {
Some(NodeKind::LeftBrace) => block(p),
_ => {
p.expected_at("body");
- Err(())
+ return Err(());
}
}
+
+ Ok(())
}
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index bc028876..3813ee84 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -62,28 +62,24 @@ 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());
- }
+ 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();
+ p.children
+ .insert(self.0, GreenNode::with_children(kind, 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)
+ pub fn filter_children<F>(&self, p: &mut Parser, f: F)
where
- F: Fn(&Green) -> bool,
- G: Fn(&NodeKind) -> (ErrorPosition, EcoString),
+ F: Fn(&Green) -> Result<(), (ErrorPosition, EcoString)>,
{
- p.filter_children(self, f, error)
+ p.filter_children(self, f)
}
/// Insert an error message that `what` was expected at the marker position.
@@ -97,6 +93,20 @@ impl Marker {
.into(),
);
}
+
+ /// Return a reference to the child after the marker.
+ pub fn child_at<'a>(&self, p: &'a Parser) -> Option<&'a Green> {
+ p.children.get(self.0)
+ }
+
+ pub fn perform<T, F>(&self, p: &mut Parser, kind: NodeKind, f: F) -> T
+ where
+ F: FnOnce(&mut Parser) -> T,
+ {
+ let success = f(p);
+ self.end(p, kind);
+ success
+ }
}
impl<'s> Parser<'s> {
@@ -121,58 +131,31 @@ impl<'s> Parser<'s> {
///
/// Each start call has to be matched with a call to `end`,
/// `end_with_custom_children`, `lift`, `abort`, or `end_or_abort`.
- pub fn start(&mut self) {
+ fn start(&mut self) {
self.stack.push(std::mem::take(&mut self.children));
}
/// Filter the last children using the given predicate.
- fn filter_children<F, G>(&mut self, count: &Marker, f: F, error: G)
+ fn filter_children<F>(&mut self, count: &Marker, f: F)
where
- F: Fn(&Green) -> bool,
- G: Fn(&NodeKind) -> (ErrorPosition, EcoString),
+ F: Fn(&Green) -> Result<(), (ErrorPosition, EcoString)>,
{
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()
- || f(&child))
+ || child.kind().is_error())
{
- let (pos, msg) = error(child.kind());
- let inner = std::mem::take(child);
- *child =
- GreenNode::with_child(NodeKind::Error(pos, msg), inner.len(), inner)
- .into();
- }
- }
- }
-
- /// Return the a child from the current stack frame specified by its
- /// non-trivia index from the back.
- pub fn child(&self, child: usize) -> Option<&Green> {
- self.node_index_from_back(child).map(|i| &self.children[i])
- }
-
- /// Map a non-trivia index from the back of the current stack frame to a
- /// normal index.
- fn node_index_from_back(&self, child: usize) -> Option<usize> {
- let len = self.children.len();
- let code = self.tokens.mode() == TokenMode::Code;
- let mut seen = 0;
- for x in (0 .. len).rev() {
- if self.skip_type(self.children[x].kind()) && code {
- continue;
- }
- if seen == child {
- return Some(x);
+ if let Err((pos, msg)) = f(child) {
+ let inner = std::mem::take(child);
+ *child =
+ GreenNode::with_child(NodeKind::Error(pos, msg), inner).into();
+ }
}
- seen += 1;
}
-
- None
}
/// End the current node as a node of given `kind`.
- pub fn end(&mut self, kind: NodeKind) {
+ fn end(&mut self, kind: NodeKind) {
let outer = self.stack.pop().unwrap();
let mut children = std::mem::replace(&mut self.children, outer);
@@ -191,15 +174,13 @@ impl<'s> Parser<'s> {
remains.reverse();
}
- let len = children.iter().map(|c| c.len()).sum();
- self.children
- .push(GreenNode::with_children(kind, len, children).into());
+ self.children.push(GreenNode::with_children(kind, children).into());
self.children.extend(remains);
}
- pub fn perform<F>(&mut self, kind: NodeKind, f: F) -> ParseResult
+ pub fn perform<T, F>(&mut self, kind: NodeKind, f: F) -> T
where
- F: FnOnce(&mut Self) -> ParseResult,
+ F: FnOnce(&mut Self) -> T,
{
self.start();
let success = f(self);
@@ -267,12 +248,12 @@ impl<'s> Parser<'s> {
/// Consume the next token if it is the given one and produce an error if
/// not.
- pub fn eat_expect(&mut self, t: &NodeKind) -> bool {
+ pub fn eat_expect(&mut self, t: &NodeKind) -> ParseResult {
let eaten = self.eat_if(t);
if !eaten {
self.expected_at(t.as_str());
}
- eaten
+ if eaten { Ok(()) } else { Err(()) }
}
/// Consume the next token, debug-asserting that it is one of the given ones.
@@ -368,10 +349,9 @@ impl<'s> Parser<'s> {
/// End the parsing of a group.
///
/// This panics if no group was started.
- pub fn end_group(&mut self) -> ParseResult {
+ pub fn end_group(&mut self) {
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();
@@ -392,7 +372,6 @@ impl<'s> Parser<'s> {
rescan = false;
} else if required {
self.push_error(format!("expected {}", end));
- success = false;
}
}
@@ -415,8 +394,6 @@ 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.
@@ -436,12 +413,13 @@ impl<'s> Parser<'s> {
pub fn expected(&mut self, what: &str) {
match self.peek().cloned() {
Some(found) => {
- self.start();
- self.eat();
- self.end(NodeKind::Error(
- ErrorPosition::Full,
- format!("expected {}, found {}", what, found).into(),
- ));
+ self.perform(
+ NodeKind::Error(
+ ErrorPosition::Full,
+ format!("expected {}, found {}", what, found).into(),
+ ),
+ Self::eat,
+ );
}
None => self.expected_at(what),
}
@@ -451,12 +429,13 @@ impl<'s> Parser<'s> {
pub fn unexpected(&mut self) {
match self.peek().cloned() {
Some(found) => {
- self.start();
- self.eat();
- self.end(NodeKind::Error(
- ErrorPosition::Full,
- format!("unexpected {}", found).into(),
- ));
+ self.perform(
+ NodeKind::Error(
+ ErrorPosition::Full,
+ format!("unexpected {}", found).into(),
+ ),
+ Self::eat,
+ );
}
None => self.push_error("unexpected end of file"),
}
diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs
index b6f64c67..1198d6b1 100644
--- a/src/syntax/ast.rs
+++ b/src/syntax/ast.rs
@@ -156,7 +156,11 @@ impl HeadingNode {
/// The section depth (numer of equals signs).
pub fn level(&self) -> u8 {
- self.0.children().filter(|n| n.kind() == &NodeKind::Eq).count() as u8
+ self.0
+ .children()
+ .filter(|n| n.kind() == &NodeKind::Eq)
+ .count()
+ .min(u8::MAX.into()) as u8
}
}
diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs
index db3b0c9a..363cbe6e 100644
--- a/src/syntax/mod.rs
+++ b/src/syntax/mod.rs
@@ -98,15 +98,20 @@ pub struct GreenNode {
impl GreenNode {
/// Creates a new node with the given kind and children.
- pub fn with_children(kind: NodeKind, len: usize, children: Vec<Green>) -> Self {
- let mut data = GreenData::new(kind, len);
- data.erroneous |= children.iter().any(|c| c.erroneous());
+ pub fn with_children(kind: NodeKind, children: Vec<Green>) -> Self {
+ let mut data = GreenData::new(kind, 0);
+ let len = children
+ .iter()
+ .inspect(|c| data.erroneous |= c.erroneous())
+ .map(Green::len)
+ .sum();
+ data.len = len;
Self { data, children }
}
/// Creates a new node with the given kind and a single child.
- pub fn with_child(kind: NodeKind, len: usize, child: impl Into<Green>) -> Self {
- Self::with_children(kind, len, vec![child.into()])
+ pub fn with_child(kind: NodeKind, child: impl Into<Green>) -> Self {
+ Self::with_children(kind, vec![child.into()])
}
/// The node's children.
diff --git a/tests/ref/markup/heading.png b/tests/ref/markup/heading.png
index ca52644b..c33da420 100644
--- a/tests/ref/markup/heading.png
+++ b/tests/ref/markup/heading.png
Binary files differ
diff --git a/tests/typ/markup/heading.typ b/tests/typ/markup/heading.typ
index 4647e7a6..cb022617 100644
--- a/tests/typ/markup/heading.typ
+++ b/tests/typ/markup/heading.typ
@@ -8,8 +8,8 @@
=== Level 2
====== Level 6
-// Too many hashtags.
-======= Level 7
+// At some point, it should stop shrinking.
+=========== Level 11
---
// Heading vs. no heading.