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 = Result; /// Parse a source file. pub fn parse(source: &str) -> Rc { @@ -52,12 +51,11 @@ fn markup_while(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); +fn heading(p: &mut Parser) { + p.perform(NodeKind::Heading, |p| { + p.eat_assert(&NodeKind::Eq); - // Count depth. - let mut level: usize = 1; - while p.eat_if(&NodeKind::Eq) { - level += 1; - } + 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 { +fn item(p: &mut Parser) -> ParseResult { 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(); + 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(); - expr(p); - Err(()) - }; - - 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 { /// 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(); - } +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(); + } - while allow_template && p.peek_direct() == Some(&NodeKind::LeftBracket) { - template(p); - } - - 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); + marker.perform(p, NodeKind::WithExpr, |p| { + p.eat_assert(&NodeKind::With); - let res = if p.peek() == Some(&NodeKind::LeftParen) { - args(p, false) - } else { - p.expected("argument list"); - Err(()) - }; - - 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"); + 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| match n.kind() { + NodeKind::Ident(_) | NodeKind::Comma => Ok(()), + _ => Err((ErrorPosition::Full, "expected identifier".into())), + }); + }); + }; + + if p.eat_expect(&NodeKind::From).is_ok() { + expr(p)?; } - p.end_group(); - marker.filter_children( - p, - |n| matches!(n.kind(), NodeKind::Ident(_) | NodeKind::Comma), - |_| (ErrorPosition::Full, "expected identifier".into()), - ); - p.end(NodeKind::ImportItems); - }; - - if p.eat_expect(&NodeKind::From) { - 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 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 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(&self, p: &mut Parser, f: F, error: G) + pub fn filter_children(&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(&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(&mut self, count: &Marker, f: F, error: G) + fn filter_children(&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(); + if let Err((pos, msg)) = f(child) { + let inner = std::mem::take(child); + *child = + GreenNode::with_child(NodeKind::Error(pos, msg), 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 { - 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); - } - 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(&mut self, kind: NodeKind, f: F) -> ParseResult + pub fn perform(&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) -> Self { - let mut data = GreenData::new(kind, len); - data.erroneous |= children.iter().any(|c| c.erroneous()); + pub fn with_children(kind: NodeKind, children: Vec) -> 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) -> Self { - Self::with_children(kind, len, vec![child.into()]) + pub fn with_child(kind: NodeKind, child: impl Into) -> 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 Binary files a/tests/ref/markup/heading.png and b/tests/ref/markup/heading.png 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.