summaryrefslogtreecommitdiff
path: root/crates/typst-library/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2025-02-03 17:04:54 +0100
committerGitHub <noreply@github.com>2025-02-03 16:04:54 +0000
commiteee903b0f8d5c0dfda3539888d7473c6163841b0 (patch)
treed92b2f4565b0153c03cbb63575e2edd4e911e853 /crates/typst-library/src
parent12dbb012b19a29612fc863c558901200b4013f5d (diff)
Refactor `Scope` (#5797)
Diffstat (limited to 'crates/typst-library/src')
-rw-r--r--crates/typst-library/src/foundations/dict.rs7
-rw-r--r--crates/typst-library/src/foundations/func.rs2
-rw-r--r--crates/typst-library/src/foundations/mod.rs4
-rw-r--r--crates/typst-library/src/foundations/module.rs15
-rw-r--r--crates/typst-library/src/foundations/plugin.rs4
-rw-r--r--crates/typst-library/src/foundations/scope.rs383
-rw-r--r--crates/typst-library/src/foundations/ty.rs9
-rw-r--r--crates/typst-library/src/html/mod.rs2
-rw-r--r--crates/typst-library/src/introspection/mod.rs2
-rw-r--r--crates/typst-library/src/layout/mod.rs2
-rw-r--r--crates/typst-library/src/lib.rs9
-rw-r--r--crates/typst-library/src/loading/mod.rs2
-rw-r--r--crates/typst-library/src/math/mod.rs2
-rw-r--r--crates/typst-library/src/model/mod.rs2
-rw-r--r--crates/typst-library/src/pdf/mod.rs2
-rw-r--r--crates/typst-library/src/symbols.rs2
-rw-r--r--crates/typst-library/src/text/mod.rs2
-rw-r--r--crates/typst-library/src/visualize/mod.rs2
18 files changed, 236 insertions, 217 deletions
diff --git a/crates/typst-library/src/foundations/dict.rs b/crates/typst-library/src/foundations/dict.rs
index e4ab54e7..c93670c1 100644
--- a/crates/typst-library/src/foundations/dict.rs
+++ b/crates/typst-library/src/foundations/dict.rs
@@ -261,7 +261,12 @@ pub struct ToDict(Dict);
cast! {
ToDict,
- v: Module => Self(v.scope().iter().map(|(k, v, _)| (Str::from(k.clone()), v.clone())).collect()),
+ v: Module => Self(v
+ .scope()
+ .iter()
+ .map(|(k, b)| (Str::from(k.clone()), b.read().clone()))
+ .collect()
+ ),
}
impl Debug for Dict {
diff --git a/crates/typst-library/src/foundations/func.rs b/crates/typst-library/src/foundations/func.rs
index a05deb1f..741b6633 100644
--- a/crates/typst-library/src/foundations/func.rs
+++ b/crates/typst-library/src/foundations/func.rs
@@ -259,7 +259,7 @@ impl Func {
let scope =
self.scope().ok_or("cannot access fields on user-defined functions")?;
match scope.get(field) {
- Some(field) => Ok(field),
+ Some(binding) => Ok(binding.read()),
None => match self.name() {
Some(name) => bail!("function `{name}` does not contain field `{field}`"),
None => bail!("function does not contain field `{field}`"),
diff --git a/crates/typst-library/src/foundations/mod.rs b/crates/typst-library/src/foundations/mod.rs
index a790da4f..c335484f 100644
--- a/crates/typst-library/src/foundations/mod.rs
+++ b/crates/typst-library/src/foundations/mod.rs
@@ -94,7 +94,7 @@ pub static FOUNDATIONS: Category;
/// Hook up all `foundations` definitions.
pub(super) fn define(global: &mut Scope, inputs: Dict, features: &Features) {
- global.category(FOUNDATIONS);
+ global.start_category(FOUNDATIONS);
global.define_type::<bool>();
global.define_type::<i64>();
global.define_type::<f64>();
@@ -301,7 +301,7 @@ pub fn eval(
let dict = scope;
let mut scope = Scope::new();
for (key, value) in dict {
- scope.define_spanned(key, value, span);
+ scope.bind(key.into(), Binding::new(value, span));
}
(engine.routines.eval_string)(engine.routines, engine.world, &text, span, mode, scope)
}
diff --git a/crates/typst-library/src/foundations/module.rs b/crates/typst-library/src/foundations/module.rs
index 3ee59c10..3259c17e 100644
--- a/crates/typst-library/src/foundations/module.rs
+++ b/crates/typst-library/src/foundations/module.rs
@@ -4,7 +4,7 @@ use std::sync::Arc;
use ecow::{eco_format, EcoString};
use typst_syntax::FileId;
-use crate::diag::StrResult;
+use crate::diag::{bail, StrResult};
use crate::foundations::{repr, ty, Content, Scope, Value};
/// An module of definitions.
@@ -118,11 +118,14 @@ impl Module {
}
/// Try to access a definition in the module.
- pub fn field(&self, name: &str) -> StrResult<&Value> {
- self.scope().get(name).ok_or_else(|| match &self.name {
- Some(module) => eco_format!("module `{module}` does not contain `{name}`"),
- None => eco_format!("module does not contain `{name}`"),
- })
+ pub fn field(&self, field: &str) -> StrResult<&Value> {
+ match self.scope().get(field) {
+ Some(binding) => Ok(binding.read()),
+ None => match &self.name {
+ Some(name) => bail!("module `{name}` does not contain `{field}`"),
+ None => bail!("module does not contain `{field}`"),
+ },
+ }
}
/// Extract the module's content.
diff --git a/crates/typst-library/src/foundations/plugin.rs b/crates/typst-library/src/foundations/plugin.rs
index cbc0f52d..a33f1cb9 100644
--- a/crates/typst-library/src/foundations/plugin.rs
+++ b/crates/typst-library/src/foundations/plugin.rs
@@ -8,7 +8,7 @@ use wasmi::Memory;
use crate::diag::{bail, At, SourceResult, StrResult};
use crate::engine::Engine;
-use crate::foundations::{cast, func, scope, Bytes, Func, Module, Scope, Value};
+use crate::foundations::{cast, func, scope, Binding, Bytes, Func, Module, Scope, Value};
use crate::loading::{DataSource, Load};
/// Loads a WebAssembly module.
@@ -369,7 +369,7 @@ impl Plugin {
if matches!(export.ty(), wasmi::ExternType::Func(_)) {
let name = EcoString::from(export.name());
let func = PluginFunc { plugin: shared.clone(), name: name.clone() };
- scope.define(name, Func::from(func));
+ scope.bind(name, Binding::detached(Func::from(func)));
}
}
diff --git a/crates/typst-library/src/foundations/scope.rs b/crates/typst-library/src/foundations/scope.rs
index b7b4a6d9..e73afeac 100644
--- a/crates/typst-library/src/foundations/scope.rs
+++ b/crates/typst-library/src/foundations/scope.rs
@@ -5,8 +5,8 @@ use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use ecow::{eco_format, EcoString};
+use indexmap::map::Entry;
use indexmap::IndexMap;
-use typst_syntax::ast::{self, AstNode};
use typst_syntax::Span;
use typst_utils::Static;
@@ -46,14 +46,14 @@ impl<'a> Scopes<'a> {
self.top = self.scopes.pop().expect("no pushed scope");
}
- /// Try to access a variable immutably.
- pub fn get(&self, var: &str) -> HintedStrResult<&Value> {
+ /// Try to access a binding immutably.
+ pub fn get(&self, var: &str) -> HintedStrResult<&Binding> {
std::iter::once(&self.top)
.chain(self.scopes.iter().rev())
.find_map(|scope| scope.get(var))
.or_else(|| {
self.base.and_then(|base| match base.global.scope().get(var) {
- Some(value) => Some(value),
+ Some(binding) => Some(binding),
None if var == "std" => Some(&base.std),
None => None,
})
@@ -61,14 +61,28 @@ impl<'a> Scopes<'a> {
.ok_or_else(|| unknown_variable(var))
}
- /// Try to access a variable immutably in math.
- pub fn get_in_math(&self, var: &str) -> HintedStrResult<&Value> {
+ /// Try to access a binding mutably.
+ pub fn get_mut(&mut self, var: &str) -> HintedStrResult<&mut Binding> {
+ std::iter::once(&mut self.top)
+ .chain(&mut self.scopes.iter_mut().rev())
+ .find_map(|scope| scope.get_mut(var))
+ .ok_or_else(|| {
+ match self.base.and_then(|base| base.global.scope().get(var)) {
+ Some(_) => cannot_mutate_constant(var),
+ _ if var == "std" => cannot_mutate_constant(var),
+ _ => unknown_variable(var),
+ }
+ })
+ }
+
+ /// Try to access a binding immutably in math.
+ pub fn get_in_math(&self, var: &str) -> HintedStrResult<&Binding> {
std::iter::once(&self.top)
.chain(self.scopes.iter().rev())
.find_map(|scope| scope.get(var))
.or_else(|| {
self.base.and_then(|base| match base.math.scope().get(var) {
- Some(value) => Some(value),
+ Some(binding) => Some(binding),
None if var == "std" => Some(&base.std),
None => None,
})
@@ -81,20 +95,6 @@ impl<'a> Scopes<'a> {
})
}
- /// Try to access a variable mutably.
- pub fn get_mut(&mut self, var: &str) -> HintedStrResult<&mut Value> {
- std::iter::once(&mut self.top)
- .chain(&mut self.scopes.iter_mut().rev())
- .find_map(|scope| scope.get_mut(var))
- .ok_or_else(|| {
- match self.base.and_then(|base| base.global.scope().get(var)) {
- Some(_) => cannot_mutate_constant(var),
- _ if var == "std" => cannot_mutate_constant(var),
- _ => unknown_variable(var),
- }
- })?
- }
-
/// Check if an std variable is shadowed.
pub fn check_std_shadowed(&self, var: &str) -> bool {
self.base.is_some_and(|base| base.global.scope().get(var).is_some())
@@ -104,84 +104,28 @@ impl<'a> Scopes<'a> {
}
}
-#[cold]
-fn cannot_mutate_constant(var: &str) -> HintedString {
- eco_format!("cannot mutate a constant: {}", var).into()
-}
-
-/// The error message when a variable is not found.
-#[cold]
-fn unknown_variable(var: &str) -> HintedString {
- let mut res = HintedString::new(eco_format!("unknown variable: {}", var));
-
- if var.contains('-') {
- res.hint(eco_format!(
- "if you meant to use subtraction, try adding spaces around the minus sign{}: `{}`",
- if var.matches('-').count() > 1 { "s" } else { "" },
- var.replace('-', " - ")
- ));
- }
-
- res
-}
-
-#[cold]
-fn unknown_variable_math(var: &str, in_global: bool) -> HintedString {
- let mut res = HintedString::new(eco_format!("unknown variable: {}", var));
-
- if matches!(var, "none" | "auto" | "false" | "true") {
- res.hint(eco_format!(
- "if you meant to use a literal, try adding a hash before it: `#{var}`",
- ));
- } else if in_global {
- res.hint(eco_format!(
- "`{var}` is not available directly in math, try adding a hash before it: `#{var}`",
- ));
- } else {
- res.hint(eco_format!(
- "if you meant to display multiple letters as is, try adding spaces between each letter: `{}`",
- var.chars()
- .flat_map(|c| [' ', c])
- .skip(1)
- .collect::<EcoString>()
- ));
- res.hint(eco_format!(
- "or if you meant to display this as text, try placing it in quotes: `\"{var}\"`"
- ));
- }
-
- res
-}
-
/// A map from binding names to values.
#[derive(Default, Clone)]
pub struct Scope {
- map: IndexMap<EcoString, Slot>,
+ map: IndexMap<EcoString, Binding>,
deduplicate: bool,
category: Option<Category>,
}
+/// Scope construction.
impl Scope {
/// Create a new empty scope.
pub fn new() -> Self {
Default::default()
}
- /// Create a new scope with the given capacity.
- pub fn with_capacity(capacity: usize) -> Self {
- Self {
- map: IndexMap::with_capacity(capacity),
- ..Default::default()
- }
- }
-
/// Create a new scope with duplication prevention.
pub fn deduplicating() -> Self {
Self { deduplicate: true, ..Default::default() }
}
/// Enter a new category.
- pub fn category(&mut self, category: Category) {
+ pub fn start_category(&mut self, category: Category) {
self.category = Some(category);
}
@@ -190,102 +134,87 @@ impl Scope {
self.category = None;
}
- /// Bind a value to a name.
- #[track_caller]
- pub fn define(&mut self, name: impl Into<EcoString>, value: impl IntoValue) {
- self.define_spanned(name, value, Span::detached())
- }
-
- /// Bind a value to a name defined by an identifier.
- #[track_caller]
- pub fn define_ident(&mut self, ident: ast::Ident, value: impl IntoValue) {
- self.define_spanned(ident.get().clone(), value, ident.span())
- }
-
- /// Bind a value to a name.
- #[track_caller]
- pub fn define_spanned(
- &mut self,
- name: impl Into<EcoString>,
- value: impl IntoValue,
- span: Span,
- ) {
- let name = name.into();
-
- #[cfg(debug_assertions)]
- if self.deduplicate && self.map.contains_key(&name) {
- panic!("duplicate definition: {name}");
- }
-
- self.map.insert(
- name,
- Slot::new(value.into_value(), span, Kind::Normal, self.category),
- );
- }
-
- /// Define a captured, immutable binding.
- pub fn define_captured(
- &mut self,
- name: EcoString,
- value: Value,
- capturer: Capturer,
- span: Span,
- ) {
- self.map.insert(
- name,
- Slot::new(value.into_value(), span, Kind::Captured(capturer), self.category),
- );
- }
-
/// Define a native function through a Rust type that shadows the function.
- pub fn define_func<T: NativeFunc>(&mut self) {
+ #[track_caller]
+ pub fn define_func<T: NativeFunc>(&mut self) -> &mut Binding {
let data = T::data();
- self.define(data.name, Func::from(data));
+ self.define(data.name, Func::from(data))
}
/// Define a native function with raw function data.
- pub fn define_func_with_data(&mut self, data: &'static NativeFuncData) {
- self.define(data.name, Func::from(data));
+ #[track_caller]
+ pub fn define_func_with_data(
+ &mut self,
+ data: &'static NativeFuncData,
+ ) -> &mut Binding {
+ self.define(data.name, Func::from(data))
}
/// Define a native type.
- pub fn define_type<T: NativeType>(&mut self) {
+ #[track_caller]
+ pub fn define_type<T: NativeType>(&mut self) -> &mut Binding {
let data = T::data();
- self.define(data.name, Type::from(data));
+ self.define(data.name, Type::from(data))
}
/// Define a native element.
- pub fn define_elem<T: NativeElement>(&mut self) {
+ #[track_caller]
+ pub fn define_elem<T: NativeElement>(&mut self) -> &mut Binding {
let data = T::data();
- self.define(data.name, Element::from(data));
+ self.define(data.name, Element::from(data))
}
- /// Try to access a variable immutably.
- pub fn get(&self, var: &str) -> Option<&Value> {
- self.map.get(var).map(Slot::read)
+ /// Define a built-in with compile-time known name and returns a mutable
+ /// reference to it.
+ ///
+ /// When the name isn't compile-time known, you should instead use:
+ /// - `Vm::bind` if you already have [`Binding`]
+ /// - `Vm::define` if you only have a [`Value`]
+ /// - [`Scope::bind`](Self::bind) if you are not operating in the context of
+ /// a `Vm` or if you are binding to something that is not an AST
+ /// identifier (e.g. when constructing a dynamic
+ /// [`Module`](super::Module))
+ #[track_caller]
+ pub fn define(&mut self, name: &'static str, value: impl IntoValue) -> &mut Binding {
+ #[cfg(debug_assertions)]
+ if self.deduplicate && self.map.contains_key(name) {
+ panic!("duplicate definition: {name}");
+ }
+
+ let mut binding = Binding::detached(value);
+ binding.category = self.category;
+ self.bind(name.into(), binding)
}
+}
- /// Try to access a variable mutably.
- pub fn get_mut(&mut self, var: &str) -> Option<HintedStrResult<&mut Value>> {
- self.map
- .get_mut(var)
- .map(Slot::write)
- .map(|res| res.map_err(HintedString::from))
+/// Scope manipulation and access.
+impl Scope {
+ /// Inserts a binding into this scope and returns a mutable reference to it.
+ ///
+ /// Prefer `Vm::bind` if you are operating in the context of a `Vm`.
+ pub fn bind(&mut self, name: EcoString, binding: Binding) -> &mut Binding {
+ match self.map.entry(name) {
+ Entry::Occupied(mut entry) => {
+ entry.insert(binding);
+ entry.into_mut()
+ }
+ Entry::Vacant(entry) => entry.insert(binding),
+ }
}
- /// Get the span of a definition.
- pub fn get_span(&self, var: &str) -> Option<Span> {
- Some(self.map.get(var)?.span)
+ /// Try to access a binding immutably.
+ pub fn get(&self, var: &str) -> Option<&Binding> {
+ self.map.get(var)
}
- /// Get the category of a definition.
- pub fn get_category(&self, var: &str) -> Option<Category> {
- self.map.get(var)?.category
+ /// Try to access a binding mutably.
+ pub fn get_mut(&mut self, var: &str) -> Option<&mut Binding> {
+ self.map.get_mut(var)
}
/// Iterate over all definitions.
- pub fn iter(&self) -> impl Iterator<Item = (&EcoString, &Value, Span)> {
- self.map.iter().map(|(k, v)| (k, v.read(), v.span))
+ pub fn iter(&self) -> impl Iterator<Item = (&EcoString, &Binding)> {
+ self.map.iter()
}
}
@@ -318,64 +247,92 @@ pub trait NativeScope {
fn scope() -> Scope;
}
-/// A slot where a value is stored.
-#[derive(Clone, Hash)]
-struct Slot {
- /// The stored value.
+/// A bound value with metadata.
+#[derive(Debug, Clone, Hash)]
+pub struct Binding {
+ /// The bound value.
value: Value,
- /// The kind of slot, determines how the value can be accessed.
- kind: Kind,
- /// A span associated with the stored value.
+ /// The kind of binding, determines how the value can be accessed.
+ kind: BindingKind,
+ /// A span associated with the binding.
span: Span,
- /// The category of the slot.
+ /// The category of the binding.
category: Option<Category>,
}
/// The different kinds of slots.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-enum Kind {
+enum BindingKind {
/// A normal, mutable binding.
Normal,
/// A captured copy of another variable.
Captured(Capturer),
}
-/// What the variable was captured by.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum Capturer {
- /// Captured by a function / closure.
- Function,
- /// Captured by a context expression.
- Context,
-}
+impl Binding {
+ /// Create a new binding with a span marking its definition site.
+ pub fn new(value: impl IntoValue, span: Span) -> Self {
+ Self {
+ value: value.into_value(),
+ span,
+ kind: BindingKind::Normal,
+ category: None,
+ }
+ }
-impl Slot {
- /// Create a new slot.
- fn new(value: Value, span: Span, kind: Kind, category: Option<Category>) -> Self {
- Self { value, span, kind, category }
+ /// Create a binding without a span.
+ pub fn detached(value: impl IntoValue) -> Self {
+ Self::new(value, Span::detached())
}
/// Read the value.
- fn read(&self) -> &Value {
+ pub fn read(&self) -> &Value {
&self.value
}
/// Try to write to the value.
- fn write(&mut self) -> StrResult<&mut Value> {
+ ///
+ /// This fails if the value is a read-only closure capture.
+ pub fn write(&mut self) -> StrResult<&mut Value> {
match self.kind {
- Kind::Normal => Ok(&mut self.value),
- Kind::Captured(capturer) => {
- bail!(
- "variables from outside the {} are \
- read-only and cannot be modified",
- match capturer {
- Capturer::Function => "function",
- Capturer::Context => "context expression",
- }
- )
- }
+ BindingKind::Normal => Ok(&mut self.value),
+ BindingKind::Captured(capturer) => bail!(
+ "variables from outside the {} are \
+ read-only and cannot be modified",
+ match capturer {
+ Capturer::Function => "function",
+ Capturer::Context => "context expression",
+ }
+ ),
+ }
+ }
+
+ /// Create a copy of the binding for closure capturing.
+ pub fn capture(&self, capturer: Capturer) -> Self {
+ Self {
+ kind: BindingKind::Captured(capturer),
+ ..self.clone()
}
}
+
+ /// A span associated with the stored value.
+ pub fn span(&self) -> Span {
+ self.span
+ }
+
+ /// The category of the value, if any.
+ pub fn category(&self) -> Option<Category> {
+ self.category
+ }
+}
+
+/// What the variable was captured by.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+pub enum Capturer {
+ /// Captured by a function / closure.
+ Function,
+ /// Captured by a context expression.
+ Context,
}
/// A group of related definitions.
@@ -417,3 +374,57 @@ pub struct CategoryData {
pub title: &'static str,
pub docs: &'static str,
}
+
+/// The error message when trying to mutate a variable from the standard
+/// library.
+#[cold]
+fn cannot_mutate_constant(var: &str) -> HintedString {
+ eco_format!("cannot mutate a constant: {}", var).into()
+}
+
+/// The error message when a variable wasn't found.
+#[cold]
+fn unknown_variable(var: &str) -> HintedString {
+ let mut res = HintedString::new(eco_format!("unknown variable: {}", var));
+
+ if var.contains('-') {
+ res.hint(eco_format!(
+ "if you meant to use subtraction, \
+ try adding spaces around the minus sign{}: `{}`",
+ if var.matches('-').count() > 1 { "s" } else { "" },
+ var.replace('-', " - ")
+ ));
+ }
+
+ res
+}
+
+/// The error message when a variable wasn't found it math.
+#[cold]
+fn unknown_variable_math(var: &str, in_global: bool) -> HintedString {
+ let mut res = HintedString::new(eco_format!("unknown variable: {}", var));
+
+ if matches!(var, "none" | "auto" | "false" | "true") {
+ res.hint(eco_format!(
+ "if you meant to use a literal, \
+ try adding a hash before it: `#{var}`",
+ ));
+ } else if in_global {
+ res.hint(eco_format!(
+ "`{var}` is not available directly in math, \
+ try adding a hash before it: `#{var}`",
+ ));
+ } else {
+ res.hint(eco_format!(
+ "if you meant to display multiple letters as is, \
+ try adding spaces between each letter: `{}`",
+ var.chars().flat_map(|c| [' ', c]).skip(1).collect::<EcoString>()
+ ));
+ res.hint(eco_format!(
+ "or if you meant to display this as text, \
+ try placing it in quotes: `\"{var}\"`"
+ ));
+ }
+
+ res
+}
diff --git a/crates/typst-library/src/foundations/ty.rs b/crates/typst-library/src/foundations/ty.rs
index 973c1cb6..09f5efa1 100644
--- a/crates/typst-library/src/foundations/ty.rs
+++ b/crates/typst-library/src/foundations/ty.rs
@@ -8,7 +8,7 @@ use std::sync::LazyLock;
use ecow::{eco_format, EcoString};
use typst_utils::Static;
-use crate::diag::StrResult;
+use crate::diag::{bail, StrResult};
use crate::foundations::{
cast, func, AutoValue, Func, NativeFuncData, NoneValue, Repr, Scope, Value,
};
@@ -95,9 +95,10 @@ impl Type {
/// Get a field from this type's scope, if possible.
pub fn field(&self, field: &str) -> StrResult<&'static Value> {
- self.scope()
- .get(field)
- .ok_or_else(|| eco_format!("type {self} does not contain field `{field}`"))
+ match self.scope().get(field) {
+ Some(binding) => Ok(binding.read()),
+ None => bail!("type {self} does not contain field `{field}`"),
+ }
}
}
diff --git a/crates/typst-library/src/html/mod.rs b/crates/typst-library/src/html/mod.rs
index ea248172..c412b460 100644
--- a/crates/typst-library/src/html/mod.rs
+++ b/crates/typst-library/src/html/mod.rs
@@ -15,7 +15,7 @@ pub static HTML: Category;
/// Create a module with all HTML definitions.
pub fn module() -> Module {
let mut html = Scope::deduplicating();
- html.category(HTML);
+ html.start_category(HTML);
html.define_elem::<HtmlElem>();
html.define_elem::<FrameElem>();
Module::new("html", html)
diff --git a/crates/typst-library/src/introspection/mod.rs b/crates/typst-library/src/introspection/mod.rs
index b1ff2e08..d8184330 100644
--- a/crates/typst-library/src/introspection/mod.rs
+++ b/crates/typst-library/src/introspection/mod.rs
@@ -42,7 +42,7 @@ pub static INTROSPECTION: Category;
/// Hook up all `introspection` definitions.
pub fn define(global: &mut Scope) {
- global.category(INTROSPECTION);
+ global.start_category(INTROSPECTION);
global.define_type::<Location>();
global.define_type::<Counter>();
global.define_type::<State>();
diff --git a/crates/typst-library/src/layout/mod.rs b/crates/typst-library/src/layout/mod.rs
index 574a2830..57518fe7 100644
--- a/crates/typst-library/src/layout/mod.rs
+++ b/crates/typst-library/src/layout/mod.rs
@@ -74,7 +74,7 @@ pub static LAYOUT: Category;
/// Hook up all `layout` definitions.
pub fn define(global: &mut Scope) {
- global.category(LAYOUT);
+ global.start_category(LAYOUT);
global.define_type::<Length>();
global.define_type::<Angle>();
global.define_type::<Ratio>();
diff --git a/crates/typst-library/src/lib.rs b/crates/typst-library/src/lib.rs
index 22f3a62a..460321aa 100644
--- a/crates/typst-library/src/lib.rs
+++ b/crates/typst-library/src/lib.rs
@@ -33,7 +33,7 @@ use typst_syntax::{FileId, Source, Span};
use typst_utils::{LazyHash, SmallBitSet};
use crate::diag::FileResult;
-use crate::foundations::{Array, Bytes, Datetime, Dict, Module, Scope, Styles, Value};
+use crate::foundations::{Array, Binding, Bytes, Datetime, Dict, Module, Scope, Styles};
use crate::layout::{Alignment, Dir};
use crate::text::{Font, FontBook};
use crate::visualize::Color;
@@ -148,7 +148,7 @@ pub struct Library {
/// everything else configurable via set and show rules).
pub styles: Styles,
/// The standard library as a value. Used to provide the `std` variable.
- pub std: Value,
+ pub std: Binding,
/// In-development features that were enabled.
pub features: Features,
}
@@ -196,12 +196,11 @@ impl LibraryBuilder {
let math = math::module();
let inputs = self.inputs.unwrap_or_default();
let global = global(math.clone(), inputs, &self.features);
- let std = Value::Module(global.clone());
Library {
- global,
+ global: global.clone(),
math,
styles: Styles::new(),
- std,
+ std: Binding::detached(global),
features: self.features,
}
}
diff --git a/crates/typst-library/src/loading/mod.rs b/crates/typst-library/src/loading/mod.rs
index 171ae651..c645b691 100644
--- a/crates/typst-library/src/loading/mod.rs
+++ b/crates/typst-library/src/loading/mod.rs
@@ -41,7 +41,7 @@ pub static DATA_LOADING: Category;
/// Hook up all `data-loading` definitions.
pub(super) fn define(global: &mut Scope) {
- global.category(DATA_LOADING);
+ global.start_category(DATA_LOADING);
global.define_func::<read>();
global.define_func::<csv>();
global.define_func::<json>();
diff --git a/crates/typst-library/src/math/mod.rs b/crates/typst-library/src/math/mod.rs
index 3b4b133d..a97a19b0 100644
--- a/crates/typst-library/src/math/mod.rs
+++ b/crates/typst-library/src/math/mod.rs
@@ -150,7 +150,7 @@ pub const WIDE: Em = Em::new(2.0);
/// Create a module with all math definitions.
pub fn module() -> Module {
let mut math = Scope::deduplicating();
- math.category(MATH);
+ math.start_category(MATH);
math.define_elem::<EquationElem>();
math.define_elem::<TextElem>();
math.define_elem::<LrElem>();
diff --git a/crates/typst-library/src/model/mod.rs b/crates/typst-library/src/model/mod.rs
index 7dad51c3..586e10ec 100644
--- a/crates/typst-library/src/model/mod.rs
+++ b/crates/typst-library/src/model/mod.rs
@@ -52,7 +52,7 @@ pub static MODEL: Category;
/// Hook up all `model` definitions.
pub fn define(global: &mut Scope) {
- global.category(MODEL);
+ global.start_category(MODEL);
global.define_elem::<DocumentElem>();
global.define_elem::<RefElem>();
global.define_elem::<LinkElem>();
diff --git a/crates/typst-library/src/pdf/mod.rs b/crates/typst-library/src/pdf/mod.rs
index ec075463..3bd3b0c5 100644
--- a/crates/typst-library/src/pdf/mod.rs
+++ b/crates/typst-library/src/pdf/mod.rs
@@ -12,7 +12,7 @@ pub static PDF: Category;
/// Hook up the `pdf` module.
pub(super) fn define(global: &mut Scope) {
- global.category(PDF);
+ global.start_category(PDF);
global.define("pdf", module());
}
diff --git a/crates/typst-library/src/symbols.rs b/crates/typst-library/src/symbols.rs
index 1617d3aa..aee7fb83 100644
--- a/crates/typst-library/src/symbols.rs
+++ b/crates/typst-library/src/symbols.rs
@@ -39,7 +39,7 @@ fn extend_scope_from_codex_module(scope: &mut Scope, module: codex::Module) {
/// Hook up all `symbol` definitions.
pub(super) fn define(global: &mut Scope) {
- global.category(SYMBOLS);
+ global.start_category(SYMBOLS);
extend_scope_from_codex_module(global, codex::ROOT);
}
diff --git a/crates/typst-library/src/text/mod.rs b/crates/typst-library/src/text/mod.rs
index edbd2413..f506397e 100644
--- a/crates/typst-library/src/text/mod.rs
+++ b/crates/typst-library/src/text/mod.rs
@@ -63,7 +63,7 @@ pub static TEXT: Category;
/// Hook up all `text` definitions.
pub(super) fn define(global: &mut Scope) {
- global.category(TEXT);
+ global.start_category(TEXT);
global.define_elem::<TextElem>();
global.define_elem::<LinebreakElem>();
global.define_elem::<SmartQuoteElem>();
diff --git a/crates/typst-library/src/visualize/mod.rs b/crates/typst-library/src/visualize/mod.rs
index 43119149..b0e627af 100644
--- a/crates/typst-library/src/visualize/mod.rs
+++ b/crates/typst-library/src/visualize/mod.rs
@@ -36,7 +36,7 @@ pub static VISUALIZE: Category;
/// Hook up all visualize definitions.
pub(super) fn define(global: &mut Scope) {
- global.category(VISUALIZE);
+ global.start_category(VISUALIZE);
global.define_type::<Color>();
global.define_type::<Gradient>();
global.define_type::<Tiling>();