Make parameters traceable

This commit is contained in:
Laurenz 2023-03-17 18:51:42 +01:00
parent 59903270dc
commit 9315e2f08e
2 changed files with 18 additions and 19 deletions

View File

@ -5,7 +5,6 @@ use std::hash::{Hash, Hasher};
use std::sync::Arc; use std::sync::Arc;
use comemo::{Prehashed, Track, Tracked, TrackedMut}; use comemo::{Prehashed, Track, Tracked, TrackedMut};
use ecow::EcoString;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use super::{ use super::{
@ -14,7 +13,7 @@ use super::{
}; };
use crate::diag::{bail, SourceResult, StrResult}; use crate::diag::{bail, SourceResult, StrResult};
use crate::model::{Introspector, NodeId, Selector, StabilityProvider, StyleMap, Vt}; use crate::model::{Introspector, NodeId, Selector, StabilityProvider, StyleMap, Vt};
use crate::syntax::ast::{self, AstNode, Expr}; use crate::syntax::ast::{self, AstNode, Expr, Ident};
use crate::syntax::{SourceId, Span, SyntaxNode}; use crate::syntax::{SourceId, Span, SyntaxNode};
use crate::util::hash128; use crate::util::hash128;
use crate::World; use crate::World;
@ -294,14 +293,14 @@ pub(super) struct Closure {
/// The source file where the closure was defined. /// The source file where the closure was defined.
pub location: SourceId, pub location: SourceId,
/// The name of the closure. /// The name of the closure.
pub name: Option<EcoString>, pub name: Option<Ident>,
/// Captured values from outer scopes. /// Captured values from outer scopes.
pub captured: Scope, pub captured: Scope,
/// The parameter names and default values. Parameters with default value /// The parameter names and default values. Parameters with default value
/// are named parameters. /// are named parameters.
pub params: Vec<(EcoString, Option<Value>)>, pub params: Vec<(Ident, Option<Value>)>,
/// The name of an argument sink where remaining arguments are placed. /// The name of an argument sink where remaining arguments are placed.
pub sink: Option<EcoString>, pub sink: Option<Ident>,
/// The expression the closure should evaluate to. /// The expression the closure should evaluate to.
pub body: Expr, pub body: Expr,
} }
@ -329,14 +328,19 @@ impl Closure {
let mut scopes = Scopes::new(None); let mut scopes = Scopes::new(None);
scopes.top = closure.captured.clone(); scopes.top = closure.captured.clone();
// Evaluate the body.
let vt = Vt { world, tracer, provider, introspector };
let mut vm = Vm::new(vt, route, closure.location, scopes);
vm.depth = depth;
// Provide the closure itself for recursive calls. // Provide the closure itself for recursive calls.
if let Some(name) = &closure.name { if let Some(name) = &closure.name {
scopes.top.define(name.clone(), Value::Func(this.clone())); vm.define(name.clone(), Value::Func(this.clone()));
} }
// Parse the arguments according to the parameter list. // Parse the arguments according to the parameter list.
for (param, default) in &closure.params { for (param, default) in &closure.params {
scopes.top.define( vm.define(
param.clone(), param.clone(),
match default { match default {
Some(default) => { Some(default) => {
@ -349,20 +353,15 @@ impl Closure {
// Put the remaining arguments into the sink. // Put the remaining arguments into the sink.
if let Some(sink) = &closure.sink { if let Some(sink) = &closure.sink {
scopes.top.define(sink.clone(), args.take()); vm.define(sink.clone(), args.take());
} }
// Ensure all arguments have been used. // Ensure all arguments have been used.
args.finish()?; args.finish()?;
// Evaluate the body.
let vt = Vt { world, tracer, provider, introspector };
let mut sub = Vm::new(vt, route, closure.location, scopes);
sub.depth = depth;
// Handle control flow. // Handle control flow.
let result = closure.body.eval(&mut sub); let result = closure.body.eval(&mut vm);
match sub.flow { match vm.flow {
Some(Flow::Return(_, Some(explicit))) => return Ok(explicit), Some(Flow::Return(_, Some(explicit))) => return Ok(explicit),
Some(Flow::Return(_, None)) => {} Some(Flow::Return(_, None)) => {}
Some(flow) => bail!(flow.forbidden()), Some(flow) => bail!(flow.forbidden()),

View File

@ -1140,7 +1140,7 @@ impl Eval for ast::Closure {
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
// The closure's name is defined by its let binding if there's one. // The closure's name is defined by its let binding if there's one.
let name = self.name().map(ast::Ident::take); let name = self.name();
// Collect captured variables. // Collect captured variables.
let captured = { let captured = {
@ -1156,16 +1156,16 @@ impl Eval for ast::Closure {
for param in self.params() { for param in self.params() {
match param { match param {
ast::Param::Pos(name) => { ast::Param::Pos(name) => {
params.push((name.take(), None)); params.push((name, None));
} }
ast::Param::Named(named) => { ast::Param::Named(named) => {
params.push((named.name().take(), Some(named.expr().eval(vm)?))); params.push((named.name(), Some(named.expr().eval(vm)?)));
} }
ast::Param::Sink(name) => { ast::Param::Sink(name) => {
if sink.is_some() { if sink.is_some() {
bail!(name.span(), "only one argument sink is allowed"); bail!(name.span(), "only one argument sink is allowed");
} }
sink = Some(name.take()); sink = Some(name);
} }
} }
} }