difftreelog
feat field destructuring
in: master
22 files changed
bindings/jsonnet/src/native.rsdiffbeforeafterboth9use jrsonnet_evaluator::{9use jrsonnet_evaluator::{10 error::{Error, LocError},10 error::{Error, LocError},11 function::builtin::{BuiltinParam, NativeCallback, NativeCallbackHandler},11 function::builtin::{BuiltinParam, NativeCallback, NativeCallbackHandler},12 gc::TraceBox,12 tb,13 typed::Typed,13 typed::Typed,14 IStr, State, Val,14 IStr, State, Val,15};15};78 vm.add_native(78 vm.add_native(79 name,79 name,80 #[allow(deprecated)]80 #[allow(deprecated)]81 Cc::new(TraceBox(Box::new(NativeCallback::new(81 Cc::new(tb!(NativeCallback::new(82 params,82 params,83 TraceBox(Box::new(JsonnetNativeCallbackHandler { ctx, cb })),83 tb!(JsonnetNativeCallbackHandler { ctx, cb }),84 )))),84 ))),85 )85 )86}86}8787bindings/jsonnet/src/val_modify.rsdiffbeforeafterboth5use std::{ffi::CStr, os::raw::c_char};5use std::{ffi::CStr, os::raw::c_char};667use gcmodule::Cc;7use gcmodule::Cc;8use jrsonnet_evaluator::{val::ArrValue, LazyVal, State, Val};8use jrsonnet_evaluator::{val::ArrValue, State, Thunk, Val};9910/// # Safety10/// # Safety11///11///19 new.push(item);19 new.push(item);20 }20 }2121 new.push(LazyVal::new_resolved(val.clone()));22 new.push(Thunk::evaluated(val.clone()));22 *arr = Val::Arr(ArrValue::Lazy(Cc::new(new)));23 *arr = Val::Arr(ArrValue::Lazy(Cc::new(new)));23 }24 }24 _ => panic!("should receive array"),25 _ => panic!("should receive array"),cmds/jrsonnet/Cargo.tomldiffbeforeafterboth16 "jrsonnet-evaluator/exp-serde-preserve-order",16 "jrsonnet-evaluator/exp-serde-preserve-order",17 "jrsonnet-cli/exp-preserve-order",17 "jrsonnet-cli/exp-preserve-order",18]18]19# Destructuring of locals20exp-destruct = ["jrsonnet-evaluator/exp-destruct"]192120[dependencies]22[dependencies]21jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "0.4.2" }23jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "0.4.2" }crates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth18# Allows to preserve field order in objects18# Allows to preserve field order in objects19exp-preserve-order = []19exp-preserve-order = []20exp-serde-preserve-order = ["serde_json/preserve_order"]20exp-serde-preserve-order = ["serde_json/preserve_order"]21# Implements field destructuring22exp-destruct = []212322[dependencies]24[dependencies]23jrsonnet-interner = { path = "../jrsonnet-interner", version = "0.4.2" }25jrsonnet-interner = { path = "../jrsonnet-interner", version = "0.4.2" }crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth4use jrsonnet_interner::IStr;4use jrsonnet_interner::IStr;556use crate::{6use crate::{7 cc_ptr_eq, error::Error::*, gc::GcHashMap, map::LayeredHashMap, FutureWrapper, LazyBinding,7 cc_ptr_eq, error::Error::*, gc::GcHashMap, map::LayeredHashMap, LazyBinding, ObjValue, Pending,8 LazyVal, ObjValue, Result, State, Val,8 Result, State, Thunk, Val,9};9};101011#[derive(Clone, Trace)]11#[derive(Clone, Trace)]12pub struct ContextCreator(pub Context, pub FutureWrapper<GcHashMap<IStr, LazyBinding>>);12pub struct ContextCreator(pub Context, pub Pending<GcHashMap<IStr, LazyBinding>>);13impl ContextCreator {13impl ContextCreator {14 pub fn create(14 pub fn create(15 &self,15 &self,43#[derive(Debug, Clone, Trace)]43#[derive(Debug, Clone, Trace)]44pub struct Context(Cc<ContextInternals>);44pub struct Context(Cc<ContextInternals>);45impl Context {45impl Context {46 pub fn new_future() -> FutureWrapper<Self> {46 pub fn new_future() -> Pending<Self> {47 FutureWrapper::new()47 Pending::new()48 }48 }494950 pub fn dollar(&self) -> &Option<ObjValue> {50 pub fn dollar(&self) -> &Option<ObjValue> {68 }))68 }))69 }69 }707071 pub fn binding(&self, name: IStr) -> Result<LazyVal> {71 pub fn binding(&self, name: IStr) -> Result<Thunk<Val>> {72 Ok(self72 Ok(self73 .073 .074 .bindings74 .bindings80 self.0.bindings.contains_key(&name)80 self.0.bindings.contains_key(&name)81 }81 }82 #[must_use]82 #[must_use]83 pub fn into_future(self, ctx: FutureWrapper<Self>) -> Self {83 pub fn into_future(self, ctx: Pending<Self>) -> Self {84 {84 {85 ctx.0.borrow_mut().replace(self);85 ctx.0.borrow_mut().replace(self);86 }86 }90 #[must_use]90 #[must_use]91 pub fn with_var(self, name: IStr, value: Val) -> Self {91 pub fn with_var(self, name: IStr, value: Val) -> Self {92 let mut new_bindings = GcHashMap::with_capacity(1);92 let mut new_bindings = GcHashMap::with_capacity(1);93 new_bindings.insert(name, LazyVal::new_resolved(value));93 new_bindings.insert(name, Thunk::evaluated(value));94 self.extend(new_bindings, None, None, None)94 self.extend(new_bindings, None, None, None)95 }95 }9696102 #[must_use]102 #[must_use]103 pub fn extend(103 pub fn extend(104 self,104 self,105 new_bindings: GcHashMap<IStr, LazyVal>,105 new_bindings: GcHashMap<IStr, Thunk<Val>>,106 new_dollar: Option<ObjValue>,106 new_dollar: Option<ObjValue>,107 new_this: Option<ObjValue>,107 new_this: Option<ObjValue>,108 new_super_obj: Option<ObjValue>,108 new_super_obj: Option<ObjValue>,124 }))124 }))125 }125 }126 #[must_use]126 #[must_use]127 pub fn extend_bound(self, new_bindings: GcHashMap<IStr, LazyVal>) -> Self {127 pub fn extend_bound(self, new_bindings: GcHashMap<IStr, Thunk<Val>>) -> Self {128 let new_this = self.0.this.clone();128 let new_this = self.0.this.clone();129 let new_super_obj = self.0.super_obj.clone();129 let new_super_obj = self.0.super_obj.clone();130 self.extend(new_bindings, None, new_this, new_super_obj)130 self.extend(new_bindings, None, new_this, new_super_obj)crates/jrsonnet-evaluator/src/dynamic.rsdiffbeforeafterboth3use gcmodule::{Cc, Trace};3use gcmodule::{Cc, Trace};445#[derive(Clone, Trace)]5#[derive(Clone, Trace)]6pub struct FutureWrapper<V: Trace + 'static>(pub Cc<RefCell<Option<V>>>);6pub struct Pending<V: Trace + 'static>(pub Cc<RefCell<Option<V>>>);7impl<T: Trace + 'static> FutureWrapper<T> {7impl<T: Trace + 'static> Pending<T> {8 pub fn new() -> Self {8 pub fn new() -> Self {9 Self(Cc::new(RefCell::new(None)))9 Self(Cc::new(RefCell::new(None)))10 }10 }15 self.0.borrow_mut().replace(value);15 self.0.borrow_mut().replace(value);16 }16 }17}17}18impl<T: Clone + Trace + 'static> FutureWrapper<T> {18impl<T: Clone + Trace + 'static> Pending<T> {19 /// # Panics19 /// # Panics20 /// If wrapper is not yet filled20 /// If wrapper is not yet filled21 pub fn unwrap(&self) -> T {21 pub fn unwrap(&self) -> T {22 self.0.borrow().as_ref().cloned().unwrap()22 self.0.borrow().as_ref().cloned().unwrap()23 }23 }24}24}252526impl<T: Trace + 'static> Default for FutureWrapper<T> {26impl<T: Trace + 'static> Default for Pending<T> {27 fn default() -> Self {27 fn default() -> Self {28 Self::new()28 Self::new()29 }29 }crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth454546 #[error("variable is not defined: {0}")]46 #[error("variable is not defined: {0}")]47 VariableIsNotDefined(IStr),47 VariableIsNotDefined(IStr),48 #[error("duplicate local var: {0}")]49 DuplicateLocalVar(IStr),5048 #[error("type mismatch: expected {}, got {2} {0}", .1.iter().map(|e| format!("{}", e)).collect::<Vec<_>>().join(", "))]51 #[error("type mismatch: expected {}, got {2} {0}", .1.iter().map(|e| format!("{}", e)).collect::<Vec<_>>().join(", "))]49 TypeMismatch(&'static str, Vec<ValType>, ValType),52 TypeMismatch(&'static str, Vec<ValType>, ValType),crates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterbothno changes
crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth1use gcmodule::{Cc, Trace};1use gcmodule::{Cc, Trace};2use jrsonnet_interner::IStr;2use jrsonnet_interner::IStr;3use jrsonnet_parser::{3use jrsonnet_parser::{4 ArgsDesc, AssertStmt, BindSpec, CompSpec, Expr, FieldMember, ForSpecData, IfSpecData,4 ArgsDesc, AssertStmt, BindSpec, CompSpec, Destruct, Expr, FieldMember, ForSpecData, IfSpecData,5 LiteralType, LocExpr, Member, ObjBody, ParamsDesc,5 LiteralType, LocExpr, Member, ObjBody, ParamsDesc,6};6};7use jrsonnet_types::ValType;7use jrsonnet_types::ValType;889use crate::{9use crate::{10 destructure::evaluate_dest,10 error::Error::*,11 error::Error::*,11 evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op},12 evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op},12 function::{CallLocation, FuncDesc, FuncVal},13 function::{CallLocation, FuncDesc, FuncVal},13 gc::TraceBox,14 stdlib::{std_slice, BUILTINS},14 stdlib::{std_slice, BUILTINS},15 throw,15 tb, throw,16 typed::Typed,16 typed::Typed,17 val::{ArrValue, LazyValValue},17 val::{ArrValue, Thunk, ThunkValue},18 Bindable, Context, ContextCreator, FutureWrapper, GcHashMap, LazyBinding, LazyVal, ObjValue,18 Bindable, Context, ContextCreator, GcHashMap, LazyBinding, ObjValue, ObjValueBuilder,19 ObjValueBuilder, ObjectAssertion, Result, State, Val,19 ObjectAssertion, Pending, Result, State, Val,20};20};21pub mod operator;21pub mod destructure;2223pub fn evaluate_binding_in_future(b: &BindSpec, fctx: FutureWrapper<Context>) -> LazyVal {22pub mod operator;24 let b = b.clone();25 if let Some(params) = &b.params {26 #[derive(Trace)]27 struct LazyMethodBinding {28 fctx: FutureWrapper<Context>,29 name: IStr,30 params: ParamsDesc,31 value: LocExpr,32 }33 impl LazyValValue for LazyMethodBinding {34 fn get(self: Box<Self>, _: State) -> Result<Val> {35 Ok(evaluate_method(36 self.fctx.unwrap(),37 self.name,38 self.params,39 self.value,40 ))41 }42 }4344 let params = params.clone();4546 LazyVal::new(TraceBox(Box::new(LazyMethodBinding {47 fctx,48 name: b.name.clone(),49 params,50 value: b.value.clone(),51 })))52 } else {53 #[derive(Trace)]54 struct LazyNamedBinding {55 fctx: FutureWrapper<Context>,56 name: IStr,57 value: LocExpr,58 }59 impl LazyValValue for LazyNamedBinding {60 fn get(self: Box<Self>, s: State) -> Result<Val> {61 evaluate_named(s, self.fctx.unwrap(), &self.value, self.name)62 }63 }64 LazyVal::new(TraceBox(Box::new(LazyNamedBinding {65 fctx,66 name: b.name.clone(),67 value: b.value,68 })))69 }70}712372#[allow(clippy::too_many_lines)]24#[allow(clippy::too_many_lines)]73pub fn evaluate_binding(b: &BindSpec, cctx: ContextCreator) -> (IStr, LazyBinding) {25pub fn evaluate_binding(b: BindSpec, cctx: ContextCreator) -> Result<(IStr, LazyBinding)> {74 let b = b.clone();26 match b {27 BindSpec::Field {75 if let Some(params) = &b.params {28 into: Destruct::Full(name),29 value,30 } => {76 #[derive(Trace)]31 #[derive(Trace)]77 struct BindableMethodLazyVal {32 struct BindableNamedThunk {78 this: Option<ObjValue>,33 this: Option<ObjValue>,79 super_obj: Option<ObjValue>,34 super_obj: Option<ObjValue>,803581 cctx: ContextCreator,36 cctx: ContextCreator,82 name: IStr,37 name: IStr,83 params: ParamsDesc,84 value: LocExpr,38 value: LocExpr,85 }39 }86 impl LazyValValue for BindableMethodLazyVal {40 impl ThunkValue for BindableNamedThunk {41 type Output = Val;87 fn get(self: Box<Self>, s: State) -> Result<Val> {42 fn get(self: Box<Self>, s: State) -> Result<Val> {88 Ok(evaluate_method(43 evaluate_named(44 s.clone(),89 self.cctx.create(s, self.this, self.super_obj)?,45 self.cctx.create(s, self.this, self.super_obj)?,90 self.name,46 &self.value,91 self.params,47 self.name,92 self.value,93 ))48 )94 }49 }95 }50 }965197 #[derive(Trace)]52 #[derive(Trace)]98 struct BindableMethod {53 struct BindableNamed {99 cctx: ContextCreator,54 cctx: ContextCreator,100 name: IStr,55 name: IStr,101 params: ParamsDesc,102 value: LocExpr,56 value: LocExpr,103 }57 }104 impl Bindable for BindableMethod {58 impl Bindable for BindableNamed {105 fn bind(59 fn bind(106 &self,60 &self,107 _: State,61 _: State,108 this: Option<ObjValue>,62 this: Option<ObjValue>,109 super_obj: Option<ObjValue>,63 super_obj: Option<ObjValue>,110 ) -> Result<LazyVal> {64 ) -> Result<Thunk<Val>> {111 Ok(LazyVal::new(TraceBox(Box::new(BindableMethodLazyVal {65 Ok(Thunk::new(tb!(BindableNamedThunk {112 this,66 this,113 super_obj,67 super_obj,11468115 cctx: self.cctx.clone(),69 cctx: self.cctx.clone(),116 name: self.name.clone(),70 name: self.name.clone(),117 params: self.params.clone(),118 value: self.value.clone(),71 value: self.value.clone(),119 }))))72 })))120 }73 }121 }74 }122123 let params = params.clone();12475125 (76 Ok((126 b.name.clone(),77 name.clone(),127 LazyBinding::Bindable(Cc::new(TraceBox(Box::new(BindableMethod {78 LazyBinding::Bindable(Cc::new(tb!(BindableNamed {128 cctx,79 cctx,129 name: b.name.clone(),80 name: name.clone(),130 params,131 value: b.value.clone(),81 value: value.clone(),132 })))),82 }))),133 )83 ))134 } else {84 }85 #[cfg(feature = "exp-destruct")]86 BindSpec::Field { into: _, .. } => {87 use crate::throw_runtime;88 throw_runtime!("destructuring is not yet supported here")89 }90 BindSpec::Function {91 name,92 params,93 value,94 } => {135 #[derive(Trace)]95 #[derive(Trace)]136 struct BindableNamedLazyVal {96 struct BindableMethodThunk {137 this: Option<ObjValue>,97 this: Option<ObjValue>,138 super_obj: Option<ObjValue>,98 super_obj: Option<ObjValue>,13999140 cctx: ContextCreator,100 cctx: ContextCreator,141 name: IStr,101 name: IStr,102 params: ParamsDesc,142 value: LocExpr,103 value: LocExpr,143 }104 }144 impl LazyValValue for BindableNamedLazyVal {105 impl ThunkValue for BindableMethodThunk {106 type Output = Val;145 fn get(self: Box<Self>, s: State) -> Result<Val> {107 fn get(self: Box<Self>, s: State) -> Result<Val> {146 evaluate_named(108 Ok(evaluate_method(147 s.clone(),148 self.cctx.create(s, self.this, self.super_obj)?,109 self.cctx.create(s, self.this, self.super_obj)?,149 &self.value,110 self.name,150 self.name,111 self.params,112 self.value,151 )113 ))152 }114 }153 }115 }154116155 #[derive(Trace)]117 #[derive(Trace)]156 struct BindableNamed {118 struct BindableMethod {157 cctx: ContextCreator,119 cctx: ContextCreator,158 name: IStr,120 name: IStr,121 params: ParamsDesc,159 value: LocExpr,122 value: LocExpr,160 }123 }161 impl Bindable for BindableNamed {124 impl Bindable for BindableMethod {162 fn bind(125 fn bind(163 &self,126 &self,164 _: State,127 _: State,165 this: Option<ObjValue>,128 this: Option<ObjValue>,166 super_obj: Option<ObjValue>,129 super_obj: Option<ObjValue>,167 ) -> Result<LazyVal> {130 ) -> Result<Thunk<Val>> {168 Ok(LazyVal::new(TraceBox(Box::new(BindableNamedLazyVal {131 Ok(Thunk::<Val>::new(tb!(BindableMethodThunk {169 this,132 this,170 super_obj,133 super_obj,171134172 cctx: self.cctx.clone(),135 cctx: self.cctx.clone(),173 name: self.name.clone(),136 name: self.name.clone(),137 params: self.params.clone(),174 value: self.value.clone(),138 value: self.value.clone(),175 }))))139 })))176 }140 }177 }141 }142143 let params = params.clone();178144179 (145 Ok((180 b.name.clone(),146 name.clone(),181 LazyBinding::Bindable(Cc::new(TraceBox(Box::new(BindableNamed {147 LazyBinding::Bindable(Cc::new(tb!(BindableMethod {182 cctx,148 cctx,183 name: b.name.clone(),149 name: name.clone(),150 params,184 value: b.value.clone(),151 value,185 })))),152 }))),186 )153 ))187 }154 }155 }188}156}189157190pub fn evaluate_method(ctx: Context, name: IStr, params: ParamsDesc, body: LocExpr) -> Val {158pub fn evaluate_method(ctx: Context, name: IStr, params: ParamsDesc, body: LocExpr) -> Val {252220253#[allow(clippy::too_many_lines)]221#[allow(clippy::too_many_lines)]254pub fn evaluate_member_list_object(s: State, ctx: Context, members: &[Member]) -> Result<ObjValue> {222pub fn evaluate_member_list_object(s: State, ctx: Context, members: &[Member]) -> Result<ObjValue> {255 let new_bindings = FutureWrapper::new();223 let new_bindings = Pending::new();256 let future_this = FutureWrapper::new();224 let future_this = Pending::new();257 let cctx = ContextCreator(ctx.clone(), new_bindings.clone());225 let cctx = ContextCreator(ctx.clone(), new_bindings.clone());258 {226 {259 let mut bindings: GcHashMap<IStr, LazyBinding> = GcHashMap::with_capacity(members.len());227 let mut bindings: GcHashMap<IStr, LazyBinding> = GcHashMap::with_capacity(members.len());260 for (n, b) in members228 for r in members261 .iter()229 .iter()262 .filter_map(|m| match m {230 .filter_map(|m| match m {263 Member::BindStmt(b) => Some(b.clone()),231 Member::BindStmt(b) => Some(b.clone()),264 _ => None,232 _ => None,265 })233 })266 .map(|b| evaluate_binding(&b, cctx.clone()))234 .map(|b| evaluate_binding(b.clone(), cctx.clone()))267 {235 {236 let (n, b) = r?;268 bindings.insert(n, b);237 bindings.insert(n, b);269 }238 }270 new_bindings.fill(bindings);239 new_bindings.fill(bindings);292 s: State,261 s: State,293 this: Option<ObjValue>,262 this: Option<ObjValue>,294 super_obj: Option<ObjValue>,263 super_obj: Option<ObjValue>,295 ) -> Result<LazyVal> {264 ) -> Result<Thunk<Val>> {296 Ok(LazyVal::new_resolved(evaluate_named(265 Ok(Thunk::evaluated(evaluate_named(297 s.clone(),266 s.clone(),298 self.cctx.create(s, this, super_obj)?,267 self.cctx.create(s, this, super_obj)?,299 &self.value,268 &self.value,316 .with_location(value.1.clone())285 .with_location(value.1.clone())317 .bindable(286 .bindable(318 s.clone(),287 s.clone(),319 TraceBox(Box::new(ObjMemberBinding {288 tb!(ObjMemberBinding {320 cctx: cctx.clone(),289 cctx: cctx.clone(),321 value: value.clone(),290 value: value.clone(),322 name,291 name,323 })),292 }),324 )?;293 )?;325 }294 }326 Member::Field(FieldMember {295 Member::Field(FieldMember {342 s: State,311 s: State,343 this: Option<ObjValue>,312 this: Option<ObjValue>,344 super_obj: Option<ObjValue>,313 super_obj: Option<ObjValue>,345 ) -> Result<LazyVal> {314 ) -> Result<Thunk<Val>> {346 Ok(LazyVal::new_resolved(evaluate_method(315 Ok(Thunk::evaluated(evaluate_method(347 self.cctx.create(s, this, super_obj)?,316 self.cctx.create(s, this, super_obj)?,348 self.name.clone(),317 self.name.clone(),349 self.params.clone(),318 self.params.clone(),364 .with_location(value.1.clone())333 .with_location(value.1.clone())365 .bindable(334 .bindable(366 s.clone(),335 s.clone(),367 TraceBox(Box::new(ObjMemberBinding {336 tb!(ObjMemberBinding {368 cctx: cctx.clone(),337 cctx: cctx.clone(),369 value: value.clone(),338 value: value.clone(),370 params: params.clone(),339 params: params.clone(),371 name,340 name,372 })),341 }),373 )?;342 )?;374 }343 }375 Member::BindStmt(_) => {}344 Member::BindStmt(_) => {}390 evaluate_assert(s, ctx, &self.assert)359 evaluate_assert(s, ctx, &self.assert)391 }360 }392 }361 }393 builder.assert(TraceBox(Box::new(ObjectAssert {362 builder.assert(tb!(ObjectAssert {394 cctx: cctx.clone(),363 cctx: cctx.clone(),395 assert: stmt.clone(),364 assert: stmt.clone(),396 })));365 }));397 }366 }398 }367 }399 }368 }406 Ok(match object {375 Ok(match object {407 ObjBody::MemberList(members) => evaluate_member_list_object(s, ctx, members)?,376 ObjBody::MemberList(members) => evaluate_member_list_object(s, ctx, members)?,408 ObjBody::ObjComp(obj) => {377 ObjBody::ObjComp(obj) => {409 let future_this = FutureWrapper::new();378 let future_this = Pending::new();410 let mut builder = ObjValueBuilder::new();379 let mut builder = ObjValueBuilder::new();411 evaluate_comp(s.clone(), ctx, &obj.compspecs, &mut |ctx| {380 evaluate_comp(s.clone(), ctx, &obj.compspecs, &mut |ctx| {412 let new_bindings = FutureWrapper::new();381 let new_bindings = Pending::new();413 let cctx = ContextCreator(ctx.clone(), new_bindings.clone());382 let cctx = ContextCreator(ctx.clone(), new_bindings.clone());414 let mut bindings: GcHashMap<IStr, LazyBinding> =383 let mut bindings: GcHashMap<IStr, LazyBinding> =415 GcHashMap::with_capacity(obj.pre_locals.len() + obj.post_locals.len());384 GcHashMap::with_capacity(obj.pre_locals.len() + obj.post_locals.len());416 for (n, b) in obj385 for r in obj417 .pre_locals386 .pre_locals418 .iter()387 .iter()419 .chain(obj.post_locals.iter())388 .chain(obj.post_locals.iter())420 .map(|b| evaluate_binding(b, cctx.clone()))389 .map(|b| evaluate_binding(b.clone(), cctx.clone()))421 {390 {391 let (n, b) = r?;422 bindings.insert(n, b);392 bindings.insert(n, b);423 }393 }424 new_bindings.fill(bindings.clone());394 new_bindings.fill(bindings.clone());439 s: State,409 s: State,440 this: Option<ObjValue>,410 this: Option<ObjValue>,441 _super_obj: Option<ObjValue>,411 _super_obj: Option<ObjValue>,442 ) -> Result<LazyVal> {412 ) -> Result<Thunk<Val>> {443 Ok(LazyVal::new_resolved(evaluate(413 Ok(Thunk::evaluated(evaluate(444 s,414 s,445 self.ctx.clone().extend(GcHashMap::new(), None, this, None),415 self.ctx.clone().extend(GcHashMap::new(), None, this, None),446 &self.value,416 &self.value,453 .with_add(obj.plus)423 .with_add(obj.plus)454 .bindable(424 .bindable(455 s.clone(),425 s.clone(),456 TraceBox(Box::new(ObjCompBinding {426 tb!(ObjCompBinding {457 ctx,427 ctx,458 value: obj.value.clone(),428 value: obj.value.clone(),459 })),429 }),460 )?;430 )?;461 }431 }462 v => throw!(FieldMustBeStringGot(v.value_type())),432 v => throw!(FieldMustBeStringGot(v.value_type())),620 }590 }621 }591 }622 LocalExpr(bindings, returned) => {592 LocalExpr(bindings, returned) => {623 let mut new_bindings: GcHashMap<IStr, LazyVal> =593 let mut new_bindings: GcHashMap<IStr, Thunk<Val>> =624 GcHashMap::with_capacity(bindings.len());594 GcHashMap::with_capacity(bindings.len());625 let fctx = Context::new_future();595 let fctx = Context::new_future();626 for b in bindings {596 for b in bindings {627 new_bindings.insert(b.name.clone(), evaluate_binding_in_future(b, fctx.clone()));597 evaluate_dest(b, fctx.clone(), &mut new_bindings)?;628 }598 }629 let ctx = ctx.extend_bound(new_bindings).into_future(fctx);599 let ctx = ctx.extend_bound(new_bindings).into_future(fctx);630 evaluate(s, ctx, &returned.clone())?600 evaluate(s, ctx, &returned.clone())?638 ctx: Context,608 ctx: Context,639 item: LocExpr,609 item: LocExpr,640 }610 }641 impl LazyValValue for ArrayElement {611 impl ThunkValue for ArrayElement {612 type Output = Val;642 fn get(self: Box<Self>, s: State) -> Result<Val> {613 fn get(self: Box<Self>, s: State) -> Result<Val> {643 evaluate(s, self.ctx, &self.item)614 evaluate(s, self.ctx, &self.item)644 }615 }645 }616 }646 out.push(LazyVal::new(TraceBox(Box::new(ArrayElement {617 out.push(Thunk::new(tb!(ArrayElement {647 ctx: ctx.clone(),618 ctx: ctx.clone(),648 item: item.clone(),619 item: item.clone(),649 }))));620 })));650 }621 }651 Val::Arr(out.into())622 Val::Arr(out.into())652 }623 }crates/jrsonnet-evaluator/src/function/arglike.rsdiffbeforeafterboth5use jrsonnet_parser::{ArgsDesc, LocExpr};5use jrsonnet_parser::{ArgsDesc, LocExpr};667use crate::{7use crate::{8 error::Result, evaluate, gc::TraceBox, typed::Typed, val::LazyValValue, Context, LazyVal,8 error::Result, evaluate, tb, typed::Typed, val::ThunkValue, Context, State, Thunk, Val,9 State, Val,10};9};111012#[derive(Trace)]11#[derive(Trace)]13struct EvaluateLazyVal {12struct EvaluateThunk {14 ctx: Context,13 ctx: Context,15 expr: LocExpr,14 expr: LocExpr,16}15}17impl LazyValValue for EvaluateLazyVal {16impl ThunkValue for EvaluateThunk {17 type Output = Val;18 fn get(self: Box<Self>, s: State) -> Result<Val> {18 fn get(self: Box<Self>, s: State) -> Result<Val> {19 evaluate(s, self.ctx, &self.expr)19 evaluate(s, self.ctx, &self.expr)20 }20 }21}21}222223pub trait ArgLike {23pub trait ArgLike {24 fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<LazyVal>;24 fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;25}25}262627impl ArgLike for &LocExpr {27impl ArgLike for &LocExpr {28 fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<LazyVal> {28 fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {29 Ok(if tailstrict {29 Ok(if tailstrict {30 LazyVal::new_resolved(evaluate(s, ctx, self)?)30 Thunk::evaluated(evaluate(s, ctx, self)?)31 } else {31 } else {32 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {32 Thunk::new(tb!(EvaluateThunk {33 ctx,33 ctx,34 expr: (*self).clone(),34 expr: (*self).clone(),35 })))35 }))36 })36 })37 }37 }38}38}41where41where42 T: Typed + Clone,42 T: Typed + Clone,43{43{44 fn evaluate_arg(&self, s: State, _ctx: Context, _tailstrict: bool) -> Result<LazyVal> {44 fn evaluate_arg(&self, s: State, _ctx: Context, _tailstrict: bool) -> Result<Thunk<Val>> {45 let val = T::into_untyped(self.clone(), s)?;45 let val = T::into_untyped(self.clone(), s)?;46 Ok(LazyVal::new_resolved(val))46 Ok(Thunk::evaluated(val))47 }47 }48}48}494953 Val(Val),53 Val(Val),54}54}55impl ArgLike for TlaArg {55impl ArgLike for TlaArg {56 fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<LazyVal> {56 fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {57 match self {57 match self {58 TlaArg::String(s) => Ok(LazyVal::new_resolved(Val::Str(s.clone()))),58 TlaArg::String(s) => Ok(Thunk::evaluated(Val::Str(s.clone()))),59 TlaArg::Code(code) => Ok(if tailstrict {59 TlaArg::Code(code) => Ok(if tailstrict {60 LazyVal::new_resolved(evaluate(s, ctx, code)?)60 Thunk::evaluated(evaluate(s, ctx, code)?)61 } else {61 } else {62 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {62 Thunk::new(tb!(EvaluateThunk {63 ctx,63 ctx,64 expr: code.clone(),64 expr: code.clone(),65 })))65 }))66 }),66 }),67 TlaArg::Val(val) => Ok(LazyVal::new_resolved(val.clone())),67 TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),68 }68 }69 }69 }70}70}83 s: State,83 s: State,84 ctx: Context,84 ctx: Context,85 tailstrict: bool,85 tailstrict: bool,86 handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,86 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,87 ) -> Result<()>;87 ) -> Result<()>;88 fn named_iter(88 fn named_iter(89 &self,89 &self,90 s: State,90 s: State,91 ctx: Context,91 ctx: Context,92 tailstrict: bool,92 tailstrict: bool,93 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,93 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,94 ) -> Result<()>;94 ) -> Result<()>;95 fn named_names(&self, handler: &mut dyn FnMut(&IStr));95 fn named_names(&self, handler: &mut dyn FnMut(&IStr));96}96}105 s: State,105 s: State,106 ctx: Context,106 ctx: Context,107 tailstrict: bool,107 tailstrict: bool,108 handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,108 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,109 ) -> Result<()> {109 ) -> Result<()> {110 for (id, arg) in self.unnamed.iter().enumerate() {110 for (id, arg) in self.unnamed.iter().enumerate() {111 handler(111 handler(112 id,112 id,113 if tailstrict {113 if tailstrict {114 LazyVal::new_resolved(evaluate(s.clone(), ctx.clone(), arg)?)114 Thunk::evaluated(evaluate(s.clone(), ctx.clone(), arg)?)115 } else {115 } else {116 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {116 Thunk::new(tb!(EvaluateThunk {117 ctx: ctx.clone(),117 ctx: ctx.clone(),118 expr: arg.clone(),118 expr: arg.clone(),119 })))119 }))120 },120 },121 )?;121 )?;122 }122 }128 s: State,128 s: State,129 ctx: Context,129 ctx: Context,130 tailstrict: bool,130 tailstrict: bool,131 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,131 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,132 ) -> Result<()> {132 ) -> Result<()> {133 for (name, arg) in &self.named {133 for (name, arg) in &self.named {134 handler(134 handler(135 name,135 name,136 if tailstrict {136 if tailstrict {137 LazyVal::new_resolved(evaluate(s.clone(), ctx.clone(), arg)?)137 Thunk::evaluated(evaluate(s.clone(), ctx.clone(), arg)?)138 } else {138 } else {139 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {139 Thunk::new(tb!(EvaluateThunk {140 ctx: ctx.clone(),140 ctx: ctx.clone(),141 expr: arg.clone(),141 expr: arg.clone(),142 })))142 }))143 },143 },144 )?;144 )?;145 }145 }164 _s: State,164 _s: State,165 _ctx: Context,165 _ctx: Context,166 _tailstrict: bool,166 _tailstrict: bool,167 _handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,167 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,168 ) -> Result<()> {168 ) -> Result<()> {169 Ok(())169 Ok(())170 }170 }174 s: State,174 s: State,175 ctx: Context,175 ctx: Context,176 tailstrict: bool,176 tailstrict: bool,177 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,177 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,178 ) -> Result<()> {178 ) -> Result<()> {179 for (name, value) in self.iter() {179 for (name, value) in self.iter() {180 handler(180 handler(205 s: State,205 s: State,206 ctx: Context,206 ctx: Context,207 tailstrict: bool,207 tailstrict: bool,208 handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,208 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,209 ) -> Result<()> {209 ) -> Result<()> {210 let mut i = 0usize;210 let mut i = 0usize;211 let ($($gen,)*) = self;211 let ($($gen,)*) = self;220 _s: State,220 _s: State,221 _ctx: Context,221 _ctx: Context,222 _tailstrict: bool,222 _tailstrict: bool,223 _handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,223 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,224 ) -> Result<()> {224 ) -> Result<()> {225 Ok(())225 Ok(())226 }226 }236 _s: State,236 _s: State,237 _ctx: Context,237 _ctx: Context,238 _tailstrict: bool,238 _tailstrict: bool,239 _handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,239 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,240 ) -> Result<()> {240 ) -> Result<()> {241 Ok(())241 Ok(())242 }242 }246 s: State,246 s: State,247 ctx: Context,247 ctx: Context,248 tailstrict: bool,248 tailstrict: bool,249 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,249 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,250 ) -> Result<()> {250 ) -> Result<()> {251 let ($($gen,)*) = self;251 let ($($gen,)*) = self;252 $(252 $(285 _s: State,285 _s: State,286 _ctx: Context,286 _ctx: Context,287 _tailstrict: bool,287 _tailstrict: bool,288 _handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,288 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,289 ) -> Result<()> {289 ) -> Result<()> {290 Ok(())290 Ok(())291 }291 }295 _s: State,295 _s: State,296 _ctx: Context,296 _ctx: Context,297 _tailstrict: bool,297 _tailstrict: bool,298 _handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,298 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,299 ) -> Result<()> {299 ) -> Result<()> {300 Ok(())300 Ok(())301 }301 }crates/jrsonnet-evaluator/src/function/parse.rsdiffbeforeafterboth9use crate::{9use crate::{10 error::{Error::*, Result},10 error::{Error::*, Result},11 evaluate_named,11 evaluate_named,12 gc::{GcHashMap, TraceBox},12 gc::GcHashMap,13 throw,13 tb, throw,14 val::LazyValValue,14 val::ThunkValue,15 Context, FutureWrapper, LazyVal, State, Val,15 Context, Pending, State, Thunk, Val,16};16};171718#[derive(Trace)]18#[derive(Trace)]19struct EvaluateNamedLazyVal {19struct EvaluateNamedThunk {20 ctx: FutureWrapper<Context>,20 ctx: Pending<Context>,21 name: IStr,21 name: IStr,22 value: LocExpr,22 value: LocExpr,23}23}242425impl LazyValValue for EvaluateNamedLazyVal {25impl ThunkValue for EvaluateNamedThunk {26 type Output = Val;26 fn get(self: Box<Self>, s: State) -> Result<Val> {27 fn get(self: Box<Self>, s: State) -> Result<Val> {27 evaluate_named(s, self.ctx.unwrap(), &self.value, self.name)28 evaluate_named(s, self.ctx.unwrap(), &self.value, self.name)28 }29 }838484 defaults.insert(85 defaults.insert(85 param.0.clone(),86 param.0.clone(),86 LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {87 Thunk::new(tb!(EvaluateNamedThunk {87 ctx: fctx.clone(),88 ctx: fctx.clone(),88 name: param.0.clone(),89 name: param.0.clone(),89 value: param.1.clone().expect("default exists"),90 value: param.1.clone().expect("default exists"),90 }))),91 })),91 );92 );92 filled_args += 1;93 filled_args += 1;93 }94 }131 params: &[BuiltinParam],132 params: &[BuiltinParam],132 args: &dyn ArgsLike,133 args: &dyn ArgsLike,133 tailstrict: bool,134 tailstrict: bool,134) -> Result<GcHashMap<BuiltinParamName, LazyVal>> {135) -> Result<GcHashMap<BuiltinParamName, Thunk<Val>>> {135 let mut passed_args = GcHashMap::with_capacity(params.len());136 let mut passed_args = GcHashMap::with_capacity(params.len());136 if args.unnamed_len() > params.len() {137 if args.unnamed_len() > params.len() {137 throw!(TooManyArgsFunctionHas(params.len()))138 throw!(TooManyArgsFunctionHas(params.len()))191pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Context {192pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Context {192 #[derive(Trace)]193 #[derive(Trace)]193 struct DependsOnUnbound(IStr);194 struct DependsOnUnbound(IStr);194 impl LazyValValue for DependsOnUnbound {195 impl ThunkValue for DependsOnUnbound {196 type Output = Val;195 fn get(self: Box<Self>, _: State) -> Result<Val> {197 fn get(self: Box<Self>, _: State) -> Result<Val> {196 Err(FunctionParameterNotBoundInCall(self.0.clone()).into())198 Err(FunctionParameterNotBoundInCall(self.0.clone()).into())197 }199 }205 if let Some(v) = ¶m.1 {207 if let Some(v) = ¶m.1 {206 bindings.insert(208 bindings.insert(207 param.0.clone(),209 param.0.clone(),208 LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {210 Thunk::new(tb!(EvaluateNamedThunk {209 ctx: fctx.clone(),211 ctx: fctx.clone(),210 name: param.0.clone(),212 name: param.0.clone(),211 value: v.clone(),213 value: v.clone(),212 }))),214 })),213 );215 );214 } else {216 } else {215 bindings.insert(217 bindings.insert(216 param.0.clone(),218 param.0.clone(),217 LazyVal::new(TraceBox(Box::new(DependsOnUnbound(param.0.clone())))),219 Thunk::new(tb!(DependsOnUnbound(param.0.clone()))),218 );220 );219 }221 }220 }222 }crates/jrsonnet-evaluator/src/gc.rsdiffbeforeafterboth10use rustc_hash::{FxHashMap, FxHashSet};10use rustc_hash::{FxHashMap, FxHashSet};111112/// Replacement for box, which assumes that the underlying type is [`Trace`]12/// Replacement for box, which assumes that the underlying type is [`Trace`]13/// Used in places, where Cc<dyn Trait> should be used instead, but it can't, because CoerceUnsiced is not stable13#[derive(Debug, Clone)]14#[derive(Debug, Clone)]14pub struct TraceBox<T: ?Sized>(pub Box<T>);15pub struct TraceBox<T: ?Sized>(pub Box<T>);16#[macro_export]17macro_rules! tb {18 ($v:expr) => {19 $crate::gc::TraceBox(Box::new($v))20 };21}152216impl<T: ?Sized + Trace> Trace for TraceBox<T> {23impl<T: ?Sized + Trace> Trace for TraceBox<T> {17 fn trace(&self, tracer: &mut Tracer) {24 fn trace(&self, tracer: &mut Tracer) {crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth58use jrsonnet_parser::*;58use jrsonnet_parser::*;59pub use obj::*;59pub use obj::*;60use trace::{location_to_offset, offset_to_location, CodeLocation, CompactFormat, TraceFormat};60use trace::{location_to_offset, offset_to_location, CodeLocation, CompactFormat, TraceFormat};61pub use val::{LazyVal, ManifestFormat, Val};61pub use val::{ManifestFormat, Thunk, Val};626263pub trait Bindable: Trace + 'static {63pub trait Bindable: Trace + 'static {64 fn bind(64 fn bind(65 &self,65 &self,66 s: State,66 s: State,67 this: Option<ObjValue>,67 this: Option<ObjValue>,68 super_obj: Option<ObjValue>,68 super_obj: Option<ObjValue>,69 ) -> Result<LazyVal>;69 ) -> Result<Thunk<Val>>;70}70}717172#[derive(Clone, Trace)]72#[derive(Clone, Trace)]73pub enum LazyBinding {73pub enum LazyBinding {74 Bindable(Cc<TraceBox<dyn Bindable>>),74 Bindable(Cc<TraceBox<dyn Bindable>>),75 Bound(LazyVal),75 Bound(Thunk<Val>),76}76}777778impl Debug for LazyBinding {78impl Debug for LazyBinding {86 s: State,86 s: State,87 this: Option<ObjValue>,87 this: Option<ObjValue>,88 super_obj: Option<ObjValue>,88 super_obj: Option<ObjValue>,89 ) -> Result<LazyVal> {89 ) -> Result<Thunk<Val>> {90 match self {90 match self {91 Self::Bindable(v) => v.bind(s, this, super_obj),91 Self::Bindable(v) => v.bind(s, this, super_obj),92 Self::Bound(v) => Ok(v.clone()),92 Self::Bound(v) => Ok(v.clone()),343 let globals = &self.settings().globals;343 let globals = &self.settings().globals;344 let mut new_bindings = GcHashMap::with_capacity(globals.len());344 let mut new_bindings = GcHashMap::with_capacity(globals.len());345 for (name, value) in globals.iter() {345 for (name, value) in globals.iter() {346 new_bindings.insert(name.clone(), LazyVal::new_resolved(value.clone()));346 new_bindings.insert(name.clone(), Thunk::evaluated(value.clone()));347 }347 }348 Context::new().extend_bound(new_bindings)348 Context::new().extend_bound(new_bindings)349 }349 }crates/jrsonnet-evaluator/src/map.rsdiffbeforeafterboth1use gcmodule::{Cc, Trace};1use gcmodule::{Cc, Trace};2use jrsonnet_interner::IStr;2use jrsonnet_interner::IStr;334use crate::{GcHashMap, LazyVal};4use crate::{GcHashMap, Thunk, Val};556#[derive(Trace)]6#[derive(Trace)]7#[force_tracking]7#[force_tracking]8pub struct LayeredHashMapInternals {8pub struct LayeredHashMapInternals {9 parent: Option<LayeredHashMap>,9 parent: Option<LayeredHashMap>,10 current: GcHashMap<IStr, LazyVal>,10 current: GcHashMap<IStr, Thunk<Val>>,11}11}121213#[derive(Trace)]13#[derive(Trace)]14pub struct LayeredHashMap(Cc<LayeredHashMapInternals>);14pub struct LayeredHashMap(Cc<LayeredHashMapInternals>);151516impl LayeredHashMap {16impl LayeredHashMap {17 pub fn extend(self, new_layer: GcHashMap<IStr, LazyVal>) -> Self {17 pub fn extend(self, new_layer: GcHashMap<IStr, Thunk<Val>>) -> Self {18 Self(Cc::new(LayeredHashMapInternals {18 Self(Cc::new(LayeredHashMapInternals {19 parent: Some(self),19 parent: Some(self),20 current: new_layer,20 current: new_layer,21 }))21 }))22 }22 }232324 pub fn get(&self, key: &IStr) -> Option<&LazyVal> {24 pub fn get(&self, key: &IStr) -> Option<&Thunk<Val>> {25 (self.0)25 (self.0)26 .current26 .current27 .get(key)27 .get(key)crates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth16 function::CallLocation,16 function::CallLocation,17 gc::{GcHashMap, GcHashSet, TraceBox},17 gc::{GcHashMap, GcHashSet, TraceBox},18 operator::evaluate_add_op,18 operator::evaluate_add_op,19 throw, weak_ptr_eq, weak_raw, Bindable, LazyBinding, LazyVal, Result, State, Val,19 throw, weak_ptr_eq, weak_raw, Bindable, LazyBinding, Result, State, Thunk, Val,20};20};212122#[cfg(not(feature = "exp-preserve-order"))]22#[cfg(not(feature = "exp-preserve-order"))]581pub struct ValueBuilder<'v>(&'v mut ObjValueBuilder);581pub struct ValueBuilder<'v>(&'v mut ObjValueBuilder);582impl<'v> ObjMemberBuilder<ValueBuilder<'v>> {582impl<'v> ObjMemberBuilder<ValueBuilder<'v>> {583 pub fn value(self, s: State, value: Val) -> Result<()> {583 pub fn value(self, s: State, value: Val) -> Result<()> {584 self.binding(s, LazyBinding::Bound(LazyVal::new_resolved(value)))584 self.binding(s, LazyBinding::Bound(Thunk::evaluated(value)))585 }585 }586 pub fn bindable(self, s: State, bindable: TraceBox<dyn Bindable>) -> Result<()> {586 pub fn bindable(self, s: State, bindable: TraceBox<dyn Bindable>) -> Result<()> {587 self.binding(s, LazyBinding::Bindable(Cc::new(bindable)))587 self.binding(s, LazyBinding::Bindable(Cc::new(bindable)))604pub struct ExtendBuilder<'v>(&'v mut ObjValue);604pub struct ExtendBuilder<'v>(&'v mut ObjValue);605impl<'v> ObjMemberBuilder<ExtendBuilder<'v>> {605impl<'v> ObjMemberBuilder<ExtendBuilder<'v>> {606 pub fn value(self, value: Val) {606 pub fn value(self, value: Val) {607 self.binding(LazyBinding::Bound(LazyVal::new_resolved(value)));607 self.binding(LazyBinding::Bound(Thunk::evaluated(value)));608 }608 }609 pub fn bindable(self, bindable: TraceBox<dyn Bindable>) {609 pub fn bindable(self, bindable: TraceBox<dyn Bindable>) {610 self.binding(LazyBinding::Bindable(Cc::new(bindable)));610 self.binding(LazyBinding::Bindable(Cc::new(bindable)));crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth15 throw, ObjValue, Result, State,15 throw, ObjValue, Result, State,16};16};171718pub trait LazyValValue: Trace {18pub trait ThunkValue: Trace {19 type Output;19 fn get(self: Box<Self>, s: State) -> Result<Val>;20 fn get(self: Box<Self>, s: State) -> Result<Self::Output>;20}21}212222#[derive(Trace)]23#[derive(Trace)]23enum LazyValInternals {24enum ThunkInner<T> {24 Computed(Val),25 Computed(T),25 Errored(LocError),26 Errored(LocError),26 Waiting(TraceBox<dyn LazyValValue>),27 Waiting(TraceBox<dyn ThunkValue<Output = T>>),27 Pending,28 Pending,28}29}293030#[allow(clippy::module_name_repetitions)]31#[allow(clippy::module_name_repetitions)]31#[derive(Clone, Trace)]32#[derive(Clone, Trace)]32pub struct LazyVal(Cc<RefCell<LazyValInternals>>);33pub struct Thunk<T>(Cc<RefCell<ThunkInner<T>>>);33impl LazyVal {34impl<T> Thunk<T>35where36 T: Clone + Trace,37{34 pub fn new(f: TraceBox<dyn LazyValValue>) -> Self {38 pub fn new(f: TraceBox<dyn ThunkValue<Output = T>>) -> Self {35 Self(Cc::new(RefCell::new(LazyValInternals::Waiting(f))))39 Self(Cc::new(RefCell::new(ThunkInner::Waiting(f))))36 }40 }37 pub fn new_resolved(val: Val) -> Self {41 pub fn evaluated(val: T) -> Self {38 Self(Cc::new(RefCell::new(LazyValInternals::Computed(val))))42 Self(Cc::new(RefCell::new(ThunkInner::Computed(val))))39 }43 }40 pub fn force(&self, s: State) -> Result<()> {44 pub fn force(&self, s: State) -> Result<()> {41 self.evaluate(s)?;45 self.evaluate(s)?;42 Ok(())46 Ok(())43 }47 }44 pub fn evaluate(&self, s: State) -> Result<Val> {48 pub fn evaluate(&self, s: State) -> Result<T> {45 match &*self.0.borrow() {49 match &*self.0.borrow() {46 LazyValInternals::Computed(v) => return Ok(v.clone()),50 ThunkInner::Computed(v) => return Ok(v.clone()),47 LazyValInternals::Errored(e) => return Err(e.clone()),51 ThunkInner::Errored(e) => return Err(e.clone()),48 LazyValInternals::Pending => return Err(InfiniteRecursionDetected.into()),52 ThunkInner::Pending => return Err(InfiniteRecursionDetected.into()),49 LazyValInternals::Waiting(..) => (),53 ThunkInner::Waiting(..) => (),50 };54 };51 let value = if let LazyValInternals::Waiting(value) =55 let value = if let ThunkInner::Waiting(value) =52 std::mem::replace(&mut *self.0.borrow_mut(), LazyValInternals::Pending)56 std::mem::replace(&mut *self.0.borrow_mut(), ThunkInner::Pending)53 {57 {54 value58 value55 } else {59 } else {58 let new_value = match value.0.get(s) {62 let new_value = match value.0.get(s) {59 Ok(v) => v,63 Ok(v) => v,60 Err(e) => {64 Err(e) => {61 *self.0.borrow_mut() = LazyValInternals::Errored(e.clone());65 *self.0.borrow_mut() = ThunkInner::Errored(e.clone());62 return Err(e);66 return Err(e);63 }67 }64 };68 };65 *self.0.borrow_mut() = LazyValInternals::Computed(new_value.clone());69 *self.0.borrow_mut() = ThunkInner::Computed(new_value.clone());66 Ok(new_value)70 Ok(new_value)67 }71 }68}72}697370impl Debug for LazyVal {74impl<T: Debug> Debug for Thunk<T> {71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {72 write!(f, "Lazy")76 write!(f, "Lazy")73 }77 }74}78}75impl PartialEq for LazyVal {79impl<T> PartialEq for Thunk<T> {76 fn eq(&self, other: &Self) -> bool {80 fn eq(&self, other: &Self) -> bool {77 cc_ptr_eq(&self.0, &other.0)81 cc_ptr_eq(&self.0, &other.0)78 }82 }142#[force_tracking]146#[force_tracking]143pub enum ArrValue {147pub enum ArrValue {144 Bytes(#[skip_trace] Rc<[u8]>),148 Bytes(#[skip_trace] Rc<[u8]>),145 Lazy(Cc<Vec<LazyVal>>),149 Lazy(Cc<Vec<Thunk<Val>>>),146 Eager(Cc<Vec<Val>>),150 Eager(Cc<Vec<Val>>),147 Extended(Box<(Self, Self)>),151 Extended(Box<(Self, Self)>),148 Range(i32, i32),152 Range(i32, i32),240 }244 }241 }245 }242246243 pub fn get_lazy(&self, index: usize) -> Option<LazyVal> {247 pub fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {244 match self {248 match self {245 Self::Bytes(i) => i249 Self::Bytes(i) => i246 .get(index)250 .get(index)247 .map(|b| LazyVal::new_resolved(Val::Num(f64::from(*b)))),251 .map(|b| Thunk::evaluated(Val::Num(f64::from(*b)))),248 Self::Lazy(vec) => vec.get(index).cloned(),252 Self::Lazy(vec) => vec.get(index).cloned(),249 Self::Eager(vec) => vec.get(index).cloned().map(LazyVal::new_resolved),253 Self::Eager(vec) => vec.get(index).cloned().map(Thunk::evaluated),250 Self::Extended(v) => {254 Self::Extended(v) => {251 let a_len = v.0.len();255 let a_len = v.0.len();252 if a_len > index {256 if a_len > index {259 if index >= self.len() {263 if index >= self.len() {260 return None;264 return None;261 }265 }262 Some(LazyVal::new_resolved(Val::Num(266 Some(Thunk::evaluated(Val::Num(263 ((*a as isize) + index as isize) as f64,267 ((*a as isize) + index as isize) as f64,264 )))268 )))265 }269 }343 })347 })344 }348 }345349346 pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {350 pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = Thunk<Val>> + '_ {347 (0..self.len()).map(move |idx| match self {351 (0..self.len()).map(move |idx| match self {348 Self::Bytes(b) => LazyVal::new_resolved(Val::Num(f64::from(b[idx]))),352 Self::Bytes(b) => Thunk::evaluated(Val::Num(f64::from(b[idx]))),349 Self::Lazy(l) => l[idx].clone(),353 Self::Lazy(l) => l[idx].clone(),350 Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),354 Self::Eager(e) => Thunk::evaluated(e[idx].clone()),351 Self::Slice(..) | Self::Extended(..) | Self::Range(..) | Self::Reversed(..) => {355 Self::Slice(..) | Self::Extended(..) | Self::Range(..) | Self::Reversed(..) => {352 self.get_lazy(idx).expect("idx < len")356 self.get_lazy(idx).expect("idx < len")353 }357 }391 }395 }392}396}393397394impl From<Vec<LazyVal>> for ArrValue {398impl From<Vec<Thunk<Val>>> for ArrValue {395 fn from(v: Vec<LazyVal>) -> Self {399 fn from(v: Vec<Thunk<Val>>) -> Self {396 Self::Lazy(Cc::new(v))400 Self::Lazy(Cc::new(v))397 }401 }398}402}crates/jrsonnet-evaluator/tests/builtin.rsdiffbeforeafterboth7 error::Result,7 error::Result,8 function::{builtin, builtin::Builtin, CallLocation, FuncVal},8 function::{builtin, builtin::Builtin, CallLocation, FuncVal},9 gc::TraceBox,9 gc::TraceBox,10 tb,10 typed::Typed,11 typed::Typed,11 State, Val,12 State, Val,12};13};707171#[builtin]72#[builtin]72fn curry_add(a: u32) -> Result<FuncVal> {73fn curry_add(a: u32) -> Result<FuncVal> {73 Ok(FuncVal::Builtin(Cc::new(TraceBox(Box::new(curried_add {74 Ok(FuncVal::Builtin(Cc::new(tb!(curried_add { a }))))74 a,75 })))))76}75}777678#[test]77#[test]crates/jrsonnet-evaluator/tests/common.rsdiffbeforeafterboth1use jrsonnet_evaluator::{1use jrsonnet_evaluator::{2 error::Result,2 error::Result,3 function::{builtin, FuncVal},3 function::{builtin, FuncVal},4 throw_runtime, LazyVal, ObjValueBuilder, State, Val,4 throw_runtime, ObjValueBuilder, State, Thunk, Val,5};5};667#[macro_export]7#[macro_export]38}38}393940#[builtin]40#[builtin]41fn assert_throw(s: State, lazy: LazyVal, message: String) -> Result<bool> {41fn assert_throw(s: State, lazy: Thunk<Val>, message: String) -> Result<bool> {42 match lazy.evaluate(s) {42 match lazy.evaluate(s) {43 Ok(_) => {43 Ok(_) => {44 throw_runtime!("expected argument to throw on evaluation, but it returned instead")44 throw_runtime!("expected argument to throw on evaluation, but it returned instead")crates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth150 return Ok(Self::State);150 return Ok(Self::State);151 } else if type_is_path(ty, "CallLocation").is_some() {151 } else if type_is_path(ty, "CallLocation").is_some() {152 return Ok(Self::Location);152 return Ok(Self::Location);153 } else if type_is_path(ty, "LazyVal").is_some() {153 } else if type_is_path(ty, "Thunk").is_some() {154 return Ok(Self::Lazy {154 return Ok(Self::Lazy {155 is_option: false,155 is_option: false,156 name: ident.to_string(),156 name: ident.to_string(),163 }163 }164164165 let (is_option, ty) = if let Some(ty) = extract_type_from_option(ty)? {165 let (is_option, ty) = if let Some(ty) = extract_type_from_option(ty)? {166 if type_is_path(ty, "LazyVal").is_some() {166 if type_is_path(ty, "Thunk").is_some() {167 return Ok(Self::Lazy {167 return Ok(Self::Lazy {168 is_option: true,168 is_option: true,169 name: ident.to_string(),169 name: ident.to_string(),crates/jrsonnet-parser/Cargo.tomldiffbeforeafterboth6license = "MIT"6license = "MIT"7edition = "2021"7edition = "2021"89[features]10exp-destruct = []8119[dependencies]12[dependencies]10jrsonnet-interner = { path = "../jrsonnet-interner", version = "0.4.2" }13jrsonnet-interner = { path = "../jrsonnet-interner", version = "0.4.2" }crates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth177 }177 }178}178}179180#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]181#[derive(Debug, Clone, PartialEq, Trace)]182pub enum DestructRest {183 /// ...rest184 Keep(IStr),185 /// ...186 Drop,187}188189#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]190#[derive(Debug, Clone, PartialEq, Trace)]191pub enum Destruct {192 Full(IStr),193 #[cfg(feature = "exp-destruct")]194 Skip,195 #[cfg(feature = "exp-destruct")]196 Array {197 start: Vec<Destruct>,198 rest: Option<DestructRest>,199 end: Vec<Destruct>,200 },201 #[cfg(feature = "exp-destruct")]202 Object {203 fields: Vec<(IStr, Option<Destruct>)>,204 rest: Option<DestructRest>,205 },206}179207180#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]208#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]181#[derive(Debug, Clone, PartialEq, Trace)]209#[derive(Debug, Clone, PartialEq, Trace)]182pub struct BindSpec {210pub enum BindSpec {211 Field {212 into: Destruct,213 value: LocExpr,214 },215 Function {183 pub name: IStr,216 name: IStr,184 pub params: Option<ParamsDesc>,217 params: ParamsDesc,185 pub value: LocExpr,218 value: LocExpr,219 },186}220}187221188#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]222#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]crates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth555556 /// Reserved word followed by any non-alphanumberic56 /// Reserved word followed by any non-alphanumberic57 rule reserved() = ("assert" / "else" / "error" / "false" / "for" / "function" / "if" / "import" / "importstr" / "importbin" / "in" / "local" / "null" / "tailstrict" / "then" / "self" / "super" / "true") end_of_ident()57 rule reserved() = ("assert" / "else" / "error" / "false" / "for" / "function" / "if" / "import" / "importstr" / "importbin" / "in" / "local" / "null" / "tailstrict" / "then" / "self" / "super" / "true") end_of_ident()58 rule id() = quiet!{ !reserved() alpha() (alpha() / digit())*} / expected!("<identifier>")58 rule id() -> IStr = v:$(quiet!{ !reserved() alpha() (alpha() / digit())*} / expected!("<identifier>")) { v.into() }595960 rule keyword(id: &'static str) -> ()60 rule keyword(id: &'static str) -> ()61 = ##parse_string_literal(id) end_of_ident()61 = ##parse_string_literal(id) end_of_ident()626263 pub rule param(s: &ParserSettings) -> expr::Param = name:$(id()) expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name.into(), expr) }63 pub rule param(s: &ParserSettings) -> expr::Param = name:id() expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name, expr) }64 pub rule params(s: &ParserSettings) -> expr::ParamsDesc64 pub rule params(s: &ParserSettings) -> expr::ParamsDesc65 = params:param(s) ** comma() comma()? { expr::ParamsDesc(Rc::new(params)) }65 = params:param(s) ** comma() comma()? { expr::ParamsDesc(Rc::new(params)) }66 / { expr::ParamsDesc(Rc::new(Vec::new())) }66 / { expr::ParamsDesc(Rc::new(Vec::new())) }676768 pub rule arg(s: &ParserSettings) -> (Option<IStr>, LocExpr)68 pub rule arg(s: &ParserSettings) -> (Option<IStr>, LocExpr)69 = quiet! { name:(s:$(id()) _ "=" _ {s})? expr:expr(s) {(name.map(Into::into), expr)} }69 = quiet! { name:(s:id() _ "=" _ {s})? expr:expr(s) {(name, expr)} }70 / expected!("<argument>")70 / expected!("<argument>")717172 pub rule args(s: &ParserSettings) -> expr::ArgsDesc72 pub rule args(s: &ParserSettings) -> expr::ArgsDesc89 Ok(expr::ArgsDesc::new(unnamed, named))89 Ok(expr::ArgsDesc::new(unnamed, named))90 }90 }919192 pub rule bind(s: &ParserSettings) -> expr::BindSpec92 pub rule destruct_rest() -> expr::DestructRest93 = "..." into:(_ into:id() {into})? {if let Some(into) = into {94 expr::DestructRest::Keep(into)95 } else {expr::DestructRest::Drop}}96 pub rule destruct_array(s: &ParserSettings) -> expr::Destruct93 = name:$(id()) _ "=" _ expr:expr(s) {expr::BindSpec{name:name.into(), params: None, value: expr}}97 = "[" _ start:destruct(s)**comma() rest:(98 comma() _ rest:destruct_rest()? end:(99 comma() end:destruct(s)**comma() (_ comma())? {end}100 / comma()? {Vec::new()}101 ) {(rest, end)}102 / comma()? {(None, Vec::new())}103 ) _ "]" {?104 #[cfg(feature = "exp-destruct")] return Ok(expr::Destruct::Array {105 start,106 rest: rest.0,107 end: rest.1,108 });109 #[cfg(not(feature = "exp-destruct"))] Err("experimental destructuring was not enabled")110 }111 pub rule destruct_object(s: &ParserSettings) -> expr::Destruct112 = "{" _113 fields:(name:id() _ into:(":" _ into:destruct(s) {into})? {(name, into)})**comma()114 rest:(115 comma() rest:destruct_rest()? {rest}116 / comma()? {None}117 )118 _ "}" {?119 #[cfg(feature = "exp-destruct")] return Ok(expr::Destruct::Object {120 fields,121 rest,122 });123 #[cfg(not(feature = "exp-destruct"))] Err("experimental destructuring was not enabled")124 }125 pub rule destruct(s: &ParserSettings) -> expr::Destruct126 = v:id() {expr::Destruct::Full(v)}127 / "?" {?128 #[cfg(feature = "exp-destruct")] return Ok(expr::Destruct::Skip);129 #[cfg(not(feature = "exp-destruct"))] Err("experimental destructuring was not enabled")130 }131 / arr:destruct_array(s) {arr}132 / obj:destruct_object(s) {obj}133134 pub rule bind(s: &ParserSettings) -> expr::BindSpec135 = into:destruct(s) _ "=" _ expr:expr(s) {expr::BindSpec::Field{into, value: expr}}94 / name:$(id()) _ "(" _ params:params(s) _ ")" _ "=" _ expr:expr(s) {expr::BindSpec{name:name.into(), params: Some(params), value: expr}}136 / name:id() _ "(" _ params:params(s) _ ")" _ "=" _ expr:expr(s) {expr::BindSpec::Function{name, params, value: expr}}13795 pub rule assertion(s: &ParserSettings) -> expr::AssertStmt138 pub rule assertion(s: &ParserSettings) -> expr::AssertStmt96 = keyword("assert") _ cond:expr(s) msg:(_ ":" _ e:expr(s) {e})? { expr::AssertStmt(cond, msg) }139 = keyword("assert") _ cond:expr(s) msg:(_ ":" _ e:expr(s) {e})? { expr::AssertStmt(cond, msg) }122 / string_block() } / expected!("<string>")165 / string_block() } / expected!("<string>")123166124 pub rule field_name(s: &ParserSettings) -> expr::FieldName167 pub rule field_name(s: &ParserSettings) -> expr::FieldName125 = name:$(id()) {expr::FieldName::Fixed(name.into())}168 = name:id() {expr::FieldName::Fixed(name.into())}126 / name:string() {expr::FieldName::Fixed(name.into())}169 / name:string() {expr::FieldName::Fixed(name.into())}127 / "[" _ expr:expr(s) _ "]" {expr::FieldName::Dyn(expr)}170 / "[" _ expr:expr(s) _ "]" {expr::FieldName::Dyn(expr)}128 pub rule visibility() -> expr::Visibility171 pub rule visibility() -> expr::Visibility167 pub rule ifspec(s: &ParserSettings) -> IfSpecData210 pub rule ifspec(s: &ParserSettings) -> IfSpecData168 = keyword("if") _ expr:expr(s) {IfSpecData(expr)}211 = keyword("if") _ expr:expr(s) {IfSpecData(expr)}169 pub rule forspec(s: &ParserSettings) -> ForSpecData212 pub rule forspec(s: &ParserSettings) -> ForSpecData170 = keyword("for") _ id:$(id()) _ keyword("in") _ cond:expr(s) {ForSpecData(id.into(), cond)}213 = keyword("for") _ id:id() _ keyword("in") _ cond:expr(s) {ForSpecData(id, cond)}171 pub rule compspec(s: &ParserSettings) -> Vec<expr::CompSpec>214 pub rule compspec(s: &ParserSettings) -> Vec<expr::CompSpec>172 = s:(i:ifspec(s) { expr::CompSpec::IfSpec(i) } / f:forspec(s) {expr::CompSpec::ForSpec(f)} ) ** _ {s}215 = s:(i:ifspec(s) { expr::CompSpec::IfSpec(i) } / f:forspec(s) {expr::CompSpec::ForSpec(f)} ) ** _ {s}173 pub rule local_expr(s: &ParserSettings) -> Expr216 pub rule local_expr(s: &ParserSettings) -> Expr187 pub rule number_expr(s: &ParserSettings) -> Expr230 pub rule number_expr(s: &ParserSettings) -> Expr188 = n:number() { expr::Expr::Num(n) }231 = n:number() { expr::Expr::Num(n) }189 pub rule var_expr(s: &ParserSettings) -> Expr232 pub rule var_expr(s: &ParserSettings) -> Expr190 = n:$(id()) { expr::Expr::Var(n.into()) }233 = n:id() { expr::Expr::Var(n) }191 pub rule id_loc(s: &ParserSettings) -> LocExpr234 pub rule id_loc(s: &ParserSettings) -> LocExpr192 = a:position!() n:$(id()) b:position!() { LocExpr(Rc::new(expr::Expr::Str(n.into())), ExprLocation(s.file_name.clone(), a,b)) }235 = a:position!() n:id() b:position!() { LocExpr(Rc::new(expr::Expr::Str(n)), ExprLocation(s.file_name.clone(), a,b)) }193 pub rule if_then_else_expr(s: &ParserSettings) -> Expr236 pub rule if_then_else_expr(s: &ParserSettings) -> Expr194 = cond:ifspec(s) _ keyword("then") _ cond_then:expr(s) cond_else:(_ keyword("else") _ e:expr(s) {e})? {Expr::IfElse{237 = cond:ifspec(s) _ keyword("then") _ cond_then:expr(s) cond_else:(_ keyword("else") _ e:expr(s) {e})? {Expr::IfElse{195 cond,238 cond,212255213 / quiet!{"$intrinsicThisFile" {Expr::IntrinsicThisFile}}256 / quiet!{"$intrinsicThisFile" {Expr::IntrinsicThisFile}}214 / quiet!{"$intrinsicId" {Expr::IntrinsicId}}257 / quiet!{"$intrinsicId" {Expr::IntrinsicId}}215 / quiet!{"$intrinsic(" name:$(id()) ")" {Expr::Intrinsic(name.into())}}258 / quiet!{"$intrinsic(" name:id() ")" {Expr::Intrinsic(name)}}216259217 / string_expr(s) / number_expr(s)260 / string_expr(s) / number_expr(s)218 / array_expr(s)261 / array_expr(s)693 ObjExtend(736 ObjExtend(694 el!(Obj(ObjBody::MemberList(vec![])), 0, 2),737 el!(Obj(ObjBody::MemberList(vec![])), 0, 2),695 ObjBody::MemberList(vec![738 ObjBody::MemberList(vec![696 Member::BindStmt(BindSpec {739 Member::BindStmt(BindSpec::Field {697 name: "x".into(),740 into: Destruct::Full("x".into()),698 params: None,699 value: el!(Num(1.0), 15, 16)741 value: el!(Num(1.0), 15, 16)700 }),742 }),701 Member::Field(FieldMember {743 Member::Field(FieldMember {