diff options
Diffstat (limited to 'crates/typst-eval/src/vm.rs')
| -rw-r--r-- | crates/typst-eval/src/vm.rs | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/crates/typst-eval/src/vm.rs b/crates/typst-eval/src/vm.rs new file mode 100644 index 00000000..1c8331b6 --- /dev/null +++ b/crates/typst-eval/src/vm.rs @@ -0,0 +1,60 @@ +use comemo::Tracked; +use typst_library::engine::Engine; +use typst_library::foundations::{Context, IntoValue, Scopes, Value}; +use typst_library::World; +use typst_syntax::ast::{self, AstNode}; +use typst_syntax::Span; + +use crate::FlowEvent; + +/// A virtual machine. +/// +/// Holds the state needed to [evaluate](crate::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) 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>, + /// A span that is currently under inspection. + pub(crate) inspected: Option<Span>, + /// Data that is contextually made accessible to code behind the scenes. + pub(crate) context: Tracked<'a, Context<'a>>, +} + +impl<'a> Vm<'a> { + /// Create a new virtual machine. + pub fn new( + engine: Engine<'a>, + context: Tracked<'a, Context<'a>>, + scopes: Scopes<'a>, + target: Span, + ) -> Self { + let inspected = target.id().and_then(|id| engine.traced.get(id)); + Self { engine, context, flow: None, scopes, inspected } + } + + /// Access the underlying world. + pub fn world(&self) -> Tracked<'a, dyn World + 'a> { + self.engine.world + } + + /// Define a variable in the current scope. + pub fn define(&mut self, var: ast::Ident, value: impl IntoValue) { + let value = value.into_value(); + if self.inspected == Some(var.span()) { + self.trace(value.clone()); + } + self.scopes.top.define_ident(var, value); + } + + /// Trace a value. + #[cold] + pub fn trace(&mut self, value: Value) { + self.engine + .sink + .value(value.clone(), self.context.styles().ok().map(|s| s.to_map())); + } +} |
