Track context (#3623)

This commit is contained in:
Laurenz 2024-03-12 11:28:15 +01:00 committed by GitHub
parent d01ccffad6
commit 633c32a552
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 108 additions and 67 deletions

View File

@ -67,8 +67,12 @@ pub fn analyze_import(world: &dyn World, source: &LinkedNode) -> Option<Value> {
};
let context = Context::none();
let mut vm =
Vm::new(engine, &context, Scopes::new(Some(world.library())), Span::detached());
let mut vm = Vm::new(
engine,
context.track(),
Scopes::new(Some(world.library())),
Span::detached(),
);
typst::eval::import(&mut vm, source, Span::detached(), true)
.ok()
.map(Value::Module)

View File

@ -278,7 +278,7 @@ pub(crate) fn call_closure(
route: Tracked<Route>,
locator: Tracked<Locator>,
tracer: TrackedMut<Tracer>,
context: &Context,
context: Tracked<Context>,
mut args: Args,
) -> SourceResult<Value> {
let (name, params, body) = match closure.node.cast::<ast::Closure>() {

View File

@ -63,7 +63,7 @@ pub fn eval(
let context = Context::none();
let scopes = Scopes::new(Some(world.library()));
let root = source.root();
let mut vm = Vm::new(engine, &context, scopes, root.span());
let mut vm = Vm::new(engine, context.track(), scopes, root.span());
// Check for well-formedness unless we are in trace mode.
let errors = root.errors();
@ -131,7 +131,7 @@ pub fn eval_string(
// Prepare VM.
let context = Context::none();
let scopes = Scopes::new(Some(world.library()));
let mut vm = Vm::new(engine, &context, scopes, root.span());
let mut vm = Vm::new(engine, context.track(), scopes, root.span());
vm.scopes.scopes.push(scope);
// Evaluate the code.

View File

@ -21,14 +21,14 @@ pub struct Vm<'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: &'a Context<'a>,
pub(crate) context: Tracked<'a, Context<'a>>,
}
impl<'a> Vm<'a> {
/// Create a new virtual machine.
pub fn new(
engine: Engine<'a>,
context: &'a Context<'a>,
context: Tracked<'a, Context<'a>>,
scopes: Scopes<'a>,
target: Span,
) -> Self {
@ -55,6 +55,6 @@ impl<'a> Vm<'a> {
pub fn trace(&mut self, value: Value) {
self.engine
.tracer
.value(value.clone(), self.context.styles.map(|s| s.to_map()));
.value(value.clone(), self.context.styles().ok().map(|s| s.to_map()));
}
}

View File

@ -3,6 +3,7 @@ use std::fmt::{Debug, Formatter};
use std::num::{NonZeroI64, NonZeroUsize};
use std::ops::{Add, AddAssign};
use comemo::Tracked;
use ecow::{eco_format, EcoString, EcoVec};
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
@ -301,7 +302,7 @@ impl Array {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The function to apply to each item. Must return a boolean.
searcher: Func,
) -> SourceResult<Option<Value>> {
@ -325,7 +326,7 @@ impl Array {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The function to apply to each item. Must return a boolean.
searcher: Func,
) -> SourceResult<Option<i64>> {
@ -402,7 +403,7 @@ impl Array {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The function to apply to each item. Must return a boolean.
test: Func,
) -> SourceResult<Array> {
@ -427,7 +428,7 @@ impl Array {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The function to apply to each item.
mapper: Func,
) -> SourceResult<Array> {
@ -536,7 +537,7 @@ impl Array {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The initial value to start with.
init: Value,
/// The folding function. Must have two parameters: One for the
@ -598,7 +599,7 @@ impl Array {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The function to apply to each item. Must return a boolean.
test: Func,
) -> SourceResult<bool> {
@ -618,7 +619,7 @@ impl Array {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The function to apply to each item. Must return a boolean.
test: Func,
) -> SourceResult<bool> {
@ -765,7 +766,7 @@ impl Array {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The callsite span.
span: Span,
/// If given, applies this function to the elements in the array to
@ -815,7 +816,7 @@ impl Array {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// If given, applies this function to the elements in the array to
/// determine the keys to deduplicate by.
#[named]

View File

@ -6,6 +6,7 @@ use std::marker::PhantomData;
use std::ops::{Add, AddAssign, Deref, DerefMut};
use std::sync::Arc;
use comemo::Tracked;
use ecow::{eco_format, EcoString};
use serde::{Serialize, Serializer};
use smallvec::smallvec;
@ -345,7 +346,7 @@ impl Content {
pub fn styled_with_recipe(
self,
engine: &mut Engine,
context: &Context,
context: Tracked<Context>,
recipe: Recipe,
) -> SourceResult<Self> {
if recipe.selector.is_none() {

View File

@ -1,3 +1,5 @@
use comemo::Track;
use crate::diag::{bail, Hint, HintedStrResult, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
@ -28,7 +30,10 @@ impl<'a> Context<'a> {
pub fn new(location: Option<Location>, styles: Option<StyleChain<'a>>) -> Self {
Self { location, styles }
}
}
#[comemo::track]
impl<'a> Context<'a> {
/// Try to extract the location.
pub fn location(&self) -> HintedStrResult<Location> {
require(self.location)
@ -75,6 +80,6 @@ impl Show for Packed<ContextElem> {
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
let loc = self.location().unwrap();
let context = Context::new(Some(loc), Some(styles));
Ok(self.func.call::<[Value; 0]>(engine, &context, [])?.display())
Ok(self.func.call::<[Value; 0]>(engine, context.track(), [])?.display())
}
}

View File

@ -1,7 +1,7 @@
use std::fmt::{self, Debug, Formatter};
use std::sync::Arc;
use comemo::TrackedMut;
use comemo::{Tracked, TrackedMut};
use ecow::{eco_format, EcoString};
use once_cell::sync::Lazy;
@ -261,7 +261,7 @@ impl Func {
pub fn call<A: IntoArgs>(
&self,
engine: &mut Engine,
context: &Context,
context: Tracked<Context>,
args: A,
) -> SourceResult<Value> {
self.call_impl(engine, context, args.into_args(self.span))
@ -272,7 +272,7 @@ impl Func {
fn call_impl(
&self,
engine: &mut Engine,
context: &Context,
context: Tracked<Context>,
mut args: Args,
) -> SourceResult<Value> {
match &self.repr {
@ -440,7 +440,7 @@ pub trait NativeFunc {
/// Defines a native function.
#[derive(Debug)]
pub struct NativeFuncData {
pub function: fn(&mut Engine, &Context, &mut Args) -> SourceResult<Value>,
pub function: fn(&mut Engine, Tracked<Context>, &mut Args) -> SourceResult<Value>,
pub name: &'static str,
pub title: &'static str,
pub docs: &'static str,

View File

@ -304,7 +304,7 @@ impl LocatableSelector {
pub fn resolve_unique(
&self,
introspector: Tracked<Introspector>,
context: &Context,
context: Tracked<Context>,
) -> HintedStrResult<Location> {
match &self.0 {
Selector::Location(loc) => Ok(*loc),

View File

@ -3,6 +3,7 @@ use std::fmt::{self, Debug, Display, Formatter};
use std::hash::{Hash, Hasher};
use std::ops::{Add, AddAssign, Deref, Range};
use comemo::Tracked;
use ecow::EcoString;
use serde::{Deserialize, Serialize};
use unicode_segmentation::UnicodeSegmentation;
@ -425,7 +426,7 @@ impl Str {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The pattern to search for.
pattern: StrPattern,
/// The string to replace the matches with or a function that gets a

View File

@ -3,6 +3,7 @@ use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::{mem, ptr};
use comemo::{Track, Tracked};
use ecow::{eco_vec, EcoString, EcoVec};
use smallvec::SmallVec;
@ -57,7 +58,10 @@ impl Show for Packed<StyleElem> {
#[typst_macros::time(name = "style", span = self.span())]
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
let context = Context::new(self.location(), Some(styles));
Ok(self.func().call(engine, &context, [styles.to_map()])?.display())
Ok(self
.func()
.call(engine, context.track(), [styles.to_map()])?
.display())
}
}
@ -385,7 +389,7 @@ impl Recipe {
pub fn apply(
&self,
engine: &mut Engine,
context: &Context,
context: Tracked<Context>,
content: Content,
) -> SourceResult<Content> {
let mut content = match &self.transform {

View File

@ -1,7 +1,7 @@
use std::num::NonZeroUsize;
use std::str::FromStr;
use comemo::{Tracked, TrackedMut};
use comemo::{Track, Tracked, TrackedMut};
use ecow::{eco_format, eco_vec, EcoString, EcoVec};
use smallvec::{smallvec, SmallVec};
@ -271,7 +271,7 @@ impl Counter {
let context = Context::new(Some(loc), Some(styles));
Ok(self
.at_loc(engine, loc)?
.display(engine, &context, numbering)?
.display(engine, context.track(), numbering)?
.display())
}
@ -392,7 +392,7 @@ impl Counter {
};
let context = Context::new(Some(location), styles);
state.display(engine, &context, &numbering)
state.display(engine, context.track(), &numbering)
}
}
@ -425,7 +425,7 @@ impl Counter {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The callsite span.
span: Span,
) -> SourceResult<CounterState> {
@ -446,7 +446,7 @@ impl Counter {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The call span of the display.
span: Span,
/// A [numbering pattern or a function]($numbering), which specifies how
@ -468,8 +468,8 @@ impl Counter {
#[default(false)]
both: bool,
) -> SourceResult<Value> {
if let Some(loc) = context.location {
self.display_impl(engine, loc, numbering, both, context.styles)
if let Ok(loc) = context.location() {
self.display_impl(engine, loc, numbering, both, context.styles().ok())
} else {
Ok(CounterDisplayElem::new(self, numbering, both)
.pack()
@ -494,7 +494,7 @@ impl Counter {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The callsite span.
span: Span,
/// The place at which the counter's value should be retrieved.
@ -512,7 +512,7 @@ impl Counter {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The callsite span.
span: Span,
/// _Compatibility:_ This argument only exists for compatibility with
@ -669,7 +669,7 @@ impl CounterState {
CounterUpdate::Step(level) => self.step(level, 1),
CounterUpdate::Func(func) => {
*self = func
.call(engine, &Context::none(), self.0.iter().copied())?
.call(engine, Context::none().track(), self.0.iter().copied())?
.cast()
.at(func.span())?
}
@ -700,7 +700,7 @@ impl CounterState {
pub fn display(
&self,
engine: &mut Engine,
context: &Context,
context: Tracked<Context>,
numbering: &Numbering,
) -> SourceResult<Value> {
numbering.apply(engine, context, &self.0)

View File

@ -1,3 +1,5 @@
use comemo::Tracked;
use crate::diag::HintedStrResult;
use crate::foundations::{func, Context};
use crate::introspection::Location;
@ -44,7 +46,7 @@ use crate::introspection::Location;
#[func(contextual)]
pub fn here(
/// The callsite context.
context: &Context,
context: Tracked<Context>,
) -> HintedStrResult<Location> {
context.location()
}

View File

@ -1,3 +1,5 @@
use comemo::{Track, Tracked};
use crate::diag::{HintedStrResult, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
@ -37,7 +39,7 @@ pub fn locate(
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The span of the `locate` call.
span: Span,
/// A selector that should match exactly one element. This element will be
@ -106,6 +108,6 @@ impl Show for Packed<LocateElem> {
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
let location = self.location().unwrap();
let context = Context::new(Some(location), Some(styles));
Ok(self.func().call(engine, &context, [location])?.display())
Ok(self.func().call(engine, context.track(), [location])?.display())
}
}

View File

@ -1,3 +1,5 @@
use comemo::Tracked;
use crate::diag::HintedStrResult;
use crate::engine::Engine;
use crate::foundations::{func, Array, Context, LocatableSelector, Value};
@ -135,7 +137,7 @@ pub fn query(
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// Can be
/// - an element function like a `heading` or `figure`,
/// - a `{<label>}`,

View File

@ -1,4 +1,4 @@
use comemo::{Tracked, TrackedMut};
use comemo::{Track, Tracked, TrackedMut};
use ecow::{eco_format, eco_vec, EcoString, EcoVec};
use crate::diag::{bail, At, SourceResult};
@ -249,7 +249,7 @@ impl State {
match elem.update() {
StateUpdate::Set(value) => state = value.clone(),
StateUpdate::Func(func) => {
state = func.call(&mut engine, &Context::none(), [state])?
state = func.call(&mut engine, Context::none().track(), [state])?
}
}
stops.push(state.clone());
@ -287,7 +287,7 @@ impl State {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The callsite span.
span: Span,
) -> SourceResult<Value> {
@ -310,7 +310,7 @@ impl State {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The callsite span.
span: Span,
/// The place at which the state's value should be retrieved.
@ -327,7 +327,7 @@ impl State {
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The callsite span.
span: Span,
/// _Compatibility:_ This argument only exists for compatibility with
@ -451,7 +451,7 @@ impl Show for Packed<StateDisplayElem> {
let context = Context::new(Some(location), Some(styles));
let value = self.state().at_loc(engine, location)?;
Ok(match self.func() {
Some(func) => func.call(engine, &context, [value])?.display(),
Some(func) => func.call(engine, context.track(), [value])?.display(),
None => value.display(),
})
}

View File

@ -3,6 +3,7 @@ use std::hash::Hash;
use std::num::NonZeroUsize;
use std::sync::Arc;
use comemo::Track;
use ecow::eco_format;
use super::lines::{
@ -50,7 +51,7 @@ impl<T: Default + Clone + FromValue> Celled<T> {
Ok(match self {
Self::Value(value) => value.clone(),
Self::Func(func) => func
.call(engine, &Context::new(None, Some(styles)), [x, y])?
.call(engine, Context::new(None, Some(styles)).track(), [x, y])?
.cast()
.at(func.span())?,
Self::Array(array) => x
@ -151,7 +152,7 @@ where
Ok(match &self.0 {
Celled::Value(value) => value.clone(),
Celled::Func(func) => func
.call(engine, &Context::new(None, Some(styles)), [x, y])?
.call(engine, Context::new(None, Some(styles)).track(), [x, y])?
.cast::<T>()
.at(func.span())?
.resolve(styles),

View File

@ -1,3 +1,5 @@
use comemo::Track;
use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{
@ -84,7 +86,7 @@ impl LayoutMultiple for Packed<LayoutElem> {
let context = Context::new(Some(loc), Some(styles));
let result = self
.func()
.call(engine, &context, [dict! { "width" => x, "height" => y }])?
.call(engine, context.track(), [dict! { "width" => x, "height" => y }])?
.display();
result.layout(engine, styles, regions)
}

View File

@ -2,6 +2,7 @@ use std::cmp::Ordering;
use std::fmt::{self, Debug, Formatter};
use std::ops::{Add, Div, Mul, Neg};
use comemo::Tracked;
use ecow::{eco_format, EcoString};
use crate::diag::{At, Hint, HintedStrResult, SourceResult};
@ -151,7 +152,7 @@ impl Length {
/// ]
/// ```
#[func]
pub fn to_absolute(&self, context: &Context) -> HintedStrResult<Length> {
pub fn to_absolute(&self, context: Tracked<Context>) -> HintedStrResult<Length> {
Ok(self.resolve(context.styles()?).into())
}
}

View File

@ -1,3 +1,5 @@
use comemo::Tracked;
use crate::diag::{At, SourceResult};
use crate::engine::Engine;
use crate::foundations::{dict, func, Content, Context, Dict, StyleChain, Styles};
@ -43,7 +45,7 @@ pub fn measure(
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// The callsite span.
span: Span,
/// The content whose size to measure.

View File

@ -3,6 +3,8 @@ use std::num::NonZeroUsize;
use std::ptr;
use std::str::FromStr;
use comemo::Track;
use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
@ -691,7 +693,7 @@ impl Marginal {
Ok(match self {
Self::Content(content) => Cow::Borrowed(content),
Self::Func(func) => Cow::Owned(
func.call(engine, &Context::new(None, Some(styles)), [page])?
func.call(engine, Context::new(None, Some(styles)).track(), [page])?
.display(),
),
})

View File

@ -1,3 +1,5 @@
use comemo::Track;
use crate::diag::{At, SourceResult};
use crate::foundations::{
cast, elem, Content, Context, Func, Packed, Resolve, Smart, StyleChain,
@ -204,7 +206,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(ctx.engine, &Context::new(None, Some(styles)), [default])?
.call(ctx.engine, Context::new(None, Some(styles)).track(), [default])?
.cast()
.at(span)?,
},

View File

@ -1,5 +1,6 @@
use std::str::FromStr;
use comemo::Track;
use smallvec::{smallvec, SmallVec};
use crate::diag::{bail, SourceResult};
@ -247,7 +248,8 @@ impl LayoutMultiple for Packed<EnumElem> {
let context = Context::new(None, Some(styles));
let resolved = if full {
parents.push(number);
let content = numbering.apply(engine, &context, &parents)?.display();
let content =
numbering.apply(engine, context.track(), &parents)?.display();
parents.pop();
content
} else {
@ -255,7 +257,7 @@ impl LayoutMultiple for Packed<EnumElem> {
Numbering::Pattern(pattern) => {
TextElem::packed(pattern.apply_kth(parents.len(), number))
}
other => other.apply(engine, &context, &[number])?.display(),
other => other.apply(engine, context.track(), &[number])?.display(),
}
};

View File

@ -1,3 +1,5 @@
use comemo::Track;
use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
@ -218,7 +220,7 @@ impl ListMarker {
list.get(depth % list.len()).cloned().unwrap_or_default()
}
Self::Func(func) => func
.call(engine, &Context::new(None, Some(styles)), [depth])?
.call(engine, Context::new(None, Some(styles)).track(), [depth])?
.display(),
})
}

View File

@ -1,6 +1,7 @@
use std::str::FromStr;
use chinese_number::{ChineseCase, ChineseCountMethod, ChineseVariant, NumberToChinese};
use comemo::Tracked;
use ecow::{eco_format, EcoString, EcoVec};
use crate::diag::SourceResult;
@ -36,7 +37,7 @@ pub fn numbering(
/// The engine.
engine: &mut Engine,
/// The callsite context.
context: &Context,
context: Tracked<Context>,
/// Defines how the numbering works.
///
/// **Counting symbols** are `1`, `a`, `A`, `i`, `I`, `一`, `壹`, `あ`, `い`, `ア`, `イ`, `א`, `가`,
@ -85,7 +86,7 @@ impl Numbering {
pub fn apply(
&self,
engine: &mut Engine,
context: &Context,
context: Tracked<Context>,
numbers: &[usize],
) -> SourceResult<Value> {
Ok(match self {

View File

@ -1,6 +1,8 @@
use std::num::NonZeroUsize;
use std::str::FromStr;
use comemo::Track;
use crate::diag::{bail, At, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
@ -381,7 +383,7 @@ impl OutlineIndent {
Some(Smart::Custom(OutlineIndent::Func(func))) => {
let depth = ancestors.len();
let LengthOrContent(content) = func
.call(engine, &Context::new(None, Some(styles)), [depth])?
.call(engine, Context::new(None, Some(styles)).track(), [depth])?
.cast()
.at(span)?;
if !content.is_empty() {

View File

@ -1,3 +1,4 @@
use comemo::Track;
use ecow::eco_format;
use crate::diag::{bail, At, Hint, SourceResult};
@ -275,9 +276,9 @@ impl Supplement {
) -> SourceResult<Content> {
Ok(match self {
Supplement::Content(content) => content.clone(),
Supplement::Func(func) => {
func.call(engine, &Context::new(None, Some(styles)), args)?.display()
}
Supplement::Func(func) => func
.call(engine, Context::new(None, Some(styles)).track(), args)?
.display(),
})
}
}

View File

@ -1,5 +1,6 @@
use std::cell::OnceCell;
use comemo::{Track, Tracked};
use smallvec::smallvec;
use crate::diag::SourceResult;
@ -255,11 +256,11 @@ fn show(
// text element. This invokes special regex handling.
Some(Selector::Regex(regex)) => {
let text = target.into_packed::<TextElem>().unwrap();
show_regex(engine, &text, regex, recipe, guard, &context)
show_regex(engine, &text, regex, recipe, guard, context.track())
}
// Just apply the recipe.
_ => recipe.apply(engine, &context, target.guarded(guard)),
_ => recipe.apply(engine, context.track(), target.guarded(guard)),
}
}
@ -276,7 +277,7 @@ fn show_regex(
regex: &Regex,
recipe: &Recipe,
index: RecipeIndex,
context: &Context,
context: Tracked<Context>,
) -> SourceResult<Content> {
let make = |s: &str| {
let mut fresh = target.clone();