diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-11-25 16:10:28 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-11-26 19:03:21 +0100 |
| commit | 85b1d1d4dd4628d1fb8901c3280cde84da450bbe (patch) | |
| tree | b69a629be9295268e071667b1587a5701f2bc7ef /crates | |
| parent | 2f795b5c07171affa0709195a9dae3ed5c0afbeb (diff) | |
Rework `Vt` into `Engine`
- Moves as much data out of the `Vm`
- Removes duplication with call_vm and call_vt flavours
- Uses tracked chain instead of fixed int for determining max nesting depth
- This means that nesting checks now generalizes to layout and realization, to detect crashing show rules and overly nested layouts
Diffstat (limited to 'crates')
89 files changed, 1204 insertions, 983 deletions
diff --git a/crates/typst-ide/src/analyze.rs b/crates/typst-ide/src/analyze.rs index f3e417d5..8c5117f7 100644 --- a/crates/typst-ide/src/analyze.rs +++ b/crates/typst-ide/src/analyze.rs @@ -1,9 +1,10 @@ use comemo::Track; use ecow::{eco_vec, EcoString, EcoVec}; -use typst::eval::{Route, Tracer, Vm}; +use typst::engine::{Engine, Route}; +use typst::eval::{Tracer, Vm}; use typst::foundations::{Label, Scopes, Value}; use typst::introspection::{Introspector, Locator}; -use typst::layout::{Frame, Vt}; +use typst::layout::Frame; use typst::model::BibliographyElem; use typst::syntax::{ast, LinkedNode, Span, SyntaxKind}; use typst::World; @@ -46,7 +47,6 @@ pub fn analyze_expr(world: &dyn World, node: &LinkedNode) -> EcoVec<Value> { /// Try to load a module from the current source file. pub fn analyze_import(world: &dyn World, source: &LinkedNode) -> Option<Value> { - let id = source.span().id()?; let source = analyze_expr(world, source).into_iter().next()?; if source.scope().is_some() { return Some(source); @@ -55,15 +55,15 @@ pub fn analyze_import(world: &dyn World, source: &LinkedNode) -> Option<Value> { let mut locator = Locator::default(); let introspector = Introspector::default(); let mut tracer = Tracer::new(); - let vt = Vt { + let engine = Engine { world: world.track(), + route: Route::default(), introspector: introspector.track(), locator: &mut locator, tracer: tracer.track_mut(), }; - let route = Route::default(); - let mut vm = Vm::new(vt, route.track(), Some(id), Scopes::new(Some(world.library()))); + let mut vm = Vm::new(engine, Scopes::new(Some(world.library())), Span::detached()); typst::eval::import(&mut vm, source, Span::detached(), true) .ok() .map(Value::Module) diff --git a/crates/typst-macros/src/elem.rs b/crates/typst-macros/src/elem.rs index 9791427b..ce80cc66 100644 --- a/crates/typst-macros/src/elem.rs +++ b/crates/typst-macros/src/elem.rs @@ -1083,7 +1083,7 @@ fn create_construct_impl(element: &Elem) -> TokenStream { quote! { impl #foundations::Construct for #ident { fn construct( - vm: &mut ::typst::eval::Vm, + engine: &mut ::typst::engine::Engine, args: &mut #foundations::Args, ) -> ::typst::diag::SourceResult<#foundations::Content> { #(#pre)* @@ -1115,7 +1115,7 @@ fn create_set_impl(element: &Elem) -> TokenStream { quote! { impl #foundations::Set for #ident { fn set( - vm: &mut ::typst::eval::Vm, + engine: &mut ::typst::engine::Engine, args: &mut #foundations::Args, ) -> ::typst::diag::SourceResult<#foundations::Styles> { let mut styles = #foundations::Styles::new(); diff --git a/crates/typst-macros/src/func.rs b/crates/typst-macros/src/func.rs index 8537ac4f..953df428 100644 --- a/crates/typst-macros/src/func.rs +++ b/crates/typst-macros/src/func.rs @@ -36,8 +36,7 @@ struct Func { #[derive(Default)] struct SpecialParams { self_: Option<Param>, - vm: bool, - vt: bool, + engine: bool, args: bool, span: bool, } @@ -171,8 +170,7 @@ fn parse_param( }; match ident.to_string().as_str() { - "vm" => special.vm = true, - "vt" => special.vt = true, + "engine" => special.engine = true, "args" => special.args = true, "span" => special.span = true, _ => { @@ -322,13 +320,12 @@ fn create_wrapper_closure(func: &Func) -> TokenStream { .as_ref() .map(bind) .map(|tokens| quote! { #tokens, }); - let vm_ = func.special.vm.then(|| quote! { vm, }); - let vt_ = func.special.vt.then(|| quote! { &mut vm.vt, }); + let vt_ = func.special.engine.then(|| quote! { engine, }); let args_ = func.special.args.then(|| quote! { args, }); let span_ = func.special.span.then(|| quote! { args.span, }); let forwarded = func.params.iter().filter(|param| !param.external).map(bind); quote! { - __typst_func(#self_ #vm_ #vt_ #args_ #span_ #(#forwarded,)*) + __typst_func(#self_ #vt_ #args_ #span_ #(#forwarded,)*) } }; @@ -336,7 +333,7 @@ fn create_wrapper_closure(func: &Func) -> TokenStream { let ident = &func.ident; let parent = func.parent.as_ref().map(|ty| quote! { #ty:: }); quote! { - |vm, args| { + |engine, args| { let __typst_func = #parent #ident; #handlers #finish diff --git a/crates/typst-syntax/src/span.rs b/crates/typst-syntax/src/span.rs index 14e5e216..8138a316 100644 --- a/crates/typst-syntax/src/span.rs +++ b/crates/typst-syntax/src/span.rs @@ -2,6 +2,8 @@ use std::fmt::{self, Debug, Formatter}; use std::num::NonZeroU64; use std::ops::Range; +use ecow::EcoString; + use crate::FileId; /// A unique identifier for a syntax node. @@ -80,6 +82,14 @@ impl Span { pub const fn number(self) -> u64 { self.0.get() & ((1 << Self::BITS) - 1) } + + /// Resolve a file location relative to this span's source. + pub fn resolve_path(self, path: &str) -> Result<FileId, EcoString> { + let Some(file) = self.id() else { + return Err("cannot access file system from here".into()); + }; + Ok(file.join(path)) + } } /// A value with a span locating it in the source code. diff --git a/crates/typst/src/engine.rs b/crates/typst/src/engine.rs new file mode 100644 index 00000000..189034cf --- /dev/null +++ b/crates/typst/src/engine.rs @@ -0,0 +1,159 @@ +use std::cell::Cell; + +use comemo::{Track, Tracked, TrackedMut, Validate}; + +use crate::diag::SourceResult; +use crate::eval::Tracer; +use crate::introspection::{Introspector, Locator}; +use crate::syntax::FileId; +use crate::World; + +/// The maxmium stack nesting depth. +const MAX_DEPTH: usize = 64; + +/// Holds all data needed during compilation. +pub struct Engine<'a> { + /// The compilation environment. + pub world: Tracked<'a, dyn World + 'a>, + /// Provides access to information about the document. + pub introspector: Tracked<'a, Introspector>, + /// The route the engine took during compilation. This is used to detect + /// cyclic imports and too much nesting. + pub route: Route<'a>, + /// Provides stable identities to elements. + pub locator: &'a mut Locator<'a>, + /// The tracer for inspection of the values an expression produces. + pub tracer: TrackedMut<'a, Tracer>, +} + +impl Engine<'_> { + /// 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) => { + self.tracer.delay(errors); + T::default() + } + } + } +} + +/// The route the engine took during compilation. This is used to detect +/// cyclic imports and too much nesting. +#[derive(Clone)] +pub struct Route<'a> { + // We need to override the constraint's lifetime here so that `Tracked` is + // covariant over the constraint. If it becomes invariant, we're in for a + // world of lifetime pain. + outer: Option<Tracked<'a, Self, <Route<'static> as Validate>::Constraint>>, + /// This is set if this route segment was inserted through the start of a + /// module evaluation. + id: Option<FileId>, + /// This is set whenever we enter a function, nested layout, or are applying + /// a show rule. The length of this segment plus the lengths of all `outer` + /// route segments make up the length of the route. If the length of the + /// route exceeds `MAX_DEPTH`, then we throw a "maximum ... depth exceeded" + /// error. + len: usize, + /// The upper bound we've established for the parent chain length. We don't + /// know the exact length (that would defeat the whole purpose because it + /// would prevent cache reuse of some computation at different, + /// non-exceeding depths). + upper: Cell<usize>, +} + +impl<'a> Route<'a> { + /// Create a new, empty route. + pub fn root() -> Self { + Self { id: None, outer: None, len: 0, upper: Cell::new(0) } + } + + /// Insert a new id into the route. + /// + /// You must guarantee that `outer` lives longer than the resulting + /// route is ever used. + pub fn insert(outer: Tracked<'a, Self>, id: FileId) -> Self { + Route { + outer: Some(outer), + id: Some(id), + len: 0, + upper: Cell::new(usize::MAX), + } + } + + /// Extend the route without another id. + pub fn extend(outer: Tracked<'a, Self>) -> Self { + Route { + outer: Some(outer), + id: None, + len: 1, + upper: Cell::new(usize::MAX), + } + } + + /// Start tracking this route. + /// + /// In comparison to [`Track::track`], this method skips this chain link + /// if it does not contribute anything. + pub fn track(&self) -> Tracked<'_, Self> { + match self.outer { + Some(outer) if self.id.is_none() && self.len == 0 => outer, + _ => Track::track(self), + } + } + + /// Increase the nesting depth for this route segment. + pub fn increase(&mut self) { + self.len += 1; + } + + /// Decrease the nesting depth for this route segment. + pub fn decrease(&mut self) { + self.len -= 1; + } + + /// Check whether the nesting depth exceeds the limit. + pub fn exceeding(&self) -> bool { + !self.within(MAX_DEPTH) + } +} + +#[comemo::track] +impl<'a> Route<'a> { + /// Whether the given id is part of the route. + pub fn contains(&self, id: FileId) -> bool { + self.id == Some(id) || self.outer.map_or(false, |outer| outer.contains(id)) + } + + /// Whether the route's depth is less than or equal to the given depth. + pub fn within(&self, depth: usize) -> bool { + if self.upper.get().saturating_add(self.len) <= depth { + return true; + } + + match self.outer { + Some(_) if depth < self.len => false, + Some(outer) => { + let within = outer.within(depth - self.len); + if within && depth < self.upper.get() { + self.upper.set(depth); + } + within + } + None => true, + } + } +} + +impl Default for Route<'_> { + fn default() -> Self { + Self::root() + } +} diff --git a/crates/typst/src/eval/access.rs b/crates/typst/src/eval/access.rs index ff0b7512..99b2f72e 100644 --- a/crates/typst/src/eval/access.rs +++ b/crates/typst/src/eval/access.rs @@ -31,7 +31,7 @@ impl Access for ast::Ident<'_> { let span = self.span(); let value = vm.scopes.get_mut(&self).at(span)?; if vm.inspected == Some(span) { - vm.vt.tracer.value(value.clone()); + vm.engine.tracer.value(value.clone()); } Ok(value) } diff --git a/crates/typst/src/eval/call.rs b/crates/typst/src/eval/call.rs index 7ccebe85..a57cb112 100644 --- a/crates/typst/src/eval/call.rs +++ b/crates/typst/src/eval/call.rs @@ -2,13 +2,13 @@ use comemo::{Prehashed, Tracked, TrackedMut}; use ecow::EcoVec; use crate::diag::{bail, error, At, HintedStrResult, SourceResult, Trace, Tracepoint}; +use crate::engine::Engine; use crate::eval::{Access, Eval, FlowEvent, Route, Tracer, Vm}; use crate::foundations::{ call_method_mut, is_mutating_method, Arg, Args, Bytes, Closure, Content, Func, IntoValue, NativeElement, Scope, Scopes, Value, }; use crate::introspection::{Introspector, Locator}; -use crate::layout::Vt; use crate::math::{Accent, AccentElem, LrElem}; use crate::symbols::Symbol; use crate::syntax::ast::{self, AstNode}; @@ -16,23 +16,19 @@ use crate::syntax::{Spanned, SyntaxNode}; use crate::text::TextElem; use crate::World; -/// The maxmium function call depth. -const MAX_CALL_DEPTH: usize = 64; - impl Eval for ast::FuncCall<'_> { type Output = Value; #[tracing::instrument(name = "FuncCall::eval", skip_all)] fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> { let span = self.span(); - if vm.depth >= MAX_CALL_DEPTH { - bail!(span, "maximum function call depth exceeded"); - } - let callee = self.callee(); let in_math = in_math(callee); let callee_span = callee.span(); let args = self.args(); + if vm.engine.route.exceeding() { + bail!(span, "maximum function call depth exceeded"); + } // Try to evaluate as a call to an associated function or field. let (callee, mut args) = if let ast::Expr::FieldAccess(access) = callee { @@ -146,7 +142,7 @@ impl Eval for ast::FuncCall<'_> { let callee = callee.cast::<Func>().at(callee_span)?; let point = || Tracepoint::Call(callee.name().map(Into::into)); - let f = || callee.call_vm(vm, args).trace(vm.world(), point, span); + let f = || callee.call(&mut vm.engine, args).trace(vm.world(), point, span); // Stacker is broken on WASM. #[cfg(target_arch = "wasm32")] @@ -229,7 +225,6 @@ impl Eval for ast::Closure<'_> { // Define the closure. let closure = Closure { node: self.to_untyped().clone(), - file: vm.file, defaults, captured, }; @@ -246,11 +241,10 @@ pub(crate) fn call_closure( func: &Func, closure: &Prehashed<Closure>, world: Tracked<dyn World + '_>, - route: Tracked<Route>, introspector: Tracked<Introspector>, + route: Tracked<Route>, locator: Tracked<Locator>, tracer: TrackedMut<Tracer>, - depth: usize, mut args: Args, ) -> SourceResult<Value> { let node = closure.node.cast::<ast::Closure>().unwrap(); @@ -260,13 +254,18 @@ pub(crate) fn call_closure( let mut scopes = Scopes::new(None); scopes.top = closure.captured.clone(); - // Prepare VT. + // Prepare the engine. let mut locator = Locator::chained(locator); - let vt = Vt { world, introspector, locator: &mut locator, tracer }; + let engine = Engine { + world, + introspector, + route: Route::extend(route), + locator: &mut locator, + tracer, + }; // Prepare VM. - let mut vm = Vm::new(vt, route, closure.file, scopes); - vm.depth = depth; + let mut vm = Vm::new(engine, scopes, node.span()); // Provide the closure itself for recursive calls. if let Some(name) = node.name() { @@ -279,6 +278,7 @@ pub(crate) fn call_closure( .children() .filter(|p| matches!(p, ast::Param::Pos(_))) .count(); + let num_pos_args = args.to_pos().len(); let sink_size = num_pos_args.checked_sub(num_pos_params); diff --git a/crates/typst/src/eval/code.rs b/crates/typst/src/eval/code.rs index 1df5876c..06b2f226 100644 --- a/crates/typst/src/eval/code.rs +++ b/crates/typst/src/eval/code.rs @@ -40,7 +40,7 @@ fn eval_code<'a>( } let tail = eval_code(vm, exprs)?.display(); - Value::Content(tail.styled_with_recipe(vm, recipe)?) + Value::Content(tail.styled_with_recipe(&mut vm.engine, recipe)?) } _ => expr.eval(vm)?, }; @@ -130,7 +130,7 @@ impl Eval for ast::Expr<'_> { .spanned(span); if vm.inspected == Some(span) { - vm.vt.tracer.value(v.clone()); + vm.engine.tracer.value(v.clone()); } Ok(v) diff --git a/crates/typst/src/eval/import.rs b/crates/typst/src/eval/import.rs index 79daf999..aa3388a1 100644 --- a/crates/typst/src/eval/import.rs +++ b/crates/typst/src/eval/import.rs @@ -38,7 +38,7 @@ impl Eval for ast::ModuleImport<'_> { if let ast::Expr::Ident(ident) = self.source() { if ident.as_str() == new_name.as_str() { // Warn on `import x as x` - vm.vt.tracer.warn(warning!( + vm.engine.tracer.warn(warning!( new_name.span(), "unnecessary import rename to same name", )); @@ -73,7 +73,7 @@ impl Eval for ast::ModuleImport<'_> { if renamed_item.original_name().as_str() == renamed_item.new_name().as_str() { - vm.vt.tracer.warn(warning!( + vm.engine.tracer.warn(warning!( renamed_item.new_name().span(), "unnecessary import rename to same name", )); @@ -145,27 +145,37 @@ fn import_package(vm: &mut Vm, spec: PackageSpec, span: Span) -> SourceResult<Mo let entrypoint_id = manifest_id.join(&manifest.package.entrypoint); let source = vm.world().source(entrypoint_id).at(span)?; let point = || Tracepoint::Import; - Ok(eval(vm.world(), vm.route, TrackedMut::reborrow_mut(&mut vm.vt.tracer), &source) - .trace(vm.world(), point, span)? - .with_name(manifest.package.name)) + Ok(eval( + vm.world(), + vm.engine.route.track(), + TrackedMut::reborrow_mut(&mut vm.engine.tracer), + &source, + ) + .trace(vm.world(), point, span)? + .with_name(manifest.package.name)) } /// Import a file from a path. fn import_file(vm: &mut Vm, path: &str, span: Span) -> SourceResult<Module> { // Load the source file. let world = vm.world(); - let id = vm.resolve_path(path).at(span)?; + let id = span.resolve_path(path).at(span)?; let source = world.source(id).at(span)?; // Prevent cyclic importing. - if vm.route.contains(source.id()) { + if vm.engine.route.contains(source.id()) { bail!(span, "cyclic import"); } // Evaluate the file. let point = || Tracepoint::Import; - eval(world, vm.route, TrackedMut::reborrow_mut(&mut vm.vt.tracer), &source) - .trace(world, point, span) + eval( + world, + vm.engine.route.track(), + TrackedMut::reborrow_mut(&mut vm.engine.tracer), + &source, + ) + .trace(world, point, span) } /// A parsed package manifest. diff --git a/crates/typst/src/eval/markup.rs b/crates/typst/src/eval/markup.rs index 16ea9eef..a40b978e 100644 --- a/crates/typst/src/eval/markup.rs +++ b/crates/typst/src/eval/markup.rs @@ -43,7 +43,7 @@ fn eval_markup<'a>( } let tail = eval_markup(vm, exprs)?; - seq.push(tail.styled_with_recipe(vm, recipe)?) + seq.push(tail.styled_with_recipe(&mut vm.engine, recipe)?) } expr => match expr.eval(vm)? { Value::Label(label) => { @@ -139,11 +139,11 @@ impl Eval for ast::Strong<'_> { fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> { let body = self.body(); if body.exprs().next().is_none() { - vm.vt - .tracer - .warn(warning!(self.span(), "no text within stars").with_hint( + vm.engine.tracer.warn( + warning!(self.span(), "no text within stars").with_hint( "using multiple consecutive stars (e.g. **) has no additional effect", - )); + ), + ); } Ok(StrongElem::new(body.eval(vm)?).pack()) @@ -157,7 +157,7 @@ impl Eval for ast::Emph<'_> { fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> { let body = self.body(); if body.exprs().next().is_none() { - vm.vt + vm.engine .tracer .warn(warning!(self.span(), "no text within underscores").with_hint( "using multiple consecutive underscores (e.g. __) has no additional effect" diff --git a/crates/typst/src/eval/mod.rs b/crates/typst/src/eval/mod.rs index eaba69e0..9de4f1b7 100644 --- a/crates/typst/src/eval/mod.rs +++ b/crates/typst/src/eval/mod.rs @@ -26,9 +26,9 @@ pub(crate) use self::flow::*; use comemo::{Track, Tracked, TrackedMut}; use crate::diag::{bail, SourceResult}; +use crate::engine::{Engine, Route}; use crate::foundations::{Cast, Module, NativeElement, Scope, Scopes, Value}; use crate::introspection::{Introspector, Locator}; -use crate::layout::Vt; use crate::math::EquationElem; use crate::syntax::{ast, parse, parse_code, parse_math, Source, Span}; use crate::World; @@ -48,22 +48,23 @@ pub fn eval( panic!("Tried to cyclicly evaluate {:?}", id.vpath()); } - // Prepare VT. + // Prepare the engine. let mut locator = Locator::new(); let introspector = Introspector::default(); - let vt = Vt { + let engine = Engine { world, + route: Route::insert(route, id), introspector: introspector.track(), locator: &mut locator, tracer, }; // Prepare VM. - let route = Route::insert(route, id); + let root = source.root(); let scopes = Scopes::new(Some(world.library())); - let mut vm = Vm::new(vt, route.track(), Some(id), scopes); + let mut vm = Vm::new(engine, scopes, root.span()); - let root = source.root(); + // Check for well-formedness unless we are in trace mode. let errors = root.errors(); if !errors.is_empty() && vm.inspected.is_none() { return Err(errors.into_iter().map(Into::into).collect()); @@ -108,26 +109,27 @@ pub fn eval_string( root.synthesize(span); + // Check for well-formedness. let errors = root.errors(); if !errors.is_empty() { return Err(errors.into_iter().map(Into::into).collect()); } - // Prepare VT. + // Prepare the engine. let mut tracer = Tracer::new(); let mut locator = Locator::new(); let introspector = Introspector::default(); - let vt = Vt { + let engine = Engine { world, introspector: introspector.track(), + route: Route::default(), locator: &mut locator, tracer: tracer.track_mut(), }; // Prepare VM. - let route = Route::default(); let scopes = Scopes::new(Some(world.library())); - let mut vm = Vm::new(vt, route.track(), None, scopes); + let mut vm = Vm::new(engine, scopes, root.span()); vm.scopes.scopes.push(scope); // Evaluate the code. diff --git a/crates/typst/src/eval/rules.rs b/crates/typst/src/eval/rules.rs index c85b747b..e34fe5cd 100644 --- a/crates/typst/src/eval/rules.rs +++ b/crates/typst/src/eval/rules.rs @@ -24,7 +24,7 @@ impl Eval for ast::SetRule<'_> { }) .at(target.span())?; let args = self.args().eval(vm)?; - Ok(target.set(vm, args)?.spanned(self.span())) + Ok(target.set(&mut vm.engine, args)?.spanned(self.span())) } } diff --git a/crates/typst/src/eval/vm.rs b/crates/typst/src/eval/vm.rs index c34c1070..8cedb906 100644 --- a/crates/typst/src/eval/vm.rs +++ b/crates/typst/src/eval/vm.rs @@ -1,74 +1,37 @@ -use comemo::{Track, Tracked, Validate}; +use comemo::Tracked; -use crate::diag::{bail, StrResult}; +use crate::engine::Engine; use crate::eval::FlowEvent; use crate::foundations::{IntoValue, Scopes}; -use crate::layout::Vt; use crate::syntax::ast::{self, AstNode}; -use crate::syntax::{FileId, Span}; +use crate::syntax::Span; use crate::World; /// A virtual machine. /// -/// Holds the state needed to [evaluate](crate::eval::eval()) Typst sources. A new -/// virtual machine is created for each module evaluation and function call. +/// Holds the state needed to [evaluate](crate::eval::eval()) Typst sources. A +/// new virtual machine is created for each module evaluation and function call. pub struct Vm<'a> { /// The underlying virtual typesetter. - pub(crate) vt: Vt<'a>, - /// The route of source ids the VM took to reach its current location. - pub(crate) route: Tracked<'a, Route<'a>>, - /// The id of the currently evaluated file. - pub(crate) file: Option<FileId>, + pub(crate) engine: Engine<'a>, /// A control flow event that is currently happening. pub(crate) flow: Option<FlowEvent>, /// The stack of scopes. pub(crate) scopes: Scopes<'a>, - /// The current call depth. - pub(crate) depth: usize, /// A span that is currently under inspection. pub(crate) inspected: Option<Span>, } impl<'a> Vm<'a> { /// Create a new virtual machine. - pub fn new( - vt: Vt<'a>, - route: Tracked<'a, Route>, - file: Option<FileId>, - scopes: Scopes<'a>, - ) -> Self { - let inspected = file.and_then(|id| vt.tracer.inspected(id)); - Self { - vt, - route, - file, - flow: None, - scopes, - depth: 0, - inspected, - } + pub fn new(engine: Engine<'a>, scopes: Scopes<'a>, target: Span) -> Self { + let inspected = target.id().and_then(|id| engine.tracer.inspected(id)); + Self { engine, flow: None, scopes, inspected } } /// Access the underlying world. pub fn world(&self) -> Tracked<'a, dyn World + 'a> { - self.vt.world - } - - /// The id of the currently evaluated file. - /// - /// Returns `None` if the VM is in a detached context, e.g. when evaluating - /// a user-provided string. - pub fn file(&self) -> Option<FileId> { - self.file - } - - /// Resolve a path relative to the currently evaluated file. - pub fn resolve_path(&self, path: &str) -> StrResult<FileId> { - let Some(file) = self.file else { - bail!("cannot access file system from here"); - }; - - Ok(file.join(path)) + self.engine.world } /// Define a variable in the current scope. @@ -76,52 +39,8 @@ impl<'a> Vm<'a> { pub fn define(&mut self, var: ast::Ident, value: impl IntoValue) { let value = value.into_value(); if self.inspected == Some(var.span()) { - self.vt.tracer.value(value.clone()); + self.engine.tracer.value(value.clone()); } self.scopes.top.define(var.get().clone(), value); } } - -/// A route of source ids. -#[derive(Default)] -pub struct Route<'a> { - // We need to override the constraint's lifetime here so that `Tracked` is - // covariant over the constraint. If it becomes invariant, we're in for a - // world of lifetime pain. - outer: Option<Tracked<'a, Self, <Route<'static> as Validate>::Constraint>>, - id: Option<FileId>, -} - -impl<'a> Route<'a> { - /// Create a new route with just one entry. - pub fn new(id: Option<FileId>) -> Self { - Self { id, outer: None } - } - - /// Insert a new id into the route. - /// - /// You must guarantee that `outer` lives longer than the resulting - /// route is ever used. - pub fn insert(outer: Tracked<'a, Self>, id: FileId) -> Self { - Route { outer: Some(outer), id: Some(id) } - } - - /// Start tracking this locator. - /// - /// In comparison to [`Track::track`], this method skips this chain link - /// if it does not contribute anything. - pub fn track(&self) -> Tracked<'_, Self> { - match self.outer { - Some(outer) if self.id.is_none() => outer, - _ => Track::track(self), - } - } -} - -#[comemo::track] -impl<'a> Route<'a> { - /// Whether the given id is part of the route. - pub fn contains(&self, id: FileId) -> bool { - self.id == Some(id) || self.outer.map_or(false, |outer| outer.contains(id)) - } -} diff --git a/crates/typst/src/foundations/args.rs b/crates/typst/src/foundations/args.rs index af5d07b1..e11fe2bb 100644 --- a/crates/typst/src/foundations/args.rs +++ b/crates/typst/src/foundations/args.rs @@ -320,3 +320,26 @@ impl PartialEq for Arg { self.name == other.name && self.value.v == other.value.v } } + +/// Things that can be used as arguments. +pub trait IntoArgs { + /// Convert into arguments, attaching the `fallback` span in case `Self` + /// doesn't have a span. + fn into_args(self, fallback: Span) -> Args; +} + +impl IntoArgs for Args { + fn into_args(self, _: Span) -> Args { + self + } +} + +impl<I, T> IntoArgs for I +where + I: IntoIterator<Item = T>, + T: IntoValue, +{ + fn into_args(self, fallback: Span) -> Args { + Args::new(fallback, self) + } +} diff --git a/crates/typst/src/foundations/array.rs b/crates/typst/src/foundations/array.rs index 47afa9e2..8f2e9149 100644 --- a/crates/typst/src/foundations/array.rs +++ b/crates/typst/src/foundations/array.rs @@ -8,7 +8,8 @@ use serde::{Deserialize, Serialize}; use smallvec::SmallVec; use crate::diag::{At, SourceResult, StrResult}; -use crate::eval::{ops, Vm}; +use crate::engine::Engine; +use crate::eval::ops; use crate::foundations::{ cast, func, repr, scope, ty, Args, Bytes, CastInfo, FromValue, Func, IntoValue, Reflect, Repr, Value, Version, @@ -297,14 +298,17 @@ impl Array { #[func] pub fn find( &self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The function to apply to each item. Must return a boolean. searcher: Func, ) -> SourceResult<Option<Value>> { for item in self.iter() { - let args = Args::new(searcher.span(), [item.clone()]); - if searcher.call_vm(vm, args)?.cast::<bool>().at(searcher.span())? { + if searcher + .call(engine, [item.clone()])? + .cast::<bool>() + .at(searcher.span())? + { return Ok(Some(item.clone())); } } @@ -316,14 +320,17 @@ impl Array { #[func] pub fn position( &self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The function to apply to each item. Must return a boolean. searcher: Func, ) -> SourceResult<Option<i64>> { for (i, item) in self.iter().enumerate() { - let args = Args::new(searcher.span(), [item.clone()]); - if searcher.call_vm(vm, args)?.cast::<bool>().at(searcher.span())? { + if searcher + .call(engine, [item.clone()])? + .cast::<bool>() + .at(searcher.span())? + { return Ok(Some(i as i64)); } } @@ -388,15 +395,14 @@ impl Array { #[func] pub fn filter( &self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The function to apply to each item. Must return a boolean. test: Func, ) -> SourceResult<Array> { let mut kept = EcoVec::new(); for item in self.iter() { - let args = Args::new(test.span(), [item.clone()]); - if test.call_vm(vm, args)?.cast::<bool>().at(test.span())? { + if test.call(engine, [item.clone()])?.cast::<bool>().at(test.span())? { kept.push(item.clone()) } } @@ -408,17 +414,12 @@ impl Array { #[func] pub fn map( self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The function to apply to each item. mapper: Func, ) -> SourceResult<Array> { - self.into_iter() - .map(|item| { - let args = Args::new(mapper.span(), [item]); - mapper.call_vm(vm, args) - }) - .collect() + self.into_iter().map(|item| mapper.call(engine, [item])).collect() } /// Returns a new array with the values alongside their indices. @@ -518,8 +519,8 @@ impl Array { #[func] pub fn fold( self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The initial value to start with. init: Value, /// The folding function. Must have two parameters: One for the @@ -528,8 +529,7 @@ impl Array { ) -> SourceResult<Value> { let mut acc = init; for item in self { - let args = Args::new(folder.span(), [acc, item]); - acc = folder.call_vm(vm, args)?; + acc = folder.call(engine, [acc, item])?; } Ok(acc) } @@ -579,14 +579,13 @@ impl Array { #[func] pub fn any( self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The function to apply to each item. Must return a boolean. test: Func, ) -> SourceResult<bool> { for item in self { - let args = Args::new(test.span(), [item]); - if test.call_vm(vm, args)?.cast::<bool>().at(test.span())? { + if test.call(engine, [item])?.cast::<bool>().at(test.span())? { return Ok(true); } } @@ -598,14 +597,13 @@ impl Array { #[func] pub fn all( self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The function to apply to each item. Must return a boolean. test: Func, ) -> SourceResult<bool> { for item in self { - let args = Args::new(test.span(), [item]); - if !test.call_vm(vm, args)?.cast::<bool>().at(test.span())? { + if !test.call(engine, [item])?.cast::<bool>().at(test.span())? { return Ok(false); } } @@ -714,8 +712,8 @@ impl Array { #[func] pub fn sorted( self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The callsite span. span: Span, /// If given, applies this function to the elements in the array to @@ -728,7 +726,7 @@ impl Array { let mut key_of = |x: Value| match &key { // NOTE: We are relying on `comemo`'s memoization of function // evaluation to not excessively reevaluate the `key`. - Some(f) => f.call_vm(vm, Args::new(f.span(), [x])), + Some(f) => f.call(engine, [x]), None => Ok(x), }; vec.make_mut().sort_by(|a, b| { @@ -762,8 +760,8 @@ impl Array { #[func(title = "Deduplicate")] pub fn dedup( self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// If given, applies this function to the elements in the array to /// determine the keys to deduplicate by. #[named] @@ -773,7 +771,7 @@ impl Array { let mut key_of = |x: Value| match &key { // NOTE: We are relying on `comemo`'s memoization of function // evaluation to not excessively reevaluate the `key`. - Some(f) => f.call_vm(vm, Args::new(f.span(), [x])), + Some(f) => f.call(engine, [x]), None => Ok(x), }; diff --git a/crates/typst/src/foundations/cast.rs b/crates/typst/src/foundations/cast.rs index fbd5ab14..e3b7dd01 100644 --- a/crates/typst/src/foundations/cast.rs +++ b/crates/typst/src/foundations/cast.rs @@ -12,6 +12,7 @@ use crate::diag::{At, SourceResult, StrResult}; use crate::foundations::{repr, Repr, Type, Value}; use crate::syntax::{Span, Spanned}; +#[rustfmt::skip] #[doc(inline)] pub use typst_macros::{cast, Cast}; diff --git a/crates/typst/src/foundations/content.rs b/crates/typst/src/foundations/content.rs index 7a402629..111b33ea 100644 --- a/crates/typst/src/foundations/content.rs +++ b/crates/typst/src/foundations/content.rs @@ -10,7 +10,7 @@ use serde::{Serialize, Serializer}; use smallvec::smallvec; use crate::diag::{SourceResult, StrResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ elem, func, scope, ty, Dict, Element, FromValue, Guard, IntoValue, Label, NativeElement, Recipe, Repr, Selector, Str, Style, Styles, Value, @@ -299,16 +299,19 @@ impl Content { /// Access the child and styles. pub fn to_styled(&self) -> Option<(&Content, &Styles)> { let styled = self.to::<StyledElem>()?; - let child = styled.child(); let styles = styled.styles(); Some((child, styles)) } /// Style this content with a recipe, eagerly applying it if possible. - pub fn styled_with_recipe(self, vm: &mut Vm, recipe: Recipe) -> SourceResult<Self> { + pub fn styled_with_recipe( + self, + engine: &mut Engine, + recipe: Recipe, + ) -> SourceResult<Self> { if recipe.selector.is_none() { - recipe.apply_vm(vm, self) + recipe.apply(engine, self) } else { Ok(self.styled(recipe)) } diff --git a/crates/typst/src/foundations/datetime.rs b/crates/typst/src/foundations/datetime.rs index f50daf72..78290c99 100644 --- a/crates/typst/src/foundations/datetime.rs +++ b/crates/typst/src/foundations/datetime.rs @@ -8,7 +8,7 @@ use time::macros::format_description; use time::{format_description, Month, PrimitiveDateTime}; use crate::diag::{bail, StrResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ cast, func, repr, scope, ty, Dict, Duration, Repr, Smart, Str, Value, }; @@ -296,16 +296,15 @@ impl Datetime { /// ``` #[func] pub fn today( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// An offset to apply to the current UTC date. If set to `{auto}`, the /// offset will be the local offset. #[named] #[default] offset: Smart<i64>, ) -> StrResult<Datetime> { - Ok(vm - .vt + Ok(engine .world .today(offset.as_custom()) .ok_or("unable to get the current date")?) diff --git a/crates/typst/src/foundations/element.rs b/crates/typst/src/foundations/element.rs index 64b47b78..8e4d159a 100644 --- a/crates/typst/src/foundations/element.rs +++ b/crates/typst/src/foundations/element.rs @@ -10,13 +10,12 @@ use once_cell::sync::Lazy; use smallvec::SmallVec; use crate::diag::{SourceResult, StrResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ cast, Args, Content, Dict, Func, Label, ParamInfo, Repr, Scope, Selector, StyleChain, Styles, Value, }; use crate::introspection::Location; -use crate::layout::Vt; use crate::syntax::Span; use crate::text::{Lang, Region}; use crate::util::Static; @@ -66,13 +65,17 @@ impl Element { } /// Construct an instance of this element. - pub fn construct(self, vm: &mut Vm, args: &mut Args) -> SourceResult<Content> { - (self.0.construct)(vm, args) + pub fn construct( + self, + engine: &mut Engine, + args: &mut Args, + ) -> SourceResult<Content> { + (self.0.construct)(engine, args) } /// Execute the set rule for the element and return the resulting style map. - pub fn set(self, vm: &mut Vm, mut args: Args) -> SourceResult<Styles> { - let styles = (self.0.set)(vm, &mut args)?; + pub fn set(self, engine: &mut Engine, mut args: Args) -> SourceResult<Styles> { + let styles = (self.0.set)(engine, &mut args)?; args.finish()?; Ok(styles) } @@ -275,7 +278,7 @@ pub trait Construct { /// /// This is passed only the arguments that remain after execution of the /// element's set rule. - fn construct(vm: &mut Vm, args: &mut Args) -> SourceResult<Content> + fn construct(engine: &mut Engine, args: &mut Args) -> SourceResult<Content> where Self: Sized; } @@ -283,7 +286,7 @@ pub trait Construct { /// An element's set rule. pub trait Set { /// Parse relevant arguments into style properties for this element. - fn set(vm: &mut Vm, args: &mut Args) -> SourceResult<Styles> + fn set(engine: &mut Engine, args: &mut Args) -> SourceResult<Styles> where Self: Sized; } @@ -295,8 +298,8 @@ pub struct NativeElementData { pub title: &'static str, pub docs: &'static str, pub keywords: &'static [&'static str], - pub construct: fn(&mut Vm, &mut Args) -> SourceResult<Content>, - pub set: fn(&mut Vm, &mut Args) -> SourceResult<Styles>, + pub construct: fn(&mut Engine, &mut Args) -> SourceResult<Content>, + pub set: fn(&mut Engine, &mut Args) -> SourceResult<Styles>, pub vtable: fn(of: TypeId) -> Option<*const ()>, pub field_id: fn(name: &str) -> Option<u8>, pub field_name: fn(u8) -> Option<&'static str>, @@ -320,13 +323,14 @@ cast! { /// rule. pub trait Synthesize { /// Prepare the element for show rule application. - fn synthesize(&mut self, vt: &mut Vt, styles: StyleChain) -> SourceResult<()>; + fn synthesize(&mut self, engine: &mut Engine, styles: StyleChain) + -> SourceResult<()>; } /// The base recipe for an element. pub trait Show { /// Execute the base recipe for this element. - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content>; + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content>; } /// Post-process an element after it was realized. diff --git a/crates/typst/src/foundations/func.rs b/crates/typst/src/foundations/func.rs index f1da6e37..6729b39d 100644 --- a/crates/typst/src/foundations/func.rs +++ b/crates/typst/src/foundations/func.rs @@ -6,14 +6,12 @@ use ecow::{eco_format, EcoString}; use once_cell::sync::Lazy; use crate::diag::{bail, SourceResult, StrResult}; -use crate::eval::{Route, Vm}; +use crate::engine::Engine; use crate::foundations::{ - cast, repr, scope, ty, Args, CastInfo, Content, Element, IntoValue, Scope, Scopes, - Selector, Type, Value, + cast, repr, scope, ty, Args, CastInfo, Content, Element, IntoArgs, Scope, Selector, + Type, Value, }; -use crate::introspection::Locator; -use crate::layout::Vt; -use crate::syntax::{ast, FileId, Span, SyntaxNode}; +use crate::syntax::{ast, Span, SyntaxNode}; use crate::util::Static; #[doc(inline)] @@ -252,7 +250,13 @@ impl Func { } /// Call the function with the given arguments. - pub fn call_vm(&self, vm: &mut Vm, mut args: Args) -> SourceResult<Value> { + #[tracing::instrument(skip_all)] + pub fn call(&self, engine: &mut Engine, args: impl IntoArgs) -> SourceResult<Value> { + self.call_impl(engine, args.into_args(self.span)) + } + + /// Non-generic implementation of `call`. + fn call_impl(&self, engine: &mut Engine, mut args: Args) -> SourceResult<Value> { let _span = tracing::info_span!( "call", name = self.name().unwrap_or("<anon>"), @@ -261,59 +265,32 @@ impl Func { match &self.repr { Repr::Native(native) => { - let value = (native.function)(vm, &mut args)?; + let value = (native.function)(engine, &mut args)?; args.finish()?; Ok(value) } Repr::Element(func) => { - let value = func.construct(vm, &mut args)?; + let value = func.construct(engine, &mut args)?; args.finish()?; Ok(Value::Content(value)) } - Repr::Closure(closure) => { - // Determine the route inside the closure. - let fresh = Route::new(closure.file); - let route = if vm.file.is_none() { fresh.track() } else { vm.route }; - crate::eval::call_closure( - self, - closure, - vm.world(), - route, - vm.vt.introspector, - vm.vt.locator.track(), - TrackedMut::reborrow_mut(&mut vm.vt.tracer), - vm.depth + 1, - args, - ) - } + Repr::Closure(closure) => crate::eval::call_closure( + self, + closure, + engine.world, + engine.introspector, + engine.route.track(), + engine.locator.track(), + TrackedMut::reborrow_mut(&mut engine.tracer), + args, + ), Repr::With(with) => { args.items = with.1.items.iter().cloned().chain(args.items).collect(); - with.0.call_vm(vm, args) + with.0.call(engine, args) } } } - /// Call the function with a Vt. - #[tracing::instrument(skip_all)] - pub fn call_vt<T: IntoValue>( - &self, - vt: &mut Vt, - args: impl IntoIterator<Item = T>, - ) -> SourceResult<Value> { - let route = Route::default(); - let scopes = Scopes::new(None); - let mut locator = Locator::chained(vt.locator.track()); - let vt = Vt { - world: vt.world, - introspector: vt.introspector, - locator: &mut locator, - tracer: TrackedMut::reborrow_mut(&mut vt.tracer), - }; - let mut vm = Vm::new(vt, route.track(), None, scopes); - let args = Args::new(self.span(), args); - self.call_vm(&mut vm, args) - } - /// The function's span. pub fn span(&self) -> Span { self.span @@ -443,7 +420,7 @@ pub trait NativeFunc { /// Defines a native function. #[derive(Debug)] pub struct NativeFuncData { - pub function: fn(&mut Vm, &mut Args) -> SourceResult<Value>, + pub function: fn(&mut Engine, &mut Args) -> SourceResult<Value>, pub name: &'static str, pub title: &'static str, pub docs: &'static str, @@ -495,8 +472,6 @@ pub struct ParamInfo { pub struct Closure { /// The closure's syntax node. Must be castable to `ast::Closure`. pub node: SyntaxNode, - /// The source file where the closure was defined. - pub file: Option<FileId>, /// Default values of named parameters. pub defaults: Vec<Value>, /// Captured values from outer scopes. diff --git a/crates/typst/src/foundations/mod.rs b/crates/typst/src/foundations/mod.rs index b2c35194..4ddc2162 100644 --- a/crates/typst/src/foundations/mod.rs +++ b/crates/typst/src/foundations/mod.rs @@ -60,6 +60,7 @@ pub use self::ty::*; pub use self::value::*; pub use self::version::*; +#[rustfmt::skip] #[doc(hidden)] pub use { ecow::{eco_format, eco_vec}, @@ -70,7 +71,8 @@ pub use { use ecow::EcoString; use crate::diag::{bail, SourceResult, StrResult}; -use crate::eval::{EvalMode, Vm}; +use crate::engine::Engine; +use crate::eval::EvalMode; use crate::syntax::Spanned; /// Foundational types and functions. @@ -251,8 +253,8 @@ impl assert { /// ``` #[func(title = "Evaluate")] pub fn eval( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// A string of Typst code to evaluate. /// /// The code in the string cannot interact with the file system. @@ -289,5 +291,5 @@ pub fn eval( for (key, value) in dict { scope.define(key, value); } - crate::eval::eval_string(vm.world(), &text, span, mode, scope) + crate::eval::eval_string(engine.world, &text, span, mode, scope) } diff --git a/crates/typst/src/foundations/plugin.rs b/crates/typst/src/foundations/plugin.rs index 6071b3bd..89237f94 100644 --- a/crates/typst/src/foundations/plugin.rs +++ b/crates/typst/src/foundations/plugin.rs @@ -3,10 +3,10 @@ use std::hash::{Hash, Hasher}; use std::sync::{Arc, Mutex}; use ecow::{eco_format, EcoString}; -use wasmi::{AsContext, AsContextMut, Caller, Engine, Linker, Module}; +use wasmi::{AsContext, AsContextMut}; use crate::diag::{bail, At, SourceResult, StrResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{func, repr, scope, ty, Bytes}; use crate::syntax::Spanned; use crate::World; @@ -152,14 +152,14 @@ impl Plugin { /// Creates a new plugin from a WebAssembly file. #[func(constructor)] pub fn construct( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Path to a WebAssembly file. path: Spanned<EcoString>, ) -> SourceResult<Plugin> { let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; Plugin::new(data).at(span) } } @@ -168,11 +168,11 @@ impl Plugin { /// Create a new plugin from raw WebAssembly bytes. #[comemo::memoize] pub fn new(bytes: Bytes) -> StrResult<Self> { - let engine = Engine::default(); - let module = Module::new(&engine, bytes.as_slice()) + let engine = wasmi::Engine::default(); + let module = wasmi::Module::new(&engine, bytes.as_slice()) .map_err(|err| format!("failed to load WebAssembly module ({err})"))?; - let mut linker = Linker::new(&engine); + let mut linker = wasmi::Linker::new(&engine); linker .func_wrap( "typst_env", @@ -323,7 +323,10 @@ impl Hash for Plugin { } /// Write the arguments to the plugin function into the plugin's memory. -fn wasm_minimal_protocol_write_args_to_buffer(mut caller: Caller<StoreData>, ptr: u32) { +fn wasm_minimal_protocol_write_args_to_buffer( + mut caller: wasmi::Caller<StoreData>, + ptr: u32, +) { let memory = caller.get_export("memory").unwrap().into_memory().unwrap(); let arguments = std::mem::take(&mut caller.data_mut().args); let mut offset = ptr as usize; @@ -342,7 +345,7 @@ fn wasm_minimal_protocol_write_args_to_buffer(mut caller: Caller<StoreData>, ptr /// Extracts the output of the plugin function from the plugin's memory. fn wasm_minimal_protocol_send_result_to_host( - mut caller: Caller<StoreData>, + mut caller: wasmi::Caller<StoreData>, ptr: u32, len: u32, ) { diff --git a/crates/typst/src/foundations/str.rs b/crates/typst/src/foundations/str.rs index 4b56971a..83bde675 100644 --- a/crates/typst/src/foundations/str.rs +++ b/crates/typst/src/foundations/str.rs @@ -8,10 +8,10 @@ use serde::{Deserialize, Serialize}; use unicode_segmentation::UnicodeSegmentation; use crate::diag::{bail, At, SourceResult, StrResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ - cast, dict, func, repr, scope, ty, Args, Array, Bytes, Dict, Func, IntoValue, Label, - Repr, Type, Value, Version, + cast, dict, func, repr, scope, ty, Array, Bytes, Dict, Func, IntoValue, Label, Repr, + Type, Value, Version, }; use crate::layout::Align; use crate::syntax::{Span, Spanned}; @@ -422,8 +422,8 @@ impl Str { #[func] pub fn replace( &self, - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The pattern to search for. pattern: StrPattern, /// The string to replace the matches with or a function that gets a @@ -449,8 +449,8 @@ impl Str { match &replacement { Replacement::Str(s) => output.push_str(s), Replacement::Func(func) => { - let args = Args::new(func.span(), [dict.into_value()]); - let piece = func.call_vm(vm, args)?.cast::<Str>().at(func.span())?; + let piece = + func.call(engine, [dict])?.cast::<Str>().at(func.span())?; output.push_str(&piece); } } diff --git a/crates/typst/src/foundations/styles.rs b/crates/typst/src/foundations/styles.rs index 78bd24d6..ca6a9e78 100644 --- a/crates/typst/src/foundations/styles.rs +++ b/crates/typst/src/foundations/styles.rs @@ -10,12 +10,10 @@ use once_cell::sync::Lazy; use smallvec::SmallVec; use crate::diag::{SourceResult, Trace, Tracepoint}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ - cast, elem, func, ty, Args, Content, Element, Func, NativeElement, Repr, Selector, - Show, Value, + cast, elem, func, ty, Content, Element, Func, NativeElement, Repr, Selector, Show, }; -use crate::layout::Vt; use crate::syntax::Span; use crate::text::{FontFamily, FontList, TextElem}; @@ -58,8 +56,8 @@ struct StyleElem { impl Show for StyleElem { #[tracing::instrument(name = "StyleElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { - Ok(self.func().call_vt(vt, [styles.to_map()])?.display()) + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { + Ok(self.func().call(engine, [styles.to_map()])?.display()) } } @@ -356,37 +354,23 @@ impl Recipe { } /// Apply the recipe to the given content. - pub fn apply_vm(&self, vm: &mut Vm, content: Content) -> SourceResult<Content> { - match &self.transform { - Transformation::Content(content) => Ok(content.clone()), + pub fn apply(&self, engine: &mut Engine, content: Content) -> SourceResult<Content> { + let mut content = match &self.transform { + Transformation::Content(content) => content.clone(), Transformation::Func(func) => { - let args = Args::new(self.span, [Value::Content(content.clone())]); - let mut result = func.call_vm(vm, args); - // For selector-less show rules, a tracepoint makes no sense. + let mut result = func.call(engine, [content.clone()]); if self.selector.is_some() { let point = || Tracepoint::Show(content.func().name().into()); - result = result.trace(vm.world(), point, content.span()); + result = result.trace(engine.world, point, content.span()); } - Ok(result?.display()) + result?.display() } - Transformation::Style(styles) => Ok(content.styled_with_map(styles.clone())), - } - } - - /// Apply the recipe to the given content. - pub fn apply_vt(&self, vt: &mut Vt, content: Content) -> SourceResult<Content> { - match &self.transform { - Transformation::Content(content) => Ok(content.clone()), - Transformation::Func(func) => { - let mut result = func.call_vt(vt, [Value::Content(content.clone())]); - if self.selector.is_some() { - let point = || Tracepoint::Show(content.func().name().into()); - result = result.trace(vt.world, point, content.span()); - } - Ok(result?.display()) - } - Transformation::Style(styles) => Ok(content.styled_with_map(styles.clone())), + Transformation::Style(styles) => content.styled_with_map(styles.clone()), + }; + if content.span().is_detached() { + content = content.spanned(self.span); } + Ok(content) } } diff --git a/crates/typst/src/foundations/ty.rs b/crates/typst/src/foundations/ty.rs index 47add6ec..4c2098f3 100644 --- a/crates/typst/src/foundations/ty.rs +++ b/crates/typst/src/foundations/ty.rs @@ -8,6 +8,7 @@ use crate::diag::StrResult; use crate::foundations::{cast, func, Func, NativeFuncData, Repr, Scope, Value}; use crate::util::Static; +#[rustfmt::skip] #[doc(inline)] pub use typst_macros::{scope, ty}; diff --git a/crates/typst/src/introspection/counter.rs b/crates/typst/src/introspection/counter.rs index 7b073681..ce485997 100644 --- a/crates/typst/src/introspection/counter.rs +++ b/crates/typst/src/introspection/counter.rs @@ -6,6 +6,7 @@ use ecow::{eco_format, eco_vec, EcoString, EcoVec}; use smallvec::{smallvec, SmallVec}; use crate::diag::{At, SourceResult, StrResult}; +use crate::engine::{Engine, Route}; use crate::eval::Tracer; use crate::foundations::{ cast, elem, func, scope, select_where, ty, Array, Content, Element, Func, IntoValue, @@ -13,7 +14,7 @@ use crate::foundations::{ Value, }; use crate::introspection::{Introspector, Locatable, Location, Locator, Meta}; -use crate::layout::{Frame, FrameItem, PageElem, Vt}; +use crate::layout::{Frame, FrameItem, PageElem}; use crate::math::EquationElem; use crate::model::{FigureElem, HeadingElem, Numbering, NumberingPattern}; use crate::util::NonZeroExt; @@ -222,9 +223,13 @@ impl Counter { } /// Gets the current and final value of the state combined in one state. - pub fn both(&self, vt: &mut Vt, location: Location) -> SourceResult<CounterState> { - let sequence = self.sequence(vt)?; - let offset = vt + pub fn both( + &self, + engine: &mut Engine, + location: Location, + ) -> SourceResult<CounterState> { + let sequence = self.sequence(engine)?; + let offset = engine .introspector .query(&self.selector().before(location.into(), true)) .len(); @@ -232,10 +237,10 @@ impl Counter { let (mut final_state, final_page) = sequence.last().unwrap().clone(); if self.is_page() { let at_delta = - vt.introspector.page(location).get().saturating_sub(at_page.get()); + engine.introspector.page(location).get().saturating_sub(at_page.get()); at_state.step(NonZeroUsize::ONE, at_delta); let final_delta = - vt.introspector.pages().get().saturating_sub(final_page.get()); + engine.introspector.pages().get().saturating_sub(final_page.get()); final_state.step(NonZeroUsize::ONE, final_delta); } Ok(CounterState(smallvec![at_state.first(), final_state.first()])) @@ -247,13 +252,14 @@ impl Counter { /// of counter updates from quadratic to linear. fn sequence( &self, - vt: &mut Vt, + engine: &mut Engine, ) -> SourceResult<EcoVec<(CounterState, NonZeroUsize)>> { self.sequence_impl( - vt.world, - vt.introspector, - vt.locator.track(), - TrackedMut::reborrow_mut(&mut vt.tracer), + engine.world, + engine.introspector, + engine.route.track(), + engine.locator.track(), + TrackedMut::reborrow_mut(&mut engine.tracer), ) } @@ -263,11 +269,18 @@ impl Counter { &self, world: Tracked<dyn World + '_>, introspector: Tracked<Introspector>, + route: Tracked<Route>, locator: Tracked<Locator>, tracer: TrackedMut<Tracer>, ) -> SourceResult<EcoVec<(CounterState, NonZeroUsize)>> { let mut locator = Locator::chained(locator); - let mut vt = Vt { world, introspector, locator: &mut locator, tracer }; + let mut engine = Engine { + world, + introspector, + route: Route::extend(route), + locator: &mut locator, + tracer, + }; let mut state = CounterState::init(&self.0); let mut page = NonZeroUsize::ONE; @@ -288,7 +301,7 @@ impl Counter { Some(countable) => countable.update(), None => Some(CounterUpdate::Step(NonZeroUsize::ONE)), } { - state.update(&mut vt, update)?; + state.update(&mut engine, update)?; } stops.push((state.clone(), page)); @@ -399,21 +412,22 @@ impl Counter { #[func] pub fn at( &self, - /// The virtual typesetter. - vt: &mut Vt, + /// The engine. + engine: &mut Engine, /// The location at which the counter value should be retrieved. A /// suitable location can be retrieved from [`locate`]($locate) or /// [`query`]($query). location: Location, ) -> SourceResult<CounterState> { - let sequence = self.sequence(vt)?; - let offset = vt + let sequence = self.sequence(engine)?; + let offset = engine .introspector .query(&self.selector().before(location.into(), true)) .len(); let (mut state, page) = sequence[offset].clone(); if self.is_page() { - let delta = vt.introspector.page(location).get().saturating_sub(page.get()); + let delta = + engine.introspector.page(location).get().saturating_sub(page.get()); state.step(NonZeroUsize::ONE, delta); } @@ -425,8 +439,8 @@ impl Counter { #[func] pub fn final_( &self, - /// The virtual typesetter. - vt: &mut Vt, + /// The engine. + engine: &mut Engine, /// Can be an arbitrary location, as its value is irrelevant for the /// method's return value. Why is it required then? Typst has to /// evaluate parts of your code multiple times to determine all counter @@ -438,10 +452,10 @@ impl Counter { location: Location, ) -> SourceResult<CounterState> { let _ = location; - let sequence = self.sequence(vt)?; + let sequence = self.sequence(engine)?; let (mut state, page) = sequence.last().unwrap().clone(); if self.is_page() { - let delta = vt.introspector.pages().get().saturating_sub(page.get()); + let delta = engine.introspector.pages().get().saturating_sub(page.get()); state.step(NonZeroUsize::ONE, delta); } Ok(state) @@ -544,12 +558,17 @@ impl CounterState { } /// Advance the counter and return the numbers for the given heading. - pub fn update(&mut self, vt: &mut Vt, update: CounterUpdate) -> SourceResult<()> { + pub fn update( + &mut self, + engine: &mut Engine, + update: CounterUpdate, + ) -> SourceResult<()> { match update { CounterUpdate::Set(state) => *self = state, CounterUpdate::Step(level) => self.step(level, 1), CounterUpdate::Func(func) => { - *self = func.call_vt(vt, self.0.iter().copied())?.cast().at(func.span())? + *self = + func.call(engine, self.0.iter().copied())?.cast().at(func.span())? } } Ok(()) @@ -575,8 +594,12 @@ impl CounterState { } /// Display the counter state with a numbering. - pub fn display(&self, vt: &mut Vt, numbering: &Numbering) -> SourceResult<Content> { - Ok(numbering.apply_vt(vt, &self.0)?.display()) + pub fn display( + &self, + engine: &mut Engine, + numbering: &Numbering, + ) -> SourceResult<Content> { + Ok(numbering.apply(engine, &self.0)?.display()) } } @@ -608,8 +631,8 @@ struct DisplayElem { impl Show for DisplayElem { #[tracing::instrument(name = "DisplayElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { - Ok(vt.delayed(|vt| { + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { + Ok(engine.delayed(|engine| { let location = self.location().unwrap(); let counter = self.counter(); let numbering = self @@ -633,12 +656,12 @@ impl Show for DisplayElem { .unwrap_or_else(|| NumberingPattern::from_str("1.1").unwrap().into()); let state = if *self.both() { - counter.both(vt, location)? + counter.both(engine, location)? } else { - counter.at(vt, location)? + counter.at(engine, location)? }; - state.display(vt, &numbering) + state.display(engine, &numbering) })) } } @@ -657,7 +680,7 @@ struct UpdateElem { impl Show for UpdateElem { #[tracing::instrument(name = "UpdateElem::show", skip(self))] - fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { Ok(Content::empty()) } } @@ -693,15 +716,15 @@ impl ManualPageCounter { } /// Advance past a page. - pub fn visit(&mut self, vt: &mut Vt, page: &Frame) -> SourceResult<()> { + pub fn visit(&mut self, engine: &mut Engine, page: &Frame) -> SourceResult<()> { for (_, item) in page.items() { match item { - FrameItem::Group(group) => self.visit(vt, &group.frame)?, + FrameItem::Group(group) => self.visit(engine, &group.frame)?, FrameItem::Meta(Meta::Elem(elem), _) => { let Some(elem) = elem.to::<UpdateElem>() else { continue }; if *elem.key() == CounterKey::Page { let mut state = CounterState(smallvec![self.logical]); - state.update(vt, elem.update().clone())?; + state.update(engine, elem.update().clone())?; self.logical = state.first(); } } diff --git a/crates/typst/src/introspection/locate.rs b/crates/typst/src/introspection/locate.rs index 1c4f0e5a..69dcadd8 100644 --- a/crates/typst/src/introspection/locate.rs +++ b/crates/typst/src/introspection/locate.rs @@ -1,7 +1,7 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, func, Content, Func, NativeElement, Show, StyleChain}; use crate::introspection::Locatable; -use crate::layout::Vt; /// Provides access to the location of content. /// @@ -37,11 +37,11 @@ struct LocateElem { } impl Show for LocateElem { - #[tracing::instrument(name = "LocateElem::show", skip(self, vt))] - fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> { - Ok(vt.delayed(|vt| { + #[tracing::instrument(name = "LocateElem::show", skip(self, engine))] + fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { + Ok(engine.delayed(|engine| { let location = self.location().unwrap(); - Ok(self.func().call_vt(vt, [location])?.display()) + Ok(self.func().call(engine, [location])?.display()) })) } } diff --git a/crates/typst/src/introspection/location.rs b/crates/typst/src/introspection/location.rs index b70dc4ad..0ceaac8b 100644 --- a/crates/typst/src/introspection/location.rs +++ b/crates/typst/src/introspection/location.rs @@ -2,7 +2,7 @@ use std::num::NonZeroUsize; use ecow::EcoString; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{cast, func, scope, ty, Dict, Repr}; use crate::model::Numbering; @@ -45,8 +45,8 @@ impl Location { /// If you want to know the value of the page counter, use /// `{counter(page).at(loc)}` instead. #[func] - pub fn page(self, vm: &mut Vm) -> NonZeroUsize { - vm.vt.introspector.page(self) + pub fn page(self, engine: &mut Engine) -> NonZeroUsize { + engine.introspector.page(self) } /// Return a dictionary with the page number and the x, y position for this @@ -56,8 +56,8 @@ impl Location { /// If you only need the page number, use `page()` instead as it allows /// Typst to skip unnecessary work. #[func] - pub fn position(self, vm: &mut Vm) -> Dict { - vm.vt.introspector.position(self).into() + pub fn position(self, engine: &mut Engine) -> Dict { + engine.introspector.position(self).into() } /// Returns the page numbering pattern of the page at this location. This @@ -68,8 +68,8 @@ impl Location { /// If the page numbering is set to `none` at that location, this function /// returns `none`. #[func] - pub fn page_numbering(self, vm: &mut Vm) -> Option<Numbering> { - vm.vt.introspector.page_numbering(self).cloned() + pub fn page_numbering(self, engine: &mut Engine) -> Option<Numbering> { + engine.introspector.page_numbering(self).cloned() } } @@ -83,5 +83,5 @@ cast! { type Location, } -/// Makes this element locatable through `vt.locate`. +/// Makes this element locatable through `engine.locate`. pub trait Locatable {} diff --git a/crates/typst/src/introspection/metadata.rs b/crates/typst/src/introspection/metadata.rs index 4042bc04..15d144eb 100644 --- a/crates/typst/src/introspection/metadata.rs +++ b/crates/typst/src/introspection/metadata.rs @@ -1,7 +1,7 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Behave, Behaviour, Content, Show, StyleChain, Value}; use crate::introspection::Locatable; -use crate::layout::Vt; /// Exposes a value to the query system without producing visible content. /// @@ -31,7 +31,7 @@ pub struct MetadataElem { } impl Show for MetadataElem { - fn show(&self, _vt: &mut Vt, _styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, _styles: StyleChain) -> SourceResult<Content> { Ok(Content::empty()) } } diff --git a/crates/typst/src/introspection/query.rs b/crates/typst/src/introspection/query.rs index 1024238e..5b70ba51 100644 --- a/crates/typst/src/introspection/query.rs +++ b/crates/typst/src/introspection/query.rs @@ -1,4 +1,4 @@ -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{func, Array, LocatableSelector, Value}; use crate::introspection::Location; @@ -129,8 +129,8 @@ use crate::introspection::Location; /// ``` #[func] pub fn query( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Can be an element function like a `heading` or `figure`, a `{<label>}` /// or a more complex selector like `{heading.where(level: 1)}`. /// @@ -152,7 +152,7 @@ pub fn query( location: Location, ) -> Array { let _ = location; - let vec = vm.vt.introspector.query(&target.0); + let vec = engine.introspector.query(&target.0); vec.into_iter() .map(|elem| Value::Content(elem.into_inner())) .collect() diff --git a/crates/typst/src/introspection/state.rs b/crates/typst/src/introspection/state.rs index af6d7933..8479bace 100644 --- a/crates/typst/src/introspection/state.rs +++ b/crates/typst/src/introspection/state.rs @@ -2,13 +2,13 @@ use comemo::{Tracked, TrackedMut}; use ecow::{eco_format, eco_vec, EcoString, EcoVec}; use crate::diag::SourceResult; +use crate::engine::{Engine, Route}; use crate::eval::Tracer; use crate::foundations::{ cast, elem, func, scope, select_where, ty, Content, Func, NativeElement, Repr, Selector, Show, Str, StyleChain, Value, }; use crate::introspection::{Introspector, Locatable, Location, Locator}; -use crate::layout::Vt; use crate::World; /// Manages stateful parts of your document. @@ -204,12 +204,13 @@ impl State { /// /// This has to happen just once for all states, cutting down the number /// of state updates from quadratic to linear. - fn sequence(&self, vt: &mut Vt) -> SourceResult<EcoVec<Value>> { + fn sequence(&self, engine: &mut Engine) -> SourceResult<EcoVec<Value>> { self.sequence_impl( - vt.world, - vt.introspector, - vt.locator.track(), - TrackedMut::reborrow_mut(&mut vt.tracer), + engine.world, + engine.introspector, + engine.route.track(), + engine.locator.track(), + TrackedMut::reborrow_mut(&mut engine.tracer), ) } @@ -219,11 +220,18 @@ impl State { &self, world: Tracked<dyn World + '_>, introspector: Tracked<Introspector>, + route: Tracked<Route>, locator: Tracked<Locator>, tracer: TrackedMut<Tracer>, ) -> SourceResult<EcoVec<Value>> { let mut locator = Locator::chained(locator); - let mut vt = Vt { world, introspector, locator: &mut locator, tracer }; + let mut engine = Engine { + world, + introspector, + route: Route::extend(route), + locator: &mut locator, + tracer, + }; let mut state = self.init.clone(); let mut stops = eco_vec![state.clone()]; @@ -231,7 +239,7 @@ impl State { let elem = elem.to::<UpdateElem>().unwrap(); match elem.update() { StateUpdate::Set(value) => state = value.clone(), - StateUpdate::Func(func) => state = func.call_vt(&mut vt, [state])?, + StateUpdate::Func(func) => state = func.call(&mut engine, [state])?, } stops.push(state.clone()); } @@ -295,15 +303,15 @@ impl State { #[func] pub fn at( &self, - /// The virtual typesetter. - vt: &mut Vt, + /// The engine. + engine: &mut Engine, /// The location at which the state's value should be retrieved. A /// suitable location can be retrieved from [`locate`]($locate) or /// [`query`]($query). location: Location, ) -> SourceResult<Value> { - let sequence = self.sequence(vt)?; - let offset = vt + let sequence = self.sequence(engine)?; + let offset = engine .introspector .query(&self.selector().before(location.into(), true)) .len(); @@ -314,8 +322,8 @@ impl State { #[func] pub fn final_( &self, - /// The virtual typesetter. - vt: &mut Vt, + /// The engine. + engine: &mut Engine, /// Can be an arbitrary location, as its value is irrelevant for the /// method's return value. Why is it required then? As noted before, /// Typst has to evaluate parts of your code multiple times to determine @@ -327,7 +335,7 @@ impl State { location: Location, ) -> SourceResult<Value> { let _ = location; - let sequence = self.sequence(vt)?; + let sequence = self.sequence(engine)?; Ok(sequence.last().unwrap().clone()) } } @@ -377,13 +385,13 @@ struct DisplayElem { } impl Show for DisplayElem { - #[tracing::instrument(name = "DisplayElem::show", skip(self, vt))] - fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> { - Ok(vt.delayed(|vt| { + #[tracing::instrument(name = "DisplayElem::show", skip(self, engine))] + fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { + Ok(engine.delayed(|engine| { let location = self.location().unwrap(); - let value = self.state().at(vt, location)?; + let value = self.state().at(engine, location)?; Ok(match self.func() { - Some(func) => func.call_vt(vt, [value])?.display(), + Some(func) => func.call(engine, [value])?.display(), None => value.display(), }) })) @@ -404,7 +412,7 @@ struct UpdateElem { impl Show for UpdateElem { #[tracing::instrument(name = "UpdateElem::show")] - fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { Ok(Content::empty()) } } diff --git a/crates/typst/src/layout/align.rs b/crates/typst/src/layout/align.rs index 74db4373..3d4017f3 100644 --- a/crates/typst/src/layout/align.rs +++ b/crates/typst/src/layout/align.rs @@ -3,10 +3,11 @@ use std::ops::Add; use ecow::{eco_format, EcoString}; use crate::diag::{bail, SourceResult, StrResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, func, scope, ty, Content, Fold, Repr, Resolve, Show, StyleChain, }; -use crate::layout::{Abs, Axes, Axis, Dir, Side, Vt}; +use crate::layout::{Abs, Axes, Axis, Dir, Side}; use crate::text::TextElem; /// Aligns content horizontally and vertically. @@ -46,7 +47,7 @@ pub struct AlignElem { impl Show for AlignElem { #[tracing::instrument(name = "AlignElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self .body() .clone() diff --git a/crates/typst/src/layout/columns.rs b/crates/typst/src/layout/columns.rs index 852ef8f8..275dbbeb 100644 --- a/crates/typst/src/layout/columns.rs +++ b/crates/typst/src/layout/columns.rs @@ -1,9 +1,10 @@ use std::num::NonZeroUsize; use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Behave, Behaviour, Content, StyleChain}; use crate::layout::{ - Abs, Axes, Dir, Fragment, Frame, Layout, Length, Point, Ratio, Regions, Rel, Size, Vt, + Abs, Axes, Dir, Fragment, Frame, Layout, Length, Point, Ratio, Regions, Rel, Size, }; use crate::text::TextElem; use crate::util::Numeric; @@ -60,7 +61,7 @@ impl Layout for ColumnsElem { #[tracing::instrument(name = "ColumnsElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -69,7 +70,7 @@ impl Layout for ColumnsElem { // Separating the infinite space into infinite columns does not make // much sense. if !regions.size.x.is_finite() { - return body.layout(vt, styles, regions); + return body.layout(engine, styles, regions); } // Determine the width of the gutter and each column. @@ -94,7 +95,7 @@ impl Layout for ColumnsElem { }; // Layout the children. - let mut frames = body.layout(vt, styles, pod)?.into_iter(); + let mut frames = body.layout(engine, styles, pod)?.into_iter(); let mut finished = vec![]; let dir = TextElem::dir_in(styles); diff --git a/crates/typst/src/layout/container.rs b/crates/typst/src/layout/container.rs index cb65d4d8..cdc5c489 100644 --- a/crates/typst/src/layout/container.rs +++ b/crates/typst/src/layout/container.rs @@ -1,10 +1,11 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{ cast, elem, AutoValue, Content, NativeElement, Resolve, Smart, StyleChain, Value, }; use crate::layout::{ Abs, Axes, Corners, Em, Fr, Fragment, FrameKind, Layout, Length, Ratio, Regions, Rel, - Sides, Size, Spacing, VElem, Vt, + Sides, Size, Spacing, VElem, }; use crate::util::Numeric; use crate::visualize::{clip_rect, Paint, Stroke}; @@ -112,7 +113,7 @@ impl Layout for BoxElem { #[tracing::instrument(name = "BoxElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -140,7 +141,7 @@ impl Layout for BoxElem { // Select the appropriate base and expansion for the child depending // on whether it is automatically or relatively sized. let pod = Regions::one(size, expand); - let mut frame = body.layout(vt, styles, pod)?.into_frame(); + let mut frame = body.layout(engine, styles, pod)?.into_frame(); // Enforce correct size. *frame.size_mut() = expand.select(size, frame.size()); @@ -344,7 +345,7 @@ impl Layout for BlockElem { #[tracing::instrument(name = "BlockElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -368,7 +369,7 @@ impl Layout for BlockElem { // Measure to ensure frames for all regions have the same width. if sizing.x == Smart::Auto { let pod = Regions::one(size, Axes::splat(false)); - let frame = body.measure(vt, styles, pod)?.into_frame(); + let frame = body.measure(engine, styles, pod)?.into_frame(); size.x = frame.width(); expand.x = true; } @@ -403,7 +404,7 @@ impl Layout for BlockElem { pod.last = None; } - let mut frames = body.layout(vt, styles, pod)?.into_frames(); + let mut frames = body.layout(engine, styles, pod)?.into_frames(); for (frame, &height) in frames.iter_mut().zip(&heights) { *frame.size_mut() = expand.select(Size::new(size.x, height), frame.size()); @@ -411,7 +412,7 @@ impl Layout for BlockElem { frames } else { let pod = Regions::one(size, expand); - let mut frames = body.layout(vt, styles, pod)?.into_frames(); + let mut frames = body.layout(engine, styles, pod)?.into_frames(); *frames[0].size_mut() = expand.select(size, frames[0].size()); frames }; diff --git a/crates/typst/src/layout/flow.rs b/crates/typst/src/layout/flow.rs index 1c97c110..b4e7afd1 100644 --- a/crates/typst/src/layout/flow.rs +++ b/crates/typst/src/layout/flow.rs @@ -1,12 +1,13 @@ use comemo::Prehashed; use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{elem, Content, NativeElement, Resolve, Smart, StyleChain}; use crate::introspection::{Meta, MetaElem}; use crate::layout::{ Abs, AlignElem, Axes, BlockElem, ColbreakElem, ColumnsElem, FixedAlign, Fr, Fragment, Frame, FrameItem, Layout, PlaceElem, Point, Regions, Rel, Size, Spacing, VAlign, - VElem, Vt, + VElem, }; use crate::model::{FootnoteElem, FootnoteEntry, ParElem}; use crate::util::Numeric; @@ -30,7 +31,7 @@ impl Layout for FlowElem { #[tracing::instrument(name = "FlowElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -51,9 +52,9 @@ impl Layout for FlowElem { } if let Some(elem) = child.to::<VElem>() { - layouter.layout_spacing(vt, elem, styles)?; + layouter.layout_spacing(engine, elem, styles)?; } else if let Some(elem) = child.to::<ParElem>() { - layouter.layout_par(vt, elem, styles)?; + layouter.layout_par(engine, elem, styles)?; } else if child.is::<LineElem>() || child.is::<RectElem>() || child.is::<SquareElem>() @@ -64,7 +65,7 @@ impl Layout for FlowElem { || child.is::<PathElem>() { let layoutable = child.with::<dyn Layout>().unwrap(); - layouter.layout_single(vt, layoutable, styles)?; + layouter.layout_single(engine, layoutable, styles)?; } else if child.is::<MetaElem>() { let mut frame = Frame::soft(Size::zero()); frame.meta(styles, true); @@ -75,20 +76,20 @@ impl Layout for FlowElem { movable: false, }); } else if let Some(placed) = child.to::<PlaceElem>() { - layouter.layout_placed(vt, placed, styles)?; + layouter.layout_placed(engine, placed, styles)?; } else if child.can::<dyn Layout>() { - layouter.layout_multiple(vt, child, styles)?; + layouter.layout_multiple(engine, child, styles)?; } else if child.is::<ColbreakElem>() { if !layouter.regions.backlog.is_empty() || layouter.regions.last.is_some() { - layouter.finish_region(vt)?; + layouter.finish_region(engine)?; } } else { bail!(child.span(), "unexpected flow child"); } } - layouter.finish(vt) + layouter.finish(engine) } } @@ -193,12 +194,12 @@ impl<'a> FlowLayouter<'a> { #[tracing::instrument(name = "FlowLayouter::layout_spacing", skip_all)] fn layout_spacing( &mut self, - vt: &mut Vt, + engine: &mut Engine, v: &VElem, styles: StyleChain, ) -> SourceResult<()> { self.layout_item( - vt, + engine, match v.amount() { Spacing::Rel(rel) => FlowItem::Absolute( rel.resolve(styles).relative_to(self.initial.y), @@ -213,7 +214,7 @@ impl<'a> FlowLayouter<'a> { #[tracing::instrument(name = "FlowLayouter::layout_par", skip_all)] fn layout_par( &mut self, - vt: &mut Vt, + engine: &mut Engine, par: &ParElem, styles: StyleChain, ) -> SourceResult<()> { @@ -221,7 +222,13 @@ impl<'a> FlowLayouter<'a> { let leading = ParElem::leading_in(styles); let consecutive = self.last_was_par; let lines = par - .layout(vt, styles, consecutive, self.regions.base(), self.regions.expand.x)? + .layout( + engine, + styles, + consecutive, + self.regions.base(), + self.regions.expand.x, + )? .into_frames(); let mut sticky = self.items.len(); @@ -236,20 +243,20 @@ impl<'a> FlowLayouter<'a> { if let Some(first) = lines.first() { if !self.regions.size.y.fits(first.height()) && !self.regions.in_last() { let carry: Vec<_> = self.items.drain(sticky..).collect(); - self.finish_region(vt)?; + self.finish_region(engine)?; for item in carry { - self.layout_item(vt, item)?; + self.layout_item(engine, item)?; } } } for (i, frame) in lines.into_iter().enumerate() { if i > 0 { - self.layout_item(vt, FlowItem::Absolute(leading, true))?; + self.layout_item(engine, FlowItem::Absolute(leading, true))?; } self.layout_item( - vt, + engine, FlowItem::Frame { frame, align, sticky: false, movable: true }, )?; } @@ -262,15 +269,18 @@ impl<'a> FlowLayouter<'a> { #[tracing::instrument(name = "FlowLayouter::layout_single", skip_all)] fn layout_single( &mut self, - vt: &mut Vt, + engine: &mut Engine, content: &dyn Layout, styles: StyleChain, ) -> SourceResult<()> { let align = AlignElem::alignment_in(styles).resolve(styles); let sticky = BlockElem::sticky_in(styles); let pod = Regions::one(self.regions.base(), Axes::splat(false)); - let frame = content.layout(vt, styles, pod)?.into_frame(); - self.layout_item(vt, FlowItem::Frame { frame, align, sticky, movable: true })?; + let frame = content.layout(engine, styles, pod)?.into_frame(); + self.layout_item( + engine, + FlowItem::Frame { frame, align, sticky, movable: true }, + )?; self.last_was_par = false; Ok(()) } @@ -278,7 +288,7 @@ impl<'a> FlowLayouter<'a> { /// Layout a placed element. fn layout_placed( &mut self, - vt: &mut Vt, + engine: &mut Engine, placed: &PlaceElem, styles: StyleChain, ) -> SourceResult<()> { @@ -290,15 +300,15 @@ impl<'a> FlowLayouter<'a> { align.x().unwrap_or_default().resolve(styles) }); let y_align = alignment.map(|align| align.y().map(VAlign::fix)); - let frame = placed.layout(vt, styles, self.regions)?.into_frame(); + let frame = placed.layout(engine, styles, self.regions)?.into_frame(); let item = FlowItem::Placed { frame, x_align, y_align, delta, float, clearance }; - self.layout_item(vt, item) + self.layout_item(engine, item) } /// Layout into multiple regions. fn layout_multiple( &mut self, - vt: &mut Vt, + engine: &mut Engine, block: &Content, styles: StyleChain, ) -> SourceResult<()> { @@ -313,7 +323,7 @@ impl<'a> FlowLayouter<'a> { if self.regions.is_full() { // Skip directly if region is already full. - self.finish_region(vt)?; + self.finish_region(engine)?; } // How to align the block. @@ -328,7 +338,7 @@ impl<'a> FlowLayouter<'a> { // Layout the block itself. let sticky = BlockElem::sticky_in(styles); - let fragment = block.layout(vt, styles, self.regions)?; + let fragment = block.layout(engine, styles, self.regions)?; for (i, frame) in fragment.into_iter().enumerate() { // Find footnotes in the frame. @@ -337,14 +347,14 @@ impl<'a> FlowLayouter<'a> { } if i > 0 { - self.finish_region(vt)?; + self.finish_region(engine)?; } let item = FlowItem::Frame { frame, align, sticky, movable: false }; - self.layout_item(vt, item)?; + self.layout_item(engine, item)?; } - self.try_handle_footnotes(vt, notes)?; + self.try_handle_footnotes(engine, notes)?; self.root = is_root; self.regions.root = false; @@ -355,7 +365,11 @@ impl<'a> FlowLayouter<'a> { /// Layout a finished frame. #[tracing::instrument(name = "FlowLayouter::layout_item", skip_all)] - fn layout_item(&mut self, vt: &mut Vt, mut item: FlowItem) -> SourceResult<()> { + fn layout_item( + &mut self, + engine: &mut Engine, + mut item: FlowItem, + ) -> SourceResult<()> { match item { FlowItem::Absolute(v, weak) => { if weak @@ -372,7 +386,7 @@ impl<'a> FlowLayouter<'a> { FlowItem::Frame { ref frame, movable, .. } => { let height = frame.height(); if !self.regions.size.y.fits(height) && !self.regions.in_last() { - self.finish_region(vt)?; + self.finish_region(engine)?; } self.regions.size.y -= height; @@ -380,12 +394,12 @@ impl<'a> FlowLayouter<'a> { let mut notes = Vec::new(); find_footnotes(&mut notes, frame); self.items.push(item); - if !self.handle_footnotes(vt, &mut notes, true, false)? { + if !self.handle_footnotes(engine, &mut notes, true, false)? { let item = self.items.pop(); - self.finish_region(vt)?; + self.finish_region(engine)?; self.items.extend(item); self.regions.size.y -= height; - self.handle_footnotes(vt, &mut notes, true, true)?; + self.handle_footnotes(engine, &mut notes, true, true)?; } return Ok(()); } @@ -429,7 +443,7 @@ impl<'a> FlowLayouter<'a> { if self.root { let mut notes = vec![]; find_footnotes(&mut notes, frame); - self.try_handle_footnotes(vt, notes)?; + self.try_handle_footnotes(engine, notes)?; } } FlowItem::Footnote(_) => {} @@ -440,7 +454,7 @@ impl<'a> FlowLayouter<'a> { } /// Finish the frame for one region. - fn finish_region(&mut self, vt: &mut Vt) -> SourceResult<()> { + fn finish_region(&mut self, engine: &mut Engine) -> SourceResult<()> { // Trim weak spacing. while self .items @@ -567,23 +581,23 @@ impl<'a> FlowLayouter<'a> { // Try to place floats. for item in std::mem::take(&mut self.pending_floats) { - self.layout_item(vt, item)?; + self.layout_item(engine, item)?; } Ok(()) } /// Finish layouting and return the resulting fragment. - fn finish(mut self, vt: &mut Vt) -> SourceResult<Fragment> { + fn finish(mut self, engine: &mut Engine) -> SourceResult<Fragment> { if self.expand.y { while !self.regions.backlog.is_empty() { - self.finish_region(vt)?; + self.finish_region(engine)?; } } - self.finish_region(vt)?; + self.finish_region(engine)?; while !self.items.is_empty() { - self.finish_region(vt)?; + self.finish_region(engine)?; } Ok(Fragment::frames(self.finished)) @@ -593,12 +607,12 @@ impl<'a> FlowLayouter<'a> { impl FlowLayouter<'_> { fn try_handle_footnotes( &mut self, - vt: &mut Vt, + engine: &mut Engine, mut notes: Vec<FootnoteElem>, ) -> SourceResult<()> { - if self.root && !self.handle_footnotes(vt, &mut notes, false, false)? { - self.finish_region(vt)?; - self.handle_footnotes(vt, &mut notes, false, true)?; + if self.root && !self.handle_footnotes(engine, &mut notes, false, false)? { + self.finish_region(engine)?; + self.handle_footnotes(engine, &mut notes, false, true)?; } Ok(()) } @@ -607,7 +621,7 @@ impl FlowLayouter<'_> { #[tracing::instrument(skip_all)] fn handle_footnotes( &mut self, - vt: &mut Vt, + engine: &mut Engine, notes: &mut Vec<FootnoteElem>, movable: bool, force: bool, @@ -624,14 +638,14 @@ impl FlowLayouter<'_> { } if !self.has_footnotes { - self.layout_footnote_separator(vt)?; + self.layout_footnote_separator(engine)?; } self.regions.size.y -= self.footnote_config.gap; - let checkpoint = vt.locator.clone(); + let checkpoint = engine.locator.clone(); let frames = FootnoteEntry::new(notes[k].clone()) .pack() - .layout(vt, self.styles, self.regions.with_root(false))? + .layout(engine, self.styles, self.regions.with_root(false))? .into_frames(); // If the entries didn't fit, abort (to keep footnote and entry @@ -649,8 +663,8 @@ impl FlowLayouter<'_> { self.regions.size.y -= item.height(); } - // Undo Vt modifications. - *vt.locator = checkpoint; + // Undo locator modifications. + *engine.locator = checkpoint; return Ok(false); } @@ -659,8 +673,8 @@ impl FlowLayouter<'_> { for (i, frame) in frames.into_iter().enumerate() { find_footnotes(notes, &frame); if i > 0 { - self.finish_region(vt)?; - self.layout_footnote_separator(vt)?; + self.finish_region(engine)?; + self.layout_footnote_separator(engine)?; self.regions.size.y -= self.footnote_config.gap; } self.regions.size.y -= frame.height(); @@ -682,12 +696,12 @@ impl FlowLayouter<'_> { /// Layout and save the footnote separator, typically a line. #[tracing::instrument(skip_all)] - fn layout_footnote_separator(&mut self, vt: &mut Vt) -> SourceResult<()> { + fn layout_footnote_separator(&mut self, engine: &mut Engine) -> SourceResult<()> { let expand = Axes::new(self.regions.expand.x, false); let pod = Regions::one(self.regions.base(), expand); let separator = &self.footnote_config.separator; - let mut frame = separator.layout(vt, self.styles, pod)?.into_frame(); + let mut frame = separator.layout(engine, self.styles, pod)?.into_frame(); frame.size_mut().y += self.footnote_config.clearance; frame.translate(Point::with_y(self.footnote_config.clearance)); diff --git a/crates/typst/src/layout/grid.rs b/crates/typst/src/layout/grid.rs index cc7d1d25..606aa4a7 100644 --- a/crates/typst/src/layout/grid.rs +++ b/crates/typst/src/layout/grid.rs @@ -3,12 +3,13 @@ use std::num::NonZeroUsize; use smallvec::{smallvec, SmallVec}; use crate::diag::{bail, SourceResult, StrResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, Array, Content, NativeElement, Resolve, StyleChain, Value, }; use crate::layout::{ Abs, Axes, Dir, Fr, Fragment, Frame, Layout, Length, Point, Regions, Rel, Size, - Sizing, Vt, + Sizing, }; use crate::syntax::Span; use crate::text::TextElem; @@ -128,7 +129,7 @@ impl Layout for GridElem { #[tracing::instrument(name = "GridElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -148,7 +149,7 @@ impl Layout for GridElem { ); // Measure the columns and layout the grid row-by-row. - Ok(layouter.layout(vt)?.fragment) + Ok(layouter.layout(engine)?.fragment) } } @@ -311,24 +312,24 @@ impl<'a> GridLayouter<'a> { } /// Determines the columns sizes and then layouts the grid row-by-row. - pub fn layout(mut self, vt: &mut Vt) -> SourceResult<GridLayout> { - self.measure_columns(vt)?; + pub fn layout(mut self, engine: &mut Engine) -> SourceResult<GridLayout> { + self.measure_columns(engine)?; for y in 0..self.rows.len() { // Skip to next region if current one is full, but only for content // rows, not for gutter rows. if self.regions.is_full() && (!self.has_gutter || y % 2 == 0) { - self.finish_region(vt)?; + self.finish_region(engine)?; } match self.rows[y] { - Sizing::Auto => self.layout_auto_row(vt, y)?, - Sizing::Rel(v) => self.layout_relative_row(vt, v, y)?, + Sizing::Auto => self.layout_auto_row(engine, y)?, + Sizing::Rel(v) => self.layout_relative_row(engine, v, y)?, Sizing::Fr(v) => self.lrows.push(Row::Fr(v, y)), } } - self.finish_region(vt)?; + self.finish_region(engine)?; Ok(GridLayout { fragment: Fragment::frames(self.finished), @@ -339,7 +340,7 @@ impl<'a> GridLayouter<'a> { /// Determine all column sizes. #[tracing::instrument(name = "GridLayouter::measure_columns", skip_all)] - fn measure_columns(&mut self, vt: &mut Vt) -> SourceResult<()> { + fn measure_columns(&mut self, engine: &mut Engine) -> SourceResult<()> { // Sum of sizes of resolved relative tracks. let mut rel = Abs::zero(); @@ -365,7 +366,7 @@ impl<'a> GridLayouter<'a> { let available = self.regions.size.x - rel; if available >= Abs::zero() { // Determine size of auto columns. - let (auto, count) = self.measure_auto_columns(vt, available)?; + let (auto, count) = self.measure_auto_columns(engine, available)?; // If there is remaining space, distribute it to fractional columns, // otherwise shrink auto columns. @@ -386,7 +387,7 @@ impl<'a> GridLayouter<'a> { /// Measure the size that is available to auto columns. fn measure_auto_columns( &mut self, - vt: &mut Vt, + engine: &mut Engine, available: Abs, ) -> SourceResult<(Abs, usize)> { let mut auto = Abs::zero(); @@ -413,7 +414,7 @@ impl<'a> GridLayouter<'a> { let size = Size::new(available, height); let pod = Regions::one(size, Axes::splat(false)); - let frame = cell.measure(vt, self.styles, pod)?.into_frame(); + let frame = cell.measure(engine, self.styles, pod)?.into_frame(); resolved.set_max(frame.width()); } } @@ -474,14 +475,14 @@ impl<'a> GridLayouter<'a> { /// Layout a row with automatic height. Such a row may break across multiple /// regions. - fn layout_auto_row(&mut self, vt: &mut Vt, y: usize) -> SourceResult<()> { + fn layout_auto_row(&mut self, engine: &mut Engine, y: usize) -> SourceResult<()> { // Determine the size for each region of the row. If the first region // ends up empty for some column, skip the region and remeasure. - let mut resolved = match self.measure_auto_row(vt, y, true)? { + let mut resolved = match self.measure_auto_row(engine, y, true)? { Some(resolved) => resolved, None => { - self.finish_region(vt)?; - self.measure_auto_row(vt, y, false)?.unwrap() + self.finish_region(engine)?; + self.measure_auto_row(engine, y, false)?.unwrap() } }; @@ -492,7 +493,7 @@ impl<'a> GridLayouter<'a> { // Layout into a single region. if let &[first] = resolved.as_slice() { - let frame = self.layout_single_row(vt, first, y)?; + let frame = self.layout_single_row(engine, first, y)?; self.push_row(frame, y); return Ok(()); } @@ -510,12 +511,12 @@ impl<'a> GridLayouter<'a> { } // Layout into multiple regions. - let fragment = self.layout_multi_row(vt, &resolved, y)?; + let fragment = self.layout_multi_row(engine, &resolved, y)?; let len = fragment.len(); for (i, frame) in fragment.into_iter().enumerate() { self.push_row(frame, y); if i + 1 < len { - self.finish_region(vt)?; + self.finish_region(engine)?; } } @@ -526,7 +527,7 @@ impl<'a> GridLayouter<'a> { /// if `can_skip` is false. fn measure_auto_row( &mut self, - vt: &mut Vt, + engine: &mut Engine, y: usize, can_skip: bool, ) -> SourceResult<Option<Vec<Abs>>> { @@ -537,7 +538,7 @@ impl<'a> GridLayouter<'a> { let mut pod = self.regions; pod.size.x = rcol; - let frames = cell.measure(vt, self.styles, pod)?.into_frames(); + let frames = cell.measure(engine, self.styles, pod)?.into_frames(); // Skip the first region if one cell in it is empty. Then, // remeasure. @@ -568,17 +569,17 @@ impl<'a> GridLayouter<'a> { /// multiple regions, but it may force a region break. fn layout_relative_row( &mut self, - vt: &mut Vt, + engine: &mut Engine, v: Rel<Length>, y: usize, ) -> SourceResult<()> { let resolved = v.resolve(self.styles).relative_to(self.regions.base().y); - let frame = self.layout_single_row(vt, resolved, y)?; + let frame = self.layout_single_row(engine, resolved, y)?; // Skip to fitting region. let height = frame.height(); while !self.regions.size.y.fits(height) && !self.regions.in_last() { - self.finish_region(vt)?; + self.finish_region(engine)?; // Don't skip multiple regions for gutter and don't push a row. if self.has_gutter && y % 2 == 1 { @@ -594,7 +595,7 @@ impl<'a> GridLayouter<'a> { /// Layout a row with fixed height and return its frame. fn layout_single_row( &mut self, - vt: &mut Vt, + engine: &mut Engine, height: Abs, y: usize, ) -> SourceResult<Frame> { @@ -612,7 +613,7 @@ impl<'a> GridLayouter<'a> { if self.rows[y] == Sizing::Auto { pod.full = self.regions.full; } - let frame = cell.layout(vt, self.styles, pod)?.into_frame(); + let frame = cell.layout(engine, self.styles, pod)?.into_frame(); output.push_frame(pos, frame); } @@ -625,7 +626,7 @@ impl<'a> GridLayouter<'a> { /// Layout a row spanning multiple regions. fn layout_multi_row( &mut self, - vt: &mut Vt, + engine: &mut Engine, heights: &[Abs], y: usize, ) -> SourceResult<Fragment> { @@ -648,7 +649,7 @@ impl<'a> GridLayouter<'a> { pod.size.x = rcol; // Push the layouted frames into the individual output frames. - let fragment = cell.layout(vt, self.styles, pod)?; + let fragment = cell.layout(engine, self.styles, pod)?; for (output, frame) in outputs.iter_mut().zip(fragment) { output.push_frame(pos, frame); } @@ -667,7 +668,7 @@ impl<'a> GridLayouter<'a> { } /// Finish rows for one region. - fn finish_region(&mut self, vt: &mut Vt) -> SourceResult<()> { + fn finish_region(&mut self, engine: &mut Engine) -> SourceResult<()> { // Determine the height of existing rows in the region. let mut used = Abs::zero(); let mut fr = Fr::zero(); @@ -697,7 +698,7 @@ impl<'a> GridLayouter<'a> { Row::Fr(v, y) => { let remaining = self.regions.full - used; let height = v.share(fr, remaining); - (self.layout_single_row(vt, height, y)?, y) + (self.layout_single_row(engine, height, y)?, y) } }; diff --git a/crates/typst/src/layout/hide.rs b/crates/typst/src/layout/hide.rs index b72f2ad2..50ce8467 100644 --- a/crates/typst/src/layout/hide.rs +++ b/crates/typst/src/layout/hide.rs @@ -1,9 +1,9 @@ use smallvec::smallvec; use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Content, Show, StyleChain}; use crate::introspection::{Meta, MetaElem}; -use crate::layout::Vt; /// Hides content without affecting layout. /// @@ -26,7 +26,7 @@ pub struct HideElem { impl Show for HideElem { #[tracing::instrument(name = "HideElem::show", skip(self))] - fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(MetaElem::set_data(smallvec![Meta::Hide]))) } } diff --git a/crates/typst/src/layout/inline/mod.rs b/crates/typst/src/layout/inline/mod.rs index 44b2e113..ba88f74e 100644 --- a/crates/typst/src/layout/inline/mod.rs +++ b/crates/typst/src/layout/inline/mod.rs @@ -11,12 +11,13 @@ use self::shaping::{ END_PUNCT_PAT, }; use crate::diag::{bail, SourceResult}; +use crate::engine::{Engine, Route}; use crate::eval::Tracer; use crate::foundations::{Content, Resolve, Smart, StyleChain}; use crate::introspection::{Introspector, Locator, MetaElem}; use crate::layout::{ Abs, AlignElem, Axes, BoxElem, Dir, Em, FixedAlign, Fr, Fragment, Frame, HElem, - Layout, Point, Regions, Size, Sizing, Spacing, Vt, + Layout, Point, Regions, Size, Sizing, Spacing, }; use crate::math::EquationElem; use crate::model::{Linebreaks, ParElem}; @@ -30,7 +31,7 @@ use crate::World; /// Layout's content inline. pub(crate) fn layout_inline( children: &[Prehashed<Content>], - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, consecutive: bool, region: Size, @@ -42,6 +43,7 @@ pub(crate) fn layout_inline( children: &[Prehashed<Content>], world: Tracked<dyn World + '_>, introspector: Tracked<Introspector>, + route: Tracked<Route>, locator: Tracked<Locator>, tracer: TrackedMut<Tracer>, styles: StyleChain, @@ -50,7 +52,13 @@ pub(crate) fn layout_inline( expand: bool, ) -> SourceResult<Fragment> { let mut locator = Locator::chained(locator); - let mut vt = Vt { world, introspector, locator: &mut locator, tracer }; + let mut engine = Engine { + world, + introspector, + route: Route::extend(route), + locator: &mut locator, + tracer, + }; // Collect all text into one string for BiDi analysis. let (text, segments, spans) = collect(children, &styles, consecutive)?; @@ -58,28 +66,29 @@ pub(crate) fn layout_inline( // Perform BiDi analysis and then prepare paragraph layout by building a // representation on which we can do line breaking without layouting // each and every line from scratch. - let p = prepare(&mut vt, children, &text, segments, spans, styles, region)?; + let p = prepare(&mut engine, children, &text, segments, spans, styles, region)?; // Break the paragraph into lines. - let lines = linebreak(&vt, &p, region.x - p.hang); + let lines = linebreak(&engine, &p, region.x - p.hang); // Stack the lines into one frame per region. - finalize(&mut vt, &p, &lines, region, expand) + finalize(&mut engine, &p, &lines, region, expand) } let fragment = cached( children, - vt.world, - vt.introspector, - vt.locator.track(), - TrackedMut::reborrow_mut(&mut vt.tracer), + engine.world, + engine.introspector, + engine.route.track(), + engine.locator.track(), + TrackedMut::reborrow_mut(&mut engine.tracer), styles, consecutive, region, expand, )?; - vt.locator.visit_frames(&fragment); + engine.locator.visit_frames(&fragment); Ok(fragment) } @@ -520,7 +529,7 @@ fn collect<'a>( /// Prepare paragraph layout by shaping the whole paragraph and layouting all /// contained inline-level content. fn prepare<'a>( - vt: &mut Vt, + engine: &mut Engine, children: &'a [Prehashed<Content>], text: &'a str, segments: Vec<(Segment<'a>, StyleChain<'a>)>, @@ -546,7 +555,7 @@ fn prepare<'a>( let end = cursor + segment.len(); match segment { Segment::Text(_) => { - shape_range(&mut items, vt, &bidi, cursor..end, &spans, styles); + shape_range(&mut items, engine, &bidi, cursor..end, &spans, styles); } Segment::Spacing(spacing) => match spacing { Spacing::Rel(v) => { @@ -559,7 +568,7 @@ fn prepare<'a>( }, Segment::Equation(equation) => { let pod = Regions::one(region, Axes::splat(false)); - let mut frame = equation.layout(vt, styles, pod)?.into_frame(); + let mut frame = equation.layout(engine, styles, pod)?.into_frame(); frame.translate(Point::with_y(TextElem::baseline_in(styles))); items.push(Item::Frame(frame)); } @@ -568,7 +577,7 @@ fn prepare<'a>( items.push(Item::Fractional(v, Some((elem, styles)))); } else { let pod = Regions::one(region, Axes::splat(false)); - let mut frame = elem.layout(vt, styles, pod)?.into_frame(); + let mut frame = elem.layout(engine, styles, pod)?.into_frame(); frame.translate(Point::with_y(TextElem::baseline_in(styles))); items.push(Item::Frame(frame)); } @@ -655,7 +664,7 @@ fn add_cjk_latin_spacing(items: &mut [Item]) { /// items for them. fn shape_range<'a>( items: &mut Vec<Item<'a>>, - vt: &Vt, + engine: &Engine, bidi: &BidiInfo<'a>, range: Range, spans: &SpanMapper, @@ -666,8 +675,16 @@ fn shape_range<'a>( let region = TextElem::region_in(styles); let mut process = |range: Range, level: BidiLevel| { let dir = if level.is_ltr() { Dir::LTR } else { Dir::RTL }; - let shaped = - shape(vt, range.start, &bidi.text[range], spans, styles, dir, lang, region); + let shaped = shape( + engine, + range.start, + &bidi.text[range], + spans, + styles, + dir, + lang, + region, + ); items.push(Item::Text(shaped)); }; @@ -732,7 +749,7 @@ fn shared_get<T: PartialEq>( } /// Find suitable linebreaks. -fn linebreak<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<Line<'a>> { +fn linebreak<'a>(engine: &Engine, p: &'a Preparation<'a>, width: Abs) -> Vec<Line<'a>> { let linebreaks = p.linebreaks.unwrap_or_else(|| { if p.justify { Linebreaks::Optimized @@ -742,22 +759,26 @@ fn linebreak<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<Line<'a>> { }); match linebreaks { - Linebreaks::Simple => linebreak_simple(vt, p, width), - Linebreaks::Optimized => linebreak_optimized(vt, p, width), + Linebreaks::Simple => linebreak_simple(engine, p, width), + Linebreaks::Optimized => linebreak_optimized(engine, p, width), } } /// Perform line breaking in simple first-fit style. This means that we build /// lines greedily, always taking the longest possible line. This may lead to /// very unbalanced line, but is fast and simple. -fn linebreak_simple<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<Line<'a>> { +fn linebreak_simple<'a>( + engine: &Engine, + p: &'a Preparation<'a>, + width: Abs, +) -> Vec<Line<'a>> { let mut lines = Vec::with_capacity(16); let mut start = 0; let mut last = None; breakpoints(p, |end, breakpoint| { // Compute the line and its size. - let mut attempt = line(vt, p, start..end, breakpoint); + let mut attempt = line(engine, p, start..end, breakpoint); // If the line doesn't fit anymore, we push the last fitting attempt // into the stack and rebuild the line from the attempt's end. The @@ -766,7 +787,7 @@ fn linebreak_simple<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<Line if let Some((last_attempt, last_end)) = last.take() { lines.push(last_attempt); start = last_end; - attempt = line(vt, p, start..end, breakpoint); + attempt = line(engine, p, start..end, breakpoint); } } @@ -806,7 +827,11 @@ fn linebreak_simple<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<Line /// computed and stored in dynamic programming table) is minimal. The final /// result is simply the layout determined for the last breakpoint at the end of /// text. -fn linebreak_optimized<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<Line<'a>> { +fn linebreak_optimized<'a>( + engine: &Engine, + p: &'a Preparation<'a>, + width: Abs, +) -> Vec<Line<'a>> { /// The cost of a line or paragraph layout. type Cost = f64; @@ -829,7 +854,7 @@ fn linebreak_optimized<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<L let mut table = vec![Entry { pred: 0, total: 0.0, - line: line(vt, p, 0..0, Breakpoint::Mandatory), + line: line(engine, p, 0..0, Breakpoint::Mandatory), }]; let em = p.size; @@ -844,7 +869,7 @@ fn linebreak_optimized<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<L // Layout the line. let start = pred.line.end; - let attempt = line(vt, p, start..end, breakpoint); + let attempt = line(engine, p, start..end, breakpoint); // Determine how much the line's spaces would need to be stretched // to make it the desired width. @@ -953,7 +978,7 @@ fn linebreak_optimized<'a>(vt: &Vt, p: &'a Preparation<'a>, width: Abs) -> Vec<L /// Create a line which spans the given range. fn line<'a>( - vt: &Vt, + engine: &Engine, p: &'a Preparation, mut range: Range, breakpoint: Breakpoint, @@ -1016,9 +1041,9 @@ fn line<'a>( // are no other items in the line. if hyphen || start + shaped.text.len() > range.end || maybe_adjust_last_glyph { if hyphen || start < range.end || before.is_empty() { - let mut reshaped = shaped.reshape(vt, &p.spans, start..range.end); + let mut reshaped = shaped.reshape(engine, &p.spans, start..range.end); if hyphen || shy { - reshaped.push_hyphen(vt, p.fallback); + reshaped.push_hyphen(engine, p.fallback); } if let Some(last_glyph) = reshaped.glyphs.last() { @@ -1069,7 +1094,7 @@ fn line<'a>( if range.start + shaped.text.len() > end || maybe_adjust_first_glyph { // If the range is empty, we don't want to push an empty text item. if range.start < end { - let reshaped = shaped.reshape(vt, &p.spans, range.start..end); + let reshaped = shaped.reshape(engine, &p.spans, range.start..end); width += reshaped.width; first = Some(Item::Text(reshaped)); } @@ -1129,7 +1154,7 @@ fn line<'a>( /// Combine layouted lines into one frame per region. fn finalize( - vt: &mut Vt, + engine: &mut Engine, p: &Preparation, lines: &[Line], region: Size, @@ -1150,7 +1175,7 @@ fn finalize( // Stack the lines into one frame per region. let mut frames: Vec<Frame> = lines .iter() - .map(|line| commit(vt, p, line, width, region.y)) + .map(|line| commit(engine, p, line, width, region.y)) .collect::<SourceResult<_>>()?; // Prevent orphans. @@ -1181,7 +1206,7 @@ fn merge(first: &mut Frame, second: Frame, leading: Abs) { /// Commit to a line and build its frame. fn commit( - vt: &mut Vt, + engine: &mut Engine, p: &Preparation, line: &Line, width: Abs, @@ -1276,7 +1301,7 @@ fn commit( if let Some((elem, styles)) = elem { let region = Size::new(amount, full); let pod = Regions::one(region, Axes::new(true, false)); - let mut frame = elem.layout(vt, *styles, pod)?.into_frame(); + let mut frame = elem.layout(engine, *styles, pod)?.into_frame(); frame.translate(Point::with_y(TextElem::baseline_in(*styles))); push(&mut offset, frame); } else { @@ -1284,7 +1309,8 @@ fn commit( } } Item::Text(shaped) => { - let frame = shaped.build(vt, justification_ratio, extra_justification); + let frame = + shaped.build(engine, justification_ratio, extra_justification); push(&mut offset, frame); } Item::Frame(frame) | Item::Meta(frame) => { diff --git a/crates/typst/src/layout/inline/shaping.rs b/crates/typst/src/layout/inline/shaping.rs index 69e70967..08a617dc 100644 --- a/crates/typst/src/layout/inline/shaping.rs +++ b/crates/typst/src/layout/inline/shaping.rs @@ -9,8 +9,9 @@ use rustybuzz::{Tag, UnicodeBuffer}; use unicode_script::{Script, UnicodeScript}; use super::SpanMapper; +use crate::engine::Engine; use crate::foundations::StyleChain; -use crate::layout::{Abs, Dir, Em, Frame, FrameItem, Point, Size, Vt}; +use crate::layout::{Abs, Dir, Em, Frame, FrameItem, Point, Size}; use crate::syntax::Span; use crate::text::{ decorate, families, features, variant, Font, FontVariant, Glyph, Lang, Region, @@ -213,11 +214,11 @@ impl<'a> ShapedText<'a> { /// [justifiable glyph](ShapedGlyph::is_justifiable) will get. pub fn build( &self, - vt: &Vt, + engine: &Engine, justification_ratio: f64, extra_justification: Abs, ) -> Frame { - let (top, bottom) = self.measure(vt); + let (top, bottom) = self.measure(engine); let size = Size::new(self.width, top + bottom); let mut offset = Abs::zero(); @@ -307,7 +308,7 @@ impl<'a> ShapedText<'a> { } /// Measure the top and bottom extent of this text. - fn measure(&self, vt: &Vt) -> (Abs, Abs) { + fn measure(&self, engine: &Engine) -> (Abs, Abs) { let mut top = Abs::zero(); let mut bottom = Abs::zero(); @@ -323,7 +324,7 @@ impl<'a> ShapedText<'a> { if self.glyphs.is_empty() { // When there are no glyphs, we just use the vertical metrics of the // first available font. - let world = vt.world; + let world = engine.world; for family in families(self.styles) { if let Some(font) = world .book() @@ -387,7 +388,7 @@ impl<'a> ShapedText<'a> { /// The text `range` is relative to the whole paragraph. pub fn reshape( &'a self, - vt: &Vt, + engine: &Engine, spans: &SpanMapper, text_range: Range<usize>, ) -> ShapedText<'a> { @@ -409,7 +410,7 @@ impl<'a> ShapedText<'a> { } } else { shape( - vt, + engine, text_range.start, text, spans, @@ -422,8 +423,8 @@ impl<'a> ShapedText<'a> { } /// Push a hyphen to end of the text. - pub fn push_hyphen(&mut self, vt: &Vt, fallback: bool) { - let world = vt.world; + pub fn push_hyphen(&mut self, engine: &Engine, fallback: bool) { + let world = engine.world; let book = world.book(); let fallback_func = if fallback { Some(|| book.select_fallback(None, self.variant, "-")) @@ -553,7 +554,7 @@ impl Debug for ShapedText<'_> { /// Holds shaping results and metadata common to all shaped segments. struct ShapingContext<'a, 'v> { - vt: &'a Vt<'v>, + engine: &'a Engine<'v>, spans: &'a SpanMapper, glyphs: Vec<ShapedGlyph>, used: Vec<Font>, @@ -568,7 +569,7 @@ struct ShapingContext<'a, 'v> { /// Shape text into [`ShapedText`]. #[allow(clippy::too_many_arguments)] pub(super) fn shape<'a>( - vt: &Vt, + engine: &Engine, base: usize, text: &'a str, spans: &SpanMapper, @@ -579,7 +580,7 @@ pub(super) fn shape<'a>( ) -> ShapedText<'a> { let size = TextElem::size_in(styles); let mut ctx = ShapingContext { - vt, + engine, spans, size, glyphs: vec![], @@ -630,7 +631,7 @@ fn shape_segment<'a>( } // Find the next available family. - let world = ctx.vt.world; + let world = ctx.engine.world; let book = world.book(); let mut selection = families.find_map(|family| { book.select(family, ctx.variant) diff --git a/crates/typst/src/layout/layout.rs b/crates/typst/src/layout/layout.rs index e2c0fa2b..45b7c54a 100644 --- a/crates/typst/src/layout/layout.rs +++ b/crates/typst/src/layout/layout.rs @@ -1,6 +1,7 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{dict, elem, func, Content, Func, NativeElement, StyleChain}; -use crate::layout::{Fragment, Layout, Regions, Size, Vt}; +use crate::layout::{Fragment, Layout, Regions, Size}; /// Provides access to the current outer container's (or page's, if none) size /// (width and height). @@ -68,7 +69,7 @@ impl Layout for LayoutElem { #[tracing::instrument(name = "LayoutElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -77,8 +78,8 @@ impl Layout for LayoutElem { let Size { x, y } = regions.base(); let result = self .func() - .call_vt(vt, [dict! { "width" => x, "height" => y }])? + .call(engine, [dict! { "width" => x, "height" => y }])? .display(); - result.layout(vt, styles, regions) + result.layout(engine, styles, regions) } } diff --git a/crates/typst/src/layout/measure.rs b/crates/typst/src/layout/measure.rs index 2b82c58b..1aff7ad4 100644 --- a/crates/typst/src/layout/measure.rs +++ b/crates/typst/src/layout/measure.rs @@ -1,5 +1,5 @@ use crate::diag::SourceResult; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{dict, func, Content, Dict, StyleChain, Styles}; use crate::layout::{Abs, Axes, Layout, Regions, Size}; @@ -41,8 +41,8 @@ use crate::layout::{Abs, Axes, Layout, Regions, Size}; /// `height`, both of type [`length`]($length). #[func] pub fn measure( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// The content whose size to measure. content: Content, /// The styles with which to layout the content. @@ -50,7 +50,7 @@ pub fn measure( ) -> SourceResult<Dict> { let pod = Regions::one(Axes::splat(Abs::inf()), Axes::splat(false)); let styles = StyleChain::new(&styles); - let frame = content.measure(&mut vm.vt, styles, pod)?.into_frame(); + let frame = content.measure(engine, styles, pod)?.into_frame(); let Size { x, y } = frame.size(); Ok(dict! { "width" => x, "height" => y }) } diff --git a/crates/typst/src/layout/mod.rs b/crates/typst/src/layout/mod.rs index f291cfe9..1e1bcf9b 100644 --- a/crates/typst/src/layout/mod.rs +++ b/crates/typst/src/layout/mod.rs @@ -34,7 +34,6 @@ mod size; mod spacing; mod stack; mod transform; -mod vt; pub use self::abs::*; pub use self::align::*; @@ -67,13 +66,13 @@ pub use self::size::*; pub use self::spacing::*; pub use self::stack::*; pub use self::transform::*; -pub use self::vt::*; pub(crate) use self::inline::*; use comemo::{Tracked, TrackedMut}; -use crate::diag::SourceResult; +use crate::diag::{bail, error, SourceResult}; +use crate::engine::{Engine, Route}; use crate::eval::Tracer; use crate::foundations::{category, Category, Content, Scope, StyleChain}; use crate::introspection::{Introspector, Locator}; @@ -122,7 +121,11 @@ pub fn define(global: &mut Scope) { /// Root-level layout. pub trait LayoutRoot { /// Layout into one frame per page. - fn layout_root(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Document>; + fn layout_root( + &self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<Document>; } /// Layout into regions. @@ -130,7 +133,7 @@ pub trait Layout { /// Layout into one frame per region. fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment>; @@ -142,50 +145,64 @@ pub trait Layout { #[tracing::instrument(name = "Layout::measure", skip_all)] fn measure( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { - let mut locator = Locator::chained(vt.locator.track()); - let mut vt = Vt { - world: vt.world, - introspector: vt.introspector, + let mut locator = Locator::chained(engine.locator.track()); + let mut engine = Engine { + world: engine.world, + route: engine.route.clone(), + introspector: engine.introspector, locator: &mut locator, - tracer: TrackedMut::reborrow_mut(&mut vt.tracer), + tracer: TrackedMut::reborrow_mut(&mut engine.tracer), }; - self.layout(&mut vt, styles, regions) + self.layout(&mut engine, styles, regions) } } impl LayoutRoot for Content { #[tracing::instrument(name = "Content::layout_root", skip_all)] - fn layout_root(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Document> { + fn layout_root( + &self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<Document> { #[comemo::memoize] fn cached( content: &Content, world: Tracked<dyn World + '_>, introspector: Tracked<Introspector>, + route: Tracked<Route>, locator: Tracked<Locator>, tracer: TrackedMut<Tracer>, styles: StyleChain, ) -> SourceResult<Document> { let mut locator = Locator::chained(locator); - let mut vt = Vt { world, introspector, locator: &mut locator, tracer }; + let mut engine = Engine { + world, + introspector, + route: Route::extend(route), + locator: &mut locator, + tracer, + }; let scratch = Scratch::default(); - let (realized, styles) = realize_root(&mut vt, &scratch, content, styles)?; + let (realized, styles) = + realize_root(&mut engine, &scratch, content, styles)?; realized .with::<dyn LayoutRoot>() .unwrap() - .layout_root(&mut vt, styles) + .layout_root(&mut engine, styles) } tracing::info!("Starting layout"); cached( self, - vt.world, - vt.introspector, - vt.locator.track(), - TrackedMut::reborrow_mut(&mut vt.tracer), + engine.world, + engine.introspector, + engine.route.track(), + engine.locator.track(), + TrackedMut::reborrow_mut(&mut engine.tracer), styles, ) } @@ -195,7 +212,7 @@ impl Layout for Content { #[tracing::instrument(name = "Content::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -205,34 +222,49 @@ impl Layout for Content { content: &Content, world: Tracked<dyn World + '_>, introspector: Tracked<Introspector>, + route: Tracked<Route>, locator: Tracked<Locator>, tracer: TrackedMut<Tracer>, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { let mut locator = Locator::chained(locator); - let mut vt = Vt { world, introspector, locator: &mut locator, tracer }; + let mut engine = Engine { + world, + introspector, + route: Route::extend(route), + locator: &mut locator, + tracer, + }; + + if engine.route.exceeding() { + bail!(error!(content.span(), "maximum layout depth exceeded") + .with_hint("try to reduce the amount of nesting in your layout")); + } + let scratch = Scratch::default(); - let (realized, styles) = realize_block(&mut vt, &scratch, content, styles)?; + let (realized, styles) = + realize_block(&mut engine, &scratch, content, styles)?; realized .with::<dyn Layout>() .unwrap() - .layout(&mut vt, styles, regions) + .layout(&mut engine, styles, regions) } tracing::info!("Layouting `Content`"); let fragment = cached( self, - vt.world, - vt.introspector, - vt.locator.track(), - TrackedMut::reborrow_mut(&mut vt.tracer), + engine.world, + engine.introspector, + engine.route.track(), + engine.locator.track(), + TrackedMut::reborrow_mut(&mut engine.tracer), styles, regions, )?; - vt.locator.visit_frames(&fragment); + engine.locator.visit_frames(&fragment); Ok(fragment) } } diff --git a/crates/typst/src/layout/pad.rs b/crates/typst/src/layout/pad.rs index f5762409..35dfd0b4 100644 --- a/crates/typst/src/layout/pad.rs +++ b/crates/typst/src/layout/pad.rs @@ -1,8 +1,7 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Content, Resolve, StyleChain}; -use crate::layout::{ - Abs, Fragment, Layout, Length, Point, Regions, Rel, Sides, Size, Vt, -}; +use crate::layout::{Abs, Fragment, Layout, Length, Point, Regions, Rel, Sides, Size}; /// Adds spacing around content. /// @@ -63,7 +62,7 @@ impl Layout for PadElem { #[tracing::instrument(name = "PadElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -78,7 +77,7 @@ impl Layout for PadElem { let mut backlog = vec![]; let padding = sides.resolve(styles); let pod = regions.map(&mut backlog, |size| shrink(size, padding)); - let mut fragment = self.body().layout(vt, styles, pod)?; + let mut fragment = self.body().layout(engine, styles, pod)?; for frame in &mut fragment { // Apply the padding inversely such that the grown size padded diff --git a/crates/typst/src/layout/page.rs b/crates/typst/src/layout/page.rs index 411f9769..96e6d96a 100644 --- a/crates/typst/src/layout/page.rs +++ b/crates/typst/src/layout/page.rs @@ -4,6 +4,7 @@ use std::ptr; use std::str::FromStr; use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, AutoValue, Cast, Content, Dict, Fold, Func, NativeElement, Resolve, Smart, StyleChain, Value, @@ -11,7 +12,7 @@ use crate::foundations::{ use crate::introspection::{Counter, CounterKey, ManualPageCounter, Meta}; use crate::layout::{ Abs, Align, AlignElem, Axes, ColumnsElem, Dir, Fragment, Frame, HAlign, Layout, - Length, Point, Ratio, Regions, Rel, Sides, Size, VAlign, Vt, + Length, Point, Ratio, Regions, Rel, Sides, Size, VAlign, }; use crate::model::Numbering; @@ -342,7 +343,7 @@ impl PageElem { #[tracing::instrument(skip_all)] pub fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, page_counter: &mut ManualPageCounter, extend_to: Option<Parity>, @@ -393,7 +394,7 @@ impl PageElem { regions.root = true; // Layout the child. - let mut frames = child.layout(vt, styles, regions)?.into_frames(); + let mut frames = child.layout(engine, styles, regions)?.into_frames(); // Align the child to the pagebreak's parity. // Check for page count after adding the pending frames @@ -496,7 +497,7 @@ impl PageElem { let sub = content .clone() .styled(AlignElem::set_alignment(align)) - .layout(vt, styles, pod)? + .layout(engine, styles, pod)? .into_frame(); if ptr::eq(marginal, &header) || ptr::eq(marginal, &background) { @@ -510,7 +511,7 @@ impl PageElem { frame.fill(fill.clone()); } - page_counter.visit(vt, frame)?; + page_counter.visit(engine, frame)?; // Add a PDF page label if there is a numbering. if let Some(num) = numbering { @@ -675,10 +676,14 @@ pub enum Marginal { impl Marginal { /// Resolve the marginal based on the page number. - pub fn resolve(&self, vt: &mut Vt, page: usize) -> SourceResult<Cow<'_, Content>> { + pub fn resolve( + &self, + engine: &mut Engine, + page: usize, + ) -> SourceResult<Cow<'_, Content>> { Ok(match self { Self::Content(content) => Cow::Borrowed(content), - Self::Func(func) => Cow::Owned(func.call_vt(vt, [page])?.display()), + Self::Func(func) => Cow::Owned(func.call(engine, [page])?.display()), }) } } diff --git a/crates/typst/src/layout/place.rs b/crates/typst/src/layout/place.rs index 537b47ed..3c0012aa 100644 --- a/crates/typst/src/layout/place.rs +++ b/crates/typst/src/layout/place.rs @@ -1,10 +1,9 @@ use crate::diag::{bail, At, Hint, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ elem, Behave, Behaviour, Content, NativeElement, Smart, StyleChain, }; -use crate::layout::{ - Align, Axes, Em, Fragment, Layout, Length, Regions, Rel, VAlign, Vt, -}; +use crate::layout::{Align, Axes, Em, Fragment, Layout, Length, Regions, Rel, VAlign}; /// Places content at an absolute position. /// @@ -91,7 +90,7 @@ impl Layout for PlaceElem { #[tracing::instrument(name = "PlaceElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -118,7 +117,7 @@ impl Layout for PlaceElem { .aligned(alignment.unwrap_or_else(|| Align::CENTER)); let pod = Regions::one(base, Axes::splat(false)); - let frame = child.layout(vt, styles, pod)?.into_frame(); + let frame = child.layout(engine, styles, pod)?.into_frame(); Ok(Fragment::frame(frame)) } } diff --git a/crates/typst/src/layout/repeat.rs b/crates/typst/src/layout/repeat.rs index 29e34e18..c733ea7d 100644 --- a/crates/typst/src/layout/repeat.rs +++ b/crates/typst/src/layout/repeat.rs @@ -1,7 +1,8 @@ use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{elem, Content, NativeElement, Resolve, StyleChain}; use crate::layout::{ - Abs, AlignElem, Axes, Fragment, Frame, Layout, Point, Regions, Size, Vt, + Abs, AlignElem, Axes, Fragment, Frame, Layout, Point, Regions, Size, }; use crate::util::Numeric; @@ -37,12 +38,12 @@ impl Layout for RepeatElem { #[tracing::instrument(name = "RepeatElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { let pod = Regions::one(regions.size, Axes::new(false, false)); - let piece = self.body().layout(vt, styles, pod)?.into_frame(); + let piece = self.body().layout(engine, styles, pod)?.into_frame(); let align = AlignElem::alignment_in(styles).resolve(styles); let fill = regions.size.x; diff --git a/crates/typst/src/layout/stack.rs b/crates/typst/src/layout/stack.rs index e4dd029a..fe36cc63 100644 --- a/crates/typst/src/layout/stack.rs +++ b/crates/typst/src/layout/stack.rs @@ -1,10 +1,11 @@ use std::fmt::{self, Debug, Formatter}; use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{cast, elem, Content, Resolve, StyleChain}; use crate::layout::{ Abs, AlignElem, Axes, Axis, Dir, FixedAlign, Fr, Fragment, Frame, Layout, Point, - Regions, Size, Spacing, Vt, + Regions, Size, Spacing, }; use crate::util::{Get, Numeric}; @@ -54,7 +55,7 @@ impl Layout for StackElem { #[tracing::instrument(name = "StackElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -75,7 +76,7 @@ impl Layout for StackElem { layouter.layout_spacing(kind); } - layouter.layout_block(vt, block, styles)?; + layouter.layout_block(engine, block, styles)?; deferred = spacing; } } @@ -199,7 +200,7 @@ impl<'a> StackLayouter<'a> { #[tracing::instrument(name = "StackLayouter::layout_block", skip_all)] fn layout_block( &mut self, - vt: &mut Vt, + engine: &mut Engine, block: &Content, styles: StyleChain, ) -> SourceResult<()> { @@ -217,7 +218,7 @@ impl<'a> StackLayouter<'a> { } .resolve(styles); - let fragment = block.layout(vt, styles, self.regions)?; + let fragment = block.layout(engine, styles, self.regions)?; let len = fragment.len(); for (i, frame) in fragment.into_iter().enumerate() { // Grow our size, shrink the region and save the frame for later. diff --git a/crates/typst/src/layout/transform.rs b/crates/typst/src/layout/transform.rs index 51cc5d54..bfc35825 100644 --- a/crates/typst/src/layout/transform.rs +++ b/crates/typst/src/layout/transform.rs @@ -1,8 +1,9 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Content, Resolve, StyleChain}; use crate::layout::{ Abs, Align, Angle, Axes, FixedAlign, Fragment, HAlign, Layout, Length, Ratio, - Regions, Rel, VAlign, Vt, + Regions, Rel, VAlign, }; /// Moves content without affecting layout. @@ -40,12 +41,12 @@ impl Layout for MoveElem { #[tracing::instrument(name = "MoveElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { let pod = Regions::one(regions.base(), Axes::splat(false)); - let mut frame = self.body().layout(vt, styles, pod)?.into_frame(); + let mut frame = self.body().layout(engine, styles, pod)?.into_frame(); let delta = Axes::new(self.dx(styles), self.dy(styles)).resolve(styles); let delta = delta.zip_map(regions.base(), Rel::relative_to); frame.translate(delta.to_point()); @@ -106,12 +107,12 @@ impl Layout for RotateElem { #[tracing::instrument(name = "RotateElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { let pod = Regions::one(regions.base(), Axes::splat(false)); - let mut frame = self.body().layout(vt, styles, pod)?.into_frame(); + let mut frame = self.body().layout(engine, styles, pod)?.into_frame(); let Axes { x, y } = self .origin(styles) .resolve(styles) @@ -171,12 +172,12 @@ impl Layout for ScaleElem { #[tracing::instrument(name = "ScaleElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { let pod = Regions::one(regions.base(), Axes::splat(false)); - let mut frame = self.body().layout(vt, styles, pod)?.into_frame(); + let mut frame = self.body().layout(engine, styles, pod)?.into_frame(); let Axes { x, y } = self .origin(styles) .resolve(styles) diff --git a/crates/typst/src/layout/vt.rs b/crates/typst/src/layout/vt.rs deleted file mode 100644 index 78b8c511..00000000 --- a/crates/typst/src/layout/vt.rs +++ /dev/null @@ -1,39 +0,0 @@ -use comemo::{Tracked, TrackedMut}; - -use crate::diag::SourceResult; -use crate::eval::Tracer; -use crate::introspection::{Introspector, Locator}; -use crate::World; - -/// A virtual typesetter. -/// -/// Holds the state needed during compilation. -pub struct Vt<'a> { - /// The compilation environment. - pub world: Tracked<'a, dyn World + 'a>, - /// Provides access to information about the document. - pub introspector: Tracked<'a, Introspector>, - /// Provides stable identities to elements. - pub locator: &'a mut Locator<'a>, - /// 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) => { - self.tracer.delay(errors); - T::default() - } - } - } -} diff --git a/crates/typst/src/lib.rs b/crates/typst/src/lib.rs index 8d0001c8..52634d45 100644 --- a/crates/typst/src/lib.rs +++ b/crates/typst/src/lib.rs @@ -40,6 +40,7 @@ extern crate self as typst; #[macro_use] pub mod util; pub mod diag; +pub mod engine; pub mod eval; pub mod foundations; pub mod introspection; @@ -62,12 +63,13 @@ use comemo::{Prehashed, Track, Tracked, Validate}; use ecow::{EcoString, EcoVec}; use crate::diag::{warning, FileResult, SourceDiagnostic, SourceResult}; -use crate::eval::{Route, Tracer}; +use crate::engine::{Engine, Route}; +use crate::eval::Tracer; use crate::foundations::{ Array, Bytes, Content, Datetime, Module, Scope, StyleChain, Styles, }; use crate::introspection::{Introspector, Locator}; -use crate::layout::{Align, Dir, LayoutRoot, Vt}; +use crate::layout::{Align, Dir, LayoutRoot}; use crate::model::Document; use crate::syntax::{FileId, PackageSpec, Source, Span}; use crate::text::{Font, FontBook}; @@ -122,15 +124,17 @@ fn typeset( let constraint = <Introspector as Validate>::Constraint::new(); let mut locator = Locator::new(); - let mut vt = Vt { + let mut engine = Engine { world, + route: Route::default(), tracer: tracer.track_mut(), locator: &mut locator, introspector: introspector.track_with(&constraint), }; // Layout! - document = content.layout_root(&mut vt, styles)?; + document = content.layout_root(&mut engine, styles)?; + introspector = Introspector::new(&document.pages); iter += 1; diff --git a/crates/typst/src/loading/cbor.rs b/crates/typst/src/loading/cbor.rs index a1189dbe..ddf559f3 100644 --- a/crates/typst/src/loading/cbor.rs +++ b/crates/typst/src/loading/cbor.rs @@ -1,7 +1,7 @@ use ecow::{eco_format, EcoString}; use crate::diag::{At, SourceResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{func, scope, Bytes, Value}; use crate::syntax::Spanned; use crate::World; @@ -16,14 +16,14 @@ use crate::World; /// whether they are whole numbers. #[func(scope, title = "CBOR")] pub fn cbor( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Path to a CBOR file. path: Spanned<EcoString>, ) -> SourceResult<Value> { let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; cbor::decode(Spanned::new(data, span)) } diff --git a/crates/typst/src/loading/csv.rs b/crates/typst/src/loading/csv.rs index e195f190..0d009560 100644 --- a/crates/typst/src/loading/csv.rs +++ b/crates/typst/src/loading/csv.rs @@ -1,7 +1,7 @@ use ecow::{eco_format, EcoString}; use crate::diag::{bail, At, SourceResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{cast, func, scope, Array, IntoValue, Value}; use crate::loading::Readable; use crate::syntax::Spanned; @@ -26,8 +26,8 @@ use crate::World; /// ``` #[func(scope, title = "CSV")] pub fn csv( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Path to a CSV file. path: Spanned<EcoString>, /// The delimiter that separates columns in the CSV file. @@ -37,8 +37,8 @@ pub fn csv( delimiter: Delimiter, ) -> SourceResult<Array> { let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; self::csv::decode(Spanned::new(Readable::Bytes(data), span), delimiter) } diff --git a/crates/typst/src/loading/json.rs b/crates/typst/src/loading/json.rs index cf209971..aae1f4ad 100644 --- a/crates/typst/src/loading/json.rs +++ b/crates/typst/src/loading/json.rs @@ -1,7 +1,7 @@ use ecow::{eco_format, EcoString}; use crate::diag::{At, SourceResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{func, scope, Str, Value}; use crate::loading::Readable; use crate::syntax::Spanned; @@ -46,14 +46,14 @@ use crate::World; /// ``` #[func(scope, title = "JSON")] pub fn json( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Path to a JSON file. path: Spanned<EcoString>, ) -> SourceResult<Value> { let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; json::decode(Spanned::new(Readable::Bytes(data), span)) } diff --git a/crates/typst/src/loading/read.rs b/crates/typst/src/loading/read.rs index 49a86699..50772bee 100644 --- a/crates/typst/src/loading/read.rs +++ b/crates/typst/src/loading/read.rs @@ -1,7 +1,7 @@ use ecow::EcoString; use crate::diag::{At, SourceResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{func, Cast}; use crate::loading::Readable; use crate::syntax::Spanned; @@ -24,8 +24,8 @@ use crate::World; /// ``` #[func] pub fn read( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Path to a file. path: Spanned<EcoString>, /// The encoding to read the file with. @@ -36,8 +36,8 @@ pub fn read( encoding: Option<Encoding>, ) -> SourceResult<Readable> { let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; Ok(match encoding { None => Readable::Bytes(data), Some(Encoding::Utf8) => Readable::Str( diff --git a/crates/typst/src/loading/toml.rs b/crates/typst/src/loading/toml.rs index a4388f74..6884e6fe 100644 --- a/crates/typst/src/loading/toml.rs +++ b/crates/typst/src/loading/toml.rs @@ -1,7 +1,7 @@ use ecow::{eco_format, EcoString}; use crate::diag::{At, SourceResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{func, scope, Str, Value}; use crate::loading::Readable; use crate::syntax::{is_newline, Spanned}; @@ -29,14 +29,14 @@ use crate::World; /// ``` #[func(scope, title = "TOML")] pub fn toml( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Path to a TOML file. path: Spanned<EcoString>, ) -> SourceResult<Value> { let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; toml::decode(Spanned::new(Readable::Bytes(data), span)) } diff --git a/crates/typst/src/loading/xml.rs b/crates/typst/src/loading/xml.rs index 73aeb32a..338b2f30 100644 --- a/crates/typst/src/loading/xml.rs +++ b/crates/typst/src/loading/xml.rs @@ -1,7 +1,7 @@ use ecow::EcoString; use crate::diag::{format_xml_like_error, At, FileError, SourceResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{dict, func, scope, Array, Dict, IntoValue, Str, Value}; use crate::loading::Readable; use crate::syntax::Spanned; @@ -57,14 +57,14 @@ use crate::World; /// ``` #[func(scope, title = "XML")] pub fn xml( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Path to an XML file. path: Spanned<EcoString>, ) -> SourceResult<Value> { let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; xml::decode(Spanned::new(Readable::Bytes(data), span)) } diff --git a/crates/typst/src/loading/yaml.rs b/crates/typst/src/loading/yaml.rs index 03dd2a2c..501e3066 100644 --- a/crates/typst/src/loading/yaml.rs +++ b/crates/typst/src/loading/yaml.rs @@ -1,7 +1,7 @@ use ecow::{eco_format, EcoString}; use crate::diag::{At, SourceResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{func, scope, Str, Value}; use crate::loading::Readable; use crate::syntax::Spanned; @@ -38,14 +38,14 @@ use crate::World; /// ``` #[func(scope, title = "YAML")] pub fn yaml( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Path to a YAML file. path: Spanned<EcoString>, ) -> SourceResult<Value> { let Spanned { v: path, span } = path; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; yaml::decode(Spanned::new(Readable::Bytes(data), span)) } diff --git a/crates/typst/src/math/cancel.rs b/crates/typst/src/math/cancel.rs index 7a72f44a..6d3026b8 100644 --- a/crates/typst/src/math/cancel.rs +++ b/crates/typst/src/math/cancel.rs @@ -191,7 +191,7 @@ fn draw_cancel_line( CancelAngle::Angle(v) => *v, // This specifies a function that takes the default angle as input. CancelAngle::Func(func) => { - func.call_vt(ctx.vt, [default])?.cast().at(span)? + func.call(ctx.engine, [default])?.cast().at(span)? } }, }; diff --git a/crates/typst/src/math/ctx.rs b/crates/typst/src/math/ctx.rs index 0f7ad933..9352f08b 100644 --- a/crates/typst/src/math/ctx.rs +++ b/crates/typst/src/math/ctx.rs @@ -9,8 +9,9 @@ use unicode_math_class::MathClass; use unicode_segmentation::UnicodeSegmentation; use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{Content, NativeElement, Smart, StyleChain, Styles}; -use crate::layout::{Abs, Axes, BoxElem, Em, Frame, Layout, Regions, Size, Vt}; +use crate::layout::{Abs, Axes, BoxElem, Em, Frame, Layout, Regions, Size}; use crate::math::{ FrameFragment, GlyphFragment, LayoutMath, MathFragment, MathRow, MathSize, MathStyle, MathVariant, THICK, @@ -43,7 +44,7 @@ macro_rules! percent { /// The context for math layout. pub struct MathContext<'a, 'b, 'v> { - pub vt: &'v mut Vt<'b>, + pub engine: &'v mut Engine<'b>, pub regions: Regions<'static>, pub font: &'a Font, pub ttf: &'a ttf_parser::Face<'a>, @@ -62,7 +63,7 @@ pub struct MathContext<'a, 'b, 'v> { impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { pub fn new( - vt: &'v mut Vt<'b>, + engine: &'v mut Engine<'b>, styles: StyleChain<'a>, regions: Regions, font: &'a Font, @@ -103,7 +104,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { let variant = variant(styles); Self { - vt, + engine, regions: Regions::one(regions.base(), Axes::splat(false)), font, ttf: font.ttf(), @@ -167,13 +168,13 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { pub fn layout_box(&mut self, boxed: &BoxElem) -> SourceResult<Frame> { Ok(boxed - .layout(self.vt, self.outer.chain(&self.local), self.regions)? + .layout(self.engine, self.outer.chain(&self.local), self.regions)? .into_frame()) } pub fn layout_content(&mut self, content: &Content) -> SourceResult<Frame> { Ok(content - .layout(self.vt, self.outer.chain(&self.local), self.regions)? + .layout(self.engine, self.outer.chain(&self.local), self.regions)? .into_frame()) } @@ -270,7 +271,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { let frame = ParElem::new(vec![Prehashed::new(elem)]) .spanned(span) .layout( - self.vt, + self.engine, self.outer.chain(&self.local), false, Size::splat(Abs::inf()), @@ -288,7 +289,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { } pub fn realize(&mut self, content: &Content) -> SourceResult<Option<Content>> { - realize(self.vt, content, self.outer.chain(&self.local)) + realize(self.engine, content, self.outer.chain(&self.local)) } pub fn style(&mut self, style: MathStyle) { diff --git a/crates/typst/src/math/equation.rs b/crates/typst/src/math/equation.rs index fb58a5b7..f5fa6061 100644 --- a/crates/typst/src/math/equation.rs +++ b/crates/typst/src/math/equation.rs @@ -1,6 +1,7 @@ use std::num::NonZeroUsize; use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ elem, Content, Finalize, Guard, NativeElement, Resolve, Show, Smart, StyleChain, Synthesize, @@ -8,7 +9,7 @@ use crate::foundations::{ use crate::introspection::{Count, Counter, CounterUpdate, Locatable}; use crate::layout::{ Abs, Align, AlignElem, Axes, Dir, Em, FixedAlign, Fragment, Layout, Point, Regions, - Size, Vt, + Size, }; use crate::math::{LayoutMath, MathContext}; use crate::model::{Numbering, Outlinable, ParElem, Refable, Supplement}; @@ -88,12 +89,18 @@ pub struct EquationElem { } impl Synthesize for EquationElem { - fn synthesize(&mut self, vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize( + &mut self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<()> { // Resolve the supplement. let supplement = match self.supplement(styles) { Smart::Auto => TextElem::packed(Self::local_name_in(styles)), Smart::Custom(None) => Content::empty(), - Smart::Custom(Some(supplement)) => supplement.resolve(vt, [self.clone()])?, + Smart::Custom(Some(supplement)) => { + supplement.resolve(engine, [self.clone()])? + } }; self.push_block(self.block(styles)); @@ -106,7 +113,7 @@ impl Synthesize for EquationElem { impl Show for EquationElem { #[tracing::instrument(name = "EquationElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut realized = self.clone().pack().guarded(Guard::Base(Self::elem())); if self.block(styles) { realized = AlignElem::new(realized).pack(); @@ -133,7 +140,7 @@ impl Layout for EquationElem { #[tracing::instrument(name = "EquationElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -143,7 +150,7 @@ impl Layout for EquationElem { // Find a math font. let variant = variant(styles); - let world = vt.world; + let world = engine.world; let Some(font) = families(styles).find_map(|family| { let id = world.book().select(family, variant)?; let font = world.font(id)?; @@ -153,7 +160,7 @@ impl Layout for EquationElem { bail!(self.span(), "current font does not support math"); }; - let mut ctx = MathContext::new(vt, styles, regions, &font, block); + let mut ctx = MathContext::new(engine, styles, regions, &font, block); let mut frame = ctx.layout_frame(self)?; if block { @@ -161,7 +168,7 @@ impl Layout for EquationElem { let pod = Regions::one(regions.base(), Axes::splat(false)); let counter = Counter::of(Self::elem()) .display(Some(numbering), false) - .layout(vt, styles, pod)? + .layout(engine, styles, pod)? .into_frame(); let full_counter_width = counter.width() + NUMBER_GUTTER.resolve(styles); @@ -274,7 +281,7 @@ impl Refable for EquationElem { } impl Outlinable for EquationElem { - fn outline(&self, vt: &mut Vt) -> SourceResult<Option<Content>> { + fn outline(&self, engine: &mut Engine) -> SourceResult<Option<Content>> { if !self.block(StyleChain::default()) { return Ok(None); } @@ -294,8 +301,8 @@ impl Outlinable for EquationElem { let numbers = self .counter() - .at(vt, self.location().unwrap())? - .display(vt, &numbering)?; + .at(engine, self.location().unwrap())? + .display(engine, &numbering)?; Ok(Some(supplement + numbers)) } diff --git a/crates/typst/src/model/bibliography.rs b/crates/typst/src/model/bibliography.rs index f6e189e1..626468dc 100644 --- a/crates/typst/src/model/bibliography.rs +++ b/crates/typst/src/model/bibliography.rs @@ -20,7 +20,8 @@ use smallvec::{smallvec, SmallVec}; use typed_arena::Arena; use crate::diag::{bail, error, At, FileError, SourceResult, StrResult}; -use crate::eval::{eval_string, EvalMode, Vm}; +use crate::engine::Engine; +use crate::eval::{eval_string, EvalMode}; use crate::foundations::{ cast, elem, ty, Args, Array, Bytes, CastInfo, Content, Finalize, FromValue, IntoValue, Label, NativeElement, Reflect, Repr, Scope, Show, Smart, Str, StyleChain, @@ -28,7 +29,7 @@ use crate::foundations::{ }; use crate::introspection::{Introspector, Locatable, Location}; use crate::layout::{ - BlockElem, Em, GridElem, HElem, PadElem, Sizing, TrackSizings, VElem, Vt, + BlockElem, Em, GridElem, HElem, PadElem, Sizing, TrackSizings, VElem, }; use crate::model::{ CitationForm, CiteGroup, Destination, FootnoteElem, HeadingElem, LinkElem, ParElem, @@ -88,7 +89,7 @@ pub struct BibliographyElem { /// Path(s) to Hayagriva `.yml` and/or BibLaTeX `.bib` files. #[required] #[parse( - let (paths, bibliography) = Bibliography::parse(vm, args)?; + let (paths, bibliography) = Bibliography::parse(engine, args)?; paths )] pub path: BibliographyPaths, @@ -120,7 +121,7 @@ pub struct BibliographyElem { /// a [CSL file](https://citationstyles.org/). Some of the styles listed /// below appear twice, once with their full name and once with a short /// alias. - #[parse(CslStyle::parse(vm, args)?)] + #[parse(CslStyle::parse(engine, args)?)] #[default(CslStyle::from_name("ieee").unwrap())] pub style: CslStyle, @@ -169,9 +170,10 @@ impl BibliographyElem { } /// Whether the bibliography contains the given key. - pub fn has(vt: &Vt, key: impl Into<PicoStr>) -> bool { + pub fn has(engine: &Engine, key: impl Into<PicoStr>) -> bool { let key = key.into(); - vt.introspector + engine + .introspector .query(&Self::elem().select()) .iter() .any(|elem| elem.to::<Self>().unwrap().bibliography().has(key)) @@ -195,7 +197,7 @@ impl BibliographyElem { } impl Synthesize for BibliographyElem { - fn synthesize(&mut self, _vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { self.push_full(self.full(styles)); self.push_style(self.style(styles)); self.push_lang(TextElem::lang_in(styles)); @@ -206,7 +208,7 @@ impl Synthesize for BibliographyElem { impl Show for BibliographyElem { #[tracing::instrument(name = "BibliographyElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { const COLUMN_GUTTER: Em = Em::new(0.65); const INDENT: Em = Em::new(1.5); @@ -219,9 +221,9 @@ impl Show for BibliographyElem { seq.push(HeadingElem::new(title).with_level(NonZeroUsize::ONE).pack()); } - Ok(vt.delayed(|vt| { + Ok(engine.delayed(|engine| { let span = self.span(); - let works = Works::generate(vt.world, vt.introspector).at(span)?; + let works = Works::generate(engine.world, engine.introspector).at(span)?; let references = works .references .as_ref() @@ -316,7 +318,7 @@ pub struct Bibliography { impl Bibliography { /// Parse the bibliography argument. fn parse( - vm: &mut Vm, + engine: &mut Engine, args: &mut Args, ) -> SourceResult<(BibliographyPaths, Bibliography)> { let Spanned { v: paths, span } = @@ -327,8 +329,8 @@ impl Bibliography { .0 .iter() .map(|path| { - let id = vm.resolve_path(path).at(span)?; - vm.world().file(id).at(span) + let id = span.resolve_path(path).at(span)?; + engine.world.file(id).at(span) }) .collect::<SourceResult<Vec<Bytes>>>()?; @@ -438,19 +440,19 @@ pub struct CslStyle { impl CslStyle { /// Parse the style argument. - pub fn parse(vm: &mut Vm, args: &mut Args) -> SourceResult<Option<CslStyle>> { + pub fn parse(engine: &mut Engine, args: &mut Args) -> SourceResult<Option<CslStyle>> { let Some(Spanned { v: string, span }) = args.named::<Spanned<EcoString>>("style")? else { return Ok(None); }; - Ok(Some(Self::parse_impl(vm, &string).at(span)?)) + Ok(Some(Self::parse_impl(engine, &string, span).at(span)?)) } /// Parse the style argument with `Smart`. pub fn parse_smart( - vm: &mut Vm, + engine: &mut Engine, args: &mut Args, ) -> SourceResult<Option<Smart<CslStyle>>> { let Some(Spanned { v: smart, span }) = @@ -462,13 +464,13 @@ impl CslStyle { Ok(Some(match smart { Smart::Auto => Smart::Auto, Smart::Custom(string) => { - Smart::Custom(Self::parse_impl(vm, &string).at(span)?) + Smart::Custom(Self::parse_impl(engine, &string, span).at(span)?) } })) } /// Parse internally. - fn parse_impl(vm: &mut Vm, string: &str) -> StrResult<CslStyle> { + fn parse_impl(engine: &mut Engine, string: &str, span: Span) -> StrResult<CslStyle> { let ext = Path::new(string) .extension() .and_then(OsStr::to_str) @@ -476,8 +478,8 @@ impl CslStyle { .to_lowercase(); if ext == "csl" { - let id = vm.resolve_path(string)?; - let data = vm.world().file(id)?; + let id = span.resolve_path(string)?; + let data = engine.world.file(id)?; CslStyle::from_data(&data) } else { CslStyle::from_name(string) diff --git a/crates/typst/src/model/cite.rs b/crates/typst/src/model/cite.rs index 7ead5907..3657e83d 100644 --- a/crates/typst/src/model/cite.rs +++ b/crates/typst/src/model/cite.rs @@ -1,9 +1,9 @@ use crate::diag::{bail, At, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, Cast, Content, Label, NativeElement, Show, Smart, StyleChain, Synthesize, }; use crate::introspection::Locatable; -use crate::layout::Vt; use crate::model::bibliography::Works; use crate::model::CslStyle; use crate::text::{Lang, Region, TextElem}; @@ -85,7 +85,7 @@ pub struct CiteElem { /// /// When set to `{auto}`, automatically use the /// [bibliography's style]($bibliography.style) for the citations. - #[parse(CslStyle::parse_smart(vm, args)?)] + #[parse(CslStyle::parse_smart(engine, args)?)] pub style: Smart<CslStyle>, /// The text language setting where the citation is. @@ -100,7 +100,7 @@ pub struct CiteElem { } impl Synthesize for CiteElem { - fn synthesize(&mut self, _vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { self.push_supplement(self.supplement(styles)); self.push_form(self.form(styles)); self.push_style(self.style(styles)); @@ -143,12 +143,12 @@ pub struct CiteGroup { } impl Show for CiteGroup { - #[tracing::instrument(name = "CiteGroup::show", skip(self, vt))] - fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> { - Ok(vt.delayed(|vt| { + #[tracing::instrument(name = "CiteGroup::show", skip(self, engine))] + fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { + Ok(engine.delayed(|engine| { let location = self.location().unwrap(); let span = self.span(); - Works::generate(vt.world, vt.introspector) + Works::generate(engine.world, engine.introspector) .at(span)? .citations .get(&location) diff --git a/crates/typst/src/model/document.rs b/crates/typst/src/model/document.rs index f6ea7d24..373a1545 100644 --- a/crates/typst/src/model/document.rs +++ b/crates/typst/src/model/document.rs @@ -2,12 +2,12 @@ use comemo::Prehashed; use ecow::EcoString; use crate::diag::{bail, SourceResult, StrResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ cast, elem, Args, Array, Construct, Content, Datetime, Smart, StyleChain, Value, }; use crate::introspection::ManualPageCounter; -use crate::layout::{Frame, LayoutRoot, PageElem, Vt}; +use crate::layout::{Frame, LayoutRoot, PageElem}; /// The root element of a document and its metadata. /// @@ -56,7 +56,7 @@ pub struct DocumentElem { } impl Construct for DocumentElem { - fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { + fn construct(_: &mut Engine, args: &mut Args) -> SourceResult<Content> { bail!(args.span, "can only be used in set rules") } } @@ -64,7 +64,11 @@ impl Construct for DocumentElem { impl LayoutRoot for DocumentElem { /// Layout the document into a sequence of frames, one per page. #[tracing::instrument(name = "DocumentElem::layout_root", skip_all)] - fn layout_root(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Document> { + fn layout_root( + &self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<Document> { tracing::info!("Document layout"); let mut pages = vec![]; @@ -88,7 +92,8 @@ impl LayoutRoot for DocumentElem { .to::<PageElem>()? .clear_to(styles) }); - let fragment = page.layout(vt, styles, &mut page_counter, extend_to)?; + let fragment = + page.layout(engine, styles, &mut page_counter, extend_to)?; pages.extend(fragment); } else { bail!(child.span(), "unexpected document child"); diff --git a/crates/typst/src/model/emph.rs b/crates/typst/src/model/emph.rs index 1b7f654c..de7b8bef 100644 --- a/crates/typst/src/model/emph.rs +++ b/crates/typst/src/model/emph.rs @@ -1,6 +1,6 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Content, Show, StyleChain}; -use crate::layout::Vt; use crate::text::{ItalicToggle, TextElem}; /// Emphasizes content by setting it in italics. @@ -35,7 +35,7 @@ pub struct EmphElem { impl Show for EmphElem { #[tracing::instrument(name = "EmphElem::show", skip(self))] - fn show(&self, _: &mut Vt, _: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(TextElem::set_emph(ItalicToggle))) } } diff --git a/crates/typst/src/model/enum.rs b/crates/typst/src/model/enum.rs index f440bc39..f4583f8d 100644 --- a/crates/typst/src/model/enum.rs +++ b/crates/typst/src/model/enum.rs @@ -1,12 +1,13 @@ use std::str::FromStr; use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, Array, Content, Fold, NativeElement, Smart, StyleChain, }; use crate::layout::{ Axes, BlockElem, Em, Fragment, GridLayouter, HAlign, Layout, Length, Regions, Sizing, - Spacing, VAlign, Vt, + Spacing, VAlign, }; use crate::model::{Numbering, NumberingPattern, ParElem}; use crate::text::TextElem; @@ -209,7 +210,7 @@ impl Layout for EnumElem { #[tracing::instrument(name = "EnumElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -239,7 +240,7 @@ impl Layout for EnumElem { let resolved = if full { parents.push(number); - let content = numbering.apply_vt(vt, &parents)?.display(); + let content = numbering.apply(engine, &parents)?.display(); parents.pop(); content } else { @@ -247,7 +248,7 @@ impl Layout for EnumElem { Numbering::Pattern(pattern) => { TextElem::packed(pattern.apply_kth(parents.len(), number)) } - other => other.apply_vt(vt, &[number])?.display(), + other => other.apply(engine, &[number])?.display(), } }; @@ -277,7 +278,7 @@ impl Layout for EnumElem { self.span(), ); - Ok(layouter.layout(vt)?.fragment) + Ok(layouter.layout(engine)?.fragment) } } diff --git a/crates/typst/src/model/figure.rs b/crates/typst/src/model/figure.rs index 26a96db1..e6ab7a2a 100644 --- a/crates/typst/src/model/figure.rs +++ b/crates/typst/src/model/figure.rs @@ -5,6 +5,7 @@ use std::str::FromStr; use ecow::EcoString; use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, select_where, Content, Element, Finalize, NativeElement, Selector, Show, Smart, StyleChain, Synthesize, @@ -12,7 +13,7 @@ use crate::foundations::{ use crate::introspection::{ Count, Counter, CounterKey, CounterUpdate, Locatable, Location, }; -use crate::layout::{Align, BlockElem, Em, HAlign, Length, PlaceElem, VAlign, VElem, Vt}; +use crate::layout::{Align, BlockElem, Em, HAlign, Length, PlaceElem, VAlign, VElem}; use crate::model::{Numbering, NumberingPattern, Outlinable, Refable, Supplement}; use crate::syntax::Spanned; use crate::text::{Lang, Region, TextElem}; @@ -220,7 +221,11 @@ impl FigureElem { } impl Synthesize for FigureElem { - fn synthesize(&mut self, vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize( + &mut self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<()> { let numbering = self.numbering(styles); // Determine the figure's kind. @@ -264,7 +269,7 @@ impl Synthesize for FigureElem { }; let target = descendant.unwrap_or_else(|| Cow::Borrowed(self.body())); - Some(supplement.resolve(vt, [target])?) + Some(supplement.resolve(engine, [target])?) } }; @@ -296,7 +301,7 @@ impl Synthesize for FigureElem { impl Show for FigureElem { #[tracing::instrument(name = "FigureElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut realized = self.body().clone(); // Build the caption, if any. @@ -364,7 +369,7 @@ impl Refable for FigureElem { } impl Outlinable for FigureElem { - fn outline(&self, vt: &mut Vt) -> SourceResult<Option<Content>> { + fn outline(&self, engine: &mut Engine) -> SourceResult<Option<Content>> { if !self.outlined(StyleChain::default()) { return Ok(None); } @@ -384,7 +389,7 @@ impl Outlinable for FigureElem { self.numbering(StyleChain::default()), ) { let location = self.location().unwrap(); - let numbers = counter.at(vt, location)?.display(vt, &numbering)?; + let numbers = counter.at(engine, location)?.display(engine, &numbering)?; if !supplement.is_empty() { supplement += TextElem::packed('\u{a0}'); @@ -538,7 +543,7 @@ impl FigureCaption { } impl Synthesize for FigureCaption { - fn synthesize(&mut self, _: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { self.push_position(self.position(styles)); self.push_separator(Smart::Custom(self.get_separator(styles))); Ok(()) @@ -547,7 +552,7 @@ impl Synthesize for FigureCaption { impl Show for FigureCaption { #[tracing::instrument(name = "FigureCaption::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut realized = self.body().clone(); if let (Some(mut supplement), Some(numbering), Some(counter), Some(location)) = ( @@ -556,7 +561,7 @@ impl Show for FigureCaption { self.counter(), self.figure_location(), ) { - let numbers = counter.at(vt, *location)?.display(vt, numbering)?; + let numbers = counter.at(engine, *location)?.display(engine, numbering)?; if !supplement.is_empty() { supplement += TextElem::packed('\u{a0}'); } diff --git a/crates/typst/src/model/footnote.rs b/crates/typst/src/model/footnote.rs index d51ee226..df88b58c 100644 --- a/crates/typst/src/model/footnote.rs +++ b/crates/typst/src/model/footnote.rs @@ -4,12 +4,13 @@ use std::str::FromStr; use comemo::Prehashed; use crate::diag::{bail, error, At, SourceResult, StrResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, Content, Finalize, Label, NativeElement, Show, Smart, StyleChain, Synthesize, }; use crate::introspection::{Count, Counter, CounterUpdate, Locatable, Location}; -use crate::layout::{Abs, Em, HElem, Length, Ratio, Vt}; +use crate::layout::{Abs, Em, HElem, Length, Ratio}; use crate::model::{Destination, Numbering, NumberingPattern, ParElem}; use crate::text::{SuperElem, TextElem, TextSize}; use crate::util::NonZeroExt; @@ -107,14 +108,15 @@ impl FootnoteElem { } /// Returns the location of the definition of this footnote. - pub fn declaration_location(&self, vt: &Vt) -> StrResult<Location> { + pub fn declaration_location(&self, engine: &Engine) -> StrResult<Location> { match self.body() { FootnoteBody::Reference(label) => { - let element: Prehashed<Content> = vt.introspector.query_label(*label)?; + let element: Prehashed<Content> = + engine.introspector.query_label(*label)?; let footnote = element .to::<FootnoteElem>() .ok_or("referenced element should be a footnote")?; - footnote.declaration_location(vt) + footnote.declaration_location(engine) } _ => Ok(self.location().unwrap()), } @@ -122,7 +124,7 @@ impl FootnoteElem { } impl Synthesize for FootnoteElem { - fn synthesize(&mut self, _vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { self.push_numbering(self.numbering(styles).clone()); Ok(()) } @@ -130,12 +132,12 @@ impl Synthesize for FootnoteElem { impl Show for FootnoteElem { #[tracing::instrument(name = "FootnoteElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { - Ok(vt.delayed(|vt| { - let loc = self.declaration_location(vt).at(self.span())?; + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { + Ok(engine.delayed(|engine| { + let loc = self.declaration_location(engine).at(self.span())?; let numbering = self.numbering(styles); let counter = Counter::of(Self::elem()); - let num = counter.at(vt, loc)?.display(vt, numbering)?; + let num = counter.at(engine, loc)?.display(engine, numbering)?; let sup = SuperElem::new(num).pack(); let loc = loc.variant(1); // Add zero-width weak spacing to make the footnote "sticky". @@ -271,7 +273,7 @@ pub struct FootnoteEntry { } impl Show for FootnoteEntry { - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let note = self.note(); let number_gap = Em::new(0.05); let default = StyleChain::default(); @@ -283,7 +285,7 @@ impl Show for FootnoteEntry { )) }; - let num = counter.at(vt, loc)?.display(vt, numbering)?; + let num = counter.at(engine, loc)?.display(engine, numbering)?; let sup = SuperElem::new(num) .pack() .linked(Destination::Location(loc)) diff --git a/crates/typst/src/model/heading.rs b/crates/typst/src/model/heading.rs index 3365f00c..6f8932d4 100644 --- a/crates/typst/src/model/heading.rs +++ b/crates/typst/src/model/heading.rs @@ -1,12 +1,13 @@ use std::num::NonZeroUsize; use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{ cast, elem, Content, Finalize, NativeElement, Show, Smart, StyleChain, Styles, Synthesize, }; use crate::introspection::{Count, Counter, CounterUpdate, Locatable}; -use crate::layout::{BlockElem, Em, HElem, VElem, Vt}; +use crate::layout::{BlockElem, Em, HElem, VElem}; use crate::model::{Numbering, Outlinable, Refable, Supplement}; use crate::text::{FontWeight, Lang, LocalName, Region, SpaceElem, TextElem, TextSize}; use crate::util::{option_eq, NonZeroExt}; @@ -126,12 +127,18 @@ pub struct HeadingElem { } impl Synthesize for HeadingElem { - fn synthesize(&mut self, vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize( + &mut self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<()> { // Resolve the supplement. let supplement = match self.supplement(styles) { Smart::Auto => TextElem::packed(Self::local_name_in(styles)), Smart::Custom(None) => Content::empty(), - Smart::Custom(Some(supplement)) => supplement.resolve(vt, [self.clone()])?, + Smart::Custom(Some(supplement)) => { + supplement.resolve(engine, [self.clone()])? + } }; self.push_level(self.level(styles)); @@ -146,7 +153,7 @@ impl Synthesize for HeadingElem { impl Show for HeadingElem { #[tracing::instrument(name = "HeadingElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut realized = self.body().clone(); if let Some(numbering) = self.numbering(styles).as_ref() { realized = Counter::of(Self::elem()) @@ -214,7 +221,7 @@ impl Refable for HeadingElem { } impl Outlinable for HeadingElem { - fn outline(&self, vt: &mut Vt) -> SourceResult<Option<Content>> { + fn outline(&self, engine: &mut Engine) -> SourceResult<Option<Content>> { if !self.outlined(StyleChain::default()) { return Ok(None); } @@ -223,8 +230,8 @@ impl Outlinable for HeadingElem { let default = StyleChain::default(); if let Some(numbering) = self.numbering(default).as_ref() { let numbers = Counter::of(Self::elem()) - .at(vt, self.location().unwrap())? - .display(vt, numbering)?; + .at(engine, self.location().unwrap())? + .display(engine, numbering)?; content = numbers + SpaceElem::new().pack() + content; }; diff --git a/crates/typst/src/model/link.rs b/crates/typst/src/model/link.rs index 27a05737..5d1b4f19 100644 --- a/crates/typst/src/model/link.rs +++ b/crates/typst/src/model/link.rs @@ -1,11 +1,12 @@ use ecow::{eco_format, EcoString}; use crate::diag::{At, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, Content, Label, NativeElement, Repr, Show, Smart, StyleChain, }; use crate::introspection::Location; -use crate::layout::{Position, Vt}; +use crate::layout::Position; use crate::text::{Hyphenate, TextElem}; /// Links to a URL or a location in the document. @@ -89,14 +90,14 @@ impl LinkElem { } impl Show for LinkElem { - #[tracing::instrument(name = "LinkElem::show", skip(self, vt))] - fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> { + #[tracing::instrument(name = "LinkElem::show", skip(self, engine))] + fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { let body = self.body().clone(); let linked = match self.dest() { LinkTarget::Dest(dest) => body.linked(dest.clone()), - LinkTarget::Label(label) => vt - .delayed(|vt| { - let elem = vt.introspector.query_label(*label).at(self.span())?; + LinkTarget::Label(label) => engine + .delayed(|engine| { + let elem = engine.introspector.query_label(*label).at(self.span())?; let dest = Destination::Location(elem.location().unwrap()); Ok(Some(body.clone().linked(dest))) }) diff --git a/crates/typst/src/model/list.rs b/crates/typst/src/model/list.rs index e9275f03..623cafa2 100644 --- a/crates/typst/src/model/list.rs +++ b/crates/typst/src/model/list.rs @@ -1,11 +1,12 @@ use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, Array, Content, Fold, Func, NativeElement, Smart, StyleChain, Value, }; use crate::layout::{ Axes, BlockElem, Em, Fragment, GridLayouter, HAlign, Layout, Length, Regions, Sizing, - Spacing, VAlign, Vt, + Spacing, VAlign, }; use crate::model::ParElem; use crate::text::TextElem; @@ -130,7 +131,7 @@ impl Layout for ListElem { #[tracing::instrument(name = "ListElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -146,7 +147,7 @@ impl Layout for ListElem { let depth = self.depth(styles); let marker = self .marker(styles) - .resolve(vt, depth)? + .resolve(engine, depth)? // avoid '#set align' interference with the list .aligned(HAlign::Start + VAlign::Top); @@ -172,7 +173,7 @@ impl Layout for ListElem { self.span(), ); - Ok(layouter.layout(vt)?.fragment) + Ok(layouter.layout(engine)?.fragment) } } @@ -198,12 +199,12 @@ pub enum ListMarker { impl ListMarker { /// Resolve the marker for the given depth. - fn resolve(&self, vt: &mut Vt, depth: usize) -> SourceResult<Content> { + fn resolve(&self, engine: &mut Engine, depth: usize) -> SourceResult<Content> { Ok(match self { Self::Content(list) => { list.get(depth).or(list.last()).cloned().unwrap_or_default() } - Self::Func(func) => func.call_vt(vt, [depth])?.display(), + Self::Func(func) => func.call(engine, [depth])?.display(), }) } } diff --git a/crates/typst/src/model/numbering.rs b/crates/typst/src/model/numbering.rs index fa7a88c4..d91a5c52 100644 --- a/crates/typst/src/model/numbering.rs +++ b/crates/typst/src/model/numbering.rs @@ -5,9 +5,9 @@ use chinese_number::{ChineseCase, ChineseCountMethod, ChineseVariant, NumberToCh use ecow::{eco_format, EcoString, EcoVec}; use crate::diag::SourceResult; -use crate::eval::Vm; -use crate::foundations::{cast, func, Args, Func, Str, Value}; -use crate::layout::{PdfPageLabel, PdfPageLabelStyle, Vt}; +use crate::engine::Engine; +use crate::foundations::{cast, func, Func, Str, Value}; +use crate::layout::{PdfPageLabel, PdfPageLabelStyle}; use crate::text::Case; /// Applies a numbering to a sequence of numbers. @@ -35,8 +35,8 @@ use crate::text::Case; /// ``` #[func] pub fn numbering( - /// The virtual machine. - vm: &mut Vm, + /// The engine. + engine: &mut Engine, /// Defines how the numbering works. /// /// **Counting symbols** are `1`, `a`, `A`, `i`, `I`, `い`, `イ`, `א`, `가`, @@ -68,7 +68,7 @@ pub fn numbering( #[variadic] numbers: Vec<usize>, ) -> SourceResult<Value> { - numbering.apply_vm(vm, &numbers) + numbering.apply(engine, &numbers) } /// How to number a sequence of things. @@ -82,21 +82,10 @@ pub enum Numbering { impl Numbering { /// Apply the pattern to the given numbers. - pub fn apply_vm(&self, vm: &mut Vm, numbers: &[usize]) -> SourceResult<Value> { + pub fn apply(&self, engine: &mut Engine, numbers: &[usize]) -> SourceResult<Value> { Ok(match self { Self::Pattern(pattern) => Value::Str(pattern.apply(numbers).into()), - Self::Func(func) => { - let args = Args::new(func.span(), numbers.iter().copied()); - func.call_vm(vm, args)? - } - }) - } - - /// Apply the pattern to the given numbers. - pub fn apply_vt(&self, vt: &mut Vt, numbers: &[usize]) -> SourceResult<Value> { - Ok(match self { - Self::Pattern(pattern) => Value::Str(pattern.apply(numbers).into()), - Self::Func(func) => func.call_vt(vt, numbers.iter().copied())?, + Self::Func(func) => func.call(engine, numbers.iter().copied())?, }) } diff --git a/crates/typst/src/model/outline.rs b/crates/typst/src/model/outline.rs index 3b23098e..91526a9c 100644 --- a/crates/typst/src/model/outline.rs +++ b/crates/typst/src/model/outline.rs @@ -2,12 +2,13 @@ use std::num::NonZeroUsize; use std::str::FromStr; use crate::diag::{bail, error, At, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, select_where, Content, Finalize, Func, LocatableSelector, NativeElement, Show, Smart, StyleChain, }; use crate::introspection::{Counter, CounterKey, Locatable}; -use crate::layout::{BoxElem, Fr, HElem, HideElem, Length, Rel, RepeatElem, Spacing, Vt}; +use crate::layout::{BoxElem, Fr, HElem, HideElem, Length, Rel, RepeatElem, Spacing}; use crate::model::{Destination, HeadingElem, NumberingPattern, ParbreakElem, Refable}; use crate::syntax::Span; use crate::text::{Lang, LinebreakElem, LocalName, Region, SpaceElem, TextElem}; @@ -186,7 +187,7 @@ impl OutlineElem { impl Show for OutlineElem { #[tracing::instrument(name = "OutlineElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut seq = vec![ParbreakElem::new().pack()]; // Build the outline title. if let Some(title) = self.title(styles) { @@ -201,11 +202,11 @@ impl Show for OutlineElem { let depth = self.depth(styles).unwrap_or(NonZeroUsize::new(usize::MAX).unwrap()); let mut ancestors: Vec<&Content> = vec![]; - let elems = vt.introspector.query(&self.target(styles).0); + let elems = engine.introspector.query(&self.target(styles).0); for elem in &elems { let Some(entry) = OutlineEntry::from_outlinable( - vt, + engine, self.span(), elem.clone().into_inner(), self.fill(styles), @@ -229,7 +230,7 @@ impl Show for OutlineElem { ancestors.pop(); } - OutlineIndent::apply(indent, vt, &ancestors, &mut seq, self.span())?; + OutlineIndent::apply(indent, engine, &ancestors, &mut seq, self.span())?; // Add the overridable outline entry, followed by a line break. seq.push(entry.pack()); @@ -292,7 +293,7 @@ impl LocalName for OutlineElem { /// `#outline()` element. pub trait Outlinable: Refable { /// Produce an outline item for this element. - fn outline(&self, vt: &mut Vt) -> SourceResult<Option<Content>>; + fn outline(&self, engine: &mut Engine) -> SourceResult<Option<Content>>; /// Returns the nesting level of this element. fn level(&self) -> NonZeroUsize { @@ -311,7 +312,7 @@ pub enum OutlineIndent { impl OutlineIndent { fn apply( indent: &Option<Smart<Self>>, - vt: &mut Vt, + engine: &mut Engine, ancestors: &Vec<&Content>, seq: &mut Vec<Content>, span: Span, @@ -330,8 +331,8 @@ impl OutlineIndent { if let Some(numbering) = ancestor_outlinable.numbering() { let numbers = ancestor_outlinable .counter() - .at(vt, ancestor.location().unwrap())? - .display(vt, &numbering)?; + .at(engine, ancestor.location().unwrap())? + .display(engine, &numbering)?; hidden += numbers + SpaceElem::new().pack(); }; @@ -355,7 +356,7 @@ impl OutlineIndent { Some(Smart::Custom(OutlineIndent::Func(func))) => { let depth = ancestors.len(); let LengthOrContent(content) = - func.call_vt(vt, [depth])?.cast().at(span)?; + func.call(engine, [depth])?.cast().at(span)?; if !content.is_empty() { seq.push(content); } @@ -455,7 +456,7 @@ impl OutlineEntry { /// be outlined (e.g. heading with 'outlined: false'), does not generate an /// entry instance (returns `Ok(None)`). fn from_outlinable( - vt: &mut Vt, + engine: &mut Engine, span: Span, elem: Content, fill: Option<Content>, @@ -464,27 +465,27 @@ impl OutlineEntry { bail!(span, "cannot outline {}", elem.func().name()); }; - let Some(body) = outlinable.outline(vt)? else { + let Some(body) = outlinable.outline(engine)? else { return Ok(None); }; let location = elem.location().unwrap(); - let page_numbering = vt + let page_numbering = engine .introspector .page_numbering(location) .cloned() .unwrap_or_else(|| NumberingPattern::from_str("1").unwrap().into()); let page = Counter::new(CounterKey::Page) - .at(vt, location)? - .display(vt, &page_numbering)?; + .at(engine, location)? + .display(engine, &page_numbering)?; Ok(Some(Self::new(outlinable.level(), elem, body, fill, page))) } } impl Show for OutlineEntry { - fn show(&self, _vt: &mut Vt, _: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { let mut seq = vec![]; let elem = self.element(); diff --git a/crates/typst/src/model/par.rs b/crates/typst/src/model/par.rs index 84274661..c9f64efb 100644 --- a/crates/typst/src/model/par.rs +++ b/crates/typst/src/model/par.rs @@ -1,12 +1,12 @@ use comemo::Prehashed; use crate::diag::SourceResult; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ elem, Args, Cast, Construct, Content, NativeElement, Set, Smart, StyleChain, Unlabellable, }; -use crate::layout::{Em, Fragment, Length, Size, Vt}; +use crate::layout::{Em, Fragment, Length, Size}; /// Arranges text, spacing and inline-level elements into a paragraph. /// @@ -108,11 +108,11 @@ pub struct ParElem { } impl Construct for ParElem { - fn construct(vm: &mut Vm, args: &mut Args) -> SourceResult<Content> { + fn construct(engine: &mut Engine, args: &mut Args) -> SourceResult<Content> { // The paragraph constructor is special: It doesn't create a paragraph // element. Instead, it just ensures that the passed content lives in a // separate paragraph and styles it. - let styles = Self::set(vm, args)?; + let styles = Self::set(engine, args)?; let body = args.expect::<Content>("body")?; Ok(Content::sequence([ ParbreakElem::new().pack(), @@ -127,7 +127,7 @@ impl ParElem { #[tracing::instrument(name = "ParElement::layout", skip_all)] pub fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, consecutive: bool, region: Size, @@ -135,7 +135,7 @@ impl ParElem { ) -> SourceResult<Fragment> { crate::layout::layout_inline( self.children(), - vt, + engine, styles, consecutive, region, diff --git a/crates/typst/src/model/quote.rs b/crates/typst/src/model/quote.rs index 489e2657..2a709071 100644 --- a/crates/typst/src/model/quote.rs +++ b/crates/typst/src/model/quote.rs @@ -1,9 +1,10 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{ cast, elem, Content, Finalize, Label, NativeElement, Show, Smart, StyleChain, Synthesize, }; -use crate::layout::{Align, BlockElem, Em, HElem, PadElem, Spacing, VElem, Vt}; +use crate::layout::{Align, BlockElem, Em, HElem, PadElem, Spacing, VElem}; use crate::model::{CitationForm, CiteElem}; use crate::text::{SmartQuoteElem, SpaceElem, TextElem}; @@ -145,7 +146,7 @@ cast! { } impl Synthesize for QuoteElem { - fn synthesize(&mut self, _: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { self.push_block(self.block(styles)); self.push_quotes(self.quotes(styles)); Ok(()) @@ -153,7 +154,7 @@ impl Synthesize for QuoteElem { } impl Show for QuoteElem { - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut realized = self.body().clone(); let block = self.block(styles); diff --git a/crates/typst/src/model/reference.rs b/crates/typst/src/model/reference.rs index 7f328e28..d64de1ae 100644 --- a/crates/typst/src/model/reference.rs +++ b/crates/typst/src/model/reference.rs @@ -1,12 +1,12 @@ use ecow::eco_format; use crate::diag::{bail, At, Hint, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, Content, Func, IntoValue, Label, NativeElement, Show, Smart, StyleChain, Synthesize, }; use crate::introspection::{Counter, Locatable}; -use crate::layout::Vt; use crate::math::EquationElem; use crate::model::{ BibliographyElem, CiteElem, Destination, Figurable, FootnoteElem, Numbering, @@ -137,14 +137,18 @@ pub struct RefElem { } impl Synthesize for RefElem { - fn synthesize(&mut self, vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { - let citation = self.to_citation(vt, styles)?; + fn synthesize( + &mut self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<()> { + let citation = self.to_citation(engine, styles)?; self.push_citation(Some(citation)); self.push_element(None); let target = *self.target(); - if !BibliographyElem::has(vt, target) { - if let Ok(elem) = vt.introspector.query_label(target) { + if !BibliographyElem::has(engine, target) { + if let Ok(elem) = engine.introspector.query_label(target) { self.push_element(Some(elem.into_inner())); return Ok(()); } @@ -156,18 +160,18 @@ impl Synthesize for RefElem { impl Show for RefElem { #[tracing::instrument(name = "RefElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { - Ok(vt.delayed(|vt| { + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { + Ok(engine.delayed(|engine| { let target = *self.target(); - let elem = vt.introspector.query_label(target); + let elem = engine.introspector.query_label(target); let span = self.span(); - if BibliographyElem::has(vt, target) { + if BibliographyElem::has(engine, target) { if elem.is_ok() { bail!(span, "label occurs in the document and its bibliography"); } - return Ok(self.to_citation(vt, styles)?.spanned(span).pack()); + return Ok(self.to_citation(engine, styles)?.spanned(span).pack()); } let elem = elem.at(span)?; @@ -211,14 +215,14 @@ impl Show for RefElem { let numbers = refable .counter() - .at(vt, elem.location().unwrap())? - .display(vt, &numbering.trimmed())?; + .at(engine, elem.location().unwrap())? + .display(engine, &numbering.trimmed())?; let supplement = match self.supplement(styles).as_ref() { Smart::Auto => refable.supplement(), Smart::Custom(None) => Content::empty(), Smart::Custom(Some(supplement)) => { - supplement.resolve(vt, [(*elem).clone()])? + supplement.resolve(engine, [(*elem).clone()])? } }; @@ -234,10 +238,14 @@ impl Show for RefElem { impl RefElem { /// Turn the reference into a citation. - pub fn to_citation(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<CiteElem> { + pub fn to_citation( + &self, + engine: &mut Engine, + styles: StyleChain, + ) -> SourceResult<CiteElem> { let mut elem = CiteElem::new(*self.target()); elem.set_location(self.location().unwrap()); - elem.synthesize(vt, styles)?; + elem.synthesize(engine, styles)?; elem.push_supplement(match self.supplement(styles).clone() { Smart::Custom(Some(Supplement::Content(content))) => Some(content), _ => None, @@ -258,12 +266,12 @@ impl Supplement { /// Tries to resolve the supplement into its content. pub fn resolve<T: IntoValue>( &self, - vt: &mut Vt, + engine: &mut Engine, args: impl IntoIterator<Item = T>, ) -> SourceResult<Content> { Ok(match self { Supplement::Content(content) => content.clone(), - Supplement::Func(func) => func.call_vt(vt, args)?.display(), + Supplement::Func(func) => func.call(engine, args)?.display(), }) } } diff --git a/crates/typst/src/model/strong.rs b/crates/typst/src/model/strong.rs index 40b99b2f..666a4aa0 100644 --- a/crates/typst/src/model/strong.rs +++ b/crates/typst/src/model/strong.rs @@ -1,6 +1,6 @@ use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Content, Show, StyleChain}; -use crate::layout::Vt; use crate::text::{TextElem, WeightDelta}; /// Strongly emphasizes content by increasing the font weight. @@ -39,7 +39,7 @@ pub struct StrongElem { impl Show for StrongElem { #[tracing::instrument(name = "StrongElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self .body() .clone() diff --git a/crates/typst/src/model/table.rs b/crates/typst/src/model/table.rs index 278b898c..31c6636f 100644 --- a/crates/typst/src/model/table.rs +++ b/crates/typst/src/model/table.rs @@ -1,11 +1,12 @@ use crate::diag::{At, SourceResult, StrResult}; +use crate::engine::Engine; use crate::foundations::{ elem, Array, CastInfo, Content, FromValue, Func, IntoValue, NativeElement, Reflect, Smart, StyleChain, Value, }; use crate::layout::{ Abs, Align, AlignElem, Axes, Fragment, FrameItem, GridLayouter, Layout, Length, - Point, Regions, Rel, Sides, Size, TrackSizings, Vt, + Point, Regions, Rel, Sides, Size, TrackSizings, }; use crate::model::Figurable; use crate::text::{Lang, LocalName, Region}; @@ -158,7 +159,7 @@ impl Layout for TableElem { #[tracing::instrument(name = "TableElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -181,7 +182,7 @@ impl Layout for TableElem { let x = i % cols; let y = i / cols; - if let Smart::Custom(alignment) = align.resolve(vt, x, y)? { + if let Smart::Custom(alignment) = align.resolve(engine, x, y)? { child = child.styled(AlignElem::set_alignment(alignment)); } @@ -197,7 +198,7 @@ impl Layout for TableElem { GridLayouter::new(tracks, gutter, &cells, regions, styles, self.span()); // Measure the columns and layout the grid row-by-row. - let mut layout = layouter.layout(vt)?; + let mut layout = layouter.layout(engine)?; // Add lines and backgrounds. for (frame, rows) in layout.fragment.iter_mut().zip(&layout.rows) { @@ -236,7 +237,7 @@ impl Layout for TableElem { for (x, &col) in layout.cols.iter().enumerate() { let mut dy = Abs::zero(); for row in rows { - if let Some(fill) = fill.resolve(vt, x, row.y)? { + if let Some(fill) = fill.resolve(engine, x, row.y)? { let pos = Point::new(dx, dy); let size = Size::new(col, row.height); let rect = Geometry::Rect(size).filled(fill); @@ -275,10 +276,10 @@ pub enum Celled<T> { impl<T: Default + Clone + FromValue> Celled<T> { /// Resolve the value based on the cell position. - pub fn resolve(&self, vt: &mut Vt, x: usize, y: usize) -> SourceResult<T> { + pub fn resolve(&self, engine: &mut Engine, x: usize, y: usize) -> SourceResult<T> { Ok(match self { Self::Value(value) => value.clone(), - Self::Func(func) => func.call_vt(vt, [x, y])?.cast().at(func.span())?, + Self::Func(func) => func.call(engine, [x, y])?.cast().at(func.span())?, Self::Array(array) => x .checked_rem(array.len()) .and_then(|i| array.get(i)) diff --git a/crates/typst/src/model/terms.rs b/crates/typst/src/model/terms.rs index 1d256626..bbb6129a 100644 --- a/crates/typst/src/model/terms.rs +++ b/crates/typst/src/model/terms.rs @@ -1,9 +1,10 @@ use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, Array, Content, NativeElement, Smart, StyleChain, }; use crate::layout::{ - BlockElem, Em, Fragment, HElem, Layout, Length, Regions, Spacing, VElem, Vt, + BlockElem, Em, Fragment, HElem, Layout, Length, Regions, Spacing, VElem, }; use crate::model::ParElem; use crate::util::Numeric; @@ -110,7 +111,7 @@ impl Layout for TermsElem { #[tracing::instrument(name = "TermsElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -139,7 +140,7 @@ impl Layout for TermsElem { Content::sequence(seq) .styled(ParElem::set_hanging_indent(hanging_indent + indent)) - .layout(vt, styles, regions) + .layout(engine, styles, regions) } } diff --git a/crates/typst/src/realize/mod.rs b/crates/typst/src/realize/mod.rs index 2b5ce22d..c2f19303 100644 --- a/crates/typst/src/realize/mod.rs +++ b/crates/typst/src/realize/mod.rs @@ -10,7 +10,8 @@ use std::mem; use smallvec::smallvec; use typed_arena::Arena; -use crate::diag::{bail, SourceResult}; +use crate::diag::{bail, error, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ Content, Finalize, Guard, NativeElement, Recipe, Selector, Show, StyleChain, StyleVecBuilder, Styles, Synthesize, @@ -18,7 +19,7 @@ use crate::foundations::{ use crate::introspection::{Locatable, Meta, MetaElem}; use crate::layout::{ AlignElem, BlockElem, BoxElem, ColbreakElem, FlowElem, HElem, Layout, LayoutRoot, - PageElem, PagebreakElem, Parity, PlaceElem, VElem, Vt, + PageElem, PagebreakElem, Parity, PlaceElem, VElem, }; use crate::math::{EquationElem, LayoutMath}; use crate::model::{ @@ -33,6 +34,58 @@ use crate::visualize::{ SquareElem, }; +/// Realize into an element that is capable of root-level layout. +#[tracing::instrument(skip_all)] +pub fn realize_root<'a>( + engine: &mut Engine, + scratch: &'a Scratch<'a>, + content: &'a Content, + styles: StyleChain<'a>, +) -> SourceResult<(Cow<'a, Content>, StyleChain<'a>)> { + if content.can::<dyn LayoutRoot>() && !applicable(content, styles) { + return Ok((Cow::Borrowed(content), styles)); + } + + let mut builder = Builder::new(engine, scratch, true); + builder.accept(content, styles)?; + builder.interrupt_page(Some(styles), true)?; + let (pages, shared) = builder.doc.unwrap().pages.finish(); + Ok((Cow::Owned(DocumentElem::new(pages.to_vec()).pack()), shared)) +} + +/// Realize into an element that is capable of block-level layout. +#[tracing::instrument(skip_all)] +pub fn realize_block<'a>( + engine: &mut Engine, + scratch: &'a Scratch<'a>, + content: &'a Content, + styles: StyleChain<'a>, +) -> SourceResult<(Cow<'a, Content>, StyleChain<'a>)> { + // These elements implement `Layout` but still require a flow for + // proper layout. + if content.can::<dyn Layout>() + && !content.is::<BoxElem>() + && !content.is::<LineElem>() + && !content.is::<RectElem>() + && !content.is::<SquareElem>() + && !content.is::<EllipseElem>() + && !content.is::<CircleElem>() + && !content.is::<ImageElem>() + && !content.is::<PolygonElem>() + && !content.is::<PathElem>() + && !content.is::<PlaceElem>() + && !applicable(content, styles) + { + return Ok((Cow::Borrowed(content), styles)); + } + + let mut builder = Builder::new(engine, scratch, false); + builder.accept(content, styles)?; + builder.interrupt_par()?; + let (children, shared) = builder.flow.0.finish(); + Ok((Cow::Owned(FlowElem::new(children.to_vec()).pack()), shared)) +} + /// Whether the target is affected by show rules in the given style chain. pub fn applicable(target: &Content, styles: StyleChain) -> bool { if target.needs_preparation() { @@ -59,7 +112,7 @@ pub fn applicable(target: &Content, styles: StyleChain) -> bool { /// Apply the show rules in the given style chain to a target. pub fn realize( - vt: &mut Vt, + engine: &mut Engine, target: &Content, styles: StyleChain, ) -> SourceResult<Option<Content>> { @@ -67,12 +120,12 @@ pub fn realize( if target.needs_preparation() { let mut elem = target.clone(); if target.can::<dyn Locatable>() || target.label().is_some() { - let location = vt.locator.locate(hash128(target)); + let location = engine.locator.locate(hash128(target)); elem.set_location(location); } if let Some(elem) = elem.with_mut::<dyn Synthesize>() { - elem.synthesize(vt, styles)?; + elem.synthesize(engine, styles)?; } elem.mark_prepared(); @@ -97,7 +150,7 @@ pub fn realize( for recipe in styles.recipes() { let guard = Guard::Nth(n); if recipe.applicable(target) && !target.is_guarded(guard) { - if let Some(content) = try_apply(vt, target, recipe, guard)? { + if let Some(content) = try_apply(engine, target, recipe, guard)? { realized = Some(content); break; } @@ -109,7 +162,7 @@ pub fn realize( if let Some(showable) = target.with::<dyn Show>() { let guard = Guard::Base(target.func()); if realized.is_none() && !target.is_guarded(guard) { - realized = Some(showable.show(vt, styles)?); + realized = Some(showable.show(engine, styles)?); } } @@ -127,7 +180,7 @@ pub fn realize( /// Try to apply a recipe to the target. fn try_apply( - vt: &mut Vt, + engine: &mut Engine, target: &Content, recipe: &Recipe, guard: Guard, @@ -138,7 +191,7 @@ fn try_apply( return Ok(None); } - recipe.apply_vt(vt, target.clone().guarded(guard)).map(Some) + recipe.apply(engine, target.clone().guarded(guard)).map(Some) } Some(Selector::Label(label)) => { @@ -146,7 +199,7 @@ fn try_apply( return Ok(None); } - recipe.apply_vt(vt, target.clone().guarded(guard)).map(Some) + recipe.apply(engine, target.clone().guarded(guard)).map(Some) } Some(Selector::Regex(regex)) => { @@ -172,7 +225,7 @@ fn try_apply( } let piece = make(m.as_str()).guarded(guard); - let transformed = recipe.apply_vt(vt, piece)?; + let transformed = recipe.apply(engine, piece)?; result.push(transformed); cursor = m.end(); } @@ -202,62 +255,10 @@ fn try_apply( } } -/// Realize into an element that is capable of root-level layout. -#[tracing::instrument(skip_all)] -pub fn realize_root<'a>( - vt: &mut Vt, - scratch: &'a Scratch<'a>, - content: &'a Content, - styles: StyleChain<'a>, -) -> SourceResult<(Cow<'a, Content>, StyleChain<'a>)> { - if content.can::<dyn LayoutRoot>() && !applicable(content, styles) { - return Ok((Cow::Borrowed(content), styles)); - } - - let mut builder = Builder::new(vt, scratch, true); - builder.accept(content, styles)?; - builder.interrupt_page(Some(styles), true)?; - let (pages, shared) = builder.doc.unwrap().pages.finish(); - Ok((Cow::Owned(DocumentElem::new(pages.to_vec()).pack()), shared)) -} - -/// Realize into an element that is capable of block-level layout. -#[tracing::instrument(skip_all)] -pub fn realize_block<'a>( - vt: &mut Vt, - scratch: &'a Scratch<'a>, - content: &'a Content, - styles: StyleChain<'a>, -) -> SourceResult<(Cow<'a, Content>, StyleChain<'a>)> { - // These elements implement `Layout` but still require a flow for - // proper layout. - if content.can::<dyn Layout>() - && !content.is::<BoxElem>() - && !content.is::<LineElem>() - && !content.is::<RectElem>() - && !content.is::<SquareElem>() - && !content.is::<EllipseElem>() - && !content.is::<CircleElem>() - && !content.is::<ImageElem>() - && !content.is::<PolygonElem>() - && !content.is::<PathElem>() - && !content.is::<PlaceElem>() - && !applicable(content, styles) - { - return Ok((Cow::Borrowed(content), styles)); - } - - let mut builder = Builder::new(vt, scratch, false); - builder.accept(content, styles)?; - builder.interrupt_par()?; - let (children, shared) = builder.flow.0.finish(); - Ok((Cow::Owned(FlowElem::new(children.to_vec()).pack()), shared)) -} - /// Builds a document or a flow element from content. struct Builder<'a, 'v, 't> { - /// The virtual typesetter. - vt: &'v mut Vt<'t>, + /// The engine. + engine: &'v mut Engine<'t>, /// Scratch arenas for building. scratch: &'a Scratch<'a>, /// The current document building state. @@ -282,9 +283,9 @@ pub struct Scratch<'a> { } impl<'a, 'v, 't> Builder<'a, 'v, 't> { - fn new(vt: &'v mut Vt<'t>, scratch: &'a Scratch<'a>, top: bool) -> Self { + fn new(engine: &'v mut Engine<'t>, scratch: &'a Scratch<'a>, top: bool) -> Self { Self { - vt, + engine, scratch, doc: top.then(DocBuilder::default), flow: FlowBuilder::default(), @@ -304,9 +305,19 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> { self.scratch.content.alloc(EquationElem::new(content.clone()).pack()); } - if let Some(realized) = realize(self.vt, content, styles)? { + if let Some(realized) = realize(self.engine, content, styles)? { + self.engine.route.increase(); + if self.engine.route.exceeding() { + bail!(error!(content.span(), "maximum show rule depth exceeded") + .with_hint("check whether the show rule matches its own output") + .with_hint( + "this is a current compiler limitation that will be resolved in the future" + )); + } let stored = self.scratch.content.alloc(realized); - return self.accept(stored, styles); + let v = self.accept(stored, styles); + self.engine.route.decrease(); + return v; } if let Some((elem, local)) = content.to_styled() { diff --git a/crates/typst/src/text/deco.rs b/crates/typst/src/text/deco.rs index f7ee8cbc..348ddf34 100644 --- a/crates/typst/src/text/deco.rs +++ b/crates/typst/src/text/deco.rs @@ -4,8 +4,9 @@ use ttf_parser::{GlyphId, OutlineBuilder}; use ecow::{eco_format, EcoString}; use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{cast, elem, ty, Content, Fold, Repr, Show, Smart, StyleChain}; -use crate::layout::{Abs, Em, Frame, FrameItem, Length, Point, Size, Vt}; +use crate::layout::{Abs, Em, Frame, FrameItem, Length, Point, Size}; use crate::syntax::Span; use crate::text::{ BottomEdge, BottomEdgeMetric, TextElem, TextItem, TopEdge, TopEdgeMetric, @@ -85,7 +86,7 @@ pub struct UnderlineElem { impl Show for UnderlineElem { #[tracing::instrument(name = "UnderlineElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(TextElem::set_deco(Decoration { line: DecoLine::Underline { stroke: self.stroke(styles).unwrap_or_default(), @@ -177,7 +178,7 @@ pub struct OverlineElem { impl Show for OverlineElem { #[tracing::instrument(name = "OverlineElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(TextElem::set_deco(Decoration { line: DecoLine::Overline { stroke: self.stroke(styles).unwrap_or_default(), @@ -254,7 +255,7 @@ pub struct StrikeElem { impl Show for StrikeElem { #[tracing::instrument(name = "StrikeElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(TextElem::set_deco(Decoration { // Note that we do not support evade option for strikethrough. line: DecoLine::Strikethrough { @@ -324,7 +325,7 @@ pub struct HighlightElem { impl Show for HighlightElem { #[tracing::instrument(name = "HighlightElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(TextElem::set_deco(Decoration { line: DecoLine::Highlight { fill: self.fill(styles), diff --git a/crates/typst/src/text/mod.rs b/crates/typst/src/text/mod.rs index 45de35f9..da3580a5 100644 --- a/crates/typst/src/text/mod.rs +++ b/crates/typst/src/text/mod.rs @@ -35,7 +35,7 @@ use rustybuzz::{Feature, Tag}; use ttf_parser::Rect; use crate::diag::{bail, error, SourceResult, StrResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ cast, category, elem, Args, Array, Cast, Category, Construct, Content, Dict, Fold, NativeElement, Never, PlainText, Repr, Resolve, Scope, Set, Smart, StyleChain, Value, @@ -656,11 +656,11 @@ impl Repr for TextElem { } impl Construct for TextElem { - fn construct(vm: &mut Vm, args: &mut Args) -> SourceResult<Content> { + fn construct(engine: &mut Engine, args: &mut Args) -> SourceResult<Content> { // The text constructor is special: It doesn't create a text element. // Instead, it leaves the passed argument structurally unchanged, but // styles all text in it. - let styles = Self::set(vm, args)?; + let styles = Self::set(engine, args)?; let body = args.expect::<Content>("body")?; Ok(body.styled_with_map(styles)) } diff --git a/crates/typst/src/text/raw.rs b/crates/typst/src/text/raw.rs index 1142281c..6962dbce 100644 --- a/crates/typst/src/text/raw.rs +++ b/crates/typst/src/text/raw.rs @@ -10,12 +10,12 @@ use syntect::parsing::{SyntaxDefinition, SyntaxSet, SyntaxSetBuilder}; use unicode_segmentation::UnicodeSegmentation; use crate::diag::{At, FileError, SourceResult, StrResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, Args, Array, Bytes, Content, Finalize, Fold, NativeElement, PlainText, Show, Smart, StyleChain, Styles, Synthesize, Value, }; -use crate::layout::{BlockElem, Em, HAlign, Vt}; +use crate::layout::{BlockElem, Em, HAlign}; use crate::model::Figurable; use crate::syntax::{split_newlines, LinkedNode, Spanned}; use crate::text::{ @@ -191,7 +191,7 @@ pub struct RawElem { /// ``` /// ```` #[parse( - let (syntaxes, syntaxes_data) = parse_syntaxes(vm, args)?; + let (syntaxes, syntaxes_data) = parse_syntaxes(engine, args)?; syntaxes )] #[fold] @@ -229,7 +229,7 @@ pub struct RawElem { /// ``` /// ```` #[parse( - let (theme_path, theme_data) = parse_theme(vm, args)?; + let (theme_path, theme_data) = parse_theme(engine, args)?; theme_path.map(Some) )] #[borrowed] @@ -288,7 +288,7 @@ impl RawElem { } impl Synthesize for RawElem { - fn synthesize(&mut self, _vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { self.push_lang(self.lang(styles).clone()); let mut text = self.text().clone(); @@ -393,7 +393,7 @@ impl Synthesize for RawElem { impl Show for RawElem { #[tracing::instrument(name = "RawElem::show", skip_all)] - fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut lines = EcoVec::with_capacity((2 * self.lines().len()).saturating_sub(1)); for (i, line) in self.lines().iter().enumerate() { if i != 0 { @@ -495,7 +495,7 @@ pub struct RawLine { } impl Show for RawLine { - fn show(&self, _vt: &mut Vt, _styles: StyleChain) -> SourceResult<Content> { + fn show(&self, _: &mut Engine, _styles: StyleChain) -> SourceResult<Content> { Ok(self.body().clone()) } } @@ -676,7 +676,7 @@ fn load_syntaxes(paths: &SyntaxPaths, bytes: &[Bytes]) -> StrResult<Arc<SyntaxSe /// Function to parse the syntaxes argument. /// Much nicer than having it be part of the `element` macro. fn parse_syntaxes( - vm: &mut Vm, + engine: &mut Engine, args: &mut Args, ) -> SourceResult<(Option<SyntaxPaths>, Option<Vec<Bytes>>)> { let Some(Spanned { v: paths, span }) = @@ -690,8 +690,8 @@ fn parse_syntaxes( .0 .iter() .map(|path| { - let id = vm.resolve_path(path).at(span)?; - vm.world().file(id).at(span) + let id = span.resolve_path(path).at(span)?; + engine.world.file(id).at(span) }) .collect::<SourceResult<Vec<Bytes>>>()?; @@ -713,7 +713,7 @@ fn load_theme(path: &str, bytes: &Bytes) -> StrResult<Arc<synt::Theme>> { /// Function to parse the theme argument. /// Much nicer than having it be part of the `element` macro. fn parse_theme( - vm: &mut Vm, + engine: &mut Engine, args: &mut Args, ) -> SourceResult<(Option<EcoString>, Option<Bytes>)> { let Some(Spanned { v: path, span }) = args.named::<Spanned<EcoString>>("theme")? @@ -722,8 +722,8 @@ fn parse_theme( }; // Load theme file. - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; // Check that parsing works. let _ = load_theme(&path, &data).at(span)?; diff --git a/crates/typst/src/text/shift.rs b/crates/typst/src/text/shift.rs index 73f28343..e467d6c0 100644 --- a/crates/typst/src/text/shift.rs +++ b/crates/typst/src/text/shift.rs @@ -1,8 +1,9 @@ use ecow::EcoString; use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Content, Show, StyleChain}; -use crate::layout::{Em, Length, Vt}; +use crate::layout::{Em, Length}; use crate::text::{variant, SpaceElem, TextElem, TextSize}; use crate::World; @@ -48,12 +49,12 @@ pub struct SubElem { impl Show for SubElem { #[tracing::instrument(name = "SubElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let body = self.body().clone(); let mut transformed = None; if self.typographic(styles) { if let Some(text) = search_text(&body, true) { - if is_shapable(vt, &text, styles) { + if is_shapable(engine, &text, styles) { transformed = Some(TextElem::packed(text)); } } @@ -108,12 +109,12 @@ pub struct SuperElem { impl Show for SuperElem { #[tracing::instrument(name = "SuperElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { + fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let body = self.body().clone(); let mut transformed = None; if self.typographic(styles) { if let Some(text) = search_text(&body, false) { - if is_shapable(vt, &text, styles) { + if is_shapable(engine, &text, styles) { transformed = Some(TextElem::packed(text)); } } @@ -149,8 +150,8 @@ fn search_text(content: &Content, sub: bool) -> Option<EcoString> { /// Checks whether the first retrievable family contains all code points of the /// given string. -fn is_shapable(vt: &Vt, text: &str, styles: StyleChain) -> bool { - let world = vt.world; +fn is_shapable(engine: &Engine, text: &str, styles: StyleChain) -> bool { + let world = engine.world; for family in TextElem::font_in(styles) { if let Some(font) = world .book() diff --git a/crates/typst/src/visualize/image/mod.rs b/crates/typst/src/visualize/image/mod.rs index 722e77a6..159dc14a 100644 --- a/crates/typst/src/visualize/image/mod.rs +++ b/crates/typst/src/visualize/image/mod.rs @@ -14,13 +14,14 @@ use comemo::{Prehashed, Tracked}; use ecow::EcoString; use crate::diag::{bail, At, SourceResult, StrResult}; +use crate::engine::Engine; use crate::foundations::{ cast, elem, func, scope, Bytes, Cast, Content, NativeElement, Resolve, Smart, StyleChain, }; use crate::layout::{ Abs, Axes, FixedAlign, Fragment, Frame, FrameItem, Layout, Length, Point, Regions, - Rel, Size, Vt, + Rel, Size, }; use crate::loading::Readable; use crate::model::Figurable; @@ -57,8 +58,8 @@ pub struct ImageElem { #[parse( let Spanned { v: path, span } = args.expect::<Spanned<EcoString>>("path to image file")?; - let id = vm.resolve_path(&path).at(span)?; - let data = vm.world().file(id).at(span)?; + let id = span.resolve_path(&path).at(span)?; + let data = engine.world.file(id).at(span)?; path )] #[borrowed] @@ -145,7 +146,7 @@ impl Layout for ImageElem { #[tracing::instrument(name = "ImageElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { @@ -181,7 +182,7 @@ impl Layout for ImageElem { data.clone().into(), format, self.alt(styles), - vt.world, + engine.world, &families(styles).map(|s| s.into()).collect::<Vec<_>>(), ) .at(self.span())?; diff --git a/crates/typst/src/visualize/line.rs b/crates/typst/src/visualize/line.rs index 118395ec..ece93727 100644 --- a/crates/typst/src/visualize/line.rs +++ b/crates/typst/src/visualize/line.rs @@ -1,7 +1,8 @@ use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{elem, NativeElement, StyleChain}; use crate::layout::{ - Abs, Angle, Axes, Fragment, Frame, FrameItem, Layout, Length, Regions, Rel, Size, Vt, + Abs, Angle, Axes, Fragment, Frame, FrameItem, Layout, Length, Regions, Rel, Size, }; use crate::util::Numeric; use crate::visualize::{Geometry, Stroke}; @@ -61,7 +62,7 @@ impl Layout for LineElem { #[tracing::instrument(name = "LineElem::layout", skip_all)] fn layout( &self, - _: &mut Vt, + _: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { diff --git a/crates/typst/src/visualize/path.rs b/crates/typst/src/visualize/path.rs index f2e1466f..6ed07cb2 100644 --- a/crates/typst/src/visualize/path.rs +++ b/crates/typst/src/visualize/path.rs @@ -1,11 +1,12 @@ use kurbo::{CubicBez, ParamCurveExtrema}; use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ array, cast, elem, Array, NativeElement, Reflect, Resolve, Smart, StyleChain, }; use crate::layout::{ - Abs, Axes, Fragment, Frame, FrameItem, Layout, Length, Point, Regions, Rel, Size, Vt, + Abs, Axes, Fragment, Frame, FrameItem, Layout, Length, Point, Regions, Rel, Size, }; use crate::visualize::{FixedStroke, Geometry, Paint, Shape, Stroke}; @@ -73,7 +74,7 @@ impl Layout for PathElem { #[tracing::instrument(name = "PathElem::layout", skip_all)] fn layout( &self, - _: &mut Vt, + _: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { diff --git a/crates/typst/src/visualize/pattern.rs b/crates/typst/src/visualize/pattern.rs index 55d68500..3014a8e0 100644 --- a/crates/typst/src/visualize/pattern.rs +++ b/crates/typst/src/visualize/pattern.rs @@ -5,7 +5,7 @@ use comemo::Prehashed; use ecow::{eco_format, EcoString}; use crate::diag::{bail, error, SourceResult}; -use crate::eval::Vm; +use crate::engine::Engine; use crate::foundations::{func, scope, ty, Content, Repr, Smart, StyleChain}; use crate::layout::{Abs, Axes, Em, Frame, Layout, Length, Regions, Size}; use crate::syntax::{Span, Spanned}; @@ -120,7 +120,7 @@ impl Pattern { /// ``` #[func(constructor)] pub fn construct( - vm: &mut Vm, + engine: &mut Engine, /// The bounding box of each cell of the pattern. #[named] #[default(Spanned::new(Smart::Auto, Span::detached()))] @@ -173,11 +173,11 @@ impl Pattern { let region = size.unwrap_or_else(|| Axes::splat(Abs::inf())); // Layout the pattern. - let world = vm.vt.world; + let world = engine.world; let library = world.library(); let styles = StyleChain::new(&library.styles); let pod = Regions::one(region, Axes::splat(false)); - let mut frame = body.layout(&mut vm.vt, styles, pod)?.into_frame(); + let mut frame = body.layout(engine, styles, pod)?.into_frame(); // Check that the frame is non-zero. if size.is_auto() && frame.size().is_zero() { diff --git a/crates/typst/src/visualize/polygon.rs b/crates/typst/src/visualize/polygon.rs index 3b818fa4..7436f63e 100644 --- a/crates/typst/src/visualize/polygon.rs +++ b/crates/typst/src/visualize/polygon.rs @@ -1,11 +1,12 @@ use std::f64::consts::PI; use crate::diag::{bail, SourceResult}; +use crate::engine::Engine; use crate::foundations::{ elem, func, scope, Content, NativeElement, Resolve, Smart, StyleChain, }; use crate::layout::{ - Axes, Em, Fragment, Frame, FrameItem, Layout, Length, Point, Regions, Rel, Vt, + Axes, Em, Fragment, Frame, FrameItem, Layout, Length, Point, Regions, Rel, }; use crate::util::Numeric; use crate::visualize::{FixedStroke, Geometry, Paint, Path, Shape, Stroke}; @@ -125,7 +126,7 @@ impl Layout for PolygonElem { #[tracing::instrument(name = "PolygonElem::layout", skip_all)] fn layout( &self, - _: &mut Vt, + _: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { diff --git a/crates/typst/src/visualize/shape.rs b/crates/typst/src/visualize/shape.rs index d1a2a155..fcdcfc31 100644 --- a/crates/typst/src/visualize/shape.rs +++ b/crates/typst/src/visualize/shape.rs @@ -1,10 +1,11 @@ use std::f64::consts::SQRT_2; use crate::diag::SourceResult; +use crate::engine::Engine; use crate::foundations::{elem, Content, NativeElement, Resolve, Smart, StyleChain}; use crate::layout::{ Abs, Axes, Corner, Corners, Fragment, Frame, FrameItem, Layout, Length, Point, Ratio, - Regions, Rel, Sides, Size, Vt, + Regions, Rel, Sides, Size, }; use crate::syntax::Span; use crate::util::Get; @@ -134,12 +135,12 @@ impl Layout for RectElem { #[tracing::instrument(name = "RectElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { layout( - vt, + engine, styles, regions, ShapeKind::Rect, @@ -240,12 +241,12 @@ impl Layout for SquareElem { #[tracing::instrument(name = "SquareElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { layout( - vt, + engine, styles, regions, ShapeKind::Square, @@ -318,12 +319,12 @@ impl Layout for EllipseElem { #[tracing::instrument(name = "EllipseElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { layout( - vt, + engine, styles, regions, ShapeKind::Ellipse, @@ -421,12 +422,12 @@ impl Layout for CircleElem { #[tracing::instrument(name = "CircleElem::layout", skip_all)] fn layout( &self, - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, ) -> SourceResult<Fragment> { layout( - vt, + engine, styles, regions, ShapeKind::Circle, @@ -446,7 +447,7 @@ impl Layout for CircleElem { #[tracing::instrument(name = "shape::layout", skip_all)] #[allow(clippy::too_many_arguments)] fn layout( - vt: &mut Vt, + engine: &mut Engine, styles: StyleChain, regions: Regions, kind: ShapeKind, @@ -473,7 +474,7 @@ fn layout( let child = child.clone().padded(inset.map(|side| side.map(Length::from))); let expand = sizing.as_ref().map(Smart::is_custom); let pod = Regions::one(region, expand); - frame = child.layout(vt, styles, pod)?.into_frame(); + frame = child.layout(engine, styles, pod)?.into_frame(); // Enforce correct size. *frame.size_mut() = expand.select(region, frame.size()); @@ -484,7 +485,7 @@ fn layout( frame.set_size(Size::splat(frame.size().max_by_side())); let length = frame.size().max_by_side().min(region.min_by_side()); let pod = Regions::one(Size::splat(length), Axes::splat(true)); - frame = child.layout(vt, styles, pod)?.into_frame(); + frame = child.layout(engine, styles, pod)?.into_frame(); } // Enforce correct size again. |
