diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-02-09 19:46:57 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-02-09 19:46:57 +0100 |
| commit | 06ca740d01b428f12f6bd327257cd05dce737b03 (patch) | |
| tree | 995bf8ff3a606aedecf296c9e805e11e9cd0ae8e /src/parse | |
| parent | e35bbfffcb1f84b2fb0679759152ca0a5eabfad4 (diff) | |
Split evaluation and execution 🔪
Diffstat (limited to 'src/parse')
| -rw-r--r-- | src/parse/collection.rs | 69 | ||||
| -rw-r--r-- | src/parse/mod.rs | 260 | ||||
| -rw-r--r-- | src/parse/parser.rs | 139 | ||||
| -rw-r--r-- | src/parse/resolve.rs | 13 |
4 files changed, 246 insertions, 235 deletions
diff --git a/src/parse/collection.rs b/src/parse/collection.rs index 95ca9847..162a8bd5 100644 --- a/src/parse/collection.rs +++ b/src/parse/collection.rs @@ -1,8 +1,10 @@ use super::*; /// Parse the arguments to a function call. -pub fn arguments(p: &mut Parser) -> ExprArgs { - collection(p, vec![]) +pub fn args(p: &mut Parser) -> ExprArgs { + let start = p.start(); + let items = collection(p, vec![]); + ExprArgs { span: p.span_from(start), items } } /// Parse a parenthesized group, which can be either of: @@ -16,8 +18,8 @@ pub fn parenthesized(p: &mut Parser) -> Expr { } else { collection(p, State::Unknown) }; - p.end_group(); - state.into_expr() + let span = p.end_group(); + state.into_expr(span) } /// Parse a collection. @@ -25,7 +27,7 @@ fn collection<T: Collection>(p: &mut Parser, mut collection: T) -> T { let mut missing_coma = None; while !p.eof() { - if let Some(arg) = p.span_if(argument) { + if let Some(arg) = argument(p) { collection.push_arg(p, arg); if let Some(pos) = missing_coma.take() { @@ -36,7 +38,7 @@ fn collection<T: Collection>(p: &mut Parser, mut collection: T) -> T { break; } - let behind = p.last_end(); + let behind = p.end(); if p.eat_if(Token::Comma) { collection.push_comma(); } else { @@ -50,14 +52,12 @@ fn collection<T: Collection>(p: &mut Parser, mut collection: T) -> T { /// Parse an expression or a named pair. fn argument(p: &mut Parser) -> Option<Argument> { - let first = p.span_if(expr)?; + let first = expr(p)?; if p.eat_if(Token::Colon) { - if let Expr::Ident(ident) = first.v { - let name = ident.with_span(first.span); - let expr = p.span_if(expr)?; - Some(Argument::Named(Named { name, expr })) + if let Expr::Ident(name) = first { + Some(Argument::Named(Named { name, expr: expr(p)? })) } else { - p.diag(error!(first.span, "expected identifier")); + p.diag(error!(first.span(), "expected identifier")); expr(p); None } @@ -68,13 +68,13 @@ fn argument(p: &mut Parser) -> Option<Argument> { /// Abstraction for comma-separated list of expression / named pairs. trait Collection { - fn push_arg(&mut self, p: &mut Parser, arg: Spanned<Argument>); + fn push_arg(&mut self, p: &mut Parser, arg: Argument); fn push_comma(&mut self) {} } -impl Collection for ExprArgs { - fn push_arg(&mut self, _: &mut Parser, arg: Spanned<Argument>) { - self.push(arg.v); +impl Collection for Vec<Argument> { + fn push_arg(&mut self, _: &mut Parser, arg: Argument) { + self.push(arg); } } @@ -82,38 +82,38 @@ impl Collection for ExprArgs { #[derive(Debug)] enum State { Unknown, - Expr(Spanned<Expr>), - Array(ExprArray), - Dict(ExprDict), + Expr(Expr), + Array(Vec<Expr>), + Dict(Vec<Named>), } impl State { - fn into_expr(self) -> Expr { + fn into_expr(self, span: Span) -> Expr { match self { - Self::Unknown => Expr::Array(vec![]), - Self::Expr(expr) => Expr::Group(Box::new(expr)), - Self::Array(array) => Expr::Array(array), - Self::Dict(dict) => Expr::Dict(dict), + Self::Unknown => Expr::Array(ExprArray { span, items: vec![] }), + Self::Expr(expr) => Expr::Group(ExprGroup { span, expr: Box::new(expr) }), + Self::Array(items) => Expr::Array(ExprArray { span, items }), + Self::Dict(items) => Expr::Dict(ExprDict { span, items }), } } } impl Collection for State { - fn push_arg(&mut self, p: &mut Parser, arg: Spanned<Argument>) { + fn push_arg(&mut self, p: &mut Parser, arg: Argument) { match self { - Self::Unknown => match arg.v { + Self::Unknown => match arg { Argument::Pos(expr) => *self = Self::Expr(expr), Argument::Named(named) => *self = Self::Dict(vec![named]), }, - Self::Expr(prev) => match arg.v { + Self::Expr(prev) => match arg { Argument::Pos(expr) => *self = Self::Array(vec![take(prev), expr]), Argument::Named(_) => diag(p, arg), }, - Self::Array(array) => match arg.v { + Self::Array(array) => match arg { Argument::Pos(expr) => array.push(expr), Argument::Named(_) => diag(p, arg), }, - Self::Dict(dict) => match arg.v { + Self::Dict(dict) => match arg { Argument::Pos(_) => diag(p, arg), Argument::Named(named) => dict.push(named), }, @@ -127,13 +127,16 @@ impl Collection for State { } } -fn take(expr: &mut Spanned<Expr>) -> Spanned<Expr> { +fn take(expr: &mut Expr) -> Expr { // Replace with anything, it's overwritten anyway. - std::mem::replace(expr, Spanned::zero(Expr::Bool(false))) + std::mem::replace( + expr, + Expr::Lit(Lit { span: Span::ZERO, kind: LitKind::None }), + ) } -fn diag(p: &mut Parser, arg: Spanned<Argument>) { - p.diag(error!(arg.span, "{}", match arg.v { +fn diag(p: &mut Parser, arg: Argument) { + p.diag(error!(arg.span(), "{}", match arg { Argument::Pos(_) => "expected named pair, found expression", Argument::Named(_) => "expected expression, found named pair", })); diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 3fd2cca5..2c34d7b8 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -13,10 +13,11 @@ pub use resolve::*; pub use scanner::*; pub use tokens::*; +use std::rc::Rc; + use crate::diag::Pass; use crate::syntax::*; - -use collection::{arguments, parenthesized}; +use collection::{args, parenthesized}; /// Parse a string of source code. pub fn parse(src: &str) -> Pass<Tree> { @@ -31,8 +32,8 @@ fn tree(p: &mut Parser) -> Tree { let mut at_start = true; let mut tree = vec![]; while !p.eof() { - if let Some(node) = p.span_if(|p| node(p, &mut at_start)) { - if !matches!(node.v, Node::Parbreak | Node::Space) { + if let Some(node) = node(p, &mut at_start) { + if !matches!(node, Node::Parbreak | Node::Space) { at_start = false; } tree.push(node); @@ -78,12 +79,12 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option<Node> { p.start_group(group, TokenMode::Code); let expr = primary(p); if stmt && expr.is_some() && !p.eof() { - p.expected_at("semicolon or line break", p.last_end()); + p.expected_at("semicolon or line break", p.end()); } p.end_group(); // Uneat spaces we might have eaten eagerly. - p.jump(p.last_end()); + p.jump(p.end()); return expr.map(Node::Expr); } @@ -123,28 +124,24 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option<Node> { /// Parse a heading. fn heading(p: &mut Parser) -> Node { - // Count depth. - let mut level = p.span(|p| { - p.assert(&[Token::Eq]); + let start = p.start(); + p.assert(&[Token::Eq]); - let mut level = 0u8; - while p.eat_if(Token::Eq) { - level = level.saturating_add(1); - } - level - }); + // Count depth. + let mut level: usize = 0; + while p.eat_if(Token::Eq) { + level += 1; + } - if level.v > 5 { - p.diag(warning!(level.span, "should not exceed depth 6")); - level.v = 5; + if level > 5 { + p.diag(warning!(start .. p.end(), "should not exceed depth 6")); + level = 5; } // Parse the heading contents. let mut contents = vec![]; while p.check(|t| !matches!(t, Token::Space(n) if n >= 1)) { - if let Some(node) = p.span_if(|p| node(p, &mut false)) { - contents.push(node); - } + contents.extend(node(p, &mut false)); } Node::Heading(NodeHeading { level, contents }) @@ -152,7 +149,7 @@ fn heading(p: &mut Parser) -> Node { /// Handle a raw block. fn raw(p: &mut Parser, token: TokenRaw) -> Node { - let raw = resolve::resolve_raw(token.text, token.backticks); + let raw = resolve::resolve_raw(token.text, token.backticks, p.start()); if !token.terminated { p.diag(error!(p.peek_span().end, "expected backtick(s)")); } @@ -183,10 +180,9 @@ fn bracket_call(p: &mut Parser) -> Option<Expr> { // One header is guaranteed, but there may be more (through chaining). let mut outer = vec![]; - let mut inner = p.span_if(bracket_subheader); - + let mut inner = bracket_subheader(p); while p.eat_if(Token::Pipe) { - if let Some(new) = p.span_if(bracket_subheader) { + if let Some(new) = bracket_subheader(p) { outer.extend(inner); inner = Some(new); } @@ -194,49 +190,44 @@ fn bracket_call(p: &mut Parser) -> Option<Expr> { p.end_group(); - let body = if p.peek() == Some(Token::LeftBracket) { - Some(p.span(|p| Expr::Template(bracket_body(p)))) - } else { - None + let body = match p.peek() { + Some(Token::LeftBracket) => Some(bracket_body(p)), + _ => None, }; let mut inner = inner?; if let Some(body) = body { - inner.span.expand(body.span); - inner.v.args.v.push(Argument::Pos(body)); + inner.span.expand(body.span()); + inner.args.items.push(Argument::Pos(body)); } while let Some(mut top) = outer.pop() { - let span = inner.span; - let node = inner.map(|c| Node::Expr(Expr::Call(c))); - let expr = Expr::Template(vec![node]).with_span(span); - top.v.args.v.push(Argument::Pos(expr)); + top.args.items.push(Argument::Pos(Expr::Call(inner))); inner = top; } - Some(Expr::Call(inner.v)) + Some(Expr::Call(inner)) } /// Parse one subheader of a bracketed function call. fn bracket_subheader(p: &mut Parser) -> Option<ExprCall> { p.start_group(Group::Subheader, TokenMode::Code); - - let name = p.span_if(ident); - let args = p.span(arguments); - p.end_group(); - + let name = ident(p); + let args = args(p); + let span = p.end_group(); Some(ExprCall { - callee: Box::new(name?.map(Expr::Ident)), + span, + callee: Box::new(Expr::Ident(name?)), args, }) } /// Parse the body of a bracketed function call. -fn bracket_body(p: &mut Parser) -> Tree { +fn bracket_body(p: &mut Parser) -> Expr { p.start_group(Group::Bracket, TokenMode::Markup); - let tree = tree(p); - p.end_group(); - tree + let tree = Rc::new(tree(p)); + let span = p.end_group(); + Expr::Template(ExprTemplate { span, tree }) } /// Parse an expression. @@ -246,15 +237,14 @@ fn expr(p: &mut Parser) -> Option<Expr> { /// Parse an expression with operators having at least the minimum precedence. fn expr_with(p: &mut Parser, min_prec: usize) -> Option<Expr> { - let mut lhs = match p.span_if(|p| p.eat_map(UnOp::from_token)) { + let start = p.start(); + let mut lhs = match p.eat_map(UnOp::from_token) { Some(op) => { - let prec = op.v.precedence(); - let expr = p.span_if(|p| expr_with(p, prec))?; - let span = op.span.join(expr.span); - let unary = Expr::Unary(ExprUnary { op, expr: Box::new(expr) }); - unary.with_span(span) + let prec = op.precedence(); + let expr = Box::new(expr_with(p, prec)?); + Expr::Unary(ExprUnary { span: p.span_from(start), op, expr }) } - None => p.span_if(primary)?, + None => primary(p)?, }; loop { @@ -268,95 +258,87 @@ fn expr_with(p: &mut Parser, min_prec: usize) -> Option<Expr> { break; } + p.eat(); match op.associativity() { Associativity::Left => prec += 1, Associativity::Right => {} } - let op = op.with_span(p.peek_span()); - p.eat(); - - let rhs = match p.span_if(|p| expr_with(p, prec)) { + let rhs = match expr_with(p, prec) { Some(rhs) => Box::new(rhs), None => break, }; - let span = lhs.span.join(rhs.span); - let binary = Expr::Binary(ExprBinary { lhs: Box::new(lhs), op, rhs }); - lhs = binary.with_span(span); + let span = lhs.span().join(rhs.span()); + lhs = Expr::Binary(ExprBinary { span, lhs: Box::new(lhs), op, rhs }); } - Some(lhs.v) + Some(lhs) } /// Parse a primary expression. fn primary(p: &mut Parser) -> Option<Expr> { - let expr = match p.peek() { - // Basic values. - Some(Token::None) => Expr::None, - Some(Token::Bool(b)) => Expr::Bool(b), - Some(Token::Int(i)) => Expr::Int(i), - Some(Token::Float(f)) => Expr::Float(f), - Some(Token::Length(val, unit)) => Expr::Length(val, unit), - Some(Token::Angle(val, unit)) => Expr::Angle(val, unit), - Some(Token::Percent(p)) => Expr::Percent(p), - Some(Token::Color(color)) => Expr::Color(color), - Some(Token::Str(token)) => Expr::Str(string(p, token)), + if let Some(expr) = literal(p) { + return Some(expr); + } + match p.peek() { // Function or identifier. - Some(Token::Ident(id)) => { - p.eat(); - let ident = Ident(id.into()); + Some(Token::Ident(string)) => { + let ident = Ident { + span: p.eat_span(), + string: string.into(), + }; if p.peek() == Some(Token::LeftParen) { - let name = ident.with_span(p.peek_span()); - return Some(paren_call(p, name)); + Some(paren_call(p, ident)) } else { - return Some(Expr::Ident(ident)); + Some(Expr::Ident(ident)) } } // Keywords. - Some(Token::Let) => return expr_let(p), - Some(Token::If) => return expr_if(p), - Some(Token::For) => return expr_for(p), - - // Block. - Some(Token::LeftBrace) => { - return block(p, true); - } - - // Template. - Some(Token::LeftBracket) => { - return Some(template(p)); - } + Some(Token::Let) => expr_let(p), + Some(Token::If) => expr_if(p), + Some(Token::For) => expr_for(p), - // Function template. - Some(Token::HashBracket) => { - let call = p.span_if(bracket_call)?.map(Node::Expr); - return Some(Expr::Template(vec![call])); - } - - // Array, dictionary or parenthesized expression. - Some(Token::LeftParen) => { - return Some(parenthesized(p)); - } + // Structures. + Some(Token::LeftBrace) => block(p, true), + Some(Token::LeftBracket) => Some(template(p)), + Some(Token::HashBracket) => bracket_call(p), + Some(Token::LeftParen) => Some(parenthesized(p)), // Nothing. _ => { p.expected("expression"); - return None; + None } + } +} + +/// Parse a literal. +fn literal(p: &mut Parser) -> Option<Expr> { + let kind = match p.peek()? { + // Basic values. + Token::None => LitKind::None, + Token::Bool(b) => LitKind::Bool(b), + Token::Int(i) => LitKind::Int(i), + Token::Float(f) => LitKind::Float(f), + Token::Length(val, unit) => LitKind::Length(val, unit), + Token::Angle(val, unit) => LitKind::Angle(val, unit), + Token::Percent(p) => LitKind::Percent(p), + Token::Color(color) => LitKind::Color(color), + Token::Str(token) => LitKind::Str(string(p, token)), + _ => return None, }; - p.eat(); - Some(expr) + Some(Expr::Lit(Lit { span: p.eat_span(), kind })) } // Parse a template value: `[...]`. fn template(p: &mut Parser) -> Expr { p.start_group(Group::Bracket, TokenMode::Markup); - let tree = tree(p); - p.end_group(); - Expr::Template(tree) + let tree = Rc::new(tree(p)); + let span = p.end_group(); + Expr::Template(ExprTemplate { span, tree }) } /// Parse a block expression: `{...}`. @@ -365,26 +347,27 @@ fn block(p: &mut Parser, scopes: bool) -> Option<Expr> { let mut exprs = vec![]; while !p.eof() { p.start_group(Group::Stmt, TokenMode::Code); - if let Some(expr) = p.span_if(expr) { + if let Some(expr) = expr(p) { exprs.push(expr); if !p.eof() { - p.expected_at("semicolon or line break", p.last_end()); + p.expected_at("semicolon or line break", p.end()); } } p.end_group(); p.skip_white(); } - p.end_group(); - Some(Expr::Block(ExprBlock { exprs, scopes })) + let span = p.end_group(); + Some(Expr::Block(ExprBlock { span, exprs, scoping: scopes })) } /// Parse a parenthesized function call. -fn paren_call(p: &mut Parser, name: Spanned<Ident>) -> Expr { +fn paren_call(p: &mut Parser, name: Ident) -> Expr { p.start_group(Group::Paren, TokenMode::Code); - let args = p.span(arguments); + let args = args(p); p.end_group(); Expr::Call(ExprCall { - callee: Box::new(name.map(Expr::Ident)), + span: p.span_from(name.span.start), + callee: Box::new(Expr::Ident(name)), args, }) } @@ -394,22 +377,26 @@ fn string(p: &mut Parser, token: TokenStr) -> String { if !token.terminated { p.expected_at("quote", p.peek_span().end); } - resolve::resolve_string(token.string) } /// Parse a let expression. fn expr_let(p: &mut Parser) -> Option<Expr> { + let start = p.start(); p.assert(&[Token::Let]); let mut expr_let = None; - if let Some(pat) = p.span_if(ident) { + if let Some(binding) = ident(p) { let mut init = None; if p.eat_if(Token::Eq) { - init = p.span_if(expr); + init = expr(p); } - expr_let = Some(Expr::Let(ExprLet { pat, init: init.map(Box::new) })) + expr_let = Some(Expr::Let(ExprLet { + span: p.span_from(start), + binding, + init: init.map(Box::new), + })) } expr_let @@ -417,17 +404,19 @@ fn expr_let(p: &mut Parser) -> Option<Expr> { /// Parse an if expresion. fn expr_if(p: &mut Parser) -> Option<Expr> { + let start = p.start(); p.assert(&[Token::If]); let mut expr_if = None; - if let Some(condition) = p.span_if(expr) { - if let Some(if_body) = p.span_if(body) { + if let Some(condition) = expr(p) { + if let Some(if_body) = body(p) { let mut else_body = None; if p.eat_if(Token::Else) { - else_body = p.span_if(body); + else_body = body(p); } expr_if = Some(Expr::If(ExprIf { + span: p.span_from(start), condition: Box::new(condition), if_body: Box::new(if_body), else_body: else_body.map(Box::new), @@ -440,15 +429,17 @@ fn expr_if(p: &mut Parser) -> Option<Expr> { /// Parse a for expression. fn expr_for(p: &mut Parser) -> Option<Expr> { + let start = p.start(); p.assert(&[Token::For]); let mut expr_for = None; - if let Some(pat) = p.span_if(for_pattern) { + if let Some(pattern) = for_pattern(p) { if p.expect(Token::In) { - if let Some(iter) = p.span_if(expr) { - if let Some(body) = p.span_if(body) { + if let Some(iter) = expr(p) { + if let Some(body) = body(p) { expr_for = Some(Expr::For(ExprFor { - pat, + span: p.span_from(start), + pattern, iter: Box::new(iter), body: Box::new(body), })); @@ -473,15 +464,14 @@ fn for_pattern(p: &mut Parser) -> Option<ForPattern> { /// Parse an identifier. fn ident(p: &mut Parser) -> Option<Ident> { - match p.peek() { - Some(Token::Ident(id)) => { - p.eat(); - Some(Ident(id.into())) - } - _ => { - p.expected("identifier"); - None - } + if let Some(Token::Ident(string)) = p.peek() { + Some(Ident { + span: p.eat_span(), + string: string.to_string(), + }) + } else { + p.expected("identifier"); + None } } @@ -491,7 +481,7 @@ fn body(p: &mut Parser) -> Option<Expr> { Some(Token::LeftBracket) => Some(template(p)), Some(Token::LeftBrace) => block(p, true), _ => { - p.expected_at("body", p.last_end()); + p.expected_at("body", p.end()); None } } diff --git a/src/parse/parser.rs b/src/parse/parser.rs index 986a36b0..a64e39dd 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -3,7 +3,7 @@ use std::fmt::{self, Debug, Formatter}; use super::{Scanner, TokenMode, Tokens}; use crate::diag::Diag; use crate::diag::{Deco, Feedback}; -use crate::syntax::{Pos, Span, Spanned, Token, WithSpan}; +use crate::syntax::{Pos, Span, Spanned, Token}; /// A convenient token-based parser. pub struct Parser<'s> { @@ -18,14 +18,43 @@ pub struct Parser<'s> { next_start: Pos, /// The end position of the last (non-whitespace if in code mode) token. last_end: Pos, - /// The stack of modes we were in. - modes: Vec<TokenMode>, /// The stack of open groups. - groups: Vec<Group>, + groups: Vec<GroupEntry>, /// Accumulated feedback. feedback: Feedback, } +/// A logical group of tokens, e.g. `[...]`. +struct GroupEntry { + /// The start position of the group. Used by `Parser::end_group` to return + /// The group's full span. + start: Pos, + /// The kind of group this is. This decides which tokens will end the group. + /// For example, a [`GroupKind::Paren`] will be ended by + /// [`Token::RightParen`]. + kind: Group, + /// The mode the parser was in _before_ the group started. + prev_mode: TokenMode, +} + +/// A group, confined by optional start and end delimiters. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum Group { + /// A parenthesized group: `(...)`. + Paren, + /// A bracketed group: `[...]`. + Bracket, + /// A curly-braced group: `{...}`. + Brace, + /// A group ended by a chained subheader or a closing bracket: + /// `... >>`, `...]`. + Subheader, + /// A group ended by a semicolon or a line break: `;`, `\n`. + Stmt, + /// A group for a single expression. Not ended by something specific. + Expr, +} + impl<'s> Parser<'s> { /// Create a new parser for the source string. pub fn new(src: &'s str) -> Self { @@ -37,7 +66,6 @@ impl<'s> Parser<'s> { peeked: next, next_start: Pos::ZERO, last_end: Pos::ZERO, - modes: vec![], groups: vec![], feedback: Feedback::new(), } @@ -97,14 +125,17 @@ impl<'s> Parser<'s> { /// /// # Panics /// This panics if the next token does not start the given group. - pub fn start_group(&mut self, group: Group, mode: TokenMode) { - self.modes.push(self.tokens.mode()); - self.tokens.set_mode(mode); + pub fn start_group(&mut self, kind: Group, mode: TokenMode) { + self.groups.push(GroupEntry { + start: self.next_start, + kind, + prev_mode: self.tokens.mode(), + }); - self.groups.push(group); + self.tokens.set_mode(mode); self.repeek(); - match group { + match kind { Group::Paren => self.assert(&[Token::LeftParen]), Group::Bracket => self.assert(&[Token::HashBracket, Token::LeftBracket]), Group::Brace => self.assert(&[Token::LeftBrace]), @@ -118,15 +149,16 @@ impl<'s> Parser<'s> { /// /// # Panics /// This panics if no group was started. - pub fn end_group(&mut self) { + pub fn end_group(&mut self) -> Span { let prev_mode = self.tokens.mode(); - self.tokens.set_mode(self.modes.pop().expect("no pushed mode")); - let group = self.groups.pop().expect("no started group"); + self.tokens.set_mode(group.prev_mode); self.repeek(); + let mut rescan = self.tokens.mode() != prev_mode; + // Eat the end delimiter if there is one. - if let Some((end, required)) = match group { + if let Some((end, required)) = match group.kind { Group::Paren => Some((Token::RightParen, true)), Group::Bracket => Some((Token::RightBracket, true)), Group::Brace => Some((Token::RightBrace, true)), @@ -137,37 +169,19 @@ impl<'s> Parser<'s> { if self.next == Some(end) { // Bump the delimeter and return. No need to rescan in this case. self.bump(); - return; + rescan = false; } else if required { self.diag(error!(self.next_start, "expected {}", end.name())); } } // Rescan the peeked token if the mode changed. - if self.tokens.mode() != prev_mode { + if rescan { self.tokens.jump(self.last_end); self.bump(); } - } - - /// Execute `f` and return the result alongside the span of everything `f` - /// ate. Excludes leading and trailing whitespace in code mode. - pub fn span<T, F>(&mut self, f: F) -> Spanned<T> - where - F: FnOnce(&mut Self) -> T, - { - let start = self.next_start; - let output = f(self); - let end = self.last_end; - output.with_span(start .. end) - } - /// A version of [`span`](Self::span) that works better with options. - pub fn span_if<T, F>(&mut self, f: F) -> Option<Spanned<T>> - where - F: FnOnce(&mut Self) -> Option<T>, - { - self.span(f).transpose() + Span::new(group.start, self.last_end) } /// Consume the next token. @@ -200,6 +214,13 @@ impl<'s> Parser<'s> { mapped } + /// Eat the next token and return its span. + pub fn eat_span(&mut self) -> Span { + let start = self.next_start; + self.eat(); + Span::new(start, self.last_end) + } + /// Consume the next token if it is the given one and produce an error if /// not. pub fn expect(&mut self, t: Token) -> bool { @@ -264,17 +285,22 @@ impl<'s> Parser<'s> { } /// The position at which the next token starts. - pub fn next_start(&self) -> Pos { + pub fn start(&self) -> Pos { self.next_start } /// The position at which the last token ended. /// /// Refers to the end of the last _non-whitespace_ token in code mode. - pub fn last_end(&self) -> Pos { + pub fn end(&self) -> Pos { self.last_end } + /// The span from + pub fn span_from(&self, start: Pos) -> Span { + Span::new(start, self.last_end) + } + /// Jump to a position in the source string. pub fn jump(&mut self, pos: Pos) { self.tokens.jump(pos); @@ -325,13 +351,14 @@ impl<'s> Parser<'s> { None => return, }; + let inside = |x| self.kinds().any(|k| k == x); match token { - Token::RightParen if self.groups.contains(&Group::Paren) => {} - Token::RightBracket if self.groups.contains(&Group::Bracket) => {} - Token::RightBrace if self.groups.contains(&Group::Brace) => {} - Token::Semicolon if self.groups.contains(&Group::Stmt) => {} + Token::RightParen if inside(Group::Paren) => {} + Token::RightBracket if inside(Group::Bracket) => {} + Token::RightBrace if inside(Group::Brace) => {} + Token::Semicolon if inside(Group::Stmt) => {} + Token::Pipe if inside(Group::Subheader) => {} Token::Space(n) if n >= 1 && self.in_line_group() => {} - Token::Pipe if self.groups.contains(&Group::Subheader) => {} _ => return, } @@ -340,7 +367,15 @@ impl<'s> Parser<'s> { /// Whether the active group ends at a newline. fn in_line_group(&self) -> bool { - matches!(self.groups.last(), Some(&Group::Stmt) | Some(&Group::Expr)) + matches!( + self.kinds().next_back(), + Some(Group::Stmt) | Some(Group::Expr) + ) + } + + /// The outer groups. + fn kinds(&self) -> impl DoubleEndedIterator<Item = Group> + '_ { + self.groups.iter().map(|group| group.kind) } } @@ -350,21 +385,3 @@ impl Debug for Parser<'_> { write!(f, "Parser({}|{})", s.eaten(), s.rest()) } } - -/// A group, confined by optional start and end delimiters. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum Group { - /// A parenthesized group: `(...)`. - Paren, - /// A bracketed group: `[...]`. - Bracket, - /// A curly-braced group: `{...}`. - Brace, - /// A group ended by a chained subheader or a closing bracket: - /// `... >>`, `...]`. - Subheader, - /// A group ended by a semicolon or a line break: `;`, `\n`. - Stmt, - /// A group for a single expression. Not ended by something specific. - Expr, -} diff --git a/src/parse/resolve.rs b/src/parse/resolve.rs index a5e831da..4592acbc 100644 --- a/src/parse/resolve.rs +++ b/src/parse/resolve.rs @@ -1,5 +1,5 @@ use super::{is_newline, Scanner}; -use crate::syntax::{Ident, NodeRaw}; +use crate::syntax::{Ident, NodeRaw, Offset, Pos}; /// Resolve all escape sequences in a string. pub fn resolve_string(string: &str) -> String { @@ -47,12 +47,12 @@ pub fn resolve_hex(sequence: &str) -> Option<char> { } /// Resolve the language tag and trims the raw text. -pub fn resolve_raw(text: &str, backticks: usize) -> NodeRaw { +pub fn resolve_raw(text: &str, backticks: usize, start: Pos) -> NodeRaw { if backticks > 1 { let (tag, inner) = split_at_lang_tag(text); let (lines, had_newline) = trim_and_split_raw(inner); NodeRaw { - lang: Ident::new(tag), + lang: Ident::new(tag, start .. start.offset(tag.len())), lines, block: had_newline, } @@ -125,6 +125,7 @@ pub fn split_lines(text: &str) -> Vec<String> { #[cfg(test)] #[rustfmt::skip] mod tests { + use crate::syntax::Span; use super::*; #[test] @@ -173,11 +174,11 @@ mod tests { lines: &[&str], block: bool, ) { - assert_eq!(resolve_raw(raw, backticks), NodeRaw { - lang: lang.map(|id| Ident(id.into())), + Span::without_cmp(|| assert_eq!(resolve_raw(raw, backticks, Pos(0)), NodeRaw { + lang: lang.and_then(|id| Ident::new(id, 0)), lines: lines.iter().map(ToString::to_string).collect(), block, - }); + })); } // Just one backtick. |
