summaryrefslogtreecommitdiff
path: root/src/model
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-06-12 15:40:43 +0200
committerLaurenz <laurmaedje@gmail.com>2023-06-12 15:42:01 +0200
commit378ebe5f5601f11c3f428c17bed492012feb251e (patch)
tree4530bf009844faca40ca4fd6d0b9251fd51ef587 /src/model
parent19bf1f58944a42f17903869c162a33aba22b80b0 (diff)
Delayed errors
Fixes #785. Thanks to @Dherse for the idea!
Diffstat (limited to 'src/model')
-rw-r--r--src/model/introspect.rs5
-rw-r--r--src/model/mod.rs56
2 files changed, 50 insertions, 11 deletions
diff --git a/src/model/introspect.rs b/src/model/introspect.rs
index f00f89f5..b150fabf 100644
--- a/src/model/introspect.rs
+++ b/src/model/introspect.rs
@@ -241,11 +241,6 @@ impl Introspector {
#[comemo::track]
impl Introspector {
- /// Whether this introspector is not yet initialized.
- pub fn init(&self) -> bool {
- self.pages > 0
- }
-
/// Query for all matching elements.
pub fn query(&self, selector: &Selector) -> EcoVec<Prehashed<Content>> {
let hash = crate::util::hash128(selector);
diff --git a/src/model/mod.rs b/src/model/mod.rs
index 632b691f..ee940236 100644
--- a/src/model/mod.rs
+++ b/src/model/mod.rs
@@ -28,7 +28,7 @@ use std::mem::ManuallyDrop;
use comemo::{Track, Tracked, TrackedMut, Validate};
-use crate::diag::SourceResult;
+use crate::diag::{SourceError, SourceResult};
use crate::doc::Document;
use crate::eval::Tracer;
use crate::World;
@@ -46,8 +46,9 @@ pub fn typeset(
let library = world.library();
let styles = StyleChain::new(&library.styles);
- let mut document;
let mut iter = 0;
+ let mut document;
+ let mut delayed;
// We need `ManuallyDrop` until this lands in stable:
// https://github.com/rust-lang/rust/issues/70919
@@ -58,6 +59,8 @@ pub fn typeset(
loop {
tracing::info!("Layout iteration {iter}");
+ delayed = DelayedErrors::default();
+
let constraint = <Introspector as Validate>::Constraint::new();
let mut locator = Locator::new();
let mut vt = Vt {
@@ -65,6 +68,7 @@ pub fn typeset(
tracer: TrackedMut::reborrow_mut(&mut tracer),
locator: &mut locator,
introspector: introspector.track_with(&constraint),
+ delayed: delayed.track_mut(),
};
// Layout!
@@ -86,6 +90,11 @@ pub fn typeset(
// Drop the introspector.
ManuallyDrop::into_inner(introspector);
+ // Promote delayed errors.
+ if !delayed.0.is_empty() {
+ return Err(Box::new(delayed.0));
+ }
+
Ok(document)
}
@@ -95,10 +104,45 @@ pub fn typeset(
pub struct Vt<'a> {
/// The compilation environment.
pub world: Tracked<'a, dyn World + 'a>,
- /// The tracer for inspection of the values an expression produces.
- pub tracer: TrackedMut<'a, Tracer>,
- /// Provides stable identities to elements.
- pub locator: &'a mut Locator<'a>,
/// Provides access to information about the document.
pub introspector: Tracked<'a, Introspector>,
+ /// Provides stable identities to elements.
+ pub locator: &'a mut Locator<'a>,
+ /// Delayed errors that do not immediately terminate execution.
+ pub delayed: TrackedMut<'a, DelayedErrors>,
+ /// The tracer for inspection of the values an expression produces.
+ pub tracer: TrackedMut<'a, Tracer>,
+}
+
+impl Vt<'_> {
+ /// Perform a fallible operation that does not immediately terminate further
+ /// execution. Instead it produces a delayed error that is only promoted to
+ /// a fatal one if it remains at the end of the introspection loop.
+ pub fn delayed<F, T>(&mut self, f: F) -> T
+ where
+ F: FnOnce(&mut Self) -> SourceResult<T>,
+ T: Default,
+ {
+ match f(self) {
+ Ok(value) => value,
+ Err(errors) => {
+ for error in *errors {
+ self.delayed.push(error);
+ }
+ T::default()
+ }
+ }
+ }
+}
+
+/// Holds delayed errors.
+#[derive(Default, Clone)]
+pub struct DelayedErrors(Vec<SourceError>);
+
+#[comemo::track]
+impl DelayedErrors {
+ /// Push a delayed error.
+ fn push(&mut self, error: SourceError) {
+ self.0.push(error);
+ }
}