Style changes

Co-Authored-By: Martin <mhaug@live.de>
This commit is contained in:
Laurenz 2021-11-05 13:21:39 +01:00 committed by Martin Haug
parent cf2e527a02
commit 515fe89c5e
3 changed files with 127 additions and 174 deletions

View File

@ -15,8 +15,6 @@ use std::rc::Rc;
use crate::syntax::ast::{Associativity, BinOp, UnOp}; use crate::syntax::ast::{Associativity, BinOp, UnOp};
use crate::syntax::{ErrorPosition, GreenNode, NodeKind}; use crate::syntax::{ErrorPosition, GreenNode, NodeKind};
type ParseResult<T = ()> = Result<T, ()>;
/// Parse a source file. /// Parse a source file.
pub fn parse(source: &str) -> Rc<GreenNode> { pub fn parse(source: &str) -> Rc<GreenNode> {
let mut p = Parser::new(source); let mut p = Parser::new(source);
@ -53,29 +51,34 @@ where
{ {
p.perform(NodeKind::Markup, |p| { p.perform(NodeKind::Markup, |p| {
while !p.eof() && f(p) { while !p.eof() && f(p) {
markup_node(p, &mut at_start).ok(); markup_node(p, &mut at_start);
} }
}); });
} }
/// Parse a markup node. /// Parse a markup node.
fn markup_node(p: &mut Parser, at_start: &mut bool) -> ParseResult { fn markup_node(p: &mut Parser, at_start: &mut bool) {
let token = match p.peek() { let token = match p.peek() {
Some(t) => t, Some(t) => t,
None => return Ok(()), None => return,
}; };
match token { match token {
// Whitespace. // Whitespace.
NodeKind::Space(newlines) => { NodeKind::Space(newlines) => {
*at_start |= *newlines > 0; *at_start |= *newlines > 0;
if *newlines < 2 { if *newlines < 2 {
p.eat(); p.eat();
} else { } else {
p.convert(NodeKind::Parbreak); p.convert(NodeKind::Parbreak);
} }
return Ok(()); return;
}
// Comments.
NodeKind::LineComment | NodeKind::BlockComment => {
p.eat();
return;
} }
// Text and markup. // Text and markup.
@ -112,7 +115,7 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) -> ParseResult {
let group = if stmt { Group::Stmt } else { Group::Expr }; let group = if stmt { Group::Stmt } else { Group::Expr };
p.start_group(group, TokenMode::Code); p.start_group(group, TokenMode::Code);
let res = expr_with(p, true, 0); let res = expr_prec(p, true, 0);
if stmt && res.is_ok() && !p.eof() { if stmt && res.is_ok() && !p.eof() {
p.expected_at("semicolon or line break"); p.expected_at("semicolon or line break");
} }
@ -123,33 +126,18 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) -> ParseResult {
NodeKind::LeftBrace => block(p), NodeKind::LeftBrace => block(p),
NodeKind::LeftBracket => template(p), NodeKind::LeftBracket => template(p),
// Comments. NodeKind::Error(_, _) => p.eat(),
NodeKind::LineComment | NodeKind::BlockComment => { _ => p.unexpected(),
p.eat();
return Ok(());
}
NodeKind::Error(_, _) => {
p.eat();
}
_ => {
p.unexpected();
return Err(());
}
}; };
*at_start = false; *at_start = false;
Ok(())
} }
/// Parse a heading. /// Parse a heading.
fn heading(p: &mut Parser) { fn heading(p: &mut Parser) {
p.perform(NodeKind::Heading, |p| { p.perform(NodeKind::Heading, |p| {
p.eat_assert(&NodeKind::Eq); p.eat_assert(&NodeKind::Eq);
while p.eat_if(&NodeKind::Eq) {} while p.eat_if(&NodeKind::Eq) {}
let column = p.column(p.prev_end()); let column = p.column(p.prev_end());
markup_indented(p, column); markup_indented(p, column);
}); });
@ -175,7 +163,7 @@ fn enum_node(p: &mut Parser) {
/// Parse an expression. /// Parse an expression.
fn expr(p: &mut Parser) -> ParseResult { fn expr(p: &mut Parser) -> ParseResult {
expr_with(p, false, 0) expr_prec(p, false, 0)
} }
/// Parse an expression with operators having at least the minimum precedence. /// Parse an expression with operators having at least the minimum precedence.
@ -185,20 +173,17 @@ fn expr(p: &mut Parser) -> ParseResult {
/// in markup. /// in markup.
/// ///
/// Stops parsing at operations with lower precedence than `min_prec`, /// Stops parsing at operations with lower precedence than `min_prec`,
fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult { fn expr_prec(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult {
let marker = p.marker(); let marker = p.marker();
// Start the unary expression. // Start the unary expression.
match p.eat_map(|x| UnOp::from_token(&x)) { match p.eat_map(|x| UnOp::from_token(&x)) {
Some(op) => { Some(op) => {
let prec = op.precedence(); let prec = op.precedence();
expr_with(p, atomic, prec)?; expr_prec(p, atomic, prec)?;
marker.end(p, NodeKind::Unary); marker.end(p, NodeKind::Unary);
} }
None => { None => primary(p, atomic)?,
primary(p, atomic)?;
}
}; };
loop { loop {
@ -213,7 +198,7 @@ fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult {
} }
if atomic { if atomic {
break Ok(()); break;
} }
if p.peek() == Some(&NodeKind::With) { if p.peek() == Some(&NodeKind::With) {
@ -222,14 +207,12 @@ fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult {
let op = match p.peek().and_then(BinOp::from_token) { let op = match p.peek().and_then(BinOp::from_token) {
Some(binop) => binop, Some(binop) => binop,
None => { None => break,
break Ok(());
}
}; };
let mut prec = op.precedence(); let mut prec = op.precedence();
if prec < min_prec { if prec < min_prec {
break Ok(()); break;
} }
p.eat(); p.eat();
@ -239,8 +222,10 @@ fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult {
Associativity::Right => {} Associativity::Right => {}
} }
marker.perform(p, NodeKind::Binary, |p| expr_with(p, atomic, prec))?; marker.perform(p, NodeKind::Binary, |p| expr_prec(p, atomic, prec))?;
} }
Ok(())
} }
/// Parse a primary expression. /// Parse a primary expression.
@ -260,7 +245,6 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
if !atomic && p.peek() == Some(&NodeKind::Arrow) { if !atomic && p.peek() == Some(&NodeKind::Arrow) {
marker.end(p, NodeKind::ClosureParams); marker.end(p, NodeKind::ClosureParams);
p.eat(); p.eat();
marker.perform(p, NodeKind::Closure, expr) marker.perform(p, NodeKind::Closure, expr)
} else { } else {
Ok(()) Ok(())
@ -288,7 +272,7 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
Some(NodeKind::Error(_, _)) => { Some(NodeKind::Error(_, _)) => {
p.eat(); p.eat();
Ok(()) Err(())
} }
// Nothing. // Nothing.
@ -330,6 +314,7 @@ fn literal(p: &mut Parser) -> bool {
/// - Parameter list of closure expression /// - Parameter list of closure expression
fn parenthesized(p: &mut Parser) -> ParseResult { fn parenthesized(p: &mut Parser) -> ParseResult {
let marker = p.marker(); let marker = p.marker();
p.start_group(Group::Paren, TokenMode::Code); p.start_group(Group::Paren, TokenMode::Code);
let colon = p.eat_if(&NodeKind::Colon); let colon = p.eat_if(&NodeKind::Colon);
let kind = collection(p).0; let kind = collection(p).0;
@ -337,28 +322,26 @@ fn parenthesized(p: &mut Parser) -> ParseResult {
// Leading colon makes this a (empty) dictionary. // Leading colon makes this a (empty) dictionary.
if colon { if colon {
return dict(p, &marker); dict(p, &marker);
return Ok(());
} }
// Arrow means this is a closure's parameter list. // Arrow means this is a closure's parameter list.
if p.peek() == Some(&NodeKind::Arrow) { if p.peek() == Some(&NodeKind::Arrow) {
params(p, &marker, true); params(p, &marker, true);
marker.end(p, NodeKind::ClosureParams); marker.end(p, NodeKind::ClosureParams);
p.eat_assert(&NodeKind::Arrow); p.eat_assert(&NodeKind::Arrow);
return marker.perform(p, NodeKind::Closure, expr); return marker.perform(p, NodeKind::Closure, expr);
} }
// Find out which kind of collection this is. // Find out which kind of collection this is.
match kind { match kind {
CollectionKind::Group => { CollectionKind::Group => marker.end(p, NodeKind::Group),
marker.end(p, NodeKind::Group);
Ok(())
}
CollectionKind::Positional => array(p, &marker), CollectionKind::Positional => array(p, &marker),
CollectionKind::Named => dict(p, &marker), CollectionKind::Named => dict(p, &marker),
} }
Ok(())
} }
/// The type of a collection. /// The type of a collection.
@ -380,17 +363,18 @@ enum CollectionKind {
fn collection(p: &mut Parser) -> (CollectionKind, usize) { fn collection(p: &mut Parser) -> (CollectionKind, usize) {
let mut items = 0; let mut items = 0;
let mut kind = CollectionKind::Positional; let mut kind = CollectionKind::Positional;
let mut has_comma = false; let mut can_group = true;
let mut missing_coma: Option<Marker> = None; let mut missing_coma: Option<Marker> = None;
while !p.eof() { while !p.eof() {
if let Ok(item_kind) = item(p) { if let Ok(item_kind) = item(p) {
if items == 0 && item_kind == NodeKind::Named { if items == 0 && item_kind == NodeKind::Named {
kind = CollectionKind::Named; kind = CollectionKind::Named;
can_group = false;
} }
if item_kind == NodeKind::Spread { if item_kind == NodeKind::Spread {
has_comma = true; can_group = false;
} }
items += 1; items += 1;
@ -404,14 +388,14 @@ fn collection(p: &mut Parser) -> (CollectionKind, usize) {
} }
if p.eat_if(&NodeKind::Comma) { if p.eat_if(&NodeKind::Comma) {
has_comma = true; can_group = false;
} else { } else {
missing_coma = Some(p.marker()); missing_coma = Some(p.marker());
} }
} }
} }
if !has_comma && items == 1 && kind == CollectionKind::Positional { if can_group && items == 1 {
kind = CollectionKind::Group; kind = CollectionKind::Group;
} }
@ -422,23 +406,19 @@ fn collection(p: &mut Parser) -> (CollectionKind, usize) {
fn item(p: &mut Parser) -> ParseResult<NodeKind> { fn item(p: &mut Parser) -> ParseResult<NodeKind> {
let marker = p.marker(); let marker = p.marker();
if p.eat_if(&NodeKind::Dots) { if p.eat_if(&NodeKind::Dots) {
return marker marker.perform(p, NodeKind::Spread, expr)?;
.perform(p, NodeKind::Spread, |p| expr(p).map(|_| NodeKind::Spread)); return Ok(NodeKind::Spread);
} }
let ident_marker = p.marker();
expr(p)?; expr(p)?;
if p.peek() == Some(&NodeKind::Colon) { if p.peek() == Some(&NodeKind::Colon) {
marker.perform(p, NodeKind::Named, |p| { marker.perform(p, NodeKind::Named, |p| {
if matches!( if matches!(marker.child_at(p).unwrap().kind(), &NodeKind::Ident(_)) {
ident_marker.child_at(p).unwrap().kind(),
&NodeKind::Ident(_)
) {
p.eat(); p.eat();
expr(p).map(|_| NodeKind::Named) expr(p)
} else { } else {
ident_marker.end( marker.end(
p, p,
NodeKind::Error(ErrorPosition::Full, "expected identifier".into()), NodeKind::Error(ErrorPosition::Full, "expected identifier".into()),
); );
@ -447,7 +427,8 @@ fn item(p: &mut Parser) -> ParseResult<NodeKind> {
expr(p).ok(); expr(p).ok();
Err(()) Err(())
} }
}) })?;
Ok(NodeKind::Named)
} else { } else {
Ok(p.last_child().unwrap().kind().clone()) Ok(p.last_child().unwrap().kind().clone())
} }
@ -455,7 +436,7 @@ fn item(p: &mut Parser) -> ParseResult<NodeKind> {
/// Convert a collection into an array, producing errors for anything other than /// Convert a collection into an array, producing errors for anything other than
/// expressions. /// expressions.
fn array(p: &mut Parser, marker: &Marker) -> ParseResult { fn array(p: &mut Parser, marker: &Marker) {
marker.filter_children(p, |x| match x.kind() { marker.filter_children(p, |x| match x.kind() {
NodeKind::Named => Err(( NodeKind::Named => Err((
ErrorPosition::Full, ErrorPosition::Full,
@ -466,14 +447,12 @@ fn array(p: &mut Parser, marker: &Marker) -> ParseResult {
} }
_ => Ok(()), _ => Ok(()),
}); });
marker.end(p, NodeKind::Array); marker.end(p, NodeKind::Array);
Ok(())
} }
/// Convert a collection into a dictionary, producing errors for anything other /// Convert a collection into a dictionary, producing errors for anything other
/// than named pairs. /// than named pairs.
fn dict(p: &mut Parser, marker: &Marker) -> ParseResult { fn dict(p: &mut Parser, marker: &Marker) {
marker.filter_children(p, |x| match x.kind() { marker.filter_children(p, |x| match x.kind() {
NodeKind::Named | NodeKind::Comma | NodeKind::Colon => Ok(()), NodeKind::Named | NodeKind::Comma | NodeKind::Colon => Ok(()),
NodeKind::Spread => { NodeKind::Spread => {
@ -485,9 +464,7 @@ fn dict(p: &mut Parser, marker: &Marker) -> ParseResult {
"expected named pair, found expression".into(), "expected named pair, found expression".into(),
)), )),
}); });
marker.end(p, NodeKind::Dict); marker.end(p, NodeKind::Dict);
Ok(())
} }
/// Convert a collection into a list of parameters, producing errors for /// Convert a collection into a list of parameters, producing errors for
@ -591,7 +568,8 @@ fn let_expr(p: &mut Parser) -> ParseResult {
with_expr(p, &marker)?; with_expr(p, &marker)?;
} else { } else {
// If a parenthesis follows, this is a function definition. // If a parenthesis follows, this is a function definition.
let has_params = if p.peek_direct() == Some(&NodeKind::LeftParen) { let has_params = p.peek_direct() == Some(&NodeKind::LeftParen);
if has_params {
p.perform(NodeKind::ClosureParams, |p| { p.perform(NodeKind::ClosureParams, |p| {
p.start_group(Group::Paren, TokenMode::Code); p.start_group(Group::Paren, TokenMode::Code);
let marker = p.marker(); let marker = p.marker();
@ -599,10 +577,7 @@ fn let_expr(p: &mut Parser) -> ParseResult {
params(p, &marker, true); params(p, &marker, true);
p.end_group(); p.end_group();
}); });
true }
} else {
false
};
if p.eat_if(&NodeKind::Eq) { if p.eat_if(&NodeKind::Eq) {
expr(p)?; expr(p)?;
@ -655,7 +630,6 @@ fn while_expr(p: &mut Parser) -> ParseResult {
fn for_expr(p: &mut Parser) -> ParseResult { fn for_expr(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::ForExpr, |p| { p.perform(NodeKind::ForExpr, |p| {
p.eat_assert(&NodeKind::For); p.eat_assert(&NodeKind::For);
for_pattern(p)?; for_pattern(p)?;
p.eat_expect(&NodeKind::In)?; p.eat_expect(&NodeKind::In)?;
expr(p)?; expr(p)?;
@ -668,8 +642,7 @@ fn for_expr(p: &mut Parser) -> ParseResult {
fn for_pattern(p: &mut Parser) -> ParseResult { fn for_pattern(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::ForPattern, |p| { p.perform(NodeKind::ForPattern, |p| {
ident(p)?; ident(p)?;
if p.peek() == Some(&NodeKind::Comma) { if p.eat_if(&NodeKind::Comma) {
p.eat();
ident(p)?; ident(p)?;
} }
Ok(()) Ok(())
@ -699,9 +672,8 @@ fn import_expr(p: &mut Parser) -> ParseResult {
}); });
}; };
if p.eat_expect(&NodeKind::From).is_ok() { p.eat_expect(&NodeKind::From)?;
expr(p)?; expr(p)?;
}
Ok(()) Ok(())
}) })

View File

@ -1,10 +1,14 @@
use std::ops::Range; use std::ops::Range;
use std::rc::Rc; use std::rc::Rc;
use super::{ParseResult, TokenMode, Tokens}; use super::{TokenMode, Tokens};
use crate::syntax::{ErrorPosition, Green, GreenData, GreenNode, NodeKind}; use crate::syntax::{ErrorPosition, Green, GreenData, GreenNode, NodeKind};
use crate::util::EcoString; use crate::util::EcoString;
/// Allows parser methods to use the try operator. Not exposed as the parser
/// recovers from all errors.
pub(crate) type ParseResult<T = ()> = Result<T, ()>;
/// A convenient token-based parser. /// A convenient token-based parser.
pub struct Parser<'s> { pub struct Parser<'s> {
/// The parsed file. /// The parsed file.
@ -56,59 +60,6 @@ pub enum Group {
Imports, 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) {
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>(&self, p: &mut Parser, f: F)
where
F: Fn(&Green) -> Result<(), (ErrorPosition, EcoString)>,
{
p.filter_children(self, f)
}
/// 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(),
);
}
/// 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> { impl<'s> Parser<'s> {
/// Create a new parser for the source string. /// Create a new parser for the source string.
pub fn new(src: &'s str) -> Self { pub fn new(src: &'s str) -> Self {
@ -127,40 +78,16 @@ impl<'s> Parser<'s> {
} }
} }
/// Start a nested node. /// Perform a subparse that wraps its result in a node with the given kind.
/// pub fn perform<T, F>(&mut self, kind: NodeKind, f: F) -> T
/// Each start call has to be matched with a call to `end`,
/// `end_with_custom_children`, `lift`, `abort`, or `end_or_abort`.
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>(&mut self, count: &Marker, f: F)
where where
F: Fn(&Green) -> Result<(), (ErrorPosition, EcoString)>, F: FnOnce(&mut Self) -> T,
{ {
for child in &mut self.children[count.0 ..] { let prev = std::mem::take(&mut self.children);
if !((self.tokens.mode() != TokenMode::Code let output = f(self);
|| Self::skip_type_ext(child.kind(), false)) let mut children = std::mem::replace(&mut self.children, prev);
|| child.kind().is_error())
{
if let Err((pos, msg)) = f(child) {
let inner = std::mem::take(child);
*child =
GreenNode::with_child(NodeKind::Error(pos, msg), inner).into();
}
}
}
}
/// End the current node as a node of given `kind`. // Trailing trivia should not be wrapped into the new node.
fn end(&mut self, kind: NodeKind) {
let outer = self.stack.pop().unwrap();
let mut children = std::mem::replace(&mut self.children, outer);
// have trailing whitespace continue to sit in self.children in code
// mode.
let mut remains = vec![]; let mut remains = vec![];
if self.tokens.mode() == TokenMode::Code { if self.tokens.mode() == TokenMode::Code {
let len = children.len(); let len = children.len();
@ -176,16 +103,8 @@ impl<'s> Parser<'s> {
self.children.push(GreenNode::with_children(kind, children).into()); self.children.push(GreenNode::with_children(kind, children).into());
self.children.extend(remains); self.children.extend(remains);
}
pub fn perform<T, F>(&mut self, kind: NodeKind, f: F) -> T output
where
F: FnOnce(&mut Self) -> T,
{
self.start();
let success = f(self);
self.end(kind);
success
} }
/// Eat and wrap the next token. /// Eat and wrap the next token.
@ -332,7 +251,6 @@ impl<'s> Parser<'s> {
/// This panics if the next token does not start the given group. /// This panics if the next token does not start the given group.
pub fn start_group(&mut self, kind: Group, mode: TokenMode) { pub fn start_group(&mut self, kind: Group, mode: TokenMode) {
self.groups.push(GroupEntry { kind, prev_mode: self.tokens.mode() }); self.groups.push(GroupEntry { kind, prev_mode: self.tokens.mode() });
self.tokens.set_mode(mode); self.tokens.set_mode(mode);
self.repeek(); self.repeek();
@ -534,3 +452,67 @@ impl<'s> Parser<'s> {
Marker(self.children.len()) Marker(self.children.len())
} }
} }
/// 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) {
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>(&self, p: &mut Parser, f: F)
where
F: Fn(&Green) -> Result<(), (ErrorPosition, EcoString)>,
{
for child in &mut p.children[self.0 ..] {
if !((p.tokens.mode() != TokenMode::Code
|| Parser::skip_type_ext(child.kind(), false))
|| child.kind().is_error())
{
if let Err((pos, msg)) = f(child) {
let inner = std::mem::take(child);
*child =
GreenNode::with_child(NodeKind::Error(pos, msg), inner).into();
}
}
}
}
/// 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(),
);
}
/// 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
}
}

View File

@ -114,5 +114,4 @@ This is never reached.
// An item after a star. // An item after a star.
// Should output `, a from "target.typ"`. // Should output `, a from "target.typ"`.
// Error: 10 expected keyword `from` // Error: 10 expected keyword `from`
// Error: 10 expected semicolon or line break
#import *, a from "target.typ" #import *, a from "target.typ"