mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
72 lines
2.3 KiB
Rust
72 lines
2.3 KiB
Rust
use comemo::Tracked;
|
|
use typst_library::diag::warning;
|
|
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());
|
|
}
|
|
// This will become an error in the parser if 'is' becomes a keyword.
|
|
if var.get() == "is" {
|
|
self.engine.sink.warn(warning!(
|
|
var.span(),
|
|
"`is` will likely become a keyword in future versions and will \
|
|
not be allowed as an identifier";
|
|
hint: "rename this variable to avoid future errors";
|
|
hint: "try `is_` instead"
|
|
));
|
|
}
|
|
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()));
|
|
}
|
|
}
|