--- a/bindings/jsonnet/src/import.rs +++ b/bindings/jsonnet/src/import.rs @@ -15,7 +15,7 @@ use jrsonnet_evaluator::{ error::{Error::*, Result}, - throw, EvaluationState, ImportResolver, + throw, ImportResolver, State, }; pub type JsonnetImportCallback = unsafe extern "C" fn( @@ -87,7 +87,7 @@ /// # Safety #[no_mangle] pub unsafe extern "C" fn jsonnet_import_callback( - vm: &EvaluationState, + vm: &State, cb: JsonnetImportCallback, ctx: *mut c_void, ) { @@ -141,7 +141,7 @@ /// /// This function is safe, if received v is a pointer to normal C string #[no_mangle] -pub unsafe extern "C" fn jsonnet_jpath_add(vm: &EvaluationState, v: *const c_char) { +pub unsafe extern "C" fn jsonnet_jpath_add(vm: &State, v: *const c_char) { let cstr = CStr::from_ptr(v); let path = PathBuf::from(cstr.to_str().unwrap()); let any_resolver = &vm.settings().import_resolver; --- a/bindings/jsonnet/src/interop.rs +++ b/bindings/jsonnet/src/interop.rs @@ -5,7 +5,7 @@ os::raw::{c_char, c_int}, }; -use jrsonnet_evaluator::{EvaluationState, Val}; +use jrsonnet_evaluator::{State, Val}; use crate::{import::jsonnet_import_callback, native::jsonnet_native_callback}; @@ -28,17 +28,14 @@ /// # Safety #[no_mangle] -pub unsafe extern "C" fn jrsonnet_apply_static_import_callback( - vm: &EvaluationState, - ctx: *mut c_void, -) { +pub unsafe extern "C" fn jrsonnet_apply_static_import_callback(vm: &State, ctx: *mut c_void) { jsonnet_import_callback(vm, _jrsonnet_static_import_callback, ctx) } /// # Safety #[no_mangle] pub unsafe extern "C" fn jrsonnet_apply_static_native_callback( - vm: &EvaluationState, + vm: &State, name: *const c_char, ctx: *mut c_void, raw_params: *const *const c_char, @@ -47,7 +44,7 @@ } #[no_mangle] -pub extern "C" fn jrsonnet_set_trace_format(vm: &EvaluationState, format: u8) { +pub extern "C" fn jrsonnet_set_trace_format(vm: &State, format: u8) { use jrsonnet_evaluator::trace::JsFormat; match format { 1 => vm.set_trace_format(Box::new(JsFormat)), --- a/bindings/jsonnet/src/lib.rs +++ b/bindings/jsonnet/src/lib.rs @@ -16,7 +16,7 @@ }; use import::NativeImportResolver; -use jrsonnet_evaluator::{EvaluationState, IStr, ManifestFormat, Val}; +use jrsonnet_evaluator::{IStr, ManifestFormat, State, Val}; /// WASM stub #[cfg(target_arch = "wasm32")] @@ -29,8 +29,8 @@ } #[no_mangle] -pub extern "C" fn jsonnet_make() -> *mut EvaluationState { - let state = EvaluationState::default(); +pub extern "C" fn jsonnet_make() -> *mut State { + let state = State::default(); state.with_stdlib(); state.settings_mut().import_resolver = Box::new(NativeImportResolver::default()); Box::into_raw(Box::new(state)) @@ -39,23 +39,23 @@ /// # Safety #[no_mangle] #[allow(clippy::boxed_local)] -pub unsafe extern "C" fn jsonnet_destroy(vm: *mut EvaluationState) { +pub unsafe extern "C" fn jsonnet_destroy(vm: *mut State) { Box::from_raw(vm); } #[no_mangle] -pub extern "C" fn jsonnet_max_stack(vm: &EvaluationState, v: c_uint) { +pub extern "C" fn jsonnet_max_stack(vm: &State, v: c_uint) { vm.settings_mut().max_stack = v as usize; } // jrsonnet currently have no GC, so these functions is no-op #[no_mangle] -pub extern "C" fn jsonnet_gc_min_objects(_vm: &EvaluationState, _v: c_uint) {} +pub extern "C" fn jsonnet_gc_min_objects(_vm: &State, _v: c_uint) {} #[no_mangle] -pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &EvaluationState, _v: c_double) {} +pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &State, _v: c_double) {} #[no_mangle] -pub extern "C" fn jsonnet_string_output(vm: &EvaluationState, v: c_int) { +pub extern "C" fn jsonnet_string_output(vm: &State, v: c_int) { match v { 1 => vm.set_manifest_format(ManifestFormat::String), 0 => vm.set_manifest_format(ManifestFormat::Json { @@ -71,11 +71,7 @@ /// /// This function is most definitely broken, but it works somehow, see TODO inside #[no_mangle] -pub unsafe extern "C" fn jsonnet_realloc( - _vm: &EvaluationState, - buf: *mut u8, - sz: usize, -) -> *mut u8 { +pub unsafe extern "C" fn jsonnet_realloc(_vm: &State, buf: *mut u8, sz: usize) -> *mut u8 { if buf.is_null() { assert!(sz != 0); return std::alloc::alloc(Layout::from_size_align(sz, std::mem::align_of::()).unwrap()); @@ -95,12 +91,12 @@ /// # Safety #[no_mangle] #[allow(clippy::boxed_local)] -pub unsafe extern "C" fn jsonnet_json_destroy(_vm: &EvaluationState, v: *mut Val) { +pub unsafe extern "C" fn jsonnet_json_destroy(_vm: &State, v: *mut Val) { Box::from_raw(v); } #[no_mangle] -pub extern "C" fn jsonnet_max_trace(vm: &EvaluationState, v: c_uint) { +pub extern "C" fn jsonnet_max_trace(vm: &State, v: c_uint) { vm.set_max_trace(v as usize) } @@ -109,28 +105,26 @@ /// This function is safe, if received v is a pointer to normal C string #[no_mangle] pub unsafe extern "C" fn jsonnet_evaluate_file( - vm: &EvaluationState, + vm: &State, filename: *const c_char, error: &mut c_int, ) -> *const c_char { - vm.run_in_state(|| { - let filename = CStr::from_ptr(filename); - match vm - .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap())) - .and_then(|v| vm.with_tla(v)) - .and_then(|v| vm.manifest(v)) - { - Ok(v) => { - *error = 0; - CString::new(&*v as &str).unwrap().into_raw() - } - Err(e) => { - *error = 1; - let out = vm.stringify_err(&e); - CString::new(&out as &str).unwrap().into_raw() - } + let filename = CStr::from_ptr(filename); + match vm + .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap())) + .and_then(|v| vm.with_tla(v)) + .and_then(|v| vm.manifest(v)) + { + Ok(v) => { + *error = 0; + CString::new(&*v as &str).unwrap().into_raw() + } + Err(e) => { + *error = 1; + let out = vm.stringify_err(&e); + CString::new(&out as &str).unwrap().into_raw() } - }) + } } /// # Safety @@ -138,33 +132,31 @@ /// This function is safe, if received v is a pointer to normal C string #[no_mangle] pub unsafe extern "C" fn jsonnet_evaluate_snippet( - vm: &EvaluationState, + vm: &State, filename: *const c_char, snippet: *const c_char, error: &mut c_int, ) -> *const c_char { - vm.run_in_state(|| { - let filename = CStr::from_ptr(filename); - let snippet = CStr::from_ptr(snippet); - match vm - .evaluate_snippet_raw( - PathBuf::from(filename.to_str().unwrap()).into(), - snippet.to_str().unwrap().into(), - ) - .and_then(|v| vm.with_tla(v)) - .and_then(|v| vm.manifest(v)) - { - Ok(v) => { - *error = 0; - CString::new(&*v as &str).unwrap().into_raw() - } - Err(e) => { - *error = 1; - let out = vm.stringify_err(&e); - CString::new(&out as &str).unwrap().into_raw() - } + let filename = CStr::from_ptr(filename); + let snippet = CStr::from_ptr(snippet); + match vm + .evaluate_snippet_raw( + PathBuf::from(filename.to_str().unwrap()).into(), + snippet.to_str().unwrap().into(), + ) + .and_then(|v| vm.with_tla(v)) + .and_then(|v| vm.manifest(v)) + { + Ok(v) => { + *error = 0; + CString::new(&*v as &str).unwrap().into_raw() } - }) + Err(e) => { + *error = 1; + let out = vm.stringify_err(&e); + CString::new(&out as &str).unwrap().into_raw() + } + } } fn multi_to_raw(multi: Vec<(IStr, IStr)>) -> *const c_char { @@ -187,60 +179,56 @@ /// # Safety #[no_mangle] pub unsafe extern "C" fn jsonnet_evaluate_file_multi( - vm: &EvaluationState, + vm: &State, filename: *const c_char, error: &mut c_int, ) -> *const c_char { - vm.run_in_state(|| { - let filename = CStr::from_ptr(filename); - match vm - .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap())) - .and_then(|v| vm.with_tla(v)) - .and_then(|v| vm.manifest_multi(v)) - { - Ok(v) => { - *error = 0; - multi_to_raw(v) - } - Err(e) => { - *error = 1; - let out = vm.stringify_err(&e); - CString::new(&out as &str).unwrap().into_raw() - } + let filename = CStr::from_ptr(filename); + match vm + .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap())) + .and_then(|v| vm.with_tla(v)) + .and_then(|v| vm.manifest_multi(v)) + { + Ok(v) => { + *error = 0; + multi_to_raw(v) + } + Err(e) => { + *error = 1; + let out = vm.stringify_err(&e); + CString::new(&out as &str).unwrap().into_raw() } - }) + } } /// # Safety #[no_mangle] pub unsafe extern "C" fn jsonnet_evaluate_snippet_multi( - vm: &EvaluationState, + vm: &State, filename: *const c_char, snippet: *const c_char, error: &mut c_int, ) -> *const c_char { - vm.run_in_state(|| { - let filename = CStr::from_ptr(filename); - let snippet = CStr::from_ptr(snippet); - match vm - .evaluate_snippet_raw( - PathBuf::from(filename.to_str().unwrap()).into(), - snippet.to_str().unwrap().into(), - ) - .and_then(|v| vm.with_tla(v)) - .and_then(|v| vm.manifest_multi(v)) - { - Ok(v) => { - *error = 0; - multi_to_raw(v) - } - Err(e) => { - *error = 1; - let out = vm.stringify_err(&e); - CString::new(&out as &str).unwrap().into_raw() - } + let filename = CStr::from_ptr(filename); + let snippet = CStr::from_ptr(snippet); + match vm + .evaluate_snippet_raw( + PathBuf::from(filename.to_str().unwrap()).into(), + snippet.to_str().unwrap().into(), + ) + .and_then(|v| vm.with_tla(v)) + .and_then(|v| vm.manifest_multi(v)) + { + Ok(v) => { + *error = 0; + multi_to_raw(v) + } + Err(e) => { + *error = 1; + let out = vm.stringify_err(&e); + CString::new(&out as &str).unwrap().into_raw() } - }) + } } fn stream_to_raw(multi: Vec) -> *const c_char { @@ -261,58 +249,54 @@ /// # Safety #[no_mangle] pub unsafe extern "C" fn jsonnet_evaluate_file_stream( - vm: &EvaluationState, + vm: &State, filename: *const c_char, error: &mut c_int, ) -> *const c_char { - vm.run_in_state(|| { - let filename = CStr::from_ptr(filename); - match vm - .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap())) - .and_then(|v| vm.with_tla(v)) - .and_then(|v| vm.manifest_stream(v)) - { - Ok(v) => { - *error = 0; - stream_to_raw(v) - } - Err(e) => { - *error = 1; - let out = vm.stringify_err(&e); - CString::new(&out as &str).unwrap().into_raw() - } + let filename = CStr::from_ptr(filename); + match vm + .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap())) + .and_then(|v| vm.with_tla(v)) + .and_then(|v| vm.manifest_stream(v)) + { + Ok(v) => { + *error = 0; + stream_to_raw(v) + } + Err(e) => { + *error = 1; + let out = vm.stringify_err(&e); + CString::new(&out as &str).unwrap().into_raw() } - }) + } } /// # Safety #[no_mangle] pub unsafe extern "C" fn jsonnet_evaluate_snippet_stream( - vm: &EvaluationState, + vm: &State, filename: *const c_char, snippet: *const c_char, error: &mut c_int, ) -> *const c_char { - vm.run_in_state(|| { - let filename = CStr::from_ptr(filename); - let snippet = CStr::from_ptr(snippet); - match vm - .evaluate_snippet_raw( - PathBuf::from(filename.to_str().unwrap()).into(), - snippet.to_str().unwrap().into(), - ) - .and_then(|v| vm.with_tla(v)) - .and_then(|v| vm.manifest_stream(v)) - { - Ok(v) => { - *error = 0; - stream_to_raw(v) - } - Err(e) => { - *error = 1; - let out = vm.stringify_err(&e); - CString::new(&out as &str).unwrap().into_raw() - } + let filename = CStr::from_ptr(filename); + let snippet = CStr::from_ptr(snippet); + match vm + .evaluate_snippet_raw( + PathBuf::from(filename.to_str().unwrap()).into(), + snippet.to_str().unwrap().into(), + ) + .and_then(|v| vm.with_tla(v)) + .and_then(|v| vm.manifest_stream(v)) + { + Ok(v) => { + *error = 0; + stream_to_raw(v) } - }) + Err(e) => { + *error = 1; + let out = vm.stringify_err(&e); + CString::new(&out as &str).unwrap().into_raw() + } + } } --- a/bindings/jsonnet/src/native.rs +++ b/bindings/jsonnet/src/native.rs @@ -1,5 +1,4 @@ use std::{ - convert::TryFrom, ffi::{c_void, CStr}, os::raw::{c_char, c_int}, path::Path, @@ -12,7 +11,8 @@ function::BuiltinParam, gc::TraceBox, native::{NativeCallback, NativeCallbackHandler}, - EvaluationState, IStr, Val, + typed::Typed, + IStr, State, Val, }; type JsonnetNativeCallback = unsafe extern "C" fn( @@ -29,7 +29,7 @@ cb: JsonnetNativeCallback, } impl NativeCallbackHandler for JsonnetNativeCallbackHandler { - fn call(&self, _from: Option>, args: &[Val]) -> Result { + fn call(&self, s: State, _from: Option>, args: &[Val]) -> Result { let mut n_args = Vec::new(); for a in args { n_args.push(Some(Box::new(a.clone()))); @@ -47,7 +47,7 @@ if success == 1 { Ok(v) } else { - let e = IStr::try_from(v).expect("error msg"); + let e = IStr::from_untyped(v, s).expect("error msg"); Err(Error::RuntimeError(e).into()) } } @@ -56,7 +56,7 @@ /// # Safety #[no_mangle] pub unsafe extern "C" fn jsonnet_native_callback( - vm: &EvaluationState, + vm: &State, name: *const c_char, cb: JsonnetNativeCallback, ctx: *const c_void, --- a/bindings/jsonnet/src/val_extract.rs +++ b/bindings/jsonnet/src/val_extract.rs @@ -5,21 +5,17 @@ os::raw::{c_char, c_double, c_int}, }; -use jrsonnet_evaluator::{EvaluationState, Val}; +use jrsonnet_evaluator::{State, Val}; #[no_mangle] -pub extern "C" fn jsonnet_json_extract_string(_vm: &EvaluationState, v: &Val) -> *mut c_char { +pub extern "C" fn jsonnet_json_extract_string(_vm: &State, v: &Val) -> *mut c_char { match v { Val::Str(s) => CString::new(&*s as &str).unwrap().into_raw(), _ => std::ptr::null_mut(), } } #[no_mangle] -pub extern "C" fn jsonnet_json_extract_number( - _vm: &EvaluationState, - v: &Val, - out: &mut c_double, -) -> c_int { +pub extern "C" fn jsonnet_json_extract_number(_vm: &State, v: &Val, out: &mut c_double) -> c_int { match v { Val::Num(n) => { *out = *n; @@ -29,7 +25,7 @@ } } #[no_mangle] -pub extern "C" fn jsonnet_json_extract_bool(_vm: &EvaluationState, v: &Val) -> c_int { +pub extern "C" fn jsonnet_json_extract_bool(_vm: &State, v: &Val) -> c_int { match v { Val::Bool(false) => 0, Val::Bool(true) => 1, @@ -37,7 +33,7 @@ } } #[no_mangle] -pub extern "C" fn jsonnet_json_extract_null(_vm: &EvaluationState, v: &Val) -> c_int { +pub extern "C" fn jsonnet_json_extract_null(_vm: &State, v: &Val) -> c_int { match v { Val::Null => 1, _ => 0, --- a/bindings/jsonnet/src/val_make.rs +++ b/bindings/jsonnet/src/val_make.rs @@ -6,43 +6,40 @@ }; use gcmodule::Cc; -use jrsonnet_evaluator::{val::ArrValue, EvaluationState, ObjValue, Val}; +use jrsonnet_evaluator::{val::ArrValue, ObjValue, State, Val}; /// # Safety /// /// This function is safe, if received v is a pointer to normal C string #[no_mangle] -pub unsafe extern "C" fn jsonnet_json_make_string( - _vm: &EvaluationState, - v: *const c_char, -) -> *mut Val { +pub unsafe extern "C" fn jsonnet_json_make_string(_vm: &State, v: *const c_char) -> *mut Val { let cstr = CStr::from_ptr(v); let str = cstr.to_str().unwrap(); Box::into_raw(Box::new(Val::Str(str.into()))) } #[no_mangle] -pub extern "C" fn jsonnet_json_make_number(_vm: &EvaluationState, v: c_double) -> *mut Val { +pub extern "C" fn jsonnet_json_make_number(_vm: &State, v: c_double) -> *mut Val { Box::into_raw(Box::new(Val::Num(v))) } #[no_mangle] -pub extern "C" fn jsonnet_json_make_bool(_vm: &EvaluationState, v: c_int) -> *mut Val { +pub extern "C" fn jsonnet_json_make_bool(_vm: &State, v: c_int) -> *mut Val { assert!(v == 0 || v == 1); Box::into_raw(Box::new(Val::Bool(v == 1))) } #[no_mangle] -pub extern "C" fn jsonnet_json_make_null(_vm: &EvaluationState) -> *mut Val { +pub extern "C" fn jsonnet_json_make_null(_vm: &State) -> *mut Val { Box::into_raw(Box::new(Val::Null)) } #[no_mangle] -pub extern "C" fn jsonnet_json_make_array(_vm: &EvaluationState) -> *mut Val { +pub extern "C" fn jsonnet_json_make_array(_vm: &State) -> *mut Val { Box::into_raw(Box::new(Val::Arr(ArrValue::Eager(Cc::new(Vec::new()))))) } #[no_mangle] -pub extern "C" fn jsonnet_json_make_object(_vm: &EvaluationState) -> *mut Val { +pub extern "C" fn jsonnet_json_make_object(_vm: &State) -> *mut Val { Box::into_raw(Box::new(Val::Obj(ObjValue::new_empty()))) } --- a/bindings/jsonnet/src/val_modify.rs +++ b/bindings/jsonnet/src/val_modify.rs @@ -5,17 +5,13 @@ use std::{ffi::CStr, os::raw::c_char}; use gcmodule::Cc; -use jrsonnet_evaluator::{val::ArrValue, EvaluationState, LazyVal, Val}; +use jrsonnet_evaluator::{val::ArrValue, LazyVal, State, Val}; /// # Safety /// /// Received arr value should be correct pointer to array allocated by make_array #[no_mangle] -pub unsafe extern "C" fn jsonnet_json_array_append( - _vm: &EvaluationState, - arr: &mut Val, - val: &Val, -) { +pub unsafe extern "C" fn jsonnet_json_array_append(_vm: &State, arr: &mut Val, val: &Val) { match arr { Val::Arr(old) => { let mut new = Vec::new(); @@ -34,7 +30,7 @@ /// This function is safe if passed name is ok #[no_mangle] pub unsafe extern "C" fn jsonnet_json_object_append( - _vm: &EvaluationState, + _vm: &State, obj: &mut Val, name: *const c_char, val: &Val, --- a/bindings/jsonnet/src/vars_tlas.rs +++ b/bindings/jsonnet/src/vars_tlas.rs @@ -2,15 +2,11 @@ use std::{ffi::CStr, os::raw::c_char}; -use jrsonnet_evaluator::EvaluationState; +use jrsonnet_evaluator::State; /// # Safety #[no_mangle] -pub unsafe extern "C" fn jsonnet_ext_var( - vm: &EvaluationState, - name: *const c_char, - value: *const c_char, -) { +pub unsafe extern "C" fn jsonnet_ext_var(vm: &State, name: *const c_char, value: *const c_char) { let name = CStr::from_ptr(name); let value = CStr::from_ptr(value); vm.add_ext_str( @@ -21,11 +17,7 @@ /// # Safety #[no_mangle] -pub unsafe extern "C" fn jsonnet_ext_code( - vm: &EvaluationState, - name: *const c_char, - value: *const c_char, -) { +pub unsafe extern "C" fn jsonnet_ext_code(vm: &State, name: *const c_char, value: *const c_char) { let name = CStr::from_ptr(name); let value = CStr::from_ptr(value); vm.add_ext_code( @@ -36,11 +28,7 @@ } /// # Safety #[no_mangle] -pub unsafe extern "C" fn jsonnet_tla_var( - vm: &EvaluationState, - name: *const c_char, - value: *const c_char, -) { +pub unsafe extern "C" fn jsonnet_tla_var(vm: &State, name: *const c_char, value: *const c_char) { let name = CStr::from_ptr(name); let value = CStr::from_ptr(value); vm.add_tla_str( @@ -50,11 +38,7 @@ } /// # Safety #[no_mangle] -pub unsafe extern "C" fn jsonnet_tla_code( - vm: &EvaluationState, - name: *const c_char, - value: *const c_char, -) { +pub unsafe extern "C" fn jsonnet_tla_code(vm: &State, name: *const c_char, value: *const c_char) { let name = CStr::from_ptr(name); let value = CStr::from_ptr(value); vm.add_tla_code( --- a/cmds/jrsonnet/src/main.rs +++ b/cmds/jrsonnet/src/main.rs @@ -7,7 +7,7 @@ use clap::{AppSettings, IntoApp, Parser}; use clap_complete::Shell; use jrsonnet_cli::{ConfigureState, GcOpts, GeneralOpts, InputOpts, ManifestOpts, OutputOpts}; -use jrsonnet_evaluator::{error::LocError, EvaluationState}; +use jrsonnet_evaluator::{error::LocError, State}; #[cfg(feature = "mimalloc")] #[global_allocator] @@ -102,10 +102,10 @@ fn main_catch(opts: Opts) -> bool { let _printer = opts.gc.stats_printer(); - let state = EvaluationState::default(); - if let Err(e) = main_real(&state, opts) { + let s = State::default(); + if let Err(e) = main_real(&s, opts) { if let Error::Evaluation(e) = e { - eprintln!("{}", state.stringify_err(&e)); + eprintln!("{}", s.stringify_err(&e)); } else { eprintln!("{}", e); } @@ -114,13 +114,13 @@ true } -fn main_real(state: &EvaluationState, opts: Opts) -> Result<(), Error> { +fn main_real(s: &State, opts: Opts) -> Result<(), Error> { opts.gc.configure_global(); - opts.general.configure(state)?; - opts.manifest.configure(state)?; + opts.general.configure(s)?; + opts.manifest.configure(s)?; let val = if opts.input.exec { - state.evaluate_snippet_raw( + s.evaluate_snippet_raw( PathBuf::from("").into(), (&opts.input.input as &str).into(), )? @@ -128,12 +128,12 @@ let mut input = Vec::new(); std::io::stdin().read_to_end(&mut input)?; let input_str = std::str::from_utf8(&input)?.into(); - state.evaluate_snippet_raw(PathBuf::from("").into(), input_str)? + s.evaluate_snippet_raw(PathBuf::from("").into(), input_str)? } else { - state.evaluate_file_raw(&PathBuf::from(opts.input.input))? + s.evaluate_file_raw(&PathBuf::from(opts.input.input))? }; - let val = state.with_tla(val)?; + let val = s.with_tla(val)?; if let Some(multi) = opts.output.multi { if opts.output.create_output_dirs { @@ -141,7 +141,7 @@ dir.pop(); create_dir_all(dir)?; } - for (file, data) in state.manifest_multi(val)?.iter() { + for (file, data) in s.manifest_multi(val)?.iter() { let mut path = multi.clone(); path.push(file as &str); if opts.output.create_output_dirs { @@ -160,9 +160,9 @@ create_dir_all(dir)?; } let mut file = File::create(path)?; - writeln!(file, "{}", state.manifest(val)?)?; + writeln!(file, "{}", s.manifest(val)?)?; } else { - let output = state.manifest(val)?; + let output = s.manifest(val)?; if !output.is_empty() { println!("{}", output); } --- a/crates/jrsonnet-cli/src/ext.rs +++ b/crates/jrsonnet-cli/src/ext.rs @@ -1,7 +1,7 @@ use std::{fs::read_to_string, str::FromStr}; use clap::Parser; -use jrsonnet_evaluator::{error::Result, EvaluationState}; +use jrsonnet_evaluator::{error::Result, State}; use crate::ConfigureState; @@ -100,18 +100,18 @@ ext_code_file: Vec, } impl ConfigureState for ExtVarOpts { - fn configure(&self, state: &EvaluationState) -> Result<()> { + fn configure(&self, s: &State) -> Result<()> { for ext in self.ext_str.iter() { - state.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into()); + s.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into()); } for ext in self.ext_str_file.iter() { - state.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into()); + s.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into()); } for ext in self.ext_code.iter() { - state.add_ext_code((&ext.name as &str).into(), (&ext.value as &str).into())?; + s.add_ext_code((&ext.name as &str).into(), (&ext.value as &str).into())?; } for ext in self.ext_code_file.iter() { - state.add_ext_code((&ext.name as &str).into(), (&ext.value as &str).into())?; + s.add_ext_code((&ext.name as &str).into(), (&ext.value as &str).into())?; } Ok(()) } --- a/crates/jrsonnet-cli/src/lib.rs +++ b/crates/jrsonnet-cli/src/lib.rs @@ -7,13 +7,13 @@ use clap::Parser; pub use ext::*; -use jrsonnet_evaluator::{error::Result, EvaluationState, FileImportResolver}; +use jrsonnet_evaluator::{error::Result, FileImportResolver, State}; pub use manifest::*; pub use tla::*; pub use trace::*; pub trait ConfigureState { - fn configure(&self, state: &EvaluationState) -> Result<()>; + fn configure(&self, s: &State) -> Result<()>; } #[derive(Parser)] @@ -50,9 +50,9 @@ jpath: Vec, } impl ConfigureState for MiscOpts { - fn configure(&self, state: &EvaluationState) -> Result<()> { + fn configure(&self, s: &State) -> Result<()> { if !self.no_stdlib { - state.with_stdlib(); + s.with_stdlib(); } let mut library_paths = self.jpath.clone(); @@ -61,9 +61,9 @@ library_paths.extend(env::split_paths(path.as_os_str())); } - state.set_import_resolver(Box::new(FileImportResolver { library_paths })); + s.set_import_resolver(Box::new(FileImportResolver { library_paths })); - state.set_max_stack(self.max_stack); + s.set_max_stack(self.max_stack); Ok(()) } } @@ -85,12 +85,12 @@ } impl ConfigureState for GeneralOpts { - fn configure(&self, state: &EvaluationState) -> Result<()> { + fn configure(&self, s: &State) -> Result<()> { // Configure trace first, because tla-code/ext-code can throw - self.trace.configure(state)?; - self.misc.configure(state)?; - self.tla.configure(state)?; - self.ext.configure(state)?; + self.trace.configure(s)?; + self.misc.configure(s)?; + self.tla.configure(s)?; + self.ext.configure(s)?; Ok(()) } } --- a/crates/jrsonnet-cli/src/manifest.rs +++ b/crates/jrsonnet-cli/src/manifest.rs @@ -1,7 +1,7 @@ use std::{path::PathBuf, str::FromStr}; use clap::Parser; -use jrsonnet_evaluator::{error::Result, EvaluationState, ManifestFormat}; +use jrsonnet_evaluator::{error::Result, ManifestFormat, State}; use crate::ConfigureState; @@ -49,20 +49,20 @@ exp_preserve_order: bool, } impl ConfigureState for ManifestOpts { - fn configure(&self, state: &EvaluationState) -> Result<()> { + fn configure(&self, s: &State) -> Result<()> { if self.string { - state.set_manifest_format(ManifestFormat::String); + s.set_manifest_format(ManifestFormat::String); } else { #[cfg(feature = "exp-preserve-order")] let preserve_order = self.exp_preserve_order; match self.format { - ManifestFormatName::String => state.set_manifest_format(ManifestFormat::String), - ManifestFormatName::Json => state.set_manifest_format(ManifestFormat::Json { + ManifestFormatName::String => s.set_manifest_format(ManifestFormat::String), + ManifestFormatName::Json => s.set_manifest_format(ManifestFormat::Json { padding: self.line_padding.unwrap_or(3), #[cfg(feature = "exp-preserve-order")] preserve_order, }), - ManifestFormatName::Yaml => state.set_manifest_format(ManifestFormat::Yaml { + ManifestFormatName::Yaml => s.set_manifest_format(ManifestFormat::Yaml { padding: self.line_padding.unwrap_or(2), #[cfg(feature = "exp-preserve-order")] preserve_order, @@ -70,9 +70,7 @@ } } if self.yaml_stream { - state.set_manifest_format(ManifestFormat::YamlStream(Box::new( - state.manifest_format(), - ))) + s.set_manifest_format(ManifestFormat::YamlStream(Box::new(s.manifest_format()))) } Ok(()) } --- a/crates/jrsonnet-cli/src/tla.rs +++ b/crates/jrsonnet-cli/src/tla.rs @@ -1,5 +1,5 @@ use clap::Parser; -use jrsonnet_evaluator::{error::Result, EvaluationState}; +use jrsonnet_evaluator::{error::Result, State}; use crate::{ConfigureState, ExtFile, ExtStr}; @@ -47,18 +47,18 @@ tla_code_file: Vec, } impl ConfigureState for TLAOpts { - fn configure(&self, state: &EvaluationState) -> Result<()> { + fn configure(&self, s: &State) -> Result<()> { for tla in self.tla_str.iter() { - state.add_tla_str((&tla.name as &str).into(), (&tla.value as &str).into()); + s.add_tla_str((&tla.name as &str).into(), (&tla.value as &str).into()); } for tla in self.tla_str_file.iter() { - state.add_tla_str((&tla.name as &str).into(), (&tla.value as &str).into()) + s.add_tla_str((&tla.name as &str).into(), (&tla.value as &str).into()) } for tla in self.tla_code.iter() { - state.add_tla_code((&tla.name as &str).into(), (&tla.value as &str).into())?; + s.add_tla_code((&tla.name as &str).into(), (&tla.value as &str).into())?; } for tla in self.tla_code_file.iter() { - state.add_tla_code((&tla.name as &str).into(), (&tla.value as &str).into())?; + s.add_tla_code((&tla.name as &str).into(), (&tla.value as &str).into())?; } Ok(()) } --- a/crates/jrsonnet-cli/src/trace.rs +++ b/crates/jrsonnet-cli/src/trace.rs @@ -4,7 +4,7 @@ use jrsonnet_evaluator::{ error::Result, trace::{CompactFormat, ExplainingFormat, PathResolver}, - EvaluationState, + State, }; use crate::ConfigureState; @@ -41,22 +41,22 @@ max_trace: usize, } impl ConfigureState for TraceOpts { - fn configure(&self, state: &EvaluationState) -> Result<()> { + fn configure(&self, s: &State) -> Result<()> { let resolver = PathResolver::Absolute; match self .trace_format .as_ref() .unwrap_or(&TraceFormatName::Compact) { - TraceFormatName::Compact => state.set_trace_format(Box::new(CompactFormat { + TraceFormatName::Compact => s.set_trace_format(Box::new(CompactFormat { resolver, padding: 4, })), TraceFormatName::Explaining => { - state.set_trace_format(Box::new(ExplainingFormat { resolver })) + s.set_trace_format(Box::new(ExplainingFormat { resolver })) } } - state.set_max_trace(self.max_trace); + s.set_max_trace(self.max_trace); Ok(()) } } --- a/crates/jrsonnet-evaluator/src/builtin/format.rs +++ b/crates/jrsonnet-evaluator/src/builtin/format.rs @@ -1,14 +1,12 @@ //! faster std.format impl #![allow(clippy::too_many_arguments)] -use std::convert::TryFrom; - use gcmodule::Trace; use jrsonnet_interner::IStr; use jrsonnet_types::ValType; use thiserror::Error; -use crate::{error::Error::*, throw, LocError, ObjValue, Result, Val}; +use crate::{error::Error::*, throw, typed::Typed, LocError, ObjValue, Result, State, Val}; #[derive(Debug, Clone, Error, Trace)] pub enum FormatError { @@ -464,6 +462,7 @@ } pub fn format_code( + s: State, out: &mut String, value: &Val, code: &Code, @@ -485,9 +484,9 @@ let mut tmp_out = String::new(); match code.convtype { - ConvTypeV::String => tmp_out.push_str(&value.clone().to_string()?), + ConvTypeV::String => tmp_out.push_str(&value.clone().to_string(s)?), ConvTypeV::Decimal => { - let value = f64::try_from(value.clone())?; + let value = f64::from_untyped(value.clone(), s)?; render_decimal( &mut tmp_out, value as i64, @@ -498,7 +497,7 @@ ); } ConvTypeV::Octal => { - let value = f64::try_from(value.clone())?; + let value = f64::from_untyped(value.clone(), s)?; render_octal( &mut tmp_out, value as i64, @@ -510,7 +509,7 @@ ); } ConvTypeV::Hexadecimal => { - let value = f64::try_from(value.clone())?; + let value = f64::from_untyped(value.clone(), s)?; render_hexadecimal( &mut tmp_out, value as i64, @@ -523,7 +522,7 @@ ); } ConvTypeV::Scientific => { - let value = f64::try_from(value.clone())?; + let value = f64::from_untyped(value.clone(), s)?; render_float_sci( &mut tmp_out, value, @@ -537,7 +536,7 @@ ); } ConvTypeV::Float => { - let value = f64::try_from(value.clone())?; + let value = f64::from_untyped(value.clone(), s)?; render_float( &mut tmp_out, value, @@ -550,7 +549,7 @@ ); } ConvTypeV::Shorter => { - let value = f64::try_from(value.clone())?; + let value = f64::from_untyped(value.clone(), s)?; let exponent = value.log10().floor(); if exponent < -4.0 || exponent >= fpprec as f64 { render_float_sci( @@ -617,7 +616,7 @@ Ok(()) } -pub fn format_arr(str: &str, mut values: &[Val]) -> Result { +pub fn format_arr(s: State, str: &str, mut values: &[Val]) -> Result { let codes = parse_codes(str)?; let mut out = String::new(); @@ -634,7 +633,7 @@ } let value = &values[0]; values = &values[1..]; - usize::try_from(value.clone())? + usize::from_untyped(value.clone(), s.clone())? } Width::Fixed(n) => n, }; @@ -645,7 +644,7 @@ } let value = &values[0]; values = &values[1..]; - Some(usize::try_from(value.clone())?) + Some(usize::from_untyped(value.clone(), s.clone())?) } Some(Width::Fixed(n)) => Some(n), None => None, @@ -663,7 +662,7 @@ value }; - format_code(&mut out, value, &c, width, precision)?; + format_code(s.clone(), &mut out, value, &c, width, precision)?; } } } @@ -671,7 +670,7 @@ Ok(out) } -pub fn format_obj(str: &str, values: &ObjValue) -> Result { +pub fn format_obj(s: State, str: &str, values: &ObjValue) -> Result { let codes = parse_codes(str)?; let mut out = String::new(); @@ -703,14 +702,14 @@ if f.is_empty() { throw!(MappingKeysRequired); } - if let Some(v) = values.get(f.clone())? { + if let Some(v) = values.get(s.clone(), f.clone())? { v } else { throw!(NoSuchFormatField(f)); } }; - format_code(&mut out, &value, &c, width, precision)?; + format_code(s.clone(), &mut out, &value, &c, width, precision)?; } } } --- a/crates/jrsonnet-evaluator/src/builtin/manifest.rs +++ b/crates/jrsonnet-evaluator/src/builtin/manifest.rs @@ -1,6 +1,6 @@ use crate::{ error::{Error::*, Result}, - push_description_frame, throw, Val, + throw, State, Val, }; #[derive(PartialEq, Clone, Copy)] @@ -25,12 +25,13 @@ pub preserve_order: bool, } -pub fn manifest_json_ex(val: &Val, options: &ManifestJsonOptions<'_>) -> Result { +pub fn manifest_json_ex(s: State, val: &Val, options: &ManifestJsonOptions<'_>) -> Result { let mut out = String::new(); - manifest_json_ex_buf(val, &mut out, &mut String::new(), options)?; + manifest_json_ex_buf(s, val, &mut out, &mut String::new(), options)?; Ok(out) } fn manifest_json_ex_buf( + s: State, val: &Val, buf: &mut String, cur_padding: &mut String, @@ -58,7 +59,7 @@ let old_len = cur_padding.len(); cur_padding.push_str(options.padding); - for (i, item) in items.iter().enumerate() { + for (i, item) in items.iter(s.clone()).enumerate() { if i != 0 { buf.push(','); if mtype == ManifestType::ToString { @@ -68,7 +69,7 @@ } } buf.push_str(cur_padding); - manifest_json_ex_buf(&item?, buf, cur_padding, options)?; + manifest_json_ex_buf(s.clone(), &item?, buf, cur_padding, options)?; } cur_padding.truncate(old_len); @@ -85,7 +86,7 @@ buf.push(']'); } Val::Obj(obj) => { - obj.run_assertions()?; + obj.run_assertions(s.clone())?; buf.push('{'); let fields = obj.fields( #[cfg(feature = "exp-preserve-order")] @@ -110,11 +111,11 @@ buf.push_str(cur_padding); escape_string_json_buf(&field, buf); buf.push_str(options.key_val_sep); - push_description_frame( + s.push_description( || format!("field <{}> manifestification", field.clone()), || { - let value = obj.get(field.clone())?.unwrap(); - manifest_json_ex_buf(&value, buf, cur_padding, options)?; + let value = obj.get(s.clone(), field.clone())?.unwrap(); + manifest_json_ex_buf(s.clone(), &value, buf, cur_padding, options)?; Ok(Val::Null) }, )?; @@ -221,12 +222,13 @@ || string.parse::().is_ok() } -pub fn manifest_yaml_ex(val: &Val, options: &ManifestYamlOptions<'_>) -> Result { +pub fn manifest_yaml_ex(s: State, val: &Val, options: &ManifestYamlOptions<'_>) -> Result { let mut out = String::new(); - manifest_yaml_ex_buf(val, &mut out, &mut String::new(), options)?; + manifest_yaml_ex_buf(s, val, &mut out, &mut String::new(), options)?; Ok(out) } fn manifest_yaml_ex_buf( + s: State, val: &Val, buf: &mut String, cur_padding: &mut String, @@ -249,7 +251,7 @@ buf.push('|'); for line in s.split('\n') { buf.push('\n'); - buf.push_str(&cur_padding); + buf.push_str(cur_padding); buf.push_str(options.padding); buf.push_str(line); } @@ -264,7 +266,7 @@ if a.is_empty() { buf.push_str("[]"); } else { - for (i, item) in a.iter().enumerate() { + for (i, item) in a.iter(s.clone()).enumerate() { if i != 0 { buf.push('\n'); buf.push_str(cur_padding); @@ -288,7 +290,7 @@ if extra_padding { cur_padding.push_str(options.padding); } - manifest_yaml_ex_buf(&item, buf, cur_padding, options)?; + manifest_yaml_ex_buf(s.clone(), &item, buf, cur_padding, options)?; cur_padding.truncate(prev_len); } } @@ -316,7 +318,7 @@ } buf.push(':'); let prev_len = cur_padding.len(); - let item = o.get(key.clone())?.expect("field exists"); + let item = o.get(s.clone(), key.clone())?.expect("field exists"); match &item { Val::Arr(a) if !a.is_empty() => { buf.push('\n'); @@ -332,7 +334,7 @@ } _ => buf.push(' '), } - manifest_yaml_ex_buf(&item, buf, cur_padding, options)?; + manifest_yaml_ex_buf(s.clone(), &item, buf, cur_padding, options)?; cur_padding.truncate(prev_len); } } --- a/crates/jrsonnet-evaluator/src/builtin/mod.rs +++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs @@ -1,7 +1,4 @@ -use std::{ - collections::HashMap, - convert::{TryFrom, TryInto}, -}; +use std::collections::HashMap; use format::{format_arr, format_obj}; use gcmodule::Cc; @@ -14,10 +11,10 @@ error::{Error::*, Result}, function::{CallLocation, StaticBuiltin}, operator::evaluate_mod_op, - push_frame, throw, - typed::{Any, BoundedUsize, Bytes, Either2, Either4, PositiveF64, VecVal, M1}, + throw, + typed::{Any, BoundedUsize, Bytes, Either2, Either4, PositiveF64, Typed, VecVal, M1}, val::{equals, primitive_equals, ArrValue, FuncVal, IndexableVal, Slice}, - with_state, Either, ObjValue, Val, + Either, ObjValue, State, Val, }; pub mod stdlib; @@ -29,15 +26,15 @@ pub mod manifest; pub mod sort; -pub fn std_format(str: IStr, vals: Val) -> Result { - push_frame( +pub fn std_format(s: State, str: IStr, vals: Val) -> Result { + s.push( CallLocation::native(), || format!("std.format of {}", str), || { Ok(match vals { - Val::Arr(vals) => format_arr(&str, &vals.evaluated()?)?, - Val::Obj(obj) => format_obj(&str, &obj)?, - o => format_arr(&str, &[o])?, + Val::Arr(vals) => format_arr(s.clone(), &str, &vals.evaluated(s.clone())?)?, + Val::Obj(obj) => format_obj(s.clone(), &str, &obj)?, + o => format_arr(s.clone(), &str, &[o])?, }) }, ) @@ -173,10 +170,10 @@ } #[jrsonnet_macros::builtin] -fn builtin_make_array(sz: usize, func: FuncVal) -> Result { +fn builtin_make_array(s: State, sz: usize, func: FuncVal) -> Result { let mut out = Vec::with_capacity(sz); for i in 0..sz { - out.push(func.evaluate_simple(&[i as f64].as_slice())?) + out.push(func.evaluate_simple(s.clone(), &[i as f64].as_slice())?) } Ok(VecVal(Cc::new(out))) } @@ -210,23 +207,25 @@ } #[jrsonnet_macros::builtin] -fn builtin_parse_json(s: IStr) -> Result { - let value: serde_json::Value = serde_json::from_str(&s) +fn builtin_parse_json(st: State, s: IStr) -> Result { + use serde_json::Value; + let value: Value = serde_json::from_str(&s) .map_err(|e| RuntimeError(format!("failed to parse json: {}", e).into()))?; - Ok(Any(Val::try_from(&value)?)) + Ok(Any(Value::into_untyped(value, st)?)) } #[jrsonnet_macros::builtin] -fn builtin_parse_yaml(s: IStr) -> Result { +fn builtin_parse_yaml(st: State, s: IStr) -> Result { + use serde_json::Value; let value = serde_yaml::Deserializer::from_str_with_quirks( &s, DeserializingQuirks { old_octals: true }, ); let mut out = vec![]; for item in value { - let value = serde_json::Value::deserialize(item) + let value = Value::deserialize(item) .map_err(|e| RuntimeError(format!("failed to parse yaml: {}", e).into()))?; - let val = Val::try_from(&value)?; + let val = Value::into_untyped(value, st.clone())?; out.push(val); } Ok(Any(if out.is_empty() { @@ -259,8 +258,8 @@ } #[jrsonnet_macros::builtin] -fn builtin_equals(a: Any, b: Any) -> Result { - equals(&a.0, &b.0) +fn builtin_equals(s: State, a: Any, b: Any) -> Result { + equals(s, &a.0, &b.0) } #[jrsonnet_macros::builtin] @@ -269,9 +268,10 @@ } #[jrsonnet_macros::builtin] -fn builtin_mod(a: Either![f64, IStr], b: Any) -> Result { +fn builtin_mod(s: State, a: Either![f64, IStr], b: Any) -> Result { use Either2::*; Ok(Any(evaluate_mod_op( + s, &match a { A(v) => Val::Num(v), B(s) => Val::Str(s), @@ -362,35 +362,49 @@ } #[jrsonnet_macros::builtin] -fn builtin_ext_var(x: IStr) -> Result { - Ok(Any(with_state(|s| s.settings().ext_vars.get(&x).cloned()) +fn builtin_ext_var(s: State, x: IStr) -> Result { + Ok(Any(s + .settings() + .ext_vars + .get(&x) + .cloned() .ok_or(UndefinedExternalVariable(x))?)) } #[jrsonnet_macros::builtin] -fn builtin_native(name: IStr) -> Result { - Ok(with_state(|s| s.settings().ext_natives.get(&name).cloned()) +fn builtin_native(s: State, name: IStr) -> Result { + Ok(s.settings() + .ext_natives + .get(&name) + .cloned() .map(|v| FuncVal::Builtin(v.clone())) .ok_or(UndefinedExternalFunction(name))?) } #[jrsonnet_macros::builtin] -fn builtin_filter(func: FuncVal, arr: ArrValue) -> Result { - arr.filter(|val| bool::try_from(func.evaluate_simple(&[Any(val.clone())].as_slice())?)) +fn builtin_filter(s: State, func: FuncVal, arr: ArrValue) -> Result { + arr.filter(s.clone(), |val| { + bool::from_untyped( + func.evaluate_simple(s.clone(), &[Any(val.clone())].as_slice())?, + s.clone(), + ) + }) } #[jrsonnet_macros::builtin] -fn builtin_map(func: FuncVal, arr: ArrValue) -> Result { - arr.map(|val| func.evaluate_simple(&[Any(val)].as_slice())) +fn builtin_map(s: State, func: FuncVal, arr: ArrValue) -> Result { + arr.map(s.clone(), |val| { + func.evaluate_simple(s.clone(), &[Any(val)].as_slice()) + }) } #[jrsonnet_macros::builtin] -fn builtin_flatmap(func: FuncVal, arr: IndexableVal) -> Result { +fn builtin_flatmap(s: State, func: FuncVal, arr: IndexableVal) -> Result { match arr { - IndexableVal::Str(s) => { + IndexableVal::Str(str) => { let mut out = String::new(); - for c in s.chars() { - match func.evaluate_simple(&[c.to_string()].as_slice())? { + for c in str.chars() { + match func.evaluate_simple(s.clone(), &[c.to_string()].as_slice())? { Val::Str(o) => out.push_str(&o), _ => throw!(RuntimeError( "in std.join all items should be strings".into() @@ -401,11 +415,11 @@ } IndexableVal::Arr(a) => { let mut out = Vec::new(); - for el in a.iter() { + for el in a.iter(s.clone()) { let el = el?; - match func.evaluate_simple(&[Any(el)].as_slice())? { + match func.evaluate_simple(s.clone(), &[Any(el)].as_slice())? { Val::Arr(o) => { - for oe in o.iter() { + for oe in o.iter(s.clone()) { out.push(oe?) } } @@ -420,38 +434,39 @@ } #[jrsonnet_macros::builtin] -fn builtin_foldl(func: FuncVal, arr: ArrValue, init: Any) -> Result { +fn builtin_foldl(s: State, func: FuncVal, arr: ArrValue, init: Any) -> Result { let mut acc = init.0; - for i in arr.iter() { - acc = func.evaluate_simple(&[Any(acc), Any(i?)].as_slice())?; + for i in arr.iter(s.clone()) { + acc = func.evaluate_simple(s.clone(), &[Any(acc), Any(i?)].as_slice())?; } Ok(Any(acc)) } #[jrsonnet_macros::builtin] -fn builtin_foldr(func: FuncVal, arr: ArrValue, init: Any) -> Result { +fn builtin_foldr(s: State, func: FuncVal, arr: ArrValue, init: Any) -> Result { let mut acc = init.0; - for i in arr.iter().rev() { - acc = func.evaluate_simple(&[Any(i?), Any(acc)].as_slice())?; + for i in arr.iter(s.clone()).rev() { + acc = func.evaluate_simple(s.clone(), &[Any(i?), Any(acc)].as_slice())?; } Ok(Any(acc)) } #[jrsonnet_macros::builtin] #[allow(non_snake_case)] -fn builtin_sort(arr: ArrValue, keyF: Option) -> Result { +fn builtin_sort(s: State, arr: ArrValue, keyF: Option) -> Result { if arr.len() <= 1 { return Ok(arr); } Ok(ArrValue::Eager(sort::sort( - arr.evaluated()?, + s.clone(), + arr.evaluated(s)?, keyF.as_ref(), )?)) } #[jrsonnet_macros::builtin] -fn builtin_format(str: IStr, vals: Any) -> Result { - std_format(str, vals.0) +fn builtin_format(s: State, str: IStr, vals: Any) -> Result { + std_format(s, str, vals.0) } #[jrsonnet_macros::builtin] @@ -485,17 +500,15 @@ } #[jrsonnet_macros::builtin] -fn builtin_trace(loc: CallLocation, str: IStr, rest: Any) -> Result { +fn builtin_trace(s: State, loc: CallLocation, str: IStr, rest: Any) -> Result { eprint!("TRACE:"); if let Some(loc) = loc.0 { - with_state(|s| { - let locs = s.map_source_locations(&loc.0, &[loc.1]); - eprint!( - " {}:{}", - loc.0.file_name().unwrap().to_str().unwrap(), - locs[0].line - ); - }); + let locs = s.map_source_locations(&loc.0, &[loc.1]); + eprint!( + " {}:{}", + loc.0.file_name().unwrap().to_str().unwrap(), + locs[0].line + ); } eprintln!(" {}", str); Ok(rest) as Result @@ -526,26 +539,25 @@ } #[jrsonnet_macros::builtin] -fn builtin_join(sep: IndexableVal, arr: ArrValue) -> Result { +fn builtin_join(s: State, sep: IndexableVal, arr: ArrValue) -> Result { Ok(match sep { IndexableVal::Arr(joiner_items) => { let mut out = Vec::new(); let mut first = true; - for item in arr.iter() { + for item in arr.iter(s.clone()) { let item = item?.clone(); if let Val::Arr(items) = item { if !first { out.reserve(joiner_items.len()); // TODO: extend - for item in joiner_items.iter() { + for item in joiner_items.iter(s.clone()) { out.push(item?); } } first = false; out.reserve(items.len()); - // TODO: extend - for item in items.iter() { + for item in items.iter(s.clone()) { out.push(item?); } } else { @@ -561,7 +573,7 @@ let mut out = String::new(); let mut first = true; - for item in arr.iter() { + for item in arr.iter(s) { let item = item?.clone(); if let Val::Str(item) = item { if !first { @@ -588,6 +600,7 @@ #[jrsonnet_macros::builtin] fn builtin_manifest_json_ex( + s: State, value: Any, indent: IStr, newline: Option, @@ -597,6 +610,7 @@ let newline = newline.as_deref().unwrap_or("\n"); let key_val_sep = key_val_sep.as_deref().unwrap_or(": "); manifest_json_ex( + s, &value.0, &ManifestJsonOptions { padding: &indent, @@ -611,12 +625,14 @@ #[jrsonnet_macros::builtin] fn builtin_manifest_yaml_doc( + s: State, value: Any, indent_array_in_object: Option, quote_keys: Option, #[cfg(feature = "exp-preserve-order")] preserve_order: Option, ) -> Result { manifest_yaml_ex( + s, &value.0, &ManifestYamlOptions { padding: " ", @@ -670,16 +686,16 @@ } #[jrsonnet_macros::builtin] -fn builtin_member(arr: IndexableVal, x: Any) -> Result { +fn builtin_member(s: State, arr: IndexableVal, x: Any) -> Result { match arr { - IndexableVal::Str(s) => { - let x: IStr = IStr::try_from(x.0)?; - Ok(!x.is_empty() && s.contains(&*x)) + IndexableVal::Str(str) => { + let x: IStr = IStr::from_untyped(x.0, s)?; + Ok(!x.is_empty() && str.contains(&*x)) } IndexableVal::Arr(a) => { - for item in a.iter() { + for item in a.iter(s.clone()) { let item = item?; - if equals(&item, &x.0)? { + if equals(s.clone(), &item, &x.0)? { return Ok(true); } } @@ -689,10 +705,10 @@ } #[jrsonnet_macros::builtin] -fn builtin_count(arr: Vec, v: Any) -> Result { +fn builtin_count(s: State, arr: Vec, v: Any) -> Result { let mut count = 0; for item in arr.iter() { - if equals(&item.0, &v.0)? { + if equals(s.clone(), &item.0, &v.0)? { count += 1; } } @@ -700,9 +716,9 @@ } #[jrsonnet_macros::builtin] -fn builtin_any(arr: ArrValue) -> Result { - for v in arr.iter() { - let v: bool = v?.try_into()?; +fn builtin_any(s: State, arr: ArrValue) -> Result { + for v in arr.iter(s.clone()) { + let v = bool::from_untyped(v?, s.clone())?; if v { return Ok(true); } @@ -711,9 +727,9 @@ } #[jrsonnet_macros::builtin] -fn builtin_all(arr: ArrValue) -> Result { - for v in arr.iter() { - let v: bool = v?.try_into()?; +fn builtin_all(s: State, arr: ArrValue) -> Result { + for v in arr.iter(s.clone()) { + let v = bool::from_untyped(v?, s.clone())?; if !v { return Ok(false); } --- a/crates/jrsonnet-evaluator/src/builtin/sort.rs +++ b/crates/jrsonnet-evaluator/src/builtin/sort.rs @@ -5,7 +5,7 @@ throw, typed::Any, val::FuncVal, - Val, + State, Val, }; #[derive(Debug, Clone, thiserror::Error, Trace)] @@ -63,7 +63,7 @@ Ok(sort_type) } -pub fn sort(values: Cc>, key_getter: Option<&FuncVal>) -> Result>> { +pub fn sort(s: State, values: Cc>, key_getter: Option<&FuncVal>) -> Result>> { if values.len() <= 1 { return Ok(values); } @@ -73,7 +73,7 @@ for value in values.iter() { vk.push(( value.clone(), - key_getter.evaluate_simple(&[Any(value.clone())].as_slice())?, + key_getter.evaluate_simple(s.clone(), &[Any(value.clone())].as_slice())?, )); } let sort_type = get_sort_type(&mut vk, |v| &mut v.1)?; --- a/crates/jrsonnet-evaluator/src/ctx.rs +++ b/crates/jrsonnet-evaluator/src/ctx.rs @@ -5,14 +5,20 @@ use crate::{ cc_ptr_eq, error::Error::*, gc::GcHashMap, map::LayeredHashMap, FutureWrapper, LazyBinding, - LazyVal, ObjValue, Result, Val, + LazyVal, ObjValue, Result, State, Val, }; #[derive(Clone, Trace)] pub struct ContextCreator(pub Context, pub FutureWrapper>); impl ContextCreator { - pub fn create(&self, this: Option, super_obj: Option) -> Result { + pub fn create( + &self, + s: State, + this: Option, + super_obj: Option, + ) -> Result { self.0.clone().extend_unbound( + s, self.1.clone().unwrap(), self.0.dollar().clone().or_else(|| this.clone()), this, @@ -120,6 +126,7 @@ } pub fn extend_unbound( self, + s: State, new_bindings: GcHashMap, new_dollar: Option, new_this: Option, @@ -129,7 +136,7 @@ let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone()); let mut new = GcHashMap::with_capacity(new_bindings.len()); for (k, v) in new_bindings.0.into_iter() { - new.insert(k, v.evaluate(this.clone(), super_obj.clone())?); + new.insert(k, v.evaluate(s.clone(), this.clone(), super_obj.clone())?); } Ok(self.extend(new, new_dollar, this, super_obj)) } --- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs @@ -1,5 +1,3 @@ -use std::convert::TryFrom; - use gcmodule::{Cc, Trace}; use jrsonnet_interner::IStr; use jrsonnet_parser::{ @@ -14,33 +12,30 @@ evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op}, function::CallLocation, gc::TraceBox, - push_frame, throw, - typed::BoundedUsize, + throw, + typed::Typed, val::{ArrValue, FuncDesc, FuncVal, LazyValValue}, - with_state, Bindable, Context, ContextCreator, FutureWrapper, GcHashMap, LazyBinding, LazyVal, - ObjValue, ObjValueBuilder, ObjectAssertion, Result, Val, + Bindable, Context, ContextCreator, FutureWrapper, GcHashMap, LazyBinding, LazyVal, ObjValue, + ObjValueBuilder, ObjectAssertion, Result, State, Val, }; pub mod operator; -pub fn evaluate_binding_in_future( - b: &BindSpec, - context_creator: FutureWrapper, -) -> LazyVal { +pub fn evaluate_binding_in_future(b: &BindSpec, fctx: FutureWrapper) -> LazyVal { let b = b.clone(); if let Some(params) = &b.params { let params = params.clone(); #[derive(Trace)] struct LazyMethodBinding { - context_creator: FutureWrapper, + fctx: FutureWrapper, name: IStr, params: ParamsDesc, value: LocExpr, } impl LazyValValue for LazyMethodBinding { - fn get(self: Box) -> Result { + fn get(self: Box, _: State) -> Result { Ok(evaluate_method( - self.context_creator.unwrap(), + self.fctx.unwrap(), self.name, self.params, self.value, @@ -49,7 +44,7 @@ } LazyVal::new(TraceBox(Box::new(LazyMethodBinding { - context_creator, + fctx, name: b.name.clone(), params, value: b.value.clone(), @@ -57,24 +52,24 @@ } else { #[derive(Trace)] struct LazyNamedBinding { - context_creator: FutureWrapper, + fctx: FutureWrapper, name: IStr, value: LocExpr, } impl LazyValValue for LazyNamedBinding { - fn get(self: Box) -> Result { - evaluate_named(self.context_creator.unwrap(), &self.value, self.name) + fn get(self: Box, s: State) -> Result { + evaluate_named(s, self.fctx.unwrap(), &self.value, self.name) } } LazyVal::new(TraceBox(Box::new(LazyNamedBinding { - context_creator, + fctx, name: b.name.clone(), value: b.value, }))) } } -pub fn evaluate_binding(b: &BindSpec, context_creator: ContextCreator) -> (IStr, LazyBinding) { +pub fn evaluate_binding(b: &BindSpec, cctx: ContextCreator) -> (IStr, LazyBinding) { let b = b.clone(); if let Some(params) = &b.params { let params = params.clone(); @@ -84,15 +79,15 @@ this: Option, super_obj: Option, - context_creator: ContextCreator, + cctx: ContextCreator, name: IStr, params: ParamsDesc, value: LocExpr, } impl LazyValValue for BindableMethodLazyVal { - fn get(self: Box) -> Result { + fn get(self: Box, s: State) -> Result { Ok(evaluate_method( - self.context_creator.create(self.this, self.super_obj)?, + self.cctx.create(s, self.this, self.super_obj)?, self.name, self.params, self.value, @@ -102,18 +97,23 @@ #[derive(Trace)] struct BindableMethod { - context_creator: ContextCreator, + cctx: ContextCreator, name: IStr, params: ParamsDesc, value: LocExpr, } impl Bindable for BindableMethod { - fn bind(&self, this: Option, super_obj: Option) -> Result { + fn bind( + &self, + _: State, + this: Option, + super_obj: Option, + ) -> Result { Ok(LazyVal::new(TraceBox(Box::new(BindableMethodLazyVal { this, super_obj, - context_creator: self.context_creator.clone(), + cctx: self.cctx.clone(), name: self.name.clone(), params: self.params.clone(), value: self.value.clone(), @@ -124,7 +124,7 @@ ( b.name.clone(), LazyBinding::Bindable(Cc::new(TraceBox(Box::new(BindableMethod { - context_creator, + cctx, name: b.name.clone(), params, value: b.value.clone(), @@ -136,14 +136,15 @@ this: Option, super_obj: Option, - context_creator: ContextCreator, + cctx: ContextCreator, name: IStr, value: LocExpr, } impl LazyValValue for BindableNamedLazyVal { - fn get(self: Box) -> Result { + fn get(self: Box, s: State) -> Result { evaluate_named( - self.context_creator.create(self.this, self.super_obj)?, + s.clone(), + self.cctx.create(s, self.this, self.super_obj)?, &self.value, self.name, ) @@ -152,17 +153,22 @@ #[derive(Trace)] struct BindableNamed { - context_creator: ContextCreator, + cctx: ContextCreator, name: IStr, value: LocExpr, } impl Bindable for BindableNamed { - fn bind(&self, this: Option, super_obj: Option) -> Result { + fn bind( + &self, + _: State, + this: Option, + super_obj: Option, + ) -> Result { Ok(LazyVal::new(TraceBox(Box::new(BindableNamedLazyVal { this, super_obj, - context_creator: self.context_creator.clone(), + cctx: self.cctx.clone(), name: self.name.clone(), value: self.value.clone(), })))) @@ -172,7 +178,7 @@ ( b.name.clone(), LazyBinding::Bindable(Cc::new(TraceBox(Box::new(BindableNamed { - context_creator, + cctx, name: b.name.clone(), value: b.value.clone(), })))), @@ -190,20 +196,21 @@ } pub fn evaluate_field_name( - context: Context, + s: State, + ctx: Context, field_name: &jrsonnet_parser::FieldName, ) -> Result> { Ok(match field_name { jrsonnet_parser::FieldName::Fixed(n) => Some(n.clone()), - jrsonnet_parser::FieldName::Dyn(expr) => push_frame( + jrsonnet_parser::FieldName::Dyn(expr) => s.push( CallLocation::new(&expr.1), || "evaluating field name".to_string(), || { - let value = evaluate(context, expr)?; + let value = evaluate(s.clone(), ctx, expr)?; if matches!(value, Val::Null) { Ok(None) } else { - Ok(Some(IStr::try_from(value)?)) + Ok(Some(IStr::from_untyped(value, s.clone())?)) } }, )?, @@ -211,37 +218,41 @@ } pub fn evaluate_comp( - context: Context, + s: State, + ctx: Context, specs: &[CompSpec], callback: &mut impl FnMut(Context) -> Result<()>, ) -> Result<()> { match specs.get(0) { - None => callback(context)?, + None => callback(ctx)?, Some(CompSpec::IfSpec(IfSpecData(cond))) => { - if bool::try_from(evaluate(context.clone(), cond)?)? { - evaluate_comp(context, &specs[1..], callback)? + if bool::from_untyped(evaluate(s.clone(), ctx.clone(), cond)?, s.clone())? { + evaluate_comp(s, ctx, &specs[1..], callback)? } } - Some(CompSpec::ForSpec(ForSpecData(var, expr))) => match evaluate(context.clone(), expr)? { - Val::Arr(list) => { - for item in list.iter() { - evaluate_comp( - context.clone().with_var(var.clone(), item?.clone()), - &specs[1..], - callback, - )? + Some(CompSpec::ForSpec(ForSpecData(var, expr))) => { + match evaluate(s.clone(), ctx.clone(), expr)? { + Val::Arr(list) => { + for item in list.iter(s.clone()) { + evaluate_comp( + s.clone(), + ctx.clone().with_var(var.clone(), item?.clone()), + &specs[1..], + callback, + )? + } } + _ => throw!(InComprehensionCanOnlyIterateOverArray), } - _ => throw!(InComprehensionCanOnlyIterateOverArray), - }, + } } Ok(()) } -pub fn evaluate_member_list_object(context: Context, members: &[Member]) -> Result { +pub fn evaluate_member_list_object(s: State, ctx: Context, members: &[Member]) -> Result { let new_bindings = FutureWrapper::new(); let future_this = FutureWrapper::new(); - let context_creator = ContextCreator(context.clone(), new_bindings.clone()); + let cctx = ContextCreator(ctx.clone(), new_bindings.clone()); { let mut bindings: GcHashMap = GcHashMap::with_capacity(members.len()); for (n, b) in members @@ -250,7 +261,7 @@ Member::BindStmt(b) => Some(b.clone()), _ => None, }) - .map(|b| evaluate_binding(&b, context_creator.clone())) + .map(|b| evaluate_binding(&b, cctx.clone())) { bindings.insert(n, b); } @@ -267,7 +278,7 @@ visibility, value, }) => { - let name = evaluate_field_name(context.clone(), name)?; + let name = evaluate_field_name(s.clone(), ctx.clone(), name)?; if name.is_none() { continue; } @@ -275,18 +286,20 @@ #[derive(Trace)] struct ObjMemberBinding { - context_creator: ContextCreator, + cctx: ContextCreator, value: LocExpr, name: IStr, } impl Bindable for ObjMemberBinding { fn bind( &self, + s: State, this: Option, super_obj: Option, ) -> Result { Ok(LazyVal::new_resolved(evaluate_named( - self.context_creator.create(this, super_obj)?, + s.clone(), + self.cctx.create(s, this, super_obj)?, &self.value, self.name.clone(), )?)) @@ -297,11 +310,14 @@ .with_add(*plus) .with_visibility(*visibility) .with_location(value.1.clone()) - .bindable(TraceBox(Box::new(ObjMemberBinding { - context_creator: context_creator.clone(), - value: value.clone(), - name, - })))?; + .bindable( + s.clone(), + TraceBox(Box::new(ObjMemberBinding { + cctx: cctx.clone(), + value: value.clone(), + name, + })), + )?; } Member::Field(FieldMember { name, @@ -309,14 +325,14 @@ value, .. }) => { - let name = evaluate_field_name(context.clone(), name)?; + let name = evaluate_field_name(s.clone(), ctx.clone(), name)?; if name.is_none() { continue; } let name = name.unwrap(); #[derive(Trace)] struct ObjMemberBinding { - context_creator: ContextCreator, + cctx: ContextCreator, value: LocExpr, params: ParamsDesc, name: IStr, @@ -324,11 +340,12 @@ impl Bindable for ObjMemberBinding { fn bind( &self, + s: State, this: Option, super_obj: Option, ) -> Result { Ok(LazyVal::new_resolved(evaluate_method( - self.context_creator.create(this, super_obj)?, + self.cctx.create(s, this, super_obj)?, self.name.clone(), self.params.clone(), self.value.clone(), @@ -339,32 +356,36 @@ .member(name.clone()) .hide() .with_location(value.1.clone()) - .bindable(TraceBox(Box::new(ObjMemberBinding { - context_creator: context_creator.clone(), - value: value.clone(), - params: params.clone(), - name, - })))?; + .bindable( + s.clone(), + TraceBox(Box::new(ObjMemberBinding { + cctx: cctx.clone(), + value: value.clone(), + params: params.clone(), + name, + })), + )?; } Member::BindStmt(_) => {} Member::AssertStmt(stmt) => { #[derive(Trace)] struct ObjectAssert { - context_creator: ContextCreator, + cctx: ContextCreator, assert: AssertStmt, } impl ObjectAssertion for ObjectAssert { fn run( &self, + s: State, this: Option, super_obj: Option, ) -> Result<()> { - let ctx = self.context_creator.create(this, super_obj)?; - evaluate_assert(ctx, &self.assert) + let ctx = self.cctx.create(s.clone(), this, super_obj)?; + evaluate_assert(s, ctx, &self.assert) } } builder.assert(TraceBox(Box::new(ObjectAssert { - context_creator: context_creator.clone(), + cctx: cctx.clone(), assert: stmt.clone(), }))); } @@ -375,47 +396,47 @@ Ok(this) } -pub fn evaluate_object(context: Context, object: &ObjBody) -> Result { +pub fn evaluate_object(s: State, ctx: Context, object: &ObjBody) -> Result { Ok(match object { - ObjBody::MemberList(members) => evaluate_member_list_object(context, members)?, + ObjBody::MemberList(members) => evaluate_member_list_object(s, ctx, members)?, ObjBody::ObjComp(obj) => { let future_this = FutureWrapper::new(); let mut builder = ObjValueBuilder::new(); - evaluate_comp(context.clone(), &obj.compspecs, &mut |ctx| { + evaluate_comp(s.clone(), ctx, &obj.compspecs, &mut |ctx| { let new_bindings = FutureWrapper::new(); - let context_creator = ContextCreator(context.clone(), new_bindings.clone()); + let cctx = ContextCreator(ctx.clone(), new_bindings.clone()); let mut bindings: GcHashMap = GcHashMap::with_capacity(obj.pre_locals.len() + obj.post_locals.len()); for (n, b) in obj .pre_locals .iter() .chain(obj.post_locals.iter()) - .map(|b| evaluate_binding(b, context_creator.clone())) + .map(|b| evaluate_binding(b, cctx.clone())) { bindings.insert(n, b); } new_bindings.fill(bindings.clone()); - let ctx = ctx.extend_unbound(bindings, None, None, None)?; - let key = evaluate(ctx.clone(), &obj.key)?; + let ctx = ctx.extend_unbound(s.clone(), bindings, None, None, None)?; + let key = evaluate(s.clone(), ctx.clone(), &obj.key)?; match key { Val::Null => {} Val::Str(n) => { #[derive(Trace)] struct ObjCompBinding { - context: Context, + ctx: Context, value: LocExpr, } impl Bindable for ObjCompBinding { fn bind( &self, + s: State, this: Option, _super_obj: Option, ) -> Result { Ok(LazyVal::new_resolved(evaluate( - self.context - .clone() - .extend(GcHashMap::new(), None, this, None), + s, + self.ctx.clone().extend(GcHashMap::new(), None, this, None), &self.value, )?)) } @@ -424,10 +445,13 @@ .member(n) .with_location(obj.value.1.clone()) .with_add(obj.plus) - .bindable(TraceBox(Box::new(ObjCompBinding { - context: ctx, - value: obj.value.clone(), - })))?; + .bindable( + s.clone(), + TraceBox(Box::new(ObjCompBinding { + ctx, + value: obj.value.clone(), + })), + )?; } v => throw!(FieldMustBeStringGot(v.value_type())), } @@ -443,43 +467,46 @@ } pub fn evaluate_apply( - context: Context, + s: State, + ctx: Context, value: &LocExpr, args: &ArgsDesc, loc: CallLocation, tailstrict: bool, ) -> Result { - let value = evaluate(context.clone(), value)?; + let value = evaluate(s.clone(), ctx.clone(), value)?; Ok(match value { Val::Func(f) => { - let body = || f.evaluate(context, loc, args, tailstrict); + let body = || f.evaluate(s.clone(), ctx, loc, args, tailstrict); if tailstrict { body()? } else { - push_frame(loc, || format!("function <{}> call", f.name()), body)? + s.push(loc, || format!("function <{}> call", f.name()), body)? } } v => throw!(OnlyFunctionsCanBeCalledGot(v.value_type())), }) } -pub fn evaluate_assert(context: Context, assertion: &AssertStmt) -> Result<()> { +pub fn evaluate_assert(s: State, ctx: Context, assertion: &AssertStmt) -> Result<()> { let value = &assertion.0; let msg = &assertion.1; - let assertion_result = push_frame( + let assertion_result = s.push( CallLocation::new(&value.1), || "assertion condition".to_owned(), - || bool::try_from(evaluate(context.clone(), value)?), + || bool::from_untyped(evaluate(s.clone(), ctx.clone(), value)?, s.clone()), )?; if !assertion_result { - push_frame( + s.push( CallLocation::new(&value.1), || "assertion failure".to_owned(), || { if let Some(msg) = msg { - throw!(AssertionFailed(evaluate(context, msg)?.to_string()?)); + throw!(AssertionFailed( + evaluate(s.clone(), ctx, msg)?.to_string(s.clone())? + )); } else { - throw!(AssertionFailed(Val::Null.to_string()?)); + throw!(AssertionFailed(Val::Null.to_string(s.clone())?)); } }, )? @@ -487,62 +514,61 @@ Ok(()) } -pub fn evaluate_named(context: Context, lexpr: &LocExpr, name: IStr) -> Result { +pub fn evaluate_named(s: State, ctx: Context, lexpr: &LocExpr, name: IStr) -> Result { use Expr::*; let LocExpr(expr, _loc) = lexpr; Ok(match &**expr { - Function(params, body) => evaluate_method(context, name, params.clone(), body.clone()), - _ => evaluate(context, lexpr)?, + Function(params, body) => evaluate_method(ctx, name, params.clone(), body.clone()), + _ => evaluate(s, ctx, lexpr)?, }) } -pub fn evaluate(context: Context, expr: &LocExpr) -> Result { +pub fn evaluate(s: State, ctx: Context, expr: &LocExpr) -> Result { use Expr::*; let LocExpr(expr, loc) = expr; // let bp = with_state(|s| s.0.stop_at.borrow().clone()); Ok(match &**expr { Literal(LiteralType::This) => { - Val::Obj(context.this().clone().ok_or(CantUseSelfOutsideOfObject)?) + Val::Obj(ctx.this().clone().ok_or(CantUseSelfOutsideOfObject)?) } Literal(LiteralType::Super) => Val::Obj( - context - .super_obj() + ctx.super_obj() .clone() .ok_or(NoSuperFound)? - .with_this(context.this().clone().unwrap()), + .with_this(ctx.this().clone().unwrap()), ), Literal(LiteralType::Dollar) => { - Val::Obj(context.dollar().clone().ok_or(NoTopLevelObjectFound)?) + Val::Obj(ctx.dollar().clone().ok_or(NoTopLevelObjectFound)?) } Literal(LiteralType::True) => Val::Bool(true), Literal(LiteralType::False) => Val::Bool(false), Literal(LiteralType::Null) => Val::Null, - Parened(e) => evaluate(context, e)?, + Parened(e) => evaluate(s, ctx, e)?, Str(v) => Val::Str(v.clone()), Num(v) => Val::new_checked_num(*v)?, - BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, v1, *o, v2)?, - UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?, - Var(name) => push_frame( + BinaryOp(v1, o, v2) => evaluate_binary_op_special(s, ctx, v1, *o, v2)?, + UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(s, ctx, v)?)?, + Var(name) => s.push( CallLocation::new(loc), || format!("variable <{}> access", name), - || context.binding(name.clone())?.evaluate(), + || ctx.binding(name.clone())?.evaluate(s.clone()), )?, Index(value, index) => { - match (evaluate(context.clone(), value)?, evaluate(context, index)?) { - (Val::Obj(v), Val::Str(s)) => { - let sn = s.clone(); - push_frame( - CallLocation::new(loc), - || format!("field <{}> access", sn), - || { - if let Some(v) = v.get(s.clone())? { - Ok(v) - } else { - throw!(NoSuchField(s)) - } - }, - )? - } + match ( + evaluate(s.clone(), ctx.clone(), value)?, + evaluate(s.clone(), ctx, index)?, + ) { + (Val::Obj(v), Val::Str(key)) => s.push( + CallLocation::new(loc), + || format!("field <{}> access", key), + || { + if let Some(v) = v.get(s.clone(), key.clone())? { + Ok(v) + } else { + throw!(NoSuchField(key.clone())) + } + }, + )?, (Val::Obj(_), n) => throw!(ValueIndexMustBeTypeGot( ValType::Obj, ValType::Str, @@ -553,7 +579,7 @@ if n.fract() > f64::EPSILON { throw!(FractionalIndex) } - v.get(n as usize)? + v.get(s, n as usize)? .ok_or_else(|| ArrayBoundsError(n as usize, v.len()))? } (Val::Arr(_), Val::Str(n)) => throw!(AttemptedIndexAnArrayWithString(n)), @@ -582,17 +608,12 @@ LocalExpr(bindings, returned) => { let mut new_bindings: GcHashMap = GcHashMap::with_capacity(bindings.len()); - let future_context = Context::new_future(); + let fctx = Context::new_future(); for b in bindings { - new_bindings.insert( - b.name.clone(), - evaluate_binding_in_future(b, future_context.clone()), - ); + new_bindings.insert(b.name.clone(), evaluate_binding_in_future(b, fctx.clone())); } - let context = context - .extend_bound(new_bindings) - .into_future(future_context); - evaluate(context, &returned.clone())? + let ctx = ctx.extend_bound(new_bindings).into_future(fctx); + evaluate(s, ctx, &returned.clone())? } Arr(items) => { let mut out = Vec::with_capacity(items.len()); @@ -600,16 +621,16 @@ // TODO: Implement ArrValue::Lazy with same context for every element? #[derive(Trace)] struct ArrayElement { - context: Context, + ctx: Context, item: LocExpr, } impl LazyValValue for ArrayElement { - fn get(self: Box) -> Result { - evaluate(self.context, &self.item) + fn get(self: Box, s: State) -> Result { + evaluate(s, self.ctx, &self.item) } } out.push(LazyVal::new(TraceBox(Box::new(ArrayElement { - context: context.clone(), + ctx: ctx.clone(), item: item.clone(), })))); } @@ -617,22 +638,23 @@ } ArrComp(expr, comp_specs) => { let mut out = Vec::new(); - evaluate_comp(context, comp_specs, &mut |ctx| { - out.push(evaluate(ctx, expr)?); + evaluate_comp(s.clone(), ctx, comp_specs, &mut |ctx| { + out.push(evaluate(s.clone(), ctx, expr)?); Ok(()) })?; Val::Arr(ArrValue::Eager(Cc::new(out))) } - Obj(body) => Val::Obj(evaluate_object(context, body)?), - ObjExtend(s, t) => evaluate_add_op( - &evaluate(context.clone(), s)?, - &Val::Obj(evaluate_object(context, t)?), + Obj(body) => Val::Obj(evaluate_object(s, ctx, body)?), + ObjExtend(a, b) => evaluate_add_op( + s.clone(), + &evaluate(s.clone(), ctx.clone(), a)?, + &Val::Obj(evaluate_object(s, ctx, b)?), )?, Apply(value, args, tailstrict) => { - evaluate_apply(context, value, args, CallLocation::new(loc), *tailstrict)? + evaluate_apply(s, ctx, value, args, CallLocation::new(loc), *tailstrict)? } Function(params, body) => { - evaluate_method(context, "anonymous".into(), params.clone(), body.clone()) + evaluate_method(ctx, "anonymous".into(), params.clone(), body.clone()) } Intrinsic(name) => Val::Func(FuncVal::StaticBuiltin( BUILTINS @@ -640,56 +662,61 @@ .ok_or_else(|| IntrinsicNotFound(name.clone()))?, )), AssertExpr(assert, returned) => { - evaluate_assert(context.clone(), assert)?; - evaluate(context, returned)? + evaluate_assert(s.clone(), ctx.clone(), assert)?; + evaluate(s, ctx, returned)? } - ErrorStmt(e) => push_frame( + ErrorStmt(e) => s.push( CallLocation::new(loc), || "error statement".to_owned(), - || throw!(RuntimeError(evaluate(context, e)?.to_string()?,)), + || { + throw!(RuntimeError( + evaluate(s.clone(), ctx, e)?.to_string(s.clone())?, + )) + }, )?, IfElse { cond, cond_then, cond_else, } => { - if push_frame( + if s.push( CallLocation::new(loc), || "if condition".to_owned(), - || bool::try_from(evaluate(context.clone(), &cond.0)?), + || bool::from_untyped(evaluate(s.clone(), ctx.clone(), &cond.0)?, s.clone()), )? { - evaluate(context, cond_then)? + evaluate(s, ctx, cond_then)? } else { match cond_else { - Some(v) => evaluate(context, v)?, + Some(v) => evaluate(s, ctx, v)?, None => Val::Null, } } } Slice(value, desc) => { - let indexable = evaluate(context.clone(), value)?; + let indexable = evaluate(s.clone(), ctx.clone(), value)?; let loc = CallLocation::new(loc); - fn parse_idx( + fn parse_idx( loc: CallLocation, - context: &Context, + s: State, + ctx: &Context, expr: &Option, desc: &'static str, - ) -> Result>> { + ) -> Result> { if let Some(value) = expr { - Ok(Some(push_frame( + Ok(Some(s.push( loc, || format!("slice {}", desc), - || evaluate(context.clone(), value)?.try_into(), + || T::from_untyped(evaluate(s.clone(), ctx.clone(), value)?, s.clone()), )?)) } else { Ok(None) } } - let start = parse_idx(loc, &context, &desc.start, "start")?; - let end = parse_idx(loc, &context, &desc.end, "end")?; - let step = parse_idx(loc, &context, &desc.step, "step")?; + let start = parse_idx(loc, s.clone(), &ctx, &desc.start, "start")?; + let end = parse_idx(loc, s.clone(), &ctx, &desc.end, "end")?; + let step = parse_idx(loc, s, &ctx, &desc.step, "step")?; std_slice(indexable.into_indexable()?, start, end, step)? } @@ -697,23 +724,23 @@ let tmp = loc.clone().0; let mut import_location = tmp.to_path_buf(); import_location.pop(); - push_frame( + s.push( CallLocation::new(loc), || format!("import {:?}", path), - || with_state(|s| s.import_file(&import_location, path)), + || s.import_file(&import_location, path), )? } ImportStr(path) => { let tmp = loc.clone().0; let mut import_location = tmp.to_path_buf(); import_location.pop(); - Val::Str(with_state(|s| s.import_file_str(&import_location, path))?) + Val::Str(s.import_file_str(&import_location, path)?) } ImportBin(path) => { let tmp = loc.clone().0; let mut import_location = tmp.to_path_buf(); import_location.pop(); - let bytes = with_state(|s| s.import_file_bin(&import_location, path))?; + let bytes = s.import_file_bin(&import_location, path)?; Val::Arr(ArrValue::Bytes(bytes)) } }) --- a/crates/jrsonnet-evaluator/src/evaluate/operator.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/operator.rs @@ -1,9 +1,8 @@ -use std::convert::TryInto; - use jrsonnet_parser::{BinaryOpType, LocExpr, UnaryOpType}; use crate::{ - builtin::std_format, error::Error::*, evaluate, throw, val::equals, Context, Result, Val, + builtin::std_format, error::Error::*, evaluate, throw, typed::Typed, val::equals, Context, + Result, State, Val, }; pub fn evaluate_unary_op(op: UnaryOpType, b: &Val) -> Result { @@ -17,7 +16,7 @@ }) } -pub fn evaluate_add_op(a: &Val, b: &Val) -> Result { +pub fn evaluate_add_op(s: State, a: &Val, b: &Val) -> Result { use Val::*; Ok(match (a, b) { (Str(v1), Str(v2)) => Str(((**v1).to_owned() + v2).into()), @@ -26,8 +25,8 @@ (Num(n), Str(o)) => Str(format!("{}{}", n, o).into()), (Str(o), Num(n)) => Str(format!("{}{}", o, n).into()), - (Str(s), o) => Str(format!("{}{}", s, o.clone().to_string()?).into()), - (o, Str(s)) => Str(format!("{}{}", o.clone().to_string()?, s).into()), + (Str(a), o) => Str(format!("{}{}", a, o.clone().to_string(s)?).into()), + (o, Str(a)) => Str(format!("{}{}", o.clone().to_string(s)?, a).into()), (Obj(v1), Obj(v2)) => Obj(v2.extend_from(v1.clone())), (Arr(a), Arr(b)) => { @@ -45,11 +44,13 @@ }) } -pub fn evaluate_mod_op(a: &Val, b: &Val) -> Result { +pub fn evaluate_mod_op(s: State, a: &Val, b: &Val) -> Result { use Val::*; match (a, b) { (Num(a), Num(b)) => Ok(Num(a % b)), - (Str(str), vals) => std_format(str.clone(), vals.clone())?.try_into(), + (Str(str), vals) => { + String::into_untyped(std_format(s.clone(), str.clone(), vals.clone())?, s) + } (a, b) => throw!(BinaryOperatorDoesNotOperateOnValues( BinaryOpType::Mod, a.value_type(), @@ -59,31 +60,32 @@ } pub fn evaluate_binary_op_special( - context: Context, + s: State, + ctx: Context, a: &LocExpr, op: BinaryOpType, b: &LocExpr, ) -> Result { use BinaryOpType::*; use Val::*; - Ok(match (evaluate(context.clone(), a)?, op, b) { + Ok(match (evaluate(s.clone(), ctx.clone(), a)?, op, b) { (Bool(true), Or, _o) => Val::Bool(true), (Bool(false), And, _o) => Val::Bool(false), - (a, op, eb) => evaluate_binary_op_normal(&a, op, &evaluate(context, eb)?)?, + (a, op, eb) => evaluate_binary_op_normal(s.clone(), &a, op, &evaluate(s, ctx, eb)?)?, }) } -pub fn evaluate_binary_op_normal(a: &Val, op: BinaryOpType, b: &Val) -> Result { +pub fn evaluate_binary_op_normal(s: State, a: &Val, op: BinaryOpType, b: &Val) -> Result { use BinaryOpType::*; use Val::*; Ok(match (a, op, b) { - (a, Add, b) => evaluate_add_op(a, b)?, + (a, Add, b) => evaluate_add_op(s, a, b)?, - (a, Eq, b) => Bool(equals(a, b)?), - (a, Neq, b) => Bool(!equals(a, b)?), + (a, Eq, b) => Bool(equals(s, a, b)?), + (a, Neq, b) => Bool(!equals(s, a, b)?), (Str(a), In, Obj(obj)) => Bool(obj.has_field_ex(a.clone(), true)), - (a, Mod, b) => evaluate_mod_op(a, b)?, + (a, Mod, b) => evaluate_mod_op(s, a, b)?, (Str(v1), Mul, Num(v2)) => Str(v1.repeat(*v2 as usize).into()), --- a/crates/jrsonnet-evaluator/src/function.rs +++ b/crates/jrsonnet-evaluator/src/function.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, collections::HashMap, convert::TryFrom}; +use std::{borrow::Cow, collections::HashMap}; use gcmodule::Trace; use jrsonnet_interner::IStr; @@ -6,13 +6,8 @@ use jrsonnet_parser::{ArgsDesc, ExprLocation, LocExpr, ParamsDesc}; use crate::{ - error::{Error::*, LocError}, - evaluate, evaluate_named, - gc::TraceBox, - throw, - typed::Typed, - val::LazyValValue, - Context, FutureWrapper, GcHashMap, LazyVal, Result, Val, + error::Error::*, evaluate, evaluate_named, gc::TraceBox, throw, typed::Typed, + val::LazyValValue, Context, FutureWrapper, GcHashMap, LazyVal, Result, State, Val, }; #[derive(Clone, Copy)] @@ -30,37 +25,37 @@ #[derive(Trace)] struct EvaluateLazyVal { - context: Context, + ctx: Context, expr: LocExpr, } impl LazyValValue for EvaluateLazyVal { - fn get(self: Box) -> Result { - evaluate(self.context, &self.expr) + fn get(self: Box, s: State) -> Result { + evaluate(s, self.ctx, &self.expr) } } #[derive(Trace)] struct EvaluateNamedLazyVal { - future_context: FutureWrapper, + ctx: FutureWrapper, name: IStr, value: LocExpr, } impl LazyValValue for EvaluateNamedLazyVal { - fn get(self: Box) -> Result { - evaluate_named(self.future_context.unwrap(), &self.value, self.name) + fn get(self: Box, s: State) -> Result { + evaluate_named(s, self.ctx.unwrap(), &self.value, self.name) } } pub trait ArgLike { - fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result; + fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result; } impl ArgLike for &LocExpr { - fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result { + fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result { Ok(if tailstrict { - LazyVal::new_resolved(evaluate(ctx, self)?) + LazyVal::new_resolved(evaluate(s, ctx, self)?) } else { LazyVal::new(TraceBox(Box::new(EvaluateLazyVal { - context: ctx, + ctx, expr: (*self).clone(), }))) }) @@ -69,10 +64,9 @@ impl ArgLike for T where T: Typed + Clone, - Val: TryFrom, { - fn evaluate_arg(&self, _ctx: Context, _tailstrict: bool) -> Result { - let val: Val = Val::try_from(self.clone())?; + fn evaluate_arg(&self, s: State, _ctx: Context, _tailstrict: bool) -> Result { + let val = T::into_untyped(self.clone(), s)?; Ok(LazyVal::new_resolved(val)) } } @@ -82,14 +76,14 @@ Val(Val), } impl ArgLike for TlaArg { - fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result { + fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result { match self { TlaArg::String(s) => Ok(LazyVal::new_resolved(Val::Str(s.clone()))), TlaArg::Code(code) => Ok(if tailstrict { - LazyVal::new_resolved(evaluate(ctx, code)?) + LazyVal::new_resolved(evaluate(s, ctx, code)?) } else { LazyVal::new(TraceBox(Box::new(EvaluateLazyVal { - context: ctx, + ctx, expr: code.clone(), }))) }), @@ -102,12 +96,14 @@ fn unnamed_len(&self) -> usize; fn unnamed_iter( &self, + s: State, ctx: Context, tailstrict: bool, handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>, ) -> Result<()>; fn named_iter( &self, + s: State, ctx: Context, tailstrict: bool, handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>, @@ -122,6 +118,7 @@ fn unnamed_iter( &self, + s: State, ctx: Context, tailstrict: bool, handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>, @@ -130,10 +127,10 @@ handler( id, if tailstrict { - LazyVal::new_resolved(evaluate(ctx.clone(), arg)?) + LazyVal::new_resolved(evaluate(s.clone(), ctx.clone(), arg)?) } else { LazyVal::new(TraceBox(Box::new(EvaluateLazyVal { - context: ctx.clone(), + ctx: ctx.clone(), expr: arg.clone(), }))) }, @@ -144,6 +141,7 @@ fn named_iter( &self, + s: State, ctx: Context, tailstrict: bool, handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>, @@ -152,10 +150,10 @@ handler( name, if tailstrict { - LazyVal::new_resolved(evaluate(ctx.clone(), arg)?) + LazyVal::new_resolved(evaluate(s.clone(), ctx.clone(), arg)?) } else { LazyVal::new(TraceBox(Box::new(EvaluateLazyVal { - context: ctx.clone(), + ctx: ctx.clone(), expr: arg.clone(), }))) }, @@ -178,6 +176,7 @@ fn unnamed_iter( &self, + _s: State, _ctx: Context, _tailstrict: bool, _handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>, @@ -187,12 +186,13 @@ fn named_iter( &self, + s: State, ctx: Context, tailstrict: bool, handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>, ) -> Result<()> { for (name, val) in self.iter() { - handler(name, val.evaluate_arg(ctx.clone(), tailstrict)?)?; + handler(name, val.evaluate_arg(s.clone(), ctx.clone(), tailstrict)?)?; } Ok(()) } @@ -211,6 +211,7 @@ fn unnamed_iter( &self, + _s: State, _ctx: Context, _tailstrict: bool, _handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>, @@ -220,12 +221,16 @@ fn named_iter( &self, + s: State, ctx: Context, tailstrict: bool, handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>, ) -> Result<()> { for (name, value) in self.iter() { - handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?; + handler( + name, + value.evaluate_arg(s.clone(), ctx.clone(), tailstrict)?, + )?; } Ok(()) } @@ -244,18 +249,20 @@ fn unnamed_iter( &self, + s: State, ctx: Context, tailstrict: bool, handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>, ) -> Result<()> { for (i, arg) in self.iter().enumerate() { - handler(i, arg.evaluate_arg(ctx.clone(), tailstrict)?)?; + handler(i, arg.evaluate_arg(s.clone(), ctx.clone(), tailstrict)?)?; } Ok(()) } fn named_iter( &self, + _s: State, _ctx: Context, _tailstrict: bool, _handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>, @@ -272,20 +279,22 @@ fn unnamed_iter( &self, + s: State, ctx: Context, tailstrict: bool, handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>, ) -> Result<()> { - (*self).unnamed_iter(ctx, tailstrict, handler) + (*self).unnamed_iter(s, ctx, tailstrict, handler) } fn named_iter( &self, + s: State, ctx: Context, tailstrict: bool, handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>, ) -> Result<()> { - (*self).named_iter(ctx, tailstrict, handler) + (*self).named_iter(s, ctx, tailstrict, handler) } fn named_names(&self, handler: &mut dyn FnMut(&IStr)) { @@ -302,6 +311,7 @@ /// * `args`: passed function arguments /// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily pub fn parse_function_call( + s: State, ctx: Context, body_ctx: Context, params: &ParamsDesc, @@ -315,14 +325,14 @@ let mut filled_args = 0; - args.unnamed_iter(ctx.clone(), tailstrict, &mut |id, arg| { + args.unnamed_iter(s.clone(), ctx.clone(), tailstrict, &mut |id, arg| { let name = params[id].0.clone(); passed_args.insert(name, arg); filled_args += 1; Ok(()) })?; - args.named_iter(ctx, tailstrict, &mut |name, value| { + args.named_iter(s, ctx, tailstrict, &mut |name, value| { // FIXME: O(n) for arg existence check if !params.iter().any(|p| &p.0 == name) { throw!(UnknownFunctionParameter((name as &str).to_owned())); @@ -337,7 +347,7 @@ if filled_args < params.len() { // Some args are unset, but maybe we have defaults for them // Default values should be created in newly created context - let future_context = Context::new_future(); + let fctx = Context::new_future(); let mut defaults = GcHashMap::with_capacity(params.len() - filled_args); for param in params.iter().filter(|p| p.1.is_some()) { @@ -345,7 +355,7 @@ continue; } LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal { - future_context: future_context.clone(), + ctx: fctx.clone(), name: param.0.clone(), value: param.1.clone().unwrap(), }))); @@ -353,7 +363,7 @@ defaults.insert( param.0.clone(), LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal { - future_context: future_context.clone(), + ctx: fctx.clone(), name: param.0.clone(), value: param.1.clone().unwrap(), }))), @@ -380,7 +390,7 @@ Ok(body_ctx .extend(passed_args, None, None, None) .extend_bound(defaults) - .into_future(future_context)) + .into_future(fctx)) } else { let body_ctx = body_ctx.extend(passed_args, None, None, None); Ok(body_ctx) @@ -399,7 +409,7 @@ pub trait Builtin: Trace { fn name(&self) -> &str; fn params(&self) -> &[BuiltinParam]; - fn call(&self, context: Context, loc: CallLocation, args: &dyn ArgsLike) -> Result; + fn call(&self, s: State, ctx: Context, loc: CallLocation, args: &dyn ArgsLike) -> Result; } pub trait StaticBuiltin: Builtin + Send + Sync @@ -418,6 +428,7 @@ /// * `args`: passed function arguments /// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily pub fn parse_builtin_call( + s: State, ctx: Context, params: &[BuiltinParam], args: &dyn ArgsLike, @@ -430,14 +441,14 @@ let mut filled_args = 0; - args.unnamed_iter(ctx.clone(), tailstrict, &mut |id, arg| { + args.unnamed_iter(s.clone(), ctx.clone(), tailstrict, &mut |id, arg| { let name = params[id].name.clone(); passed_args.insert(name, arg); filled_args += 1; Ok(()) })?; - args.named_iter(ctx, tailstrict, &mut |name, arg| { + args.named_iter(s, ctx, tailstrict, &mut |name, arg| { // FIXME: O(n) for arg existence check let p = params .iter() @@ -480,14 +491,14 @@ /// Creates Context, which has all argument default values applied /// and with unbound values causing error to be returned pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Context { - let ctx = Context::new_future(); + let fctx = Context::new_future(); let mut bindings = GcHashMap::new(); #[derive(Trace)] struct DependsOnUnbound(IStr); impl LazyValValue for DependsOnUnbound { - fn get(self: Box) -> Result { + fn get(self: Box, _: State) -> Result { Err(FunctionParameterNotBoundInCall(self.0.clone()).into()) } } @@ -497,7 +508,7 @@ bindings.insert( param.0.clone(), LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal { - future_context: ctx.clone(), + ctx: fctx.clone(), name: param.0.clone(), value: v.clone(), }))), @@ -510,5 +521,7 @@ } } - body_ctx.extend(bindings, None, None, None).into_future(ctx) + body_ctx + .extend(bindings, None, None, None) + .into_future(fctx) } --- a/crates/jrsonnet-evaluator/src/integrations/serde.rs +++ b/crates/jrsonnet-evaluator/src/integrations/serde.rs @@ -1,28 +1,57 @@ -use std::convert::{TryFrom, TryInto}; - +use jrsonnet_types::ComplexValType; use serde_json::{Map, Number, Value}; use crate::{ - error::{Error::*, LocError, Result}, - throw, ObjValueBuilder, Val, + error::{Error::*, Result}, + throw, + typed::Typed, + ObjValueBuilder, State, Val, }; -impl TryFrom<&Val> for Value { - type Error = LocError; - fn try_from(v: &Val) -> Result { - Ok(match v { - Val::Bool(b) => Self::Bool(*b), +impl Typed for Value { + const TYPE: &'static ComplexValType = &ComplexValType::Any; + + fn into_untyped(value: Self, s: State) -> Result { + Ok(match value { + Value::Null => Val::Null, + Value::Bool(v) => Val::Bool(v), + Value::Number(n) => Val::Num(n.as_f64().ok_or_else(|| { + RuntimeError(format!("json number can't be represented as jsonnet: {}", n).into()) + })?), + Value::String(s) => Val::Str((&s as &str).into()), + Value::Array(a) => { + let mut out: Vec = Vec::with_capacity(a.len()); + for v in a { + out.push(Self::into_untyped(v, s.clone())?); + } + Val::Arr(out.into()) + } + Value::Object(o) => { + let mut builder = ObjValueBuilder::with_capacity(o.len()); + for (k, v) in o { + builder + .member((&k as &str).into()) + .value(s.clone(), Self::into_untyped(v, s.clone())?)?; + } + Val::Obj(builder.build()) + } + }) + } + + fn from_untyped(value: Val, s: State) -> Result { + Ok(match value { + Val::Bool(b) => Self::Bool(b), Val::Null => Self::Null, - Val::Str(s) => Self::String((s as &str).into()), + Val::Str(s) => Self::String((&s as &str).into()), Val::Num(n) => Self::Number(if n.fract() <= f64::EPSILON { - (*n as i64).into() + (n as i64).into() } else { - Number::from_f64(*n).expect("jsonnet numbers can't be infinite or NaN") + Number::from_f64(n).expect("jsonnet numbers can't be infinite or NaN") }), Val::Arr(a) => { let mut out = Vec::with_capacity(a.len()); - for item in a.iter() { - out.push(item?.try_into()?); + for item in a.iter(s.clone()) { + out.push(Self::from_untyped(item?, s.clone())?); } Self::Array(out) } @@ -34,56 +63,16 @@ ) { out.insert( (&key as &str).into(), - o.get(key)? - .expect("key is present in fields, so value should exist") - .try_into()?, + Self::from_untyped( + o.get(s.clone(), key)? + .expect("key is present in fields, so value should exist"), + s.clone(), + )?, ); } Self::Object(out) } Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())), }) - } -} -impl TryFrom for Value { - type Error = LocError; - - fn try_from(value: Val) -> Result { - >::try_from(&value) - } -} - -impl TryFrom<&Value> for Val { - type Error = LocError; - fn try_from(v: &Value) -> Result { - Ok(match v { - Value::Null => Self::Null, - Value::Bool(v) => Self::Bool(*v), - Value::Number(n) => Self::Num(n.as_f64().ok_or_else(|| { - RuntimeError(format!("json number can't be represented as jsonnet: {}", n).into()) - })?), - Value::String(s) => Self::Str((s as &str).into()), - Value::Array(a) => { - let mut out: Vec = Vec::with_capacity(a.len()); - for v in a { - out.push(v.try_into()?); - } - Self::Arr(out.into()) - } - Value::Object(o) => { - let mut builder = ObjValueBuilder::with_capacity(o.len()); - for (k, v) in o { - builder.member((k as &str).into()).value(v.try_into()?)?; - } - Self::Obj(builder.build()) - } - }) - } -} -impl TryFrom for Val { - type Error = LocError; - - fn try_from(value: Value) -> Result { - >::try_from(&value) } } --- a/crates/jrsonnet-evaluator/src/lib.rs +++ b/crates/jrsonnet-evaluator/src/lib.rs @@ -47,7 +47,12 @@ pub use val::{LazyVal, ManifestFormat, Val}; pub trait Bindable: Trace + 'static { - fn bind(&self, this: Option, super_obj: Option) -> Result; + fn bind( + &self, + s: State, + this: Option, + super_obj: Option, + ) -> Result; } #[derive(Clone, Trace)] @@ -62,9 +67,14 @@ } } impl LazyBinding { - pub fn evaluate(&self, this: Option, super_obj: Option) -> Result { + pub fn evaluate( + &self, + s: State, + this: Option, + super_obj: Option, + ) -> Result { match self { - Self::Bindable(v) => v.bind(this, super_obj), + Self::Bindable(v) => v.bind(s, this, super_obj), Self::Bound(v) => Ok(v.clone()), } } @@ -173,48 +183,11 @@ settings: RefCell, } -thread_local! { - /// Contains the state for a currently executed file. - /// Global state is fine here. - pub(crate) static EVAL_STATE: RefCell> = RefCell::new(None) -} - -pub(crate) fn with_state(f: impl FnOnce(&EvaluationState) -> T) -> T { - EVAL_STATE.with(|s| { - f(s.borrow().as_ref().expect( - "missing evaluation state, some functions should be called inside of run_in_state call", - )) - }) -} -pub fn push_frame( - e: CallLocation, - frame_desc: impl FnOnce() -> String, - f: impl FnOnce() -> Result, -) -> Result { - with_state(|s| s.push(e, frame_desc, f)) -} - -#[allow(dead_code)] -pub fn push_val_frame( - e: &ExprLocation, - frame_desc: impl FnOnce() -> String, - f: impl FnOnce() -> Result, -) -> Result { - with_state(|s| s.push_val(e, frame_desc, f)) -} -#[allow(dead_code)] -pub fn push_description_frame( - frame_desc: impl FnOnce() -> String, - f: impl FnOnce() -> Result, -) -> Result { - with_state(|s| s.push_description(frame_desc, f)) -} - /// Maintains stack trace and import resolution #[derive(Default, Clone)] -pub struct EvaluationState(Rc); +pub struct State(Rc); -impl EvaluationState { +impl State { /// Parses and adds file as loaded pub fn add_file(&self, path: Rc, source_code: IStr) -> Result { let parsed = parse( @@ -317,7 +290,7 @@ } value.parsed.clone() }; - let value = evaluate(self.create_default_context(), &expr)?; + let value = evaluate(self.clone(), self.create_default_context(), &expr)?; { self.data_mut() .files @@ -333,16 +306,15 @@ pub fn with_stdlib(&self) -> &Self { use jrsonnet_stdlib::STDLIB_STR; let std_path: Rc = PathBuf::from("std.jsonnet").into(); - self.run_in_state(|| { - self.add_parsed_file( - std_path.clone(), - STDLIB_STR.to_owned().into(), - builtin::get_parsed_stdlib(), - ) - .unwrap(); - let val = self.evaluate_loaded_file_raw(&std_path).unwrap(); - self.settings_mut().globals.insert("std".into(), val); - }); + + self.add_parsed_file( + std_path.clone(), + STDLIB_STR.to_owned().into(), + builtin::get_parsed_stdlib(), + ) + .unwrap(); + let val = self.evaluate_loaded_file_raw(&std_path).unwrap(); + self.settings_mut().globals.insert("std".into(), val); self } @@ -455,41 +427,7 @@ desc: frame_desc(), }); return Err(err); - } - result - } - - /// Runs passed function in state (required if function needs to modify stack trace) - pub fn run_in_state(&self, f: impl FnOnce() -> T) -> T { - EVAL_STATE.with(|v| { - let has_state = v.borrow().is_some(); - if !has_state { - v.borrow_mut().replace(self.clone()); - } - let result = f(); - if !has_state { - v.borrow_mut().take(); - } - result - }) - } - pub fn run_in_state_with_breakpoint( - &self, - bp: Rc, - f: impl FnOnce() -> Result<()>, - ) -> Result<()> { - { - let mut data = self.data_mut(); - data.breakpoints.0.push(bp); - } - - let result = self.run_in_state(f); - - { - let mut data = self.data_mut(); - data.breakpoints.0.pop(); } - result } @@ -503,43 +441,40 @@ } pub fn manifest(&self, val: Val) -> Result { - self.run_in_state(|| { - push_description_frame( - || "manifestification".to_string(), - || val.manifest(&self.manifest_format()), - ) - }) + self.push_description( + || "manifestification".to_string(), + || val.manifest(self.clone(), &self.manifest_format()), + ) } pub fn manifest_multi(&self, val: Val) -> Result> { - self.run_in_state(|| val.manifest_multi(&self.manifest_format())) + val.manifest_multi(self.clone(), &self.manifest_format()) } pub fn manifest_stream(&self, val: Val) -> Result> { - self.run_in_state(|| val.manifest_stream(&self.manifest_format())) + val.manifest_stream(self.clone(), &self.manifest_format()) } /// If passed value is function then call with set TLA pub fn with_tla(&self, val: Val) -> Result { - self.run_in_state(|| { - Ok(match val { - Val::Func(func) => push_description_frame( - || "during TLA call".to_owned(), - || { - func.evaluate( - self.create_default_context(), - CallLocation::native(), - &self.settings().tla_vars, - true, - ) - }, - )?, - v => v, - }) + Ok(match val { + Val::Func(func) => self.push_description( + || "during TLA call".to_owned(), + || { + func.evaluate( + self.clone(), + self.create_default_context(), + CallLocation::native(), + &self.settings().tla_vars, + true, + ) + }, + )?, + v => v, }) } } /// Internals -impl EvaluationState { +impl State { fn data(&self) -> Ref { self.0.data.borrow() } @@ -555,12 +490,12 @@ } /// Raw methods evaluate passed values but don't perform TLA execution -impl EvaluationState { +impl State { pub fn evaluate_file_raw(&self, name: &Path) -> Result { - self.run_in_state(|| self.import_file(&std::env::current_dir().expect("cwd"), name)) + self.import_file(&std::env::current_dir().expect("cwd"), name) } pub fn evaluate_file_raw_nocwd(&self, name: &Path) -> Result { - self.run_in_state(|| self.import_file(&PathBuf::from("."), name)) + self.import_file(&PathBuf::from("."), name) } /// Parses and evaluates the given snippet pub fn evaluate_snippet_raw(&self, source: Rc, code: IStr) -> Result { @@ -580,12 +515,12 @@ } /// Evaluates the parsed expression pub fn evaluate_expr_raw(&self, code: LocExpr) -> Result { - self.run_in_state(|| evaluate(self.create_default_context(), &code)) + evaluate(self.clone(), self.create_default_context(), &code) } } /// Settings utilities -impl EvaluationState { +impl State { pub fn add_ext_var(&self, name: IStr, value: Val) { self.settings_mut().ext_vars.insert(name, value); } @@ -712,38 +647,36 @@ gc::TraceBox, native::NativeCallbackHandler, val::primitive_equals, - EvaluationState, + State, }; #[test] #[should_panic] fn eval_state_stacktrace() { - let state = EvaluationState::default(); - state.run_in_state(|| { - state - .push( - CallLocation::new(&ExprLocation(PathBuf::from("test1.jsonnet").into(), 10, 20)), - || "outer".to_owned(), - || { - state.push( - CallLocation::new(&ExprLocation( - PathBuf::from("test2.jsonnet").into(), - 30, - 40, - )), - || "inner".to_owned(), - || Err(RuntimeError("".into()).into()), - )?; - Ok(Val::Null) - }, - ) - .unwrap(); - }); + let state = State::default(); + state + .push( + CallLocation::new(&ExprLocation(PathBuf::from("test1.jsonnet").into(), 10, 20)), + || "outer".to_owned(), + || { + state.push( + CallLocation::new(&ExprLocation( + PathBuf::from("test2.jsonnet").into(), + 30, + 40, + )), + || "inner".to_owned(), + || Err(RuntimeError("".into()).into()), + )?; + Ok(Val::Null) + }, + ) + .unwrap(); } #[test] fn eval_state_standard() { - let state = EvaluationState::default(); + let state = State::default(); state.with_stdlib(); assert!(primitive_equals( &state @@ -759,27 +692,23 @@ macro_rules! eval { ($str: expr) => {{ - let evaluator = EvaluationState::default(); + let evaluator = State::default(); evaluator.with_stdlib(); - evaluator.run_in_state(|| { - evaluator - .evaluate_snippet_raw(PathBuf::from("raw.jsonnet").into(), $str.into()) - .unwrap() - }) + evaluator + .evaluate_snippet_raw(PathBuf::from("raw.jsonnet").into(), $str.into()) + .unwrap() }}; } macro_rules! eval_json { ($str: expr) => {{ - let evaluator = EvaluationState::default(); + let evaluator = State::default(); evaluator.with_stdlib(); - evaluator.run_in_state(|| { - evaluator - .evaluate_snippet_raw(PathBuf::from("raw.jsonnet").into(), $str.into()) - .unwrap() - .to_json(0) - .unwrap() - .replace("\n", "") - }) + evaluator + .evaluate_snippet_raw(PathBuf::from("raw.jsonnet").into(), $str.into()) + .unwrap() + .to_json(0) + .unwrap() + .replace("\n", "") }}; } @@ -1143,7 +1072,7 @@ #[test] fn native_ext() -> crate::error::Result<()> { use super::native::NativeCallback; - let evaluator = EvaluationState::default(); + let evaluator = State::default(); evaluator.with_stdlib(); @@ -1178,10 +1107,12 @@ TraceBox(Box::new(NativeAdd)), )))), ); + dbg!(evaluator.settings().ext_natives.keys().collect::>()); evaluator.evaluate_snippet_raw( PathBuf::from("native_caller.jsonnet").into(), "std.assertEqual(std.native(\"native_add\")(1, 2), 3)".into(), )?; + dbg!(evaluator.settings().ext_natives.keys().collect::>()); Ok(()) } @@ -1250,14 +1181,14 @@ #[test] fn issue_23() { - let state = EvaluationState::default(); + let state = State::default(); state.set_import_resolver(Box::new(TestImportResolver(r#"import "/test""#.into()))); let _ = state.evaluate_file_raw(&PathBuf::from("/test")); } #[test] fn issue_40() { - let state = EvaluationState::default(); + let state = State::default(); state.with_stdlib(); let error = state @@ -1306,7 +1237,7 @@ mod derive_typed { use std::path::PathBuf; - use crate::{typed::Typed, EvaluationState}; + use crate::{typed::Typed, State}; #[derive(PartialEq, Debug, Typed)] struct MyTyped { @@ -1317,9 +1248,9 @@ #[test] fn test() { - let es = EvaluationState::default(); + let es = State::default(); let val = eval!("{a: 14, b: 'Hello, world!'}"); - let typed = es.run_in_state(|| MyTyped::try_from(val).unwrap()); + let typed = MyTyped::try_from(val).unwrap(); assert_eq!( typed, @@ -1328,10 +1259,9 @@ c: "Hello, world!".to_string() } ); - es.settings_mut().globals.insert( - "mytyped".into(), - es.run_in_state(|| typed.try_into()).unwrap(), - ); + es.settings_mut() + .globals + .insert("mytyped".into(), typed.try_into().unwrap()); let v = es .evaluate_snippet_raw( --- a/crates/jrsonnet-evaluator/src/native.rs +++ b/crates/jrsonnet-evaluator/src/native.rs @@ -8,7 +8,7 @@ error::Result, function::{parse_builtin_call, ArgsLike, Builtin, BuiltinParam, CallLocation}, gc::TraceBox, - Context, Val, + Context, State, Val, }; #[derive(Trace)] @@ -34,16 +34,16 @@ &self.params } - fn call(&self, context: Context, loc: CallLocation, args: &dyn ArgsLike) -> Result { - let args = parse_builtin_call(context, &self.params, args, true)?; + fn call(&self, s: State, ctx: Context, loc: CallLocation, args: &dyn ArgsLike) -> Result { + let args = parse_builtin_call(s.clone(), ctx, &self.params, args, true)?; let mut out_args = Vec::with_capacity(self.params.len()); for p in self.params.iter() { - out_args.push(args[&p.name].evaluate()?); + out_args.push(args[&p.name].evaluate(s.clone())?); } - self.handler.call(loc.0.map(|l| l.0.clone()), &out_args) + self.handler.call(s, loc.0.map(|l| l.0.clone()), &out_args) } } pub trait NativeCallbackHandler: Trace { - fn call(&self, from: Option>, args: &[Val]) -> Result; + fn call(&self, s: State, from: Option>, args: &[Val]) -> Result; } --- a/crates/jrsonnet-evaluator/src/obj.rs +++ b/crates/jrsonnet-evaluator/src/obj.rs @@ -15,7 +15,7 @@ function::CallLocation, gc::{GcHashMap, GcHashSet, TraceBox}, operator::evaluate_add_op, - push_frame, throw, weak_ptr_eq, weak_raw, Bindable, LazyBinding, LazyVal, Result, Val, + throw, weak_ptr_eq, weak_raw, Bindable, LazyBinding, LazyVal, Result, State, Val, }; #[cfg(not(feature = "exp-preserve-order"))] @@ -99,7 +99,7 @@ } pub trait ObjectAssertion: Trace { - fn run(&self, this: Option, super_obj: Option) -> Result<()>; + fn run(&self, s: State, this: Option, super_obj: Option) -> Result<()>; } // Field => This @@ -360,14 +360,14 @@ .unwrap_or(false) } - pub fn get(&self, key: IStr) -> Result> { - self.run_assertions()?; - self.get_raw(key, self.0.this_obj.as_ref()) + pub fn get(&self, s: State, key: IStr) -> Result> { + self.run_assertions(s.clone())?; + self.get_raw(s, key, self.0.this_obj.as_ref()) } // pub fn extend_with(self, key: ) - fn get_raw(&self, key: IStr, real_this: Option<&Self>) -> Result> { + fn get_raw(&self, s: State, key: IStr, real_this: Option<&Self>) -> Result> { let real_this = real_this.unwrap_or(self); let cache_key = (key.clone(), WeakObjValue(real_this.0.downgrade())); @@ -384,19 +384,20 @@ .borrow_mut() .insert(cache_key.clone(), CacheValue::Pending); let value = match (self.0.this_entries.get(&key), &self.0.super_obj) { - (Some(k), None) => Ok(Some(self.evaluate_this(k, real_this)?)), - (Some(k), Some(s)) => { - let our = self.evaluate_this(k, real_this)?; + (Some(k), None) => Ok(Some(self.evaluate_this(s, k, real_this)?)), + (Some(k), Some(super_obj)) => { + let our = self.evaluate_this(s.clone(), k, real_this)?; if k.add { - s.get_raw(key, Some(real_this))? + super_obj + .get_raw(s.clone(), key, Some(real_this))? .map_or(Ok(Some(our.clone())), |v| { - Ok(Some(evaluate_add_op(&v, &our)?)) + Ok(Some(evaluate_add_op(s.clone(), &v, &our)?)) }) } else { Ok(Some(our)) } } - (None, Some(s)) => s.get_raw(key, Some(real_this)), + (None, Some(super_obj)) => super_obj.get_raw(s, key, Some(real_this)), (None, None) => Ok(None), }; let value = match value { @@ -418,28 +419,30 @@ ); Ok(value) } - fn evaluate_this(&self, v: &ObjMember, real_this: &Self) -> Result { + fn evaluate_this(&self, s: State, v: &ObjMember, real_this: &Self) -> Result { v.invoke - .evaluate(Some(real_this.clone()), self.0.super_obj.clone())? - .evaluate() + .evaluate(s.clone(), Some(real_this.clone()), self.0.super_obj.clone())? + .evaluate(s) } - fn run_assertions_raw(&self, real_this: &Self) -> Result<()> { + fn run_assertions_raw(&self, s: State, real_this: &Self) -> Result<()> { if self.0.assertions_ran.borrow_mut().insert(real_this.clone()) { for assertion in self.0.assertions.iter() { - if let Err(e) = assertion.run(Some(real_this.clone()), self.0.super_obj.clone()) { + if let Err(e) = + assertion.run(s.clone(), Some(real_this.clone()), self.0.super_obj.clone()) + { self.0.assertions_ran.borrow_mut().remove(real_this); return Err(e); } } if let Some(super_obj) = &self.0.super_obj { - super_obj.run_assertions_raw(real_this)?; + super_obj.run_assertions_raw(s, real_this)?; } } Ok(()) } - pub fn run_assertions(&self) -> Result<()> { - self.run_assertions_raw(self) + pub fn run_assertions(&self, s: State) -> Result<()> { + self.run_assertions_raw(s, self) } pub fn ptr_eq(a: &Self, b: &Self) -> bool { @@ -565,18 +568,18 @@ pub struct ValueBuilder<'v>(&'v mut ObjValueBuilder); impl<'v> ObjMemberBuilder> { - pub fn value(self, value: Val) -> Result<()> { - self.binding(LazyBinding::Bound(LazyVal::new_resolved(value))) + pub fn value(self, s: State, value: Val) -> Result<()> { + self.binding(s, LazyBinding::Bound(LazyVal::new_resolved(value))) } - pub fn bindable(self, bindable: TraceBox) -> Result<()> { - self.binding(LazyBinding::Bindable(Cc::new(bindable))) + pub fn bindable(self, s: State, bindable: TraceBox) -> Result<()> { + self.binding(s, LazyBinding::Bindable(Cc::new(bindable))) } - pub fn binding(self, binding: LazyBinding) -> Result<()> { + pub fn binding(self, s: State, binding: LazyBinding) -> Result<()> { let (receiver, name, member) = self.build_member(binding); let location = member.location.clone(); let old = receiver.0.map.insert(name.clone(), member); if old.is_some() { - push_frame( + s.push( CallLocation(location.as_ref()), || format!("field <{}> initializtion", name.clone()), || throw!(DuplicateFieldName(name.clone())), --- a/crates/jrsonnet-evaluator/src/trace/mod.rs +++ b/crates/jrsonnet-evaluator/src/trace/mod.rs @@ -4,7 +4,7 @@ pub use location::*; -use crate::{error::Error, EvaluationState, LocError}; +use crate::{error::Error, LocError, State}; /// The way paths should be displayed pub enum PathResolver { @@ -39,16 +39,9 @@ fn write_trace( &self, out: &mut dyn std::fmt::Write, - evaluation_state: &EvaluationState, + s: &State, error: &LocError, ) -> Result<(), std::fmt::Error>; - // fn print_trace( - // &self, - // evaluation_state: &EvaluationState, - // error: &LocError, - // ) -> Result<(), std::fmt::Error> { - // self.write_trace(&mut std::fmt::stdout(), evaluation_state, error) - // } } fn print_code_location( @@ -85,7 +78,7 @@ fn write_trace( &self, out: &mut dyn std::fmt::Write, - evaluation_state: &EvaluationState, + s: &State, error: &LocError, ) -> Result<(), std::fmt::Error> { write!(out, "{}", error.error())?; @@ -128,8 +121,7 @@ if let Some(location) = location { let mut resolved_path = self.resolver.resolve(&location.0); // TODO: Process all trace elements first - let location = evaluation_state - .map_source_locations(&location.0, &[location.1, location.2]); + let location = s.map_source_locations(&location.0, &[location.1, location.2]); write!(resolved_path, ":").unwrap(); print_code_location(&mut resolved_path, &location[0], &location[1]).unwrap(); write!(resolved_path, ":").unwrap(); @@ -170,7 +162,7 @@ fn write_trace( &self, out: &mut dyn std::fmt::Write, - evaluation_state: &EvaluationState, + s: &State, error: &LocError, ) -> Result<(), std::fmt::Error> { write!(out, "{}", error.error())?; @@ -178,8 +170,7 @@ writeln!(out)?; let desc = &item.desc; if let Some(source) = &item.location { - let start_end = - evaluation_state.map_source_locations(&source.0, &[source.1, source.2]); + let start_end = s.map_source_locations(&source.0, &[source.1, source.2]); write!( out, @@ -207,7 +198,7 @@ fn write_trace( &self, out: &mut dyn std::fmt::Write, - evaluation_state: &EvaluationState, + s: &State, error: &LocError, ) -> Result<(), std::fmt::Error> { write!(out, "{}", error.error())?; @@ -240,11 +231,10 @@ writeln!(out)?; let desc = &item.desc; if let Some(source) = &item.location { - let start_end = - evaluation_state.map_source_locations(&source.0, &[source.1, source.2]); + let start_end = s.map_source_locations(&source.0, &[source.1, source.2]); self.print_snippet( out, - &evaluation_state.get_source(&source.0).unwrap(), + &s.get_source(&source.0).unwrap(), &source.0, &start_end[0], &start_end[1], --- a/crates/jrsonnet-evaluator/src/typed/conversions.rs +++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs @@ -1,8 +1,4 @@ -use std::{ - convert::{TryFrom, TryInto}, - ops::Deref, - rc::Rc, -}; +use std::{ops::Deref, rc::Rc}; use gcmodule::Cc; use jrsonnet_interner::IStr; @@ -10,11 +6,11 @@ use jrsonnet_types::{ComplexValType, ValType}; use crate::{ - error::{Error::*, LocError, Result}, + error::{Error::*, Result}, throw, typed::CheckType, val::{ArrValue, FuncDesc, FuncVal, IndexableVal}, - ObjValue, ObjValueBuilder, Val, + ObjValue, ObjValueBuilder, State, Val, }; pub trait TypedObj: Typed { @@ -27,8 +23,10 @@ } } -pub trait Typed: TryFrom + TryInto { +pub trait Typed: Sized { const TYPE: &'static ComplexValType; + fn into_untyped(typed: Self, s: State) -> Result; + fn from_untyped(untyped: Val, s: State) -> Result; } macro_rules! impl_int { @@ -36,12 +34,8 @@ impl Typed for $ty { const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64)); - } - impl TryFrom for $ty { - type Error = LocError; - - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s, &value)?; match value { Val::Num(n) => { if n.trunc() != n { @@ -58,12 +52,8 @@ _ => unreachable!(), } } - } - impl TryFrom<$ty> for Val { - type Error = LocError; - - fn try_from(value: $ty) -> Result { - Ok(Self::Num(value as f64)) + fn into_untyped(value: Self, _: State) -> Result { + Ok(Val::Num(value as f64)) } } )*}; @@ -100,12 +90,9 @@ Some(MIN as f64), Some(MAX as f64), ); - } - impl TryFrom for $name { - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s, &value)?; match value { Val::Num(n) => { if n.trunc() != n { @@ -122,12 +109,9 @@ _ => unreachable!(), } } - } - impl TryFrom<$name> for Val { - type Error = LocError; - fn try_from(value: $name) -> Result { - Ok(Self::Num(value.0 as f64)) + fn into_untyped(value: Self, _: State) -> Result { + Ok(Val::Num(value.0 as f64)) } } )*}; @@ -143,59 +127,50 @@ impl Typed for f64 { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num); -} -impl TryFrom for f64 { - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; + fn into_untyped(value: Self, _: State) -> Result { + Ok(Val::Num(value)) + } + + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s, &value)?; match value { Val::Num(n) => Ok(n), _ => unreachable!(), } } } -impl TryFrom for Val { - type Error = LocError; - - fn try_from(value: f64) -> Result { - Ok(Self::Num(value)) - } -} pub struct PositiveF64(pub f64); impl Typed for PositiveF64 { const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None); -} -impl TryFrom for PositiveF64 { - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; + fn into_untyped(value: Self, _: State) -> Result { + Ok(Val::Num(value.0)) + } + + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s, &value)?; match value { Val::Num(n) => Ok(Self(n)), _ => unreachable!(), } } } -impl TryFrom for Val { - type Error = LocError; - - fn try_from(value: PositiveF64) -> Result { - Ok(Self::Num(value.0)) - } -} - impl Typed for usize { // It is possible to store 54 bits of precision in f64, but leaving u32::MAX here for compatibility const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), Some(4294967295.0)); -} -impl TryFrom for usize { - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; + fn into_untyped(value: Self, _: State) -> Result { + if value > u32::MAX as Self { + throw!(RuntimeError("number is too large".into())) + } + Ok(Val::Num(value as f64)) + } + + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s, &value)?; match value { Val::Num(n) => { if n.trunc() != n { @@ -209,127 +184,81 @@ } } } -impl TryFrom for Val { - type Error = LocError; - fn try_from(value: usize) -> Result { - if value > u32::MAX as usize { - throw!(RuntimeError("number is too large".into())) - } - Ok(Self::Num(value as f64)) - } -} - impl Typed for IStr { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str); -} -impl TryFrom for IStr { - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; + fn into_untyped(value: Self, _: State) -> Result { + Ok(Val::Str(value)) + } + + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s, &value)?; match value { Val::Str(s) => Ok(s), _ => unreachable!(), } - } -} -impl TryFrom for Val { - type Error = LocError; - - fn try_from(value: IStr) -> Result { - Ok(Self::Str(value)) } } impl Typed for String { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str); -} -impl TryFrom for String { - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; + fn into_untyped(value: Self, _: State) -> Result { + Ok(Val::Str(value.into())) + } + + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s, &value)?; match value { Val::Str(s) => Ok(s.to_string()), _ => unreachable!(), } - } -} -impl TryFrom for Val { - type Error = LocError; - - fn try_from(value: String) -> Result { - Ok(Self::Str(value.into())) } } impl Typed for char { const TYPE: &'static ComplexValType = &ComplexValType::Char; -} -impl TryFrom for char { - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; + fn into_untyped(value: Self, _: State) -> Result { + Ok(Val::Str(value.to_string().into())) + } + + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s, &value)?; match value { Val::Str(s) => Ok(s.chars().next().unwrap()), _ => unreachable!(), } } } -impl TryFrom for Val { - type Error = LocError; - fn try_from(value: char) -> Result { - Ok(Self::Str(value.to_string().into())) - } -} - impl Typed for Vec where T: Typed, - T: TryFrom, - T: TryInto, { const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE); -} -impl TryFrom for Vec -where - T: Typed, - T: TryFrom, - T: TryInto, -{ - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; + fn into_untyped(value: Self, s: State) -> Result { + let mut o = Vec::with_capacity(value.len()); + for i in value { + o.push(T::into_untyped(i, s.clone())?); + } + Ok(Val::Arr(o.into())) + } + + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s.clone(), &value)?; match value { Val::Arr(a) => { let mut o = Self::with_capacity(a.len()); - for i in a.iter() { - o.push(T::try_from(i?)?); + for i in a.iter(s.clone()) { + o.push(T::from_untyped(i?, s.clone())?); } Ok(o) } _ => unreachable!(), - } - } -} -impl TryFrom> for Val -where - T: Typed, - T: TryFrom, - T: TryInto, -{ - type Error = LocError; - - fn try_from(value: Vec) -> Result { - let mut o = Vec::with_capacity(value.len()); - for i in value { - o.push(i.try_into()?); } - Ok(Self::Arr(o.into())) } } @@ -340,19 +269,13 @@ impl Typed for Any { const TYPE: &'static ComplexValType = &ComplexValType::Any; -} -impl TryFrom for Any { - type Error = LocError; - fn try_from(value: Val) -> Result { - Ok(Self(value)) + fn into_untyped(value: Self, _: State) -> Result { + Ok(value.0) } -} -impl TryFrom for Val { - type Error = LocError; - fn try_from(value: Any) -> Result { - Ok(value.0) + fn from_untyped(value: Val, _: State) -> Result { + Ok(Self(value)) } } @@ -361,47 +284,42 @@ impl Typed for VecVal { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr); -} -impl TryFrom for VecVal { - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; + fn into_untyped(value: Self, _: State) -> Result { + Ok(Val::Arr(ArrValue::Eager(value.0))) + } + + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s.clone(), &value)?; match value { - Val::Arr(a) => Ok(Self(a.evaluated()?)), + Val::Arr(a) => Ok(Self(a.evaluated(s)?)), _ => unreachable!(), } } } -impl TryFrom for Val { - type Error = LocError; - fn try_from(value: VecVal) -> Result { - Ok(Self::Arr(ArrValue::Eager(value.0))) - } -} - /// Specialization pub struct Bytes(pub Rc<[u8]>); impl Typed for Bytes { const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0))); -} -impl TryFrom for Bytes { - type Error = LocError; - fn try_from(value: Val) -> Result { + fn into_untyped(value: Self, _: State) -> Result { + Ok(Val::Arr(ArrValue::Bytes(value.0))) + } + + fn from_untyped(value: Val, s: State) -> Result { match value { Val::Arr(ArrValue::Bytes(bytes)) => Ok(Self(bytes)), _ => { - ::TYPE.check(&value)?; + ::TYPE.check(s.clone(), &value)?; match value { Val::Arr(a) => { let mut out = Vec::with_capacity(a.len()); - for e in a.iter() { + for e in a.iter(s.clone()) { let r = e?; - out.push(u8::try_from(r)?); + out.push(u8::from_untyped(r, s.clone())?); } Ok(Self(out.into())) } @@ -409,33 +327,20 @@ } } } - } -} -impl TryFrom for Val { - type Error = LocError; - - fn try_from(value: Bytes) -> Result { - Ok(Self::Arr(ArrValue::Bytes(value.0))) } } pub struct M1; impl Typed for M1 { const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0)); -} -impl TryFrom for M1 { - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; - Ok(Self) + fn into_untyped(_: Self, _: State) -> Result { + Ok(Val::Num(-1.0)) } -} -impl TryFrom for Val { - type Error = LocError; - fn try_from(_: M1) -> Result { - Ok(Self::Num(-1.0)) + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s, &value)?; + Ok(Self) } } @@ -449,33 +354,22 @@ $($id: Typed,)* { const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]); - } - impl<$($id),*> TryFrom for $name<$($id),*> - where - $($id: Typed,)* - { - type Error = LocError; - fn try_from(value: Val) -> Result { + fn into_untyped(value: Self, s: State) -> Result { + match value {$( + $name::$id(v) => $id::into_untyped(v, s) + ),*} + } + + fn from_untyped(value: Val, s: State) -> Result { $( - if $id::TYPE.check(&value).is_ok() { - $id::try_from(value).map(Self::$id) + if $id::TYPE.check(s.clone(), &value).is_ok() { + $id::from_untyped(value, s.clone()).map(Self::$id) } else )* { - ::TYPE.check(&value)?; + ::TYPE.check(s, &value)?; unreachable!() } - } - } - impl<$($id),*> TryFrom<$name<$($id),*>> for Val - where - $($id: Typed,)* - { - type Error = LocError; - fn try_from(value: $name<$($id),*>) -> Result { - match value {$( - $name::$id(v) => v.try_into() - ),*} } } )*} @@ -504,156 +398,113 @@ impl Typed for ArrValue { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr); -} -impl TryFrom for ArrValue { - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; + fn into_untyped(value: Self, _: State) -> Result { + Ok(Val::Arr(value)) + } + + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s, &value)?; match value { Val::Arr(a) => Ok(a), _ => unreachable!(), } } } -impl TryFrom for Val { - type Error = LocError; - fn try_from(value: ArrValue) -> Result { - Ok(Self::Arr(value)) - } -} - impl Typed for FuncVal { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func); -} -impl TryFrom for FuncVal { - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; + fn into_untyped(value: Self, _: State) -> Result { + Ok(Val::Func(value)) + } + + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s, &value)?; match value { Val::Func(a) => Ok(a), _ => unreachable!(), } } } -impl TryFrom for Val { - type Error = LocError; - fn try_from(value: FuncVal) -> Result { - Ok(Self::Func(value)) - } -} - impl Typed for Cc { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func); -} -impl TryFrom for Cc { - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; + fn into_untyped(value: Self, _: State) -> Result { + Ok(Val::Func(FuncVal::Normal(value))) + } + + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s, &value)?; match value { Val::Func(FuncVal::Normal(desc)) => Ok(desc), Val::Func(_) => throw!(RuntimeError("expected normal function, not builtin".into())), _ => unreachable!(), } - } -} -impl TryFrom> for Val { - type Error = LocError; - - fn try_from(value: Cc) -> Result { - Ok(Self::Func(FuncVal::Normal(value))) } } impl Typed for ObjValue { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Obj); -} -impl TryFrom for ObjValue { - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; + fn into_untyped(value: Self, _: State) -> Result { + Ok(Val::Obj(value)) + } + + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s, &value)?; match value { Val::Obj(a) => Ok(a), _ => unreachable!(), } } } -impl TryFrom for Val { - type Error = LocError; - fn try_from(value: ObjValue) -> Result { - Ok(Self::Obj(value)) - } -} - impl Typed for bool { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool); -} -impl TryFrom for bool { - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; + fn into_untyped(value: Self, _: State) -> Result { + Ok(Val::Bool(value)) + } + + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s, &value)?; match value { Val::Bool(a) => Ok(a), _ => unreachable!(), } } } -impl TryFrom for Val { - type Error = LocError; - - fn try_from(value: bool) -> Result { - Ok(Self::Bool(value)) - } -} - impl Typed for IndexableVal { const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[ &ComplexValType::Simple(ValType::Arr), &ComplexValType::Simple(ValType::Str), ]); -} -impl TryFrom for IndexableVal { - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; - value.into_indexable() + fn into_untyped(value: Self, _: State) -> Result { + match value { + IndexableVal::Str(s) => Ok(Val::Str(s)), + IndexableVal::Arr(a) => Ok(Val::Arr(a)), + } } -} -impl TryFrom for Val { - type Error = LocError; - fn try_from(value: IndexableVal) -> Result { - match value { - IndexableVal::Str(s) => Ok(Self::Str(s)), - IndexableVal::Arr(a) => Ok(Self::Arr(a)), - } + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s, &value)?; + value.into_indexable() } } pub struct Null; impl Typed for Null { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null); -} -impl TryFrom for Null { - type Error = LocError; - fn try_from(value: Val) -> Result { - ::TYPE.check(&value)?; - Ok(Self) + fn into_untyped(_: Self, _: State) -> Result { + Ok(Val::Null) } -} -impl TryFrom for Val { - type Error = LocError; - fn try_from(_: Null) -> Result { - Ok(Self::Null) + fn from_untyped(value: Val, s: State) -> Result { + ::TYPE.check(s, &value)?; + Ok(Self) } } --- a/crates/jrsonnet-evaluator/src/typed/mod.rs +++ b/crates/jrsonnet-evaluator/src/typed/mod.rs @@ -8,7 +8,7 @@ use crate::{ error::{Error, LocError, Result}, - push_description_frame, Val, + State, Val, }; #[derive(Debug, Error, Clone, Trace)] @@ -85,11 +85,12 @@ } fn push_type_description( + s: State, error_reason: impl Fn() -> String, path: impl Fn() -> ValuePathItem, item: impl Fn() -> Result<()>, ) -> Result<()> { - push_description_frame(error_reason, || match item() { + s.push_description(error_reason, || match item() { Ok(_) => Ok(()), Err(mut e) => { if let Error::TypeError(e) = &mut e.error_mut() { @@ -102,11 +103,11 @@ // TODO: check_fast for fast path of union type checking pub trait CheckType { - fn check(&self, value: &Val) -> Result<()>; + fn check(&self, s: State, value: &Val) -> Result<()>; } impl CheckType for ValType { - fn check(&self, value: &Val) -> Result<()> { + fn check(&self, _: State, value: &Val) -> Result<()> { let got = value.value_type(); if got != *self { let loc_error: TypeLocError = TypeError::ExpectedGot((*self).into(), got).into(); @@ -144,10 +145,10 @@ } impl CheckType for ComplexValType { - fn check(&self, value: &Val) -> Result<()> { + fn check(&self, s: State, value: &Val) -> Result<()> { match self { Self::Any => Ok(()), - Self::Simple(s) => s.check(value), + Self::Simple(t) => t.check(s, value), Self::Char => match value { Val::Str(s) if s.len() == 1 || s.chars().count() == 1 => Ok(()), v => Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()), @@ -166,11 +167,12 @@ } Self::Array(elem_type) => match value { Val::Arr(a) => { - for (i, item) in a.iter().enumerate() { + for (i, item) in a.iter(s.clone()).enumerate() { push_type_description( + s.clone(), || format!("array index {}", i), || ValuePathItem::Index(i as u64), - || elem_type.check(&item.clone()?), + || elem_type.check(s.clone(), &item.clone()?), )?; } Ok(()) @@ -179,11 +181,12 @@ }, Self::ArrayRef(elem_type) => match value { Val::Arr(a) => { - for (i, item) in a.iter().enumerate() { + for (i, item) in a.iter(s.clone()).enumerate() { push_type_description( + s.clone(), || format!("array index {}", i), || ValuePathItem::Index(i as u64), - || elem_type.check(&item.clone()?), + || elem_type.check(s.clone(), &item.clone()?), )?; } Ok(()) @@ -193,11 +196,12 @@ Self::ObjectRef(elems) => match value { Val::Obj(obj) => { for (k, v) in elems.iter() { - if let Some(got_v) = obj.get((*k).into())? { + if let Some(got_v) = obj.get(s.clone(), (*k).into())? { push_type_description( + s.clone(), || format!("property {}", k), || ValuePathItem::Field((*k).into()), - || v.check(&got_v), + || v.check(s.clone(), &got_v), )? } else { return Err( @@ -212,7 +216,7 @@ Self::Union(types) => { let mut errors = Vec::new(); for ty in types.iter() { - match ty.check(value) { + match ty.check(s.clone(), value) { Ok(()) => { return Ok(()); } @@ -227,7 +231,7 @@ Self::UnionRef(types) => { let mut errors = Vec::new(); for ty in types.iter() { - match ty.check(value) { + match ty.check(s.clone(), value) { Ok(()) => { return Ok(()); } @@ -241,13 +245,13 @@ } Self::Sum(types) => { for ty in types.iter() { - ty.check(value)? + ty.check(s.clone(), value)? } Ok(()) } Self::SumRef(types) => { for ty in types.iter() { - ty.check(value)? + ty.check(s.clone(), value)? } Ok(()) } --- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -17,11 +17,11 @@ StaticBuiltin, }, gc::TraceBox, - throw, Context, ObjValue, Result, + throw, Context, ObjValue, Result, State, }; pub trait LazyValValue: Trace { - fn get(self: Box) -> Result; + fn get(self: Box, s: State) -> Result; } #[derive(Trace)] @@ -41,11 +41,11 @@ pub fn new_resolved(val: Val) -> Self { Self(Cc::new(RefCell::new(LazyValInternals::Computed(val)))) } - pub fn force(&self) -> Result<()> { - self.evaluate()?; + pub fn force(&self, s: State) -> Result<()> { + self.evaluate(s)?; Ok(()) } - pub fn evaluate(&self) -> Result { + pub fn evaluate(&self, s: State) -> Result { match &*self.0.borrow() { LazyValInternals::Computed(v) => return Ok(v.clone()), LazyValInternals::Errored(e) => return Err(e.clone()), @@ -59,7 +59,7 @@ } else { unreachable!() }; - let new_value = match value.0.get() { + let new_value = match value.0.get(s) { Ok(v) => v, Err(e) => { *self.0.borrow_mut() = LazyValInternals::Errored(e.clone()); @@ -98,11 +98,19 @@ /// Create context, with which body code will run pub fn call_body_context( &self, + s: State, call_ctx: Context, args: &dyn ArgsLike, tailstrict: bool, ) -> Result { - parse_function_call(call_ctx, self.ctx.clone(), &self.params, args, tailstrict) + parse_function_call( + s, + call_ctx, + self.ctx.clone(), + &self.params, + args, + tailstrict, + ) } } @@ -145,6 +153,7 @@ } pub fn evaluate( &self, + s: State, call_ctx: Context, loc: CallLocation, args: &dyn ArgsLike, @@ -152,15 +161,15 @@ ) -> Result { match self { Self::Normal(func) => { - let body_ctx = func.call_body_context(call_ctx, args, tailstrict)?; - evaluate(body_ctx, &func.body) + let body_ctx = func.call_body_context(s.clone(), call_ctx, args, tailstrict)?; + evaluate(s, body_ctx, &func.body) } - Self::StaticBuiltin(b) => b.call(call_ctx, loc, args), - Self::Builtin(b) => b.call(call_ctx, loc, args), + Self::StaticBuiltin(b) => b.call(s, call_ctx, loc, args), + Self::Builtin(b) => b.call(s, call_ctx, loc, args), } } - pub fn evaluate_simple(&self, args: &dyn ArgsLike) -> Result { - self.evaluate(Context::default(), CallLocation::native(), args, true) + pub fn evaluate_simple(&self, s: State, args: &dyn ArgsLike) -> Result { + self.evaluate(s, Context::default(), CallLocation::native(), args, true) } } @@ -276,14 +285,14 @@ self.len() == 0 } - pub fn get(&self, index: usize) -> Result> { + pub fn get(&self, s: State, index: usize) -> Result> { match self { Self::Bytes(i) => i .get(index) .map_or(Ok(None), |v| Ok(Some(Val::Num(*v as f64)))), Self::Lazy(vec) => { if let Some(v) = vec.get(index) { - Ok(Some(v.evaluate()?)) + Ok(Some(v.evaluate(s)?)) } else { Ok(None) } @@ -292,9 +301,9 @@ Self::Extended(v) => { let a_len = v.0.len(); if a_len > index { - v.0.get(index) + v.0.get(s, index) } else { - v.1.get(index - a_len) + v.1.get(s, index - a_len) } } Self::Range(a, _) => { @@ -308,14 +317,14 @@ if index >= len { return Ok(None); } - v.get(len - index - 1) + v.get(s, len - index - 1) } - Self::Slice(s) => { - let index = s.from() + index * s.step(); - if index >= s.to() { + Self::Slice(v) => { + let index = v.from() + index * v.step(); + if index >= v.to() { return Ok(None); } - s.inner.get(index as usize) + v.inner.get(s, index as usize) } } } @@ -360,7 +369,7 @@ } } - pub fn evaluated(&self) -> Result>> { + pub fn evaluated(&self, s: State) -> Result>> { Ok(match self { Self::Bytes(i) => { let mut out = Vec::with_capacity(i.len()); @@ -372,14 +381,14 @@ Self::Lazy(vec) => { let mut out = Vec::with_capacity(vec.len()); for item in vec.iter() { - out.push(item.evaluate()?); + out.push(item.evaluate(s.clone())?); } Cc::new(out) } Self::Eager(vec) => vec.clone(), Self::Extended(_v) => { let mut out = Vec::with_capacity(self.len()); - for item in self.iter() { + for item in self.iter(s) { out.push(item?); } Cc::new(out) @@ -392,7 +401,7 @@ Cc::new(out) } Self::Reversed(r) => { - let mut r = r.evaluated()?; + let mut r = r.evaluated(s)?; Cc::update_with(&mut r, |v| v.reverse()); r } @@ -405,22 +414,22 @@ .take(v.to() - v.from()) .step_by(v.step()) { - out.push(v.evaluate()?) + out.push(v.evaluate(s.clone())?) } Cc::new(out) } }) } - pub fn iter(&self) -> impl DoubleEndedIterator> + '_ { + pub fn iter(&self, s: State) -> impl DoubleEndedIterator> + '_ { (0..self.len()).map(move |idx| match self { Self::Bytes(b) => Ok(Val::Num(b[idx] as f64)), - Self::Lazy(l) => l[idx].evaluate(), + Self::Lazy(l) => l[idx].evaluate(s.clone()), Self::Eager(e) => Ok(e[idx].clone()), - Self::Extended(_) => self.get(idx).map(|e| e.unwrap()), - Self::Range(..) => self.get(idx).map(|e| e.unwrap()), - Self::Reversed(..) => self.get(idx).map(|e| e.unwrap()), - Self::Slice(..) => self.get(idx).map(|e| e.unwrap()), + Self::Extended(_) => self.get(s.clone(), idx).map(|e| e.unwrap()), + Self::Range(..) => self.get(s.clone(), idx).map(|e| e.unwrap()), + Self::Reversed(..) => self.get(s.clone(), idx).map(|e| e.unwrap()), + Self::Slice(..) => self.get(s.clone(), idx).map(|e| e.unwrap()), }) } @@ -440,20 +449,20 @@ Self::Reversed(Box::new(self)) } - pub fn map(self, mapper: impl Fn(Val) -> Result) -> Result { + pub fn map(self, s: State, mapper: impl Fn(Val) -> Result) -> Result { let mut out = Vec::with_capacity(self.len()); - for value in self.iter() { + for value in self.iter(s) { out.push(mapper(value?)?); } Ok(Self::Eager(Cc::new(out))) } - pub fn filter(self, filter: impl Fn(&Val) -> Result) -> Result { + pub fn filter(self, s: State, filter: impl Fn(&Val) -> Result) -> Result { let mut out = Vec::with_capacity(self.len()); - for value in self.iter() { + for value in self.iter(s) { let value = value?; if filter(&value)? { out.push(value); @@ -566,13 +575,14 @@ } } - pub fn to_string(&self) -> Result { + pub fn to_string(&self, s: State) -> Result { Ok(match self { Self::Bool(true) => "true".into(), Self::Bool(false) => "false".into(), Self::Null => "null".into(), Self::Str(s) => s.clone(), v => manifest_json_ex( + s, v, &ManifestJsonOptions { padding: "", @@ -588,7 +598,7 @@ } /// Expects value to be object, outputs (key, manifested value) pairs - pub fn manifest_multi(&self, ty: &ManifestFormat) -> Result> { + pub fn manifest_multi(&self, s: State, ty: &ManifestFormat) -> Result> { let obj = match self { Self::Obj(obj) => obj, _ => throw!(MultiManifestOutputIsNotAObject), @@ -600,28 +610,28 @@ let mut out = Vec::with_capacity(keys.len()); for key in keys { let value = obj - .get(key.clone())? + .get(s.clone(), key.clone())? .expect("item in object") - .manifest(ty)?; + .manifest(s.clone(), ty)?; out.push((key, value)); } Ok(out) } /// Expects value to be array, outputs manifested values - pub fn manifest_stream(&self, ty: &ManifestFormat) -> Result> { + pub fn manifest_stream(&self, s: State, ty: &ManifestFormat) -> Result> { let arr = match self { Self::Arr(a) => a, _ => throw!(StreamManifestOutputIsNotAArray), }; let mut out = Vec::with_capacity(arr.len()); - for i in arr.iter() { - out.push(i?.manifest(ty)?); + for i in arr.iter(s.clone()) { + out.push(i?.manifest(s.clone(), ty)?); } Ok(out) } - pub fn manifest(&self, ty: &ManifestFormat) -> Result { + pub fn manifest(&self, s: State, ty: &ManifestFormat) -> Result { Ok(match ty { ManifestFormat::YamlStream(format) => { let arr = match self { @@ -637,9 +647,9 @@ }; if !arr.is_empty() { - for v in arr.iter() { + for v in arr.iter(s.clone()) { out.push_str("---\n"); - out.push_str(&v?.manifest(format)?); + out.push_str(&v?.manifest(s.clone(), format)?); out.push('\n'); } out.push_str("..."); @@ -652,6 +662,7 @@ #[cfg(feature = "exp-preserve-order")] preserve_order, } => self.to_yaml( + s, *padding, #[cfg(feature = "exp-preserve-order")] *preserve_order, @@ -661,11 +672,12 @@ #[cfg(feature = "exp-preserve-order")] preserve_order, } => self.to_json( + s, *padding, #[cfg(feature = "exp-preserve-order")] *preserve_order, )?, - ManifestFormat::ToString => self.to_string()?, + ManifestFormat::ToString => self.to_string(s)?, ManifestFormat::String => match self { Self::Str(s) => s.clone(), _ => throw!(StringManifestOutputIsNotAString), @@ -676,10 +688,12 @@ /// For manifestification pub fn to_json( &self, + s: State, padding: usize, #[cfg(feature = "exp-preserve-order")] preserve_order: bool, ) -> Result { manifest_json_ex( + s, self, &ManifestJsonOptions { padding: &" ".repeat(padding), @@ -700,10 +714,12 @@ /// Calls `std.manifestJson` pub fn to_std_json( &self, + s: State, padding: usize, #[cfg(feature = "exp-preserve-order")] preserve_order: bool, ) -> Result> { manifest_json_ex( + s, self, &ManifestJsonOptions { padding: &" ".repeat(padding), @@ -719,11 +735,13 @@ pub fn to_yaml( &self, + s: State, padding: usize, #[cfg(feature = "exp-preserve-order")] preserve_order: bool, ) -> Result { let padding = &" ".repeat(padding); manifest_yaml_ex( + s, self, &ManifestYamlOptions { padding, @@ -769,7 +787,7 @@ } /// Native implementation of `std.equals` -pub fn equals(val_a: &Val, val_b: &Val) -> Result { +pub fn equals(s: State, val_a: &Val, val_b: &Val) -> Result { if val_a.value_type() != val_b.value_type() { return Ok(false); } @@ -781,8 +799,8 @@ if a.len() != b.len() { return Ok(false); } - for (a, b) in a.iter().zip(b.iter()) { - if !equals(&a?, &b?)? { + for (a, b) in a.iter(s.clone()).zip(b.iter(s.clone())) { + if !equals(s.clone(), &a?, &b?)? { return Ok(false); } } @@ -804,7 +822,11 @@ return Ok(false); } for field in fields { - if !equals(&a.get(field.clone())?.unwrap(), &b.get(field)?.unwrap())? { + if !equals( + s.clone(), + &a.get(s.clone(), field.clone())?.unwrap(), + &b.get(s.clone(), field)?.unwrap(), + )? { return Ok(false); } } --- a/crates/jrsonnet-macros/src/lib.rs +++ b/crates/jrsonnet-macros/src/lib.rs @@ -129,6 +129,7 @@ is_option: bool, name: String, }, + State, Location, This, } @@ -144,7 +145,9 @@ _ => return Err(Error::new(arg.pat.span(), "arg should be plain identifier")), }; let ty = &arg.ty; - if type_is_path(ty, "CallLocation").is_some() { + if type_is_path(ty, "State").is_some() { + return Ok(Self::State); + } else if type_is_path(ty, "CallLocation").is_some() { return Ok(Self::Location); } else if type_is_path(ty, "Self").is_some() { return Ok(Self::This); @@ -208,6 +211,24 @@ } ReturnType::Type(_, ref ty) => ty.clone(), }; + let result_inner = if let Some(args) = type_is_path(&result, "Result") { + let generic_arg = match args { + PathArguments::AngleBracketed(params) => params.args.iter().next().unwrap(), + _ => return Err(Error::new(args.span(), "missing result generic")), + }; + // This argument must be a type: + match generic_arg { + GenericArgument::Type(ty) => ty, + _ => { + return Err(Error::new( + generic_arg.span(), + "option generic should be a type", + )) + } + } + } else { + return Err(Error::new(result.span(), "return value should be result")); + }; let args = fun .sig @@ -235,6 +256,7 @@ has_default: #is_option, }, }), + ArgInfo::State => None, ArgInfo::Location => None, ArgInfo::This => None, }); @@ -246,9 +268,9 @@ name, cfg_attrs, } => { - let eval = quote! {::jrsonnet_evaluator::push_description_frame( + let eval = quote! {s.push_description( || format!("argument <{}> evaluation", #name), - || <#ty>::try_from(value.evaluate()?), + || <#ty>::from_untyped(value.evaluate(s.clone())?, s.clone()), )?}; let value = if *is_option { quote! {if let Some(value) = parsed.get(#name) { @@ -280,6 +302,7 @@ } } } + ArgInfo::State => quote! {s.clone(),}, ArgInfo::Location => quote! {location,}, ArgInfo::This => quote! {self,}, }); @@ -320,6 +343,7 @@ } const _: () = { use ::jrsonnet_evaluator::{ + State, function::{Builtin, CallLocation, StaticBuiltin, BuiltinParam, ArgsLike, parse_builtin_call}, error::Result, Context, parser::ExprLocation, @@ -339,12 +363,12 @@ fn params(&self) -> &[BuiltinParam] { PARAMS } - fn call(&self, context: Context, location: CallLocation, args: &dyn ArgsLike) -> Result { - let parsed = parse_builtin_call(context, &PARAMS, args, false)?; + fn call(&self, s: State, ctx: Context, location: CallLocation, args: &dyn ArgsLike) -> Result { + let parsed = parse_builtin_call(s.clone(), ctx, &PARAMS, args, false)?; let result: #result = #name(#(#pass)*); let result = result?; - result.try_into() + <#result_inner>::into_untyped(result, s) } } }; @@ -539,6 +563,18 @@ ]; impl Typed for #ident { const TYPE: &'static ComplexValType = &ComplexValType::ObjectRef(&ITEMS); + + fn from_untyped(value: Val, s: State) -> Result { + let obj = value.as_obj().expect("shape is correct"); + Self::parse(&obj) + } + + fn into_untyped(value: Self, s: State) -> Result { + let mut out = ObjValueBuilder::new(); + value.serialize(&mut out)?; + Ok(Val::Obj(out.build())) + } + } } }; @@ -567,25 +603,8 @@ Ok(Self { #(#fields_parse)* }) - } - } - - impl TryFrom for #ident { - type Error = LocError; - fn try_from(value: Val) -> Result { - let obj = value.as_obj().expect("shape is correct"); - Self::parse(&obj) - } - } - impl TryInto for #ident { - type Error = LocError; - fn try_into(self) -> Result { - let mut out = ObjValueBuilder::new(); - self.serialize(&mut out)?; - Ok(Val::Obj(out.build())) } } - () }; }) }