From 378ebe5f5601f11c3f428c17bed492012feb251e Mon Sep 17 00:00:00 2001 From: Laurenz Date: Mon, 12 Jun 2023 15:40:43 +0200 Subject: Delayed errors Fixes #785. Thanks to @Dherse for the idea! --- src/eval/func.rs | 25 +++++++++++++++------- src/eval/mod.rs | 19 ++++++++++------- src/model/introspect.rs | 5 ----- src/model/mod.rs | 56 +++++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 79 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/eval/func.rs b/src/eval/func.rs index 1745dfb1..28d4a40d 100644 --- a/src/eval/func.rs +++ b/src/eval/func.rs @@ -11,7 +11,7 @@ use super::{ Value, Vm, }; use crate::diag::{bail, SourceResult, StrResult}; -use crate::model::{ElemFunc, Introspector, Locator, Vt}; +use crate::model::{DelayedErrors, ElemFunc, Introspector, Locator, Vt}; use crate::syntax::ast::{self, AstNode, Expr, Ident}; use crate::syntax::{SourceId, Span, SyntaxNode}; use crate::World; @@ -102,9 +102,10 @@ impl Func { self, vm.world(), route, - TrackedMut::reborrow_mut(&mut vm.vt.tracer), - vm.vt.locator.track(), vm.vt.introspector, + vm.vt.locator.track(), + TrackedMut::reborrow_mut(&mut vm.vt.delayed), + TrackedMut::reborrow_mut(&mut vm.vt.tracer), vm.depth + 1, args, ) @@ -129,9 +130,10 @@ impl Func { let mut locator = Locator::chained(vt.locator.track()); let vt = Vt { world: vt.world, - tracer: TrackedMut::reborrow_mut(&mut vt.tracer), - locator: &mut locator, introspector: vt.introspector, + locator: &mut locator, + delayed: TrackedMut::reborrow_mut(&mut vt.delayed), + tracer: TrackedMut::reborrow_mut(&mut vt.tracer), }; let mut vm = Vm::new(vt, route.track(), id, scopes); let args = Args::new(self.span(), args); @@ -326,9 +328,10 @@ impl Closure { this: &Func, world: Tracked, route: Tracked, - tracer: TrackedMut, - locator: Tracked, introspector: Tracked, + locator: Tracked, + delayed: TrackedMut, + tracer: TrackedMut, depth: usize, mut args: Args, ) -> SourceResult { @@ -344,7 +347,13 @@ impl Closure { // Prepare VT. let mut locator = Locator::chained(locator); - let vt = Vt { world, tracer, locator: &mut locator, introspector }; + let vt = Vt { + world, + introspector, + locator: &mut locator, + delayed, + tracer, + }; // Prepare VM. let mut vm = Vm::new(vt, route, closure.location, scopes); diff --git a/src/eval/mod.rs b/src/eval/mod.rs index e6016218..fe11606a 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -62,9 +62,6 @@ use ecow::{EcoString, EcoVec}; use unicode_segmentation::UnicodeSegmentation; use self::func::{CapturesVisitor, Closure}; -use crate::diag::{ - bail, error, At, SourceError, SourceResult, StrResult, Trace, Tracepoint, -}; use crate::model::{ Content, Introspector, Label, Locator, Recipe, ShowableSelector, Styles, Transform, Unlabellable, Vt, @@ -75,6 +72,10 @@ use crate::syntax::{ }; use crate::util::PathExt; use crate::World; +use crate::{ + diag::{bail, error, At, SourceError, SourceResult, StrResult, Trace, Tracepoint}, + model::DelayedErrors, +}; const MAX_ITERATIONS: usize = 10_000; const MAX_CALL_DEPTH: usize = 64; @@ -102,11 +103,13 @@ pub fn eval( // Prepare VT. let mut locator = Locator::default(); let introspector = Introspector::default(); + let mut delayed = DelayedErrors::default(); let vt = Vt { world, - tracer, - locator: &mut locator, introspector: introspector.track(), + locator: &mut locator, + delayed: delayed.track_mut(), + tracer, }; // Prepare VM. @@ -151,12 +154,14 @@ pub fn eval_string( // Prepare VT. let mut tracer = Tracer::default(); let mut locator = Locator::default(); + let mut delayed = DelayedErrors::default(); let introspector = Introspector::default(); let vt = Vt { world, - tracer: tracer.track_mut(), - locator: &mut locator, introspector: introspector.track(), + locator: &mut locator, + delayed: delayed.track_mut(), + tracer: tracer.track_mut(), }; // Prepare VM. 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> { 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 = ::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(&mut self, f: F) -> T + where + F: FnOnce(&mut Self) -> SourceResult, + 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); + +#[comemo::track] +impl DelayedErrors { + /// Push a delayed error. + fn push(&mut self, error: SourceError) { + self.0.push(error); + } } -- cgit v1.2.3