Move deco, pass and feedback into diagnostics module ↩

This commit is contained in:
Laurenz 2020-10-07 18:24:47 +02:00
parent 537545e7f8
commit d2e220245d
17 changed files with 99 additions and 151 deletions

View File

@ -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();

View File

@ -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<T> {
/// The output of this compilation pass.
pub output: T,
/// User feedback data accumulated in this pass.
pub feedback: Feedback,
}
impl<T> Pass<T> {
/// 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<U>(self, f: impl FnOnce(T) -> U) -> Pass<U> {
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<Diag>,
/// Decorations of the source code for semantic syntax highlighting.
pub decos: SpanVec<Deco>,
}
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.
///
/// ```

View File

@ -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.
///

View File

@ -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};

View File

@ -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)]

View File

@ -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;

View File

@ -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<LayoutSpace>, 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<LayoutSpace> {

View File

@ -13,8 +13,8 @@ pub struct Spacing {
impl Layout for Spacing {
async fn layout(
&self,
ctx: &mut LayoutContext,
constraints: LayoutConstraints,
_: &mut LayoutContext,
_: LayoutConstraints,
) -> Vec<LayoutItem> {
vec![LayoutItem::Spacing(self.amount)]
}

View File

@ -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<LayoutSpace>, 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<BoxLayout> {
if self.space.hard || !self.space_is_empty() {

View File

@ -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<Box<dyn Future<Output = T> + 'a>>;
/// The result of some pass: Some output `T` and feedback data.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Pass<T> {
/// The output of this compilation pass.
pub output: T,
/// User feedback data accumulated in this pass.
pub feedback: Feedback,
}
impl<T> Pass<T> {
/// 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<U>(self, f: impl FnOnce(T) -> U) -> Pass<U> {
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<Diag>,
/// Decorations of the source code for semantic syntax highlighting.
pub decos: SpanVec<Deco>,
}
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));
}
}

View File

@ -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::<Paper>() {
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);

View File

@ -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<SynTree> {
@ -56,6 +56,8 @@ fn node(p: &mut Parser, at_start: bool) -> Option<Spanned<SynNode>> {
SynNode::Parbreak
}
}
// Text.
Token::Text(text) => SynNode::Text(text.into()),
// Comments.

View File

@ -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> {

View File

@ -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::*;

View File

@ -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};

View File

@ -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,
}

View File

@ -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";