summaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2020-02-04 19:22:23 +0100
committerLaurenz <laurmaedje@gmail.com>2020-02-04 19:22:23 +0100
commite63ce52ae0d929506a1fa238477f039d14d53813 (patch)
tree74dd8ce425dc368021c6495273acbdf2e736be68 /src/lib.rs
parent5c11aa72239ecbdd9577f027bdc7e9468d68414e (diff)
Merge `Parsed` and `Layouted` types into `Pass` with `Feedback` 🌝🎢🌚
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs81
1 files changed, 73 insertions, 8 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 2d6fa021..b74837fe 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -26,10 +26,11 @@ use smallvec::smallvec;
use toddle::{Font, OwnedData};
use toddle::query::{FontLoader, FontProvider, SharedFontLoader, FontDescriptor};
-use crate::layout::{Layouted, MultiLayout};
+use crate::error::Error;
+use crate::layout::MultiLayout;
use crate::style::{LayoutStyle, PageStyle, TextStyle};
-use crate::syntax::{SyntaxModel, Scope, ParseContext, Parsed, parse};
-use crate::syntax::span::Position;
+use crate::syntax::{SyntaxModel, Scope, Decoration, ParseContext, parse};
+use crate::syntax::span::{Position, SpanVec, offset_spans};
/// Declare a module and reexport all its contents.
@@ -100,12 +101,12 @@ impl Typesetter {
}
/// Parse source code into a syntax tree.
- pub fn parse(&self, src: &str) -> Parsed<SyntaxModel> {
+ pub fn parse(&self, src: &str) -> Pass<SyntaxModel> {
parse(Position::ZERO, src, ParseContext { scope: &self.scope })
}
/// Layout a syntax tree and return the produced layout.
- pub async fn layout(&self, model: &SyntaxModel) -> Layouted<MultiLayout> {
+ pub async fn layout(&self, model: &SyntaxModel) -> Pass<MultiLayout> {
use crate::layout::prelude::*;
let margins = self.style.page.margins();
@@ -130,9 +131,73 @@ impl Typesetter {
}
/// Process source code directly into a collection of layouts.
- pub async fn typeset(&self, src: &str) -> MultiLayout {
- let tree = self.parse(src).output;
- self.layout(&tree).await.output
+ pub async fn typeset(&self, src: &str) -> Pass<MultiLayout> {
+ let parsed = self.parse(src);
+ let layouted = self.layout(&parsed.output).await;
+ let feedback = Feedback::merge(parsed.feedback, layouted.feedback);
+ Pass::new(layouted.output, feedback)
+ }
+}
+
+/// 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) -> Pass<T> {
+ Pass { output, feedback }
+ }
+
+ /// Map the output type and keep the feedback data.
+ pub fn map<F, U>(self, f: F) -> Pass<U> where F: FnOnce(T) -> U {
+ Pass {
+ output: f(self.output),
+ feedback: self.feedback,
+ }
+ }
+}
+
+/// User feedback data accumulated during a compilation pass.
+#[derive(Debug, Default, Clone, Eq, PartialEq)]
+pub struct Feedback {
+ /// Errors in the source.
+ pub errors: SpanVec<Error>,
+ /// Decorations of the source code for semantic syntax highlighting.
+ pub decos: SpanVec<Decoration>,
+}
+
+impl Feedback {
+ /// Create a new feedback instance without errors and decos.
+ pub fn new() -> Feedback {
+ Feedback {
+ errors: vec![],
+ decos: vec![],
+ }
+ }
+
+ /// Merged two feedbacks into one.
+ pub fn merge(mut a: Feedback, b: Feedback) -> Feedback {
+ a.extend(b);
+ a
+ }
+
+ /// Add other feedback data to this feedback.
+ pub fn extend(&mut self, other: Feedback) {
+ self.errors.extend(other.errors);
+ self.decos.extend(other.decos);
+ }
+
+ /// Add more feedback whose spans are local and need to be offset by an
+ /// `offset` to be correct for this feedbacks context.
+ pub fn extend_offset(&mut self, offset: Position, other: Feedback) {
+ self.errors.extend(offset_spans(offset, other.errors));
+ self.decos.extend(offset_spans(offset, other.decos));
}
}