summaryrefslogtreecommitdiff
path: root/src/eval/func.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval/func.rs')
-rw-r--r--src/eval/func.rs46
1 files changed, 24 insertions, 22 deletions
diff --git a/src/eval/func.rs b/src/eval/func.rs
index 83171ce7..16575c80 100644
--- a/src/eval/func.rs
+++ b/src/eval/func.rs
@@ -29,7 +29,7 @@ impl Func {
/// Create a new function from a native rust function.
pub fn from_fn(
name: &'static str,
- func: fn(&mut Context, &mut Args) -> TypResult<Value>,
+ func: fn(&mut Machine, &mut Args) -> TypResult<Value>,
) -> Self {
Self(Arc::new(Repr::Native(Native {
name,
@@ -86,19 +86,25 @@ impl Func {
}
/// Call the function with the given arguments.
- pub fn call(&self, ctx: &mut Context, mut args: Args) -> TypResult<Value> {
+ pub fn call(&self, vm: &mut Machine, mut args: Args) -> TypResult<Value> {
let value = match self.0.as_ref() {
- Repr::Native(native) => (native.func)(ctx, &mut args)?,
- Repr::Closure(closure) => closure.call(ctx, &mut args)?,
+ Repr::Native(native) => (native.func)(vm, &mut args)?,
+ Repr::Closure(closure) => closure.call(vm, &mut args)?,
Repr::With(wrapped, applied) => {
args.items.splice(.. 0, applied.items.iter().cloned());
- return wrapped.call(ctx, args);
+ return wrapped.call(vm, args);
}
};
args.finish()?;
Ok(value)
}
+ /// Call the function without an existing virtual machine.
+ pub fn call_detached(&self, ctx: &mut Context, args: Args) -> TypResult<Value> {
+ let mut vm = Machine::new(ctx, vec![], Scopes::new(None));
+ self.call(&mut vm, args)
+ }
+
/// Execute the function's set rule.
pub fn set(&self, mut args: Args) -> TypResult<StyleMap> {
let styles = match self.0.as_ref() {
@@ -138,7 +144,7 @@ struct Native {
/// The name of the function.
pub name: &'static str,
/// The function pointer.
- pub func: fn(&mut Context, &mut Args) -> TypResult<Value>,
+ pub func: fn(&mut Machine, &mut Args) -> TypResult<Value>,
/// The set rule.
pub set: Option<fn(&mut Args) -> TypResult<StyleMap>>,
/// The id of the node to customize with this function's show rule.
@@ -163,7 +169,7 @@ pub trait Node: 'static {
///
/// This is passed only the arguments that remain after execution of the
/// node's set rule.
- fn construct(ctx: &mut Context, args: &mut Args) -> TypResult<Content>;
+ fn construct(vm: &mut Machine, args: &mut Args) -> TypResult<Content>;
/// Parse the arguments into style properties for this node.
///
@@ -192,7 +198,7 @@ pub struct Closure {
impl Closure {
/// Call the function in the context with the arguments.
- pub fn call(&self, ctx: &mut Context, args: &mut Args) -> TypResult<Value> {
+ pub fn call(&self, vm: &mut Machine, args: &mut Args) -> TypResult<Value> {
// Don't leak the scopes from the call site. Instead, we use the
// scope of captured variables we collected earlier.
let mut scopes = Scopes::new(None);
@@ -213,24 +219,20 @@ impl Closure {
scopes.top.def_mut(sink, args.take());
}
- // Set the new route if we are detached.
- let detached = ctx.route.is_empty();
- if detached {
- ctx.route = self.location.into_iter().collect();
- }
+ // Determine the route inside the closure.
+ let detached = vm.route.is_empty();
+ let route = if detached {
+ self.location.into_iter().collect()
+ } else {
+ vm.route.clone()
+ };
// Evaluate the body.
- let mut vm = Machine::new(ctx, scopes);
- let result = self.body.eval(&mut vm);
- let flow = vm.flow;
-
- // Restore the old route.
- if detached {
- ctx.route.clear();
- }
+ let mut sub = Machine::new(vm.ctx, route, scopes);
+ let result = self.body.eval(&mut sub);
// Handle control flow.
- match flow {
+ match sub.flow {
Some(Flow::Return(_, Some(explicit))) => return Ok(explicit),
Some(Flow::Return(_, None)) => {}
Some(flow) => return Err(flow.forbidden())?,