From e63ce52ae0d929506a1fa238477f039d14d53813 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 4 Feb 2020 19:22:23 +0100 Subject: =?UTF-8?q?Merge=20`Parsed`=20and=20`Layouted`=20types=20into=20`P?= =?UTF-8?q?ass`=20with=20`Feedback`=20=F0=9F=8C=9D=F0=9F=8E=A2=F0=9F=8C=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/syntax/mod.rs | 18 ++++-------- src/syntax/parsing.rs | 78 +++++++++++++++------------------------------------ src/syntax/scope.rs | 5 ++-- src/syntax/span.rs | 5 ++-- src/syntax/test.rs | 4 +-- 5 files changed, 35 insertions(+), 75 deletions(-) (limited to 'src/syntax') diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index cfa4c2e5..8596a618 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -5,7 +5,8 @@ use std::fmt::Debug; use async_trait::async_trait; use serde::Serialize; -use crate::layout::{LayoutContext, Layouted, Commands, Command}; +use crate::{Pass, Feedback}; +use crate::layout::{LayoutContext, Commands, Command}; use self::span::{Spanned, SpanVec}; pub mod expr; @@ -25,10 +26,7 @@ mod test; pub trait Model: Debug + ModelBounds { /// Layout the model into a sequence of commands processed by a /// [`ModelLayouter`](crate::layout::ModelLayouter). - async fn layout<'a>( - &'a self, - ctx: LayoutContext<'_>, - ) -> Layouted>; + async fn layout<'a>(&'a self, ctx: LayoutContext<'_>) -> Pass>; } /// A tree representation of source code. @@ -52,14 +50,8 @@ impl SyntaxModel { #[async_trait(?Send)] impl Model for SyntaxModel { - async fn layout<'a>( - &'a self, - _: LayoutContext<'_>, - ) -> Layouted> { - Layouted { - output: vec![Command::LayoutSyntaxModel(self)], - errors: vec![], - } + async fn layout<'a>(&'a self, _: LayoutContext<'_>) -> Pass> { + Pass::new(vec![Command::LayoutSyntaxModel(self)], Feedback::new()) } } diff --git a/src/syntax/parsing.rs b/src/syntax/parsing.rs index 03866c2c..1526a5cb 100644 --- a/src/syntax/parsing.rs +++ b/src/syntax/parsing.rs @@ -1,10 +1,10 @@ //! Parsing of source code into syntax models. -use crate::error::Errors; +use crate::{Pass, Feedback}; use super::expr::*; use super::func::{FuncHeader, FuncArgs, FuncArg}; use super::scope::Scope; -use super::span::{Position, Span, Spanned, SpanVec, offset_spans}; +use super::span::{Position, Span, Spanned}; use super::tokens::{Token, Tokens, TokenizationMode}; use super::*; @@ -16,36 +16,12 @@ pub struct ParseContext<'a> { pub scope: &'a Scope, } -/// The result of parsing: Some parsed thing, errors and decorations for syntax -/// highlighting. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Parsed { - /// The result of the parsing process. - pub output: T, - /// Errors that arose in the parsing process. - pub errors: Errors, - /// Decorations for semantic syntax highlighting. - pub decorations: SpanVec, -} - -impl Parsed { - /// Map the output type and keep errors and decorations. - pub fn map(self, f: F) -> Parsed where F: FnOnce(T) -> U { - Parsed { - output: f(self.output), - errors: self.errors, - decorations: self.decorations, - } - } -} - /// Parse source code into a syntax model. /// /// All errors and decorations are offset by the `start` position. -pub fn parse(start: Position, src: &str, ctx: ParseContext) -> Parsed { +pub fn parse(start: Position, src: &str, ctx: ParseContext) -> Pass { let mut model = SyntaxModel::new(); - let mut errors = Vec::new(); - let mut decorations = Vec::new(); + let mut feedback = Feedback::new(); // We always start in body mode. The header tokenization mode is only used // in the `FuncParser`. @@ -64,16 +40,12 @@ pub fn parse(start: Position, src: &str, ctx: ParseContext) -> Parsed { - let parsed: Parsed = FuncParser::new(header, body, ctx).parse(); - - // Collect the errors and decorations from the function parsing, - // but offset their spans by the start of the function since - // they are function-local. - errors.extend(offset_spans(parsed.errors, span.start)); - decorations.extend(offset_spans(parsed.decorations, span.start)); + let parsed = FuncParser::new(header, body, ctx).parse(); + feedback.extend_offset(span.start, parsed.feedback); if !terminated { - errors.push(err!(Span::at(span.end); "expected closing bracket")); + feedback.errors.push(err!(Span::at(span.end); + "expected closing bracket")); } parsed.output @@ -87,7 +59,7 @@ pub fn parse(start: Position, src: &str, ctx: ParseContext) -> Parsed continue, other => { - errors.push(err!(span; "unexpected {}", other.name())); + feedback.errors.push(err!(span; "unexpected {}", other.name())); continue; } }; @@ -95,14 +67,13 @@ pub fn parse(start: Position, src: &str, ctx: ParseContext) -> Parsed { ctx: ParseContext<'s>, - errors: Errors, - decorations: SpanVec, + feedback: Feedback, /// ```typst /// [tokens][body] @@ -129,8 +100,7 @@ impl<'s> FuncParser<'s> { ) -> FuncParser<'s> { FuncParser { ctx, - errors: vec![], - decorations: vec![], + feedback: Feedback::new(), tokens: Tokens::new(Position::new(0, 1), header, TokenizationMode::Header), peeked: None, body, @@ -138,7 +108,7 @@ impl<'s> FuncParser<'s> { } /// Do the parsing. - fn parse(mut self) -> Parsed { + fn parse(mut self) -> Pass { let parsed = if let Some(header) = self.parse_func_header() { let name = header.name.v.as_str(); let (parser, deco) = match self.ctx.scope.get_parser(name) { @@ -147,12 +117,12 @@ impl<'s> FuncParser<'s> { // The fallback parser was returned. Invalid function. Err(parser) => { - self.errors.push(err!(header.name.span; "unknown function")); + self.feedback.errors.push(err!(header.name.span; "unknown function")); (parser, Decoration::InvalidFuncName) } }; - self.decorations.push(Spanned::new(deco, header.name.span)); + self.feedback.decos.push(Spanned::new(deco, header.name.span)); parser(header, self.body, self.ctx) } else { @@ -166,14 +136,9 @@ impl<'s> FuncParser<'s> { self.ctx.scope.get_fallback_parser()(default, self.body, self.ctx) }; - self.errors.extend(parsed.errors); - self.decorations.extend(parsed.decorations); + self.feedback.extend(parsed.feedback); - Parsed { - output: Node::Model(parsed.output), - errors: self.errors, - decorations: self.decorations, - } + Pass::new(Node::Model(parsed.output), self.feedback) } /// Parse the header tokens. @@ -235,7 +200,7 @@ impl<'s> FuncParser<'s> { self.eat(); self.skip_whitespace(); - self.decorations.push(Spanned::new(Decoration::ArgumentKey, span)); + self.feedback.decos.push(Spanned::new(Decoration::ArgumentKey, span)); self.parse_expr().map(|value| { FuncArg::Key(Pair { @@ -332,14 +297,14 @@ impl<'s> FuncParser<'s> { /// Add an error about an expected `thing` which was not found, showing /// what was found instead. fn expected_found(&mut self, thing: &str, found: Spanned) { - self.errors.push(err!(found.span; + self.feedback.errors.push(err!(found.span; "expected {}, found {}", thing, found.v.name())); } /// Add an error about an `thing` which was expected but not found at the /// given position. fn expected_at(&mut self, thing: &str, pos: Position) { - self.errors.push(err!(Span::at(pos); "expected {}", thing)); + self.feedback.errors.push(err!(Span::at(pos); "expected {}", thing)); } /// Add a expected-found-error if `found` is `Some` and an expected-error @@ -434,7 +399,8 @@ mod tests { macro_rules! e { ($s:expr => [$(($sl:tt:$sc:tt, $el:tt:$ec:tt, $e:expr)),* $(,)?]) => { let ctx = ParseContext { scope: &scope() }; - let errors = parse(Position::ZERO, $s, ctx).errors + let errors = parse(Position::ZERO, $s, ctx).feedback + .errors .into_iter() .map(|s| s.map(|e| e.message)) .collect::>(); diff --git a/src/syntax/scope.rs b/src/syntax/scope.rs index 551d0684..f7b20b9f 100644 --- a/src/syntax/scope.rs +++ b/src/syntax/scope.rs @@ -3,9 +3,10 @@ use std::collections::HashMap; use std::fmt::{self, Debug, Formatter}; +use crate::Pass; use crate::func::ParseFunc; use super::func::FuncHeader; -use super::parsing::{ParseContext, Parsed}; +use super::parsing::ParseContext; use super::span::Spanned; use super::Model; @@ -75,7 +76,7 @@ type Parser = dyn Fn( FuncHeader, Option>, ParseContext, -) -> Parsed>; +) -> Pass>; fn parser(metadata: ::Meta) -> Box where F: ParseFunc + Model + 'static { diff --git a/src/syntax/span.rs b/src/syntax/span.rs index 8973ef89..3c55daa1 100644 --- a/src/syntax/span.rs +++ b/src/syntax/span.rs @@ -160,6 +160,7 @@ pub type SpanVec = Vec>; /// [Offset](Span::offset) all spans in a vector of spanned things by a start /// position. -pub fn offset_spans(vec: SpanVec, start: Position) -> impl Iterator> { - vec.into_iter().map(move |s| s.map_span(|span| span.offset(start))) +pub fn offset_spans(start: Position, vec: SpanVec) -> impl Iterator> { + vec.into_iter() + .map(move |s| s.map_span(|span| span.offset(start))) } diff --git a/src/syntax/test.rs b/src/syntax/test.rs index e37e8cf5..df354768 100644 --- a/src/syntax/test.rs +++ b/src/syntax/test.rs @@ -12,13 +12,13 @@ function! { pub body: Option, } - parse(header, body, ctx, errors, decos) { + parse(header, body, ctx, f) { let cloned = header.clone(); header.args.pos.items.clear(); header.args.key.pairs.clear(); DebugFn { header: cloned, - body: body!(opt: body, ctx, errors, decos), + body: body!(opt: body, ctx, f), } } -- cgit v1.2.3