From d2e220245d9c17a0ac8c3474984924f65ed6b835 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Wed, 7 Oct 2020 18:24:47 +0200 Subject: [PATCH] =?UTF-8?q?Move=20deco,=20pass=20and=20feedback=20into=20d?= =?UTF-8?q?iagnostics=20module=20=E2=86=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/src/main.rs | 3 +- src/diag.rs | 79 +++++++++++++++++++++++++++++++++++- src/eval/mod.rs | 4 +- src/eval/state.rs | 2 +- src/eval/value.rs | 3 +- src/layout/mod.rs | 4 +- src/layout/nodes/par.rs | 14 ------- src/layout/nodes/spacing.rs | 4 +- src/layout/nodes/stack.rs | 21 ---------- src/lib.rs | 80 +------------------------------------ src/library/page.rs | 4 +- src/parse/mod.rs | 4 +- src/parse/parser.rs | 4 +- src/parse/tests.rs | 1 + src/prelude.rs | 3 +- src/syntax/mod.rs | 17 -------- tests/test_typeset.rs | 3 +- 17 files changed, 99 insertions(+), 151 deletions(-) diff --git a/main/src/main.rs b/main/src/main.rs index 126dbf8b1..c2bc6d132 100644 --- a/main/src/main.rs +++ b/main/src/main.rs @@ -7,11 +7,12 @@ use std::rc::Rc; use fontdock::fs::{FsIndex, FsProvider}; use futures_executor::block_on; +use typstc::diag::{Feedback, Pass}; use typstc::eval::State; use typstc::export::pdf; use typstc::font::FontLoader; use typstc::parse::LineMap; -use typstc::{typeset, Feedback, Pass}; +use typstc::typeset; fn main() { let args: Vec<_> = std::env::args().collect(); diff --git a/src/diag.rs b/src/diag.rs index 8ad41b136..431ad4502 100644 --- a/src/diag.rs +++ b/src/diag.rs @@ -1,11 +1,71 @@ -//! Diagnostics for source code. +//! Diagnostics and decorations for source code. //! //! There are no fatal errors. The document will always compile and yield a //! layout on a best effort process, but diagnostics are nevertheless generated //! for incorrect things. +use crate::syntax::SpanVec; use std::fmt::{self, Display, Formatter}; +/// The result of some pass: Some output `T` and [feedback] data. +/// +/// [feedback]: struct.Feedback.html +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Pass { + /// The output of this compilation pass. + pub output: T, + /// User feedback data accumulated in this pass. + pub feedback: Feedback, +} + +impl Pass { + /// Create a new pass from output and feedback data. + pub fn new(output: T, feedback: Feedback) -> Self { + Self { output, feedback } + } + + /// Create a new pass with empty feedback. + pub fn okay(output: T) -> Self { + Self { output, feedback: Feedback::new() } + } + + /// Map the output type and keep the feedback data. + pub fn map(self, f: impl FnOnce(T) -> U) -> Pass { + Pass { + output: f(self.output), + feedback: self.feedback, + } + } +} + +/// Diagnostic and semantic syntax highlighting data. +#[derive(Debug, Default, Clone, Eq, PartialEq)] +pub struct Feedback { + /// Diagnostics about the source code. + pub diags: SpanVec, + /// Decorations of the source code for semantic syntax highlighting. + pub decos: SpanVec, +} + +impl Feedback { + /// Create a new feedback instance without errors and decos. + pub fn new() -> Self { + Self { diags: vec![], decos: vec![] } + } + + /// Merge two feedbacks into one. + pub fn join(mut a: Self, b: Self) -> Self { + a.extend(b); + a + } + + /// Add other feedback data to this feedback. + pub fn extend(&mut self, more: Self) { + self.diags.extend(more.diags); + self.decos.extend(more.decos); + } +} + /// A diagnostic that arose in parsing or layouting. #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] @@ -41,6 +101,23 @@ impl Display for Level { } } +/// Decorations for semantic syntax highlighting. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize))] +#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))] +pub enum Deco { + /// Emphasized text. + Emph, + /// Strong text. + Strong, + /// A valid, successfully resolved name. + Resolved, + /// An invalid, unresolved name. + Unresolved, + /// A key in a dictionary. + DictKey, +} + /// Construct a diagnostic with [`Error`] level. /// /// ``` diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 101d26d96..c7d9c2a62 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -18,17 +18,15 @@ use std::any::Any; use std::mem; use std::rc::Rc; -use async_trait::async_trait; use fontdock::FontStyle; use crate::diag::Diag; -use crate::geom::Size; +use crate::diag::{Deco, Feedback, Pass}; use crate::layout::nodes::{ Document, LayoutNode, Pad, Pages, Par, Softness, Spacing, Stack, Text, }; use crate::layout::{Gen2, Spec2, Switch}; use crate::syntax::*; -use crate::{Feedback, Pass}; /// Evaluate a syntax tree into a document. /// diff --git a/src/eval/state.rs b/src/eval/state.rs index 5861ada11..7372b8513 100644 --- a/src/eval/state.rs +++ b/src/eval/state.rs @@ -5,7 +5,7 @@ use std::rc::Rc; use fontdock::{fallback, FallbackTree, FontStretch, FontStyle, FontVariant, FontWeight}; use super::Scope; -use crate::geom::{Insets, Linear, Size}; +use crate::geom::{Linear, Size}; use crate::layout::{Dir, Gen2, GenAlign, Sides}; use crate::length::Length; use crate::paper::{Paper, PaperClass, PAPER_A4}; diff --git a/src/eval/value.rs b/src/eval/value.rs index 37fd7ead0..8eea90dff 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -7,8 +7,7 @@ use std::rc::Rc; use super::{Args, Dict, Eval, EvalContext, SpannedEntry}; use crate::color::RgbaColor; use crate::geom::Linear; -use crate::syntax::{Ident, Span, SpanWith, Spanned, SynNode, SynTree}; -use crate::DynFuture; +use crate::syntax::{Ident, SynTree}; /// A computational value. #[derive(Clone, PartialEq)] diff --git a/src/layout/mod.rs b/src/layout/mod.rs index f709da1a1..bfd633d8c 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -7,11 +7,9 @@ pub use primitive::*; use async_trait::async_trait; -use crate::eval::{PageState, State, TextState}; use crate::font::SharedFontLoader; -use crate::geom::{Insets, Point, Rect, Size, SizeExt}; +use crate::geom::{Point, Rect, Size, SizeExt}; use crate::shaping::Shaped; -use crate::syntax::SynTree; use nodes::Document; diff --git a/src/layout/nodes/par.rs b/src/layout/nodes/par.rs index 38b115295..d0a58c490 100644 --- a/src/layout/nodes/par.rs +++ b/src/layout/nodes/par.rs @@ -182,20 +182,6 @@ impl LineLayouter { usable } - /// Update the layouting spaces. - /// - /// If `replace_empty` is true, the current space is replaced if there are - /// no boxes laid out into it yet. Otherwise, the followup spaces are - /// replaced. - fn set_spaces(&mut self, spaces: Vec, replace_empty: bool) { - self.stack.set_spaces(spaces, replace_empty && self.line_is_empty()); - } - - /// Update the line spacing. - fn set_line_spacing(&mut self, line_spacing: f64) { - self.ctx.line_spacing = line_spacing; - } - /// The remaining inner spaces. If something is laid out into these spaces, /// it will fit into this layouter's underlying stack. fn remaining(&self) -> Vec { diff --git a/src/layout/nodes/spacing.rs b/src/layout/nodes/spacing.rs index 66af0d177..9d72f7ca2 100644 --- a/src/layout/nodes/spacing.rs +++ b/src/layout/nodes/spacing.rs @@ -13,8 +13,8 @@ pub struct Spacing { impl Layout for Spacing { async fn layout( &self, - ctx: &mut LayoutContext, - constraints: LayoutConstraints, + _: &mut LayoutContext, + _: LayoutConstraints, ) -> Vec { vec![LayoutItem::Spacing(self.amount)] } diff --git a/src/layout/nodes/stack.rs b/src/layout/nodes/stack.rs index 983175b83..343f44613 100644 --- a/src/layout/nodes/stack.rs +++ b/src/layout/nodes/stack.rs @@ -1,5 +1,4 @@ use super::*; -use crate::geom::Linear; /// A node that stacks and aligns its children. /// @@ -158,21 +157,6 @@ impl StackLayouter { *self.space.usable.get_mut(self.ctx.dirs.main.axis()) -= added.main; } - /// Update the layouting spaces. - /// - /// If `replace_empty` is true, the current space is replaced if there are - /// no boxes laid out into it yet. Otherwise, the followup spaces are - /// replaced. - pub fn set_spaces(&mut self, spaces: Vec, replace_empty: bool) { - if replace_empty && self.space_is_empty() { - self.ctx.spaces = spaces; - self.start_space(0, self.space.hard); - } else { - self.ctx.spaces.truncate(self.space.index + 1); - self.ctx.spaces.extend(spaces); - } - } - /// Move to the first space that can fit the given size or do nothing /// if no space is capable of that. pub fn skip_to_fitting_space(&mut self, size: Size) { @@ -208,11 +192,6 @@ impl StackLayouter { self.space.used == Size::ZERO && self.space.layouts.is_empty() } - /// Whether the current layout space is the last in the followup list. - pub fn space_is_last(&self) -> bool { - self.space.index == self.ctx.spaces.len() - 1 - } - /// Finish everything up and return the final collection of boxes. pub fn finish(mut self) -> Vec { if self.space.hard || !self.space_is_empty() { diff --git a/src/lib.rs b/src/lib.rs index 6380b9292..22e3b988e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,11 +28,8 @@ //! [export]: export/index.html //! [_PDF_]: export/pdf/index.html -#![allow(unused)] - #[macro_use] pub mod diag; - pub mod color; pub mod eval; pub mod export; @@ -47,17 +44,12 @@ pub mod prelude; pub mod shaping; pub mod syntax; -use std::fmt::Debug; -use std::future::Future; -use std::pin::Pin; - -use crate::diag::Diag; +use crate::diag::{Feedback, Pass}; use crate::eval::State; use crate::font::SharedFontLoader; use crate::layout::BoxLayout; -use crate::syntax::{Deco, Offset, Pos, SpanVec}; -/// Process source code directly into a collection of layouts. +/// Process _Typst_ source code directly into a collection of layouts. pub async fn typeset( src: &str, state: State, @@ -68,71 +60,3 @@ pub async fn typeset( let layouts = layout::layout(&document, loader).await; Pass::new(layouts, Feedback::join(f1, f2)) } - -/// A dynamic future type which allows recursive invocation of async functions -/// when used as the return type. -pub type DynFuture<'a, T> = Pin + 'a>>; - -/// The result of some pass: Some output `T` and feedback data. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Pass { - /// The output of this compilation pass. - pub output: T, - /// User feedback data accumulated in this pass. - pub feedback: Feedback, -} - -impl Pass { - /// Create a new pass from output and feedback data. - pub fn new(output: T, feedback: Feedback) -> Self { - Self { output, feedback } - } - - /// Create a new pass with empty feedback. - pub fn okay(output: T) -> Self { - Self { output, feedback: Feedback::new() } - } - - /// Map the output type and keep the feedback data. - pub fn map(self, f: impl FnOnce(T) -> U) -> Pass { - Pass { - output: f(self.output), - feedback: self.feedback, - } - } -} - -/// Diagnostic and semantic syntax highlighting data. -#[derive(Debug, Default, Clone, Eq, PartialEq)] -pub struct Feedback { - /// Diagnostics about the source code. - pub diags: SpanVec, - /// Decorations of the source code for semantic syntax highlighting. - pub decos: SpanVec, -} - -impl Feedback { - /// Create a new feedback instance without errors and decos. - pub fn new() -> Self { - Self { diags: vec![], decos: vec![] } - } - - /// Merge two feedbacks into one. - pub fn join(mut a: Self, b: Self) -> Self { - a.extend(b); - a - } - - /// Add other feedback data to this feedback. - pub fn extend(&mut self, more: Self) { - self.diags.extend(more.diags); - self.decos.extend(more.decos); - } - - /// Add more feedback whose spans are local and need to be translated by an - /// `offset` to be correct in this feedback's context. - pub fn extend_offset(&mut self, more: Self, offset: Pos) { - self.diags.extend(more.diags.offset(offset)); - self.decos.extend(more.decos.offset(offset)); - } -} diff --git a/src/library/page.rs b/src/library/page.rs index 448932a5a..3c6703bc9 100644 --- a/src/library/page.rs +++ b/src/library/page.rs @@ -20,8 +20,6 @@ use crate::prelude::*; /// - `bottom`: The bottom margin (length or relative to height). /// - `flip`: Flips custom or paper-defined width and height (boolean). pub fn page(mut args: Args, ctx: &mut EvalContext) -> Value { - let snapshot = ctx.state.clone(); - if let Some(paper) = args.find::() { ctx.state.page.class = paper.class; ctx.state.page.size = paper.size(); @@ -71,7 +69,7 @@ pub fn page(mut args: Args, ctx: &mut EvalContext) -> Value { } /// `pagebreak`: Starts a new page. -pub fn pagebreak(mut args: Args, ctx: &mut EvalContext) -> Value { +pub fn pagebreak(args: Args, ctx: &mut EvalContext) -> Value { args.done(ctx); ctx.end_page_group(); ctx.start_page_group(true); diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 7fbbf1414..3d980d7cd 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -15,9 +15,9 @@ pub use tokens::*; use std::str::FromStr; use crate::color::RgbaColor; +use crate::diag::{Deco, Pass}; use crate::eval::DictKey; use crate::syntax::*; -use crate::Pass; /// Parse a string of source code. pub fn parse(src: &str) -> Pass { @@ -56,6 +56,8 @@ fn node(p: &mut Parser, at_start: bool) -> Option> { SynNode::Parbreak } } + + // Text. Token::Text(text) => SynNode::Text(text.into()), // Comments. diff --git a/src/parse/parser.rs b/src/parse/parser.rs index 83e9b0960..18c82008b 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -2,8 +2,8 @@ use std::fmt::{self, Debug, Formatter}; use super::{Scanner, TokenMode, Tokens}; use crate::diag::Diag; -use crate::syntax::{Deco, Pos, Span, SpanWith, Spanned, Token}; -use crate::Feedback; +use crate::diag::{Deco, Feedback}; +use crate::syntax::{Pos, Span, SpanWith, Spanned, Token}; /// A convenient token-based parser. pub struct Parser<'s> { diff --git a/src/parse/tests.rs b/src/parse/tests.rs index 644b7f160..588ff7654 100644 --- a/src/parse/tests.rs +++ b/src/parse/tests.rs @@ -6,6 +6,7 @@ use std::fmt::Debug; use super::parse; use crate::color::RgbaColor; +use crate::diag::Deco; use crate::eval::DictKey; use crate::length::Length; use crate::syntax::*; diff --git a/src/prelude.rs b/src/prelude.rs index 3d77263b2..82da91f4f 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,9 +1,10 @@ //! A prelude for building custom functions. +pub use crate::diag::{Feedback, Pass}; #[doc(no_inline)] pub use crate::eval::{Args, Dict, Eval, EvalContext, Value, ValueDict}; pub use crate::layout::nodes::LayoutNode; pub use crate::layout::primitive::*; #[doc(no_inline)] pub use crate::syntax::{Span, Spanned, SynTree}; -pub use crate::{Feedback, Pass}; +pub use crate::{error, warning}; diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index a85b06a98..8b716da4c 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -10,20 +10,3 @@ pub use ast::*; pub use ident::*; pub use span::*; pub use token::*; - -/// Decorations for semantic syntax highlighting. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize))] -#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))] -pub enum Deco { - /// Emphasized text. - Emph, - /// Strong text. - Strong, - /// A valid, successfully resolved name. - Resolved, - /// An invalid, unresolved name. - Unresolved, - /// A key in a dictionary. - DictKey, -} diff --git a/tests/test_typeset.rs b/tests/test_typeset.rs index 1ac06f5ec..52f7a1fa6 100644 --- a/tests/test_typeset.rs +++ b/tests/test_typeset.rs @@ -11,6 +11,7 @@ use futures_executor::block_on; use raqote::{DrawTarget, PathBuilder, SolidSource, Source, Transform, Vector}; use ttf_parser::OutlineBuilder; +use typstc::diag::{Feedback, Pass}; use typstc::eval::State; use typstc::export::pdf; use typstc::font::{FontLoader, SharedFontLoader}; @@ -18,7 +19,7 @@ use typstc::geom::{Point, Vec2}; use typstc::layout::{BoxLayout, LayoutElement}; use typstc::parse::LineMap; use typstc::shaping::Shaped; -use typstc::{typeset, Feedback, Pass}; +use typstc::typeset; const TEST_DIR: &str = "tests"; const OUT_DIR: &str = "tests/out";