difftreelog
refactor remove implicit global state
in: master
31 files changed
bindings/jsonnet/src/import.rsdiffbeforeafterboth--- 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;
bindings/jsonnet/src/interop.rsdiffbeforeafterboth--- 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)),
bindings/jsonnet/src/lib.rsdiffbeforeafterboth--- 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::<u8>()).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<IStr>) -> *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()
+ }
+ }
}
bindings/jsonnet/src/native.rsdiffbeforeafterboth--- 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<Rc<Path>>, args: &[Val]) -> Result<Val, LocError> {
+ fn call(&self, s: State, _from: Option<Rc<Path>>, args: &[Val]) -> Result<Val, LocError> {
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,
bindings/jsonnet/src/val_extract.rsdiffbeforeafterboth--- 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,
bindings/jsonnet/src/val_make.rsdiffbeforeafterboth--- 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())))
}
bindings/jsonnet/src/val_modify.rsdiffbeforeafterboth--- 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,
bindings/jsonnet/src/vars_tlas.rsdiffbeforeafterboth--- 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(
cmds/jrsonnet/src/main.rsdiffbeforeafterboth--- 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("<cmdline>").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("<stdin>").into(), input_str)?
+ s.evaluate_snippet_raw(PathBuf::from("<stdin>").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);
}
crates/jrsonnet-cli/src/ext.rsdiffbeforeafterboth--- 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<ExtFile>,
}
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(())
}
crates/jrsonnet-cli/src/lib.rsdiffbeforeafterboth--- 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<PathBuf>,
}
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(())
}
}
crates/jrsonnet-cli/src/manifest.rsdiffbeforeafterboth--- 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(())
}
crates/jrsonnet-cli/src/tla.rsdiffbeforeafterboth--- 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<ExtFile>,
}
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(())
}
crates/jrsonnet-cli/src/trace.rsdiffbeforeafterboth--- 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(())
}
}
crates/jrsonnet-evaluator/src/builtin/format.rsdiffbeforeafterboth1//! faster std.format impl2#![allow(clippy::too_many_arguments)]34use std::convert::TryFrom;56use gcmodule::Trace;7use jrsonnet_interner::IStr;8use jrsonnet_types::ValType;9use thiserror::Error;1011use crate::{error::Error::*, throw, LocError, ObjValue, Result, Val};1213#[derive(Debug, Clone, Error, Trace)]14pub enum FormatError {15 #[error("truncated format code")]16 TruncatedFormatCode,17 #[error("unrecognized conversion type: {0}")]18 UnrecognizedConversionType(char),1920 #[error("not enough values")]21 NotEnoughValues,2223 #[error("cannot use * width with object")]24 CannotUseStarWidthWithObject,25 #[error("mapping keys required")]26 MappingKeysRequired,27 #[error("no such format field: {0}")]28 NoSuchFormatField(IStr),29}3031impl From<FormatError> for LocError {32 fn from(e: FormatError) -> Self {33 Self::new(Format(e))34 }35}3637use FormatError::*;3839type ParseResult<'t, T> = std::result::Result<(T, &'t str), FormatError>;4041pub fn try_parse_mapping_key(str: &str) -> ParseResult<&str> {42 if str.is_empty() {43 return Err(TruncatedFormatCode);44 }45 let bytes = str.as_bytes();46 if bytes[0] == b'(' {47 let mut i = 1;48 while i < bytes.len() {49 if bytes[i] == b')' {50 return Ok((&str[1..i as usize], &str[i as usize + 1..]));51 }52 i += 1;53 }54 Err(TruncatedFormatCode)55 } else {56 Ok(("", str))57 }58}5960#[cfg(test)]61pub mod tests_key {62 use super::*;6364 #[test]65 fn parse_key() {66 assert_eq!(67 try_parse_mapping_key("(hello ) world").unwrap(),68 ("hello ", " world")69 );70 assert_eq!(try_parse_mapping_key("() world").unwrap(), ("", " world"));71 assert_eq!(try_parse_mapping_key(" world").unwrap(), ("", " world"));72 assert_eq!(73 try_parse_mapping_key(" () world").unwrap(),74 ("", " () world")75 );76 }7778 #[test]79 #[should_panic]80 fn parse_key_missing_start() {81 try_parse_mapping_key("").unwrap();82 }8384 #[test]85 #[should_panic]86 fn parse_key_missing_end() {87 try_parse_mapping_key("( ").unwrap();88 }89}9091#[derive(Default, Debug)]92pub struct CFlags {93 pub alt: bool,94 pub zero: bool,95 pub left: bool,96 pub blank: bool,97 pub sign: bool,98}99100pub fn try_parse_cflags(str: &str) -> ParseResult<CFlags> {101 if str.is_empty() {102 return Err(TruncatedFormatCode);103 }104 let bytes = str.as_bytes();105 let mut i = 0;106 let mut out = CFlags::default();107 loop {108 if bytes.len() == i {109 return Err(TruncatedFormatCode);110 }111 match bytes[i] {112 b'#' => out.alt = true,113 b'0' => out.zero = true,114 b'-' => out.left = true,115 b' ' => out.blank = true,116 b'+' => out.sign = true,117 _ => break,118 }119 i += 1;120 }121 Ok((out, &str[i..]))122}123124#[derive(Debug, PartialEq)]125pub enum Width {126 Star,127 Fixed(usize),128}129pub fn try_parse_field_width(str: &str) -> ParseResult<Width> {130 if str.is_empty() {131 return Err(TruncatedFormatCode);132 }133 let bytes = str.as_bytes();134 if bytes[0] == b'*' {135 return Ok((Width::Star, &str[1..]));136 }137 let mut out: usize = 0;138 let mut digits = 0;139 while let Some(digit) = (bytes[digits] as char).to_digit(10) {140 out *= 10;141 out += digit as usize;142 digits += 1;143 if digits == bytes.len() {144 return Err(TruncatedFormatCode);145 }146 }147 Ok((Width::Fixed(out), &str[digits..]))148}149150pub fn try_parse_precision(str: &str) -> ParseResult<Option<Width>> {151 if str.is_empty() {152 return Err(TruncatedFormatCode);153 }154 let bytes = str.as_bytes();155 if bytes[0] == b'.' {156 try_parse_field_width(&str[1..]).map(|(r, s)| (Some(r), s))157 } else {158 Ok((None, str))159 }160}161162// Only skips163pub fn try_parse_length_modifier(str: &str) -> ParseResult<()> {164 if str.is_empty() {165 return Err(TruncatedFormatCode);166 }167 let bytes = str.as_bytes();168 let mut idx = 0;169 while bytes[idx] == b'h' || bytes[idx] == b'l' || bytes[idx] == b'L' {170 idx += 1;171 if bytes.len() == idx {172 return Err(TruncatedFormatCode);173 }174 }175 Ok(((), &str[idx..]))176}177178#[derive(Debug, PartialEq)]179pub enum ConvTypeV {180 Decimal,181 Octal,182 Hexadecimal,183 Scientific,184 Float,185 Shorter,186 Char,187 String,188 Percent,189}190pub struct ConvType {191 v: ConvTypeV,192 caps: bool,193}194195pub fn parse_conversion_type(str: &str) -> ParseResult<ConvType> {196 if str.is_empty() {197 return Err(TruncatedFormatCode);198 }199200 let code = str.as_bytes()[0];201 let v: (ConvTypeV, bool) = match code {202 b'd' | b'i' | b'u' => (ConvTypeV::Decimal, false),203 b'o' => (ConvTypeV::Octal, false),204 b'x' => (ConvTypeV::Hexadecimal, false),205 b'X' => (ConvTypeV::Hexadecimal, true),206 b'e' => (ConvTypeV::Scientific, false),207 b'E' => (ConvTypeV::Scientific, true),208 b'f' => (ConvTypeV::Float, false),209 b'F' => (ConvTypeV::Float, true),210 b'g' => (ConvTypeV::Shorter, false),211 b'G' => (ConvTypeV::Shorter, true),212 b'c' => (ConvTypeV::Char, false),213 b's' => (ConvTypeV::String, false),214 b'%' => (ConvTypeV::Percent, false),215 c => return Err(UnrecognizedConversionType(c as char)),216 };217218 Ok((ConvType { v: v.0, caps: v.1 }, &str[1..]))219}220221#[derive(Debug)]222pub struct Code<'s> {223 mkey: &'s str,224 cflags: CFlags,225 width: Width,226 precision: Option<Width>,227 convtype: ConvTypeV,228 caps: bool,229}230pub fn parse_code(str: &str) -> ParseResult<Code> {231 if str.is_empty() {232 return Err(TruncatedFormatCode);233 }234 let (mkey, str) = try_parse_mapping_key(str)?;235 let (cflags, str) = try_parse_cflags(str)?;236 let (width, str) = try_parse_field_width(str)?;237 let (precision, str) = try_parse_precision(str)?;238 let (_, str) = try_parse_length_modifier(str)?;239 let (convtype, str) = parse_conversion_type(str)?;240241 Ok((242 Code {243 mkey,244 cflags,245 width,246 precision,247 convtype: convtype.v,248 caps: convtype.caps,249 },250 str,251 ))252}253254#[derive(Debug)]255pub enum Element<'s> {256 String(&'s str),257 Code(Code<'s>),258}259pub fn parse_codes(mut str: &str) -> Result<Vec<Element>> {260 let mut bytes = str.as_bytes();261 let mut out = vec![];262 let mut offset = 0;263264 loop {265 while offset != bytes.len() && bytes[offset] != b'%' {266 offset += 1;267 }268 if offset != 0 {269 out.push(Element::String(&str[0..offset]));270 }271 if offset == bytes.len() {272 return Ok(out);273 }274 str = &str[offset + 1..];275 let (code, nstr) = parse_code(str)?;276 str = nstr;277 bytes = str.as_bytes();278 offset = 0;279280 out.push(Element::Code(code))281 }282}283284const NUMBERS: &[u8] = b"0123456789abcdefghijklmnopqrstuvwxyz";285286#[inline]287pub fn render_integer(288 out: &mut String,289 iv: i64,290 padding: usize,291 precision: usize,292 blank: bool,293 sign: bool,294 radix: i64,295 prefix: &str,296 caps: bool,297) {298 // Digit char indexes in reverse order, i.e299 // for radix = 16 and n = 12f: [15, 2, 1]300 let digits = if iv == 0 {301 vec![0u8]302 } else {303 let mut v = iv.abs();304 let mut nums = Vec::with_capacity(1);305 while v > 0 {306 nums.push((v % radix) as u8);307 v /= radix;308 }309 nums310 };311 let neg = iv < 0;312 let zp = padding.saturating_sub(if neg || blank || sign { 1 } else { 0 });313 let zp2 = zp314 .max(precision)315 .saturating_sub(prefix.len() + digits.len());316317 if neg {318 out.push('-')319 } else if sign {320 out.push('+');321 } else if blank {322 out.push(' ');323 }324325 out.reserve(zp2);326 for _ in 0..zp2 {327 out.push('0');328 }329 out.push_str(prefix);330331 for digit in digits.into_iter().rev() {332 let ch = NUMBERS[digit as usize] as char;333 out.push(if caps { ch.to_ascii_uppercase() } else { ch });334 }335}336337pub fn render_decimal(338 out: &mut String,339 iv: i64,340 padding: usize,341 precision: usize,342 blank: bool,343 sign: bool,344) {345 render_integer(out, iv, padding, precision, blank, sign, 10, "", false)346}347pub fn render_octal(348 out: &mut String,349 iv: i64,350 padding: usize,351 precision: usize,352 alt: bool,353 blank: bool,354 sign: bool,355) {356 render_integer(357 out,358 iv,359 padding,360 precision,361 blank,362 sign,363 8,364 if alt && iv != 0 { "0" } else { "" },365 false,366 )367}368pub fn render_hexadecimal(369 out: &mut String,370 iv: i64,371 padding: usize,372 precision: usize,373 alt: bool,374 blank: bool,375 sign: bool,376 caps: bool,377) {378 render_integer(379 out,380 iv,381 padding,382 precision,383 blank,384 sign,385 16,386 match (alt, caps) {387 (true, true) => "0X",388 (true, false) => "0x",389 (false, _) => "",390 },391 caps,392 )393}394395pub fn render_float(396 out: &mut String,397 n: f64,398 mut padding: usize,399 precision: usize,400 blank: bool,401 sign: bool,402 ensure_pt: bool,403 trailing: bool,404) {405 let dot_size = if precision == 0 && !ensure_pt { 0 } else { 1 };406 padding = padding.saturating_sub(dot_size + precision);407 render_decimal(out, n.floor() as i64, padding, 0, blank, sign);408 if precision == 0 {409 if ensure_pt {410 out.push('.');411 }412 return;413 }414 let frac = n415 .fract()416 .mul_add(10.0_f64.powf(precision as f64), 0.5)417 .floor();418 if trailing || frac > 0.0 {419 out.push('.');420 let mut frac_str = String::new();421 render_decimal(&mut frac_str, frac as i64, precision, 0, false, false);422 let mut trim = frac_str.len();423 if !trailing {424 for b in frac_str.as_bytes().iter().rev() {425 if *b == b'0' {426 trim -= 1;427 }428 }429 }430 out.push_str(&frac_str[..trim]);431 } else if ensure_pt {432 out.push('.');433 }434}435436pub fn render_float_sci(437 out: &mut String,438 n: f64,439 mut padding: usize,440 precision: usize,441 blank: bool,442 sign: bool,443 ensure_pt: bool,444 trailing: bool,445 caps: bool,446) {447 let exponent = n.log10().floor();448 let mantissa = if exponent as i16 == -324 {449 n * 10.0 / 10.0_f64.powf(exponent + 1.0)450 } else {451 n / 10.0_f64.powf(exponent)452 };453 let mut exponent_str = String::new();454 render_decimal(&mut exponent_str, exponent as i64, 3, 0, false, true);455456 // +1 for e457 padding = padding.saturating_sub(exponent_str.len() + 1);458459 render_float(460 out, mantissa, padding, precision, blank, sign, ensure_pt, trailing,461 );462 out.push(if caps { 'E' } else { 'e' });463 out.push_str(&exponent_str);464}465466pub fn format_code(467 out: &mut String,468 value: &Val,469 code: &Code,470 width: usize,471 precision: Option<usize>,472) -> Result<()> {473 let clfags = &code.cflags;474 let (fpprec, iprec) = match precision {475 Some(v) => (v, v),476 None => (6, 0),477 };478 let padding = if clfags.zero && !clfags.left {479 width480 } else {481 0482 };483484 // TODO: If left padded, can optimize by writing directly to out485 let mut tmp_out = String::new();486487 match code.convtype {488 ConvTypeV::String => tmp_out.push_str(&value.clone().to_string()?),489 ConvTypeV::Decimal => {490 let value = f64::try_from(value.clone())?;491 render_decimal(492 &mut tmp_out,493 value as i64,494 padding,495 iprec,496 clfags.blank,497 clfags.sign,498 );499 }500 ConvTypeV::Octal => {501 let value = f64::try_from(value.clone())?;502 render_octal(503 &mut tmp_out,504 value as i64,505 padding,506 iprec,507 clfags.alt,508 clfags.blank,509 clfags.sign,510 );511 }512 ConvTypeV::Hexadecimal => {513 let value = f64::try_from(value.clone())?;514 render_hexadecimal(515 &mut tmp_out,516 value as i64,517 padding,518 iprec,519 clfags.alt,520 clfags.blank,521 clfags.sign,522 code.caps,523 );524 }525 ConvTypeV::Scientific => {526 let value = f64::try_from(value.clone())?;527 render_float_sci(528 &mut tmp_out,529 value,530 padding,531 fpprec,532 clfags.blank,533 clfags.sign,534 clfags.alt,535 true,536 code.caps,537 );538 }539 ConvTypeV::Float => {540 let value = f64::try_from(value.clone())?;541 render_float(542 &mut tmp_out,543 value,544 padding,545 fpprec,546 clfags.blank,547 clfags.sign,548 clfags.alt,549 true,550 );551 }552 ConvTypeV::Shorter => {553 let value = f64::try_from(value.clone())?;554 let exponent = value.log10().floor();555 if exponent < -4.0 || exponent >= fpprec as f64 {556 render_float_sci(557 &mut tmp_out,558 value,559 padding,560 fpprec - 1,561 clfags.blank,562 clfags.sign,563 clfags.alt,564 clfags.alt,565 code.caps,566 );567 } else {568 let digits_before_pt = 1.max(exponent as usize + 1);569 render_float(570 &mut tmp_out,571 value,572 padding,573 fpprec - digits_before_pt,574 clfags.blank,575 clfags.sign,576 clfags.alt,577 clfags.alt,578 );579 }580 }581 ConvTypeV::Char => match value.clone() {582 Val::Num(n) => tmp_out583 .push(std::char::from_u32(n as u32).ok_or(InvalidUnicodeCodepointGot(n as u32))?),584 Val::Str(s) => {585 if s.chars().count() != 1 {586 throw!(RuntimeError(587 format!("%c expected 1 char string, got {}", s.chars().count()).into(),588 ));589 }590 tmp_out.push_str(&s);591 }592 _ => {593 throw!(TypeMismatch(594 "%c requires number/string",595 vec![ValType::Num, ValType::Str],596 value.value_type(),597 ));598 }599 },600 ConvTypeV::Percent => tmp_out.push('%'),601 };602603 let padding = width.saturating_sub(tmp_out.len());604605 if !clfags.left {606 for _ in 0..padding {607 out.push(' ');608 }609 }610 out.push_str(&tmp_out);611 if clfags.left {612 for _ in 0..padding {613 out.push(' ');614 }615 }616617 Ok(())618}619620pub fn format_arr(str: &str, mut values: &[Val]) -> Result<String> {621 let codes = parse_codes(str)?;622 let mut out = String::new();623624 for code in codes {625 match code {626 Element::String(s) => {627 out.push_str(s);628 }629 Element::Code(c) => {630 let width = match c.width {631 Width::Star => {632 if values.is_empty() {633 throw!(NotEnoughValues);634 }635 let value = &values[0];636 values = &values[1..];637 usize::try_from(value.clone())?638 }639 Width::Fixed(n) => n,640 };641 let precision = match c.precision {642 Some(Width::Star) => {643 if values.is_empty() {644 throw!(NotEnoughValues);645 }646 let value = &values[0];647 values = &values[1..];648 Some(usize::try_from(value.clone())?)649 }650 Some(Width::Fixed(n)) => Some(n),651 None => None,652 };653654 // %% should not consume a value655 let value = if c.convtype == ConvTypeV::Percent {656 &Val::Null657 } else {658 if values.is_empty() {659 throw!(NotEnoughValues);660 }661 let value = &values[0];662 values = &values[1..];663 value664 };665666 format_code(&mut out, value, &c, width, precision)?;667 }668 }669 }670671 Ok(out)672}673674pub fn format_obj(str: &str, values: &ObjValue) -> Result<String> {675 let codes = parse_codes(str)?;676 let mut out = String::new();677678 for code in codes {679 match code {680 Element::String(s) => {681 out.push_str(s);682 }683 Element::Code(c) => {684 // TODO: Operate on ref685 let f: IStr = c.mkey.into();686 let width = match c.width {687 Width::Star => {688 throw!(CannotUseStarWidthWithObject);689 }690 Width::Fixed(n) => n,691 };692 let precision = match c.precision {693 Some(Width::Star) => {694 throw!(CannotUseStarWidthWithObject);695 }696 Some(Width::Fixed(n)) => Some(n),697 None => None,698 };699700 let value = if c.convtype == ConvTypeV::Percent {701 Val::Null702 } else {703 if f.is_empty() {704 throw!(MappingKeysRequired);705 }706 if let Some(v) = values.get(f.clone())? {707 v708 } else {709 throw!(NoSuchFormatField(f));710 }711 };712713 format_code(&mut out, &value, &c, width, precision)?;714 }715 }716 }717718 Ok(out)719}720721#[cfg(test)]722pub mod test_format {723 use super::*;724725 #[test]726 fn parse() {727 assert_eq!(728 parse_codes(729 "How much error budget is left looking at our %.3f%% availability gurantees?"730 )731 .unwrap()732 .len(),733 4734 );735 }736737 #[test]738 fn octals() {739 assert_eq!(format_arr("%#o", &[Val::Num(8.0)]).unwrap(), "010");740 assert_eq!(format_arr("%#4o", &[Val::Num(8.0)]).unwrap(), " 010");741 assert_eq!(format_arr("%4o", &[Val::Num(8.0)]).unwrap(), " 10");742 assert_eq!(format_arr("%04o", &[Val::Num(8.0)]).unwrap(), "0010");743 assert_eq!(format_arr("%+4o", &[Val::Num(8.0)]).unwrap(), " +10");744 assert_eq!(format_arr("%+04o", &[Val::Num(8.0)]).unwrap(), "+010");745 assert_eq!(format_arr("%-4o", &[Val::Num(8.0)]).unwrap(), "10 ");746 assert_eq!(format_arr("%+-4o", &[Val::Num(8.0)]).unwrap(), "+10 ");747 assert_eq!(format_arr("%+-04o", &[Val::Num(8.0)]).unwrap(), "+10 ");748 }749750 #[test]751 fn percent_doesnt_consumes_values() {752 assert_eq!(753 format_arr(754 "How much error budget is left looking at our %.3f%% availability gurantees?",755 &[Val::Num(4.0)]756 )757 .unwrap(),758 "How much error budget is left looking at our 4.000% availability gurantees?"759 );760 }761}1//! faster std.format impl2#![allow(clippy::too_many_arguments)]34use gcmodule::Trace;5use jrsonnet_interner::IStr;6use jrsonnet_types::ValType;7use thiserror::Error;89use crate::{error::Error::*, throw, typed::Typed, LocError, ObjValue, Result, State, Val};1011#[derive(Debug, Clone, Error, Trace)]12pub enum FormatError {13 #[error("truncated format code")]14 TruncatedFormatCode,15 #[error("unrecognized conversion type: {0}")]16 UnrecognizedConversionType(char),1718 #[error("not enough values")]19 NotEnoughValues,2021 #[error("cannot use * width with object")]22 CannotUseStarWidthWithObject,23 #[error("mapping keys required")]24 MappingKeysRequired,25 #[error("no such format field: {0}")]26 NoSuchFormatField(IStr),27}2829impl From<FormatError> for LocError {30 fn from(e: FormatError) -> Self {31 Self::new(Format(e))32 }33}3435use FormatError::*;3637type ParseResult<'t, T> = std::result::Result<(T, &'t str), FormatError>;3839pub fn try_parse_mapping_key(str: &str) -> ParseResult<&str> {40 if str.is_empty() {41 return Err(TruncatedFormatCode);42 }43 let bytes = str.as_bytes();44 if bytes[0] == b'(' {45 let mut i = 1;46 while i < bytes.len() {47 if bytes[i] == b')' {48 return Ok((&str[1..i as usize], &str[i as usize + 1..]));49 }50 i += 1;51 }52 Err(TruncatedFormatCode)53 } else {54 Ok(("", str))55 }56}5758#[cfg(test)]59pub mod tests_key {60 use super::*;6162 #[test]63 fn parse_key() {64 assert_eq!(65 try_parse_mapping_key("(hello ) world").unwrap(),66 ("hello ", " world")67 );68 assert_eq!(try_parse_mapping_key("() world").unwrap(), ("", " world"));69 assert_eq!(try_parse_mapping_key(" world").unwrap(), ("", " world"));70 assert_eq!(71 try_parse_mapping_key(" () world").unwrap(),72 ("", " () world")73 );74 }7576 #[test]77 #[should_panic]78 fn parse_key_missing_start() {79 try_parse_mapping_key("").unwrap();80 }8182 #[test]83 #[should_panic]84 fn parse_key_missing_end() {85 try_parse_mapping_key("( ").unwrap();86 }87}8889#[derive(Default, Debug)]90pub struct CFlags {91 pub alt: bool,92 pub zero: bool,93 pub left: bool,94 pub blank: bool,95 pub sign: bool,96}9798pub fn try_parse_cflags(str: &str) -> ParseResult<CFlags> {99 if str.is_empty() {100 return Err(TruncatedFormatCode);101 }102 let bytes = str.as_bytes();103 let mut i = 0;104 let mut out = CFlags::default();105 loop {106 if bytes.len() == i {107 return Err(TruncatedFormatCode);108 }109 match bytes[i] {110 b'#' => out.alt = true,111 b'0' => out.zero = true,112 b'-' => out.left = true,113 b' ' => out.blank = true,114 b'+' => out.sign = true,115 _ => break,116 }117 i += 1;118 }119 Ok((out, &str[i..]))120}121122#[derive(Debug, PartialEq)]123pub enum Width {124 Star,125 Fixed(usize),126}127pub fn try_parse_field_width(str: &str) -> ParseResult<Width> {128 if str.is_empty() {129 return Err(TruncatedFormatCode);130 }131 let bytes = str.as_bytes();132 if bytes[0] == b'*' {133 return Ok((Width::Star, &str[1..]));134 }135 let mut out: usize = 0;136 let mut digits = 0;137 while let Some(digit) = (bytes[digits] as char).to_digit(10) {138 out *= 10;139 out += digit as usize;140 digits += 1;141 if digits == bytes.len() {142 return Err(TruncatedFormatCode);143 }144 }145 Ok((Width::Fixed(out), &str[digits..]))146}147148pub fn try_parse_precision(str: &str) -> ParseResult<Option<Width>> {149 if str.is_empty() {150 return Err(TruncatedFormatCode);151 }152 let bytes = str.as_bytes();153 if bytes[0] == b'.' {154 try_parse_field_width(&str[1..]).map(|(r, s)| (Some(r), s))155 } else {156 Ok((None, str))157 }158}159160// Only skips161pub fn try_parse_length_modifier(str: &str) -> ParseResult<()> {162 if str.is_empty() {163 return Err(TruncatedFormatCode);164 }165 let bytes = str.as_bytes();166 let mut idx = 0;167 while bytes[idx] == b'h' || bytes[idx] == b'l' || bytes[idx] == b'L' {168 idx += 1;169 if bytes.len() == idx {170 return Err(TruncatedFormatCode);171 }172 }173 Ok(((), &str[idx..]))174}175176#[derive(Debug, PartialEq)]177pub enum ConvTypeV {178 Decimal,179 Octal,180 Hexadecimal,181 Scientific,182 Float,183 Shorter,184 Char,185 String,186 Percent,187}188pub struct ConvType {189 v: ConvTypeV,190 caps: bool,191}192193pub fn parse_conversion_type(str: &str) -> ParseResult<ConvType> {194 if str.is_empty() {195 return Err(TruncatedFormatCode);196 }197198 let code = str.as_bytes()[0];199 let v: (ConvTypeV, bool) = match code {200 b'd' | b'i' | b'u' => (ConvTypeV::Decimal, false),201 b'o' => (ConvTypeV::Octal, false),202 b'x' => (ConvTypeV::Hexadecimal, false),203 b'X' => (ConvTypeV::Hexadecimal, true),204 b'e' => (ConvTypeV::Scientific, false),205 b'E' => (ConvTypeV::Scientific, true),206 b'f' => (ConvTypeV::Float, false),207 b'F' => (ConvTypeV::Float, true),208 b'g' => (ConvTypeV::Shorter, false),209 b'G' => (ConvTypeV::Shorter, true),210 b'c' => (ConvTypeV::Char, false),211 b's' => (ConvTypeV::String, false),212 b'%' => (ConvTypeV::Percent, false),213 c => return Err(UnrecognizedConversionType(c as char)),214 };215216 Ok((ConvType { v: v.0, caps: v.1 }, &str[1..]))217}218219#[derive(Debug)]220pub struct Code<'s> {221 mkey: &'s str,222 cflags: CFlags,223 width: Width,224 precision: Option<Width>,225 convtype: ConvTypeV,226 caps: bool,227}228pub fn parse_code(str: &str) -> ParseResult<Code> {229 if str.is_empty() {230 return Err(TruncatedFormatCode);231 }232 let (mkey, str) = try_parse_mapping_key(str)?;233 let (cflags, str) = try_parse_cflags(str)?;234 let (width, str) = try_parse_field_width(str)?;235 let (precision, str) = try_parse_precision(str)?;236 let (_, str) = try_parse_length_modifier(str)?;237 let (convtype, str) = parse_conversion_type(str)?;238239 Ok((240 Code {241 mkey,242 cflags,243 width,244 precision,245 convtype: convtype.v,246 caps: convtype.caps,247 },248 str,249 ))250}251252#[derive(Debug)]253pub enum Element<'s> {254 String(&'s str),255 Code(Code<'s>),256}257pub fn parse_codes(mut str: &str) -> Result<Vec<Element>> {258 let mut bytes = str.as_bytes();259 let mut out = vec![];260 let mut offset = 0;261262 loop {263 while offset != bytes.len() && bytes[offset] != b'%' {264 offset += 1;265 }266 if offset != 0 {267 out.push(Element::String(&str[0..offset]));268 }269 if offset == bytes.len() {270 return Ok(out);271 }272 str = &str[offset + 1..];273 let (code, nstr) = parse_code(str)?;274 str = nstr;275 bytes = str.as_bytes();276 offset = 0;277278 out.push(Element::Code(code))279 }280}281282const NUMBERS: &[u8] = b"0123456789abcdefghijklmnopqrstuvwxyz";283284#[inline]285pub fn render_integer(286 out: &mut String,287 iv: i64,288 padding: usize,289 precision: usize,290 blank: bool,291 sign: bool,292 radix: i64,293 prefix: &str,294 caps: bool,295) {296 // Digit char indexes in reverse order, i.e297 // for radix = 16 and n = 12f: [15, 2, 1]298 let digits = if iv == 0 {299 vec![0u8]300 } else {301 let mut v = iv.abs();302 let mut nums = Vec::with_capacity(1);303 while v > 0 {304 nums.push((v % radix) as u8);305 v /= radix;306 }307 nums308 };309 let neg = iv < 0;310 let zp = padding.saturating_sub(if neg || blank || sign { 1 } else { 0 });311 let zp2 = zp312 .max(precision)313 .saturating_sub(prefix.len() + digits.len());314315 if neg {316 out.push('-')317 } else if sign {318 out.push('+');319 } else if blank {320 out.push(' ');321 }322323 out.reserve(zp2);324 for _ in 0..zp2 {325 out.push('0');326 }327 out.push_str(prefix);328329 for digit in digits.into_iter().rev() {330 let ch = NUMBERS[digit as usize] as char;331 out.push(if caps { ch.to_ascii_uppercase() } else { ch });332 }333}334335pub fn render_decimal(336 out: &mut String,337 iv: i64,338 padding: usize,339 precision: usize,340 blank: bool,341 sign: bool,342) {343 render_integer(out, iv, padding, precision, blank, sign, 10, "", false)344}345pub fn render_octal(346 out: &mut String,347 iv: i64,348 padding: usize,349 precision: usize,350 alt: bool,351 blank: bool,352 sign: bool,353) {354 render_integer(355 out,356 iv,357 padding,358 precision,359 blank,360 sign,361 8,362 if alt && iv != 0 { "0" } else { "" },363 false,364 )365}366pub fn render_hexadecimal(367 out: &mut String,368 iv: i64,369 padding: usize,370 precision: usize,371 alt: bool,372 blank: bool,373 sign: bool,374 caps: bool,375) {376 render_integer(377 out,378 iv,379 padding,380 precision,381 blank,382 sign,383 16,384 match (alt, caps) {385 (true, true) => "0X",386 (true, false) => "0x",387 (false, _) => "",388 },389 caps,390 )391}392393pub fn render_float(394 out: &mut String,395 n: f64,396 mut padding: usize,397 precision: usize,398 blank: bool,399 sign: bool,400 ensure_pt: bool,401 trailing: bool,402) {403 let dot_size = if precision == 0 && !ensure_pt { 0 } else { 1 };404 padding = padding.saturating_sub(dot_size + precision);405 render_decimal(out, n.floor() as i64, padding, 0, blank, sign);406 if precision == 0 {407 if ensure_pt {408 out.push('.');409 }410 return;411 }412 let frac = n413 .fract()414 .mul_add(10.0_f64.powf(precision as f64), 0.5)415 .floor();416 if trailing || frac > 0.0 {417 out.push('.');418 let mut frac_str = String::new();419 render_decimal(&mut frac_str, frac as i64, precision, 0, false, false);420 let mut trim = frac_str.len();421 if !trailing {422 for b in frac_str.as_bytes().iter().rev() {423 if *b == b'0' {424 trim -= 1;425 }426 }427 }428 out.push_str(&frac_str[..trim]);429 } else if ensure_pt {430 out.push('.');431 }432}433434pub fn render_float_sci(435 out: &mut String,436 n: f64,437 mut padding: usize,438 precision: usize,439 blank: bool,440 sign: bool,441 ensure_pt: bool,442 trailing: bool,443 caps: bool,444) {445 let exponent = n.log10().floor();446 let mantissa = if exponent as i16 == -324 {447 n * 10.0 / 10.0_f64.powf(exponent + 1.0)448 } else {449 n / 10.0_f64.powf(exponent)450 };451 let mut exponent_str = String::new();452 render_decimal(&mut exponent_str, exponent as i64, 3, 0, false, true);453454 // +1 for e455 padding = padding.saturating_sub(exponent_str.len() + 1);456457 render_float(458 out, mantissa, padding, precision, blank, sign, ensure_pt, trailing,459 );460 out.push(if caps { 'E' } else { 'e' });461 out.push_str(&exponent_str);462}463464pub fn format_code(465 s: State,466 out: &mut String,467 value: &Val,468 code: &Code,469 width: usize,470 precision: Option<usize>,471) -> Result<()> {472 let clfags = &code.cflags;473 let (fpprec, iprec) = match precision {474 Some(v) => (v, v),475 None => (6, 0),476 };477 let padding = if clfags.zero && !clfags.left {478 width479 } else {480 0481 };482483 // TODO: If left padded, can optimize by writing directly to out484 let mut tmp_out = String::new();485486 match code.convtype {487 ConvTypeV::String => tmp_out.push_str(&value.clone().to_string(s)?),488 ConvTypeV::Decimal => {489 let value = f64::from_untyped(value.clone(), s)?;490 render_decimal(491 &mut tmp_out,492 value as i64,493 padding,494 iprec,495 clfags.blank,496 clfags.sign,497 );498 }499 ConvTypeV::Octal => {500 let value = f64::from_untyped(value.clone(), s)?;501 render_octal(502 &mut tmp_out,503 value as i64,504 padding,505 iprec,506 clfags.alt,507 clfags.blank,508 clfags.sign,509 );510 }511 ConvTypeV::Hexadecimal => {512 let value = f64::from_untyped(value.clone(), s)?;513 render_hexadecimal(514 &mut tmp_out,515 value as i64,516 padding,517 iprec,518 clfags.alt,519 clfags.blank,520 clfags.sign,521 code.caps,522 );523 }524 ConvTypeV::Scientific => {525 let value = f64::from_untyped(value.clone(), s)?;526 render_float_sci(527 &mut tmp_out,528 value,529 padding,530 fpprec,531 clfags.blank,532 clfags.sign,533 clfags.alt,534 true,535 code.caps,536 );537 }538 ConvTypeV::Float => {539 let value = f64::from_untyped(value.clone(), s)?;540 render_float(541 &mut tmp_out,542 value,543 padding,544 fpprec,545 clfags.blank,546 clfags.sign,547 clfags.alt,548 true,549 );550 }551 ConvTypeV::Shorter => {552 let value = f64::from_untyped(value.clone(), s)?;553 let exponent = value.log10().floor();554 if exponent < -4.0 || exponent >= fpprec as f64 {555 render_float_sci(556 &mut tmp_out,557 value,558 padding,559 fpprec - 1,560 clfags.blank,561 clfags.sign,562 clfags.alt,563 clfags.alt,564 code.caps,565 );566 } else {567 let digits_before_pt = 1.max(exponent as usize + 1);568 render_float(569 &mut tmp_out,570 value,571 padding,572 fpprec - digits_before_pt,573 clfags.blank,574 clfags.sign,575 clfags.alt,576 clfags.alt,577 );578 }579 }580 ConvTypeV::Char => match value.clone() {581 Val::Num(n) => tmp_out582 .push(std::char::from_u32(n as u32).ok_or(InvalidUnicodeCodepointGot(n as u32))?),583 Val::Str(s) => {584 if s.chars().count() != 1 {585 throw!(RuntimeError(586 format!("%c expected 1 char string, got {}", s.chars().count()).into(),587 ));588 }589 tmp_out.push_str(&s);590 }591 _ => {592 throw!(TypeMismatch(593 "%c requires number/string",594 vec![ValType::Num, ValType::Str],595 value.value_type(),596 ));597 }598 },599 ConvTypeV::Percent => tmp_out.push('%'),600 };601602 let padding = width.saturating_sub(tmp_out.len());603604 if !clfags.left {605 for _ in 0..padding {606 out.push(' ');607 }608 }609 out.push_str(&tmp_out);610 if clfags.left {611 for _ in 0..padding {612 out.push(' ');613 }614 }615616 Ok(())617}618619pub fn format_arr(s: State, str: &str, mut values: &[Val]) -> Result<String> {620 let codes = parse_codes(str)?;621 let mut out = String::new();622623 for code in codes {624 match code {625 Element::String(s) => {626 out.push_str(s);627 }628 Element::Code(c) => {629 let width = match c.width {630 Width::Star => {631 if values.is_empty() {632 throw!(NotEnoughValues);633 }634 let value = &values[0];635 values = &values[1..];636 usize::from_untyped(value.clone(), s.clone())?637 }638 Width::Fixed(n) => n,639 };640 let precision = match c.precision {641 Some(Width::Star) => {642 if values.is_empty() {643 throw!(NotEnoughValues);644 }645 let value = &values[0];646 values = &values[1..];647 Some(usize::from_untyped(value.clone(), s.clone())?)648 }649 Some(Width::Fixed(n)) => Some(n),650 None => None,651 };652653 // %% should not consume a value654 let value = if c.convtype == ConvTypeV::Percent {655 &Val::Null656 } else {657 if values.is_empty() {658 throw!(NotEnoughValues);659 }660 let value = &values[0];661 values = &values[1..];662 value663 };664665 format_code(s.clone(), &mut out, value, &c, width, precision)?;666 }667 }668 }669670 Ok(out)671}672673pub fn format_obj(s: State, str: &str, values: &ObjValue) -> Result<String> {674 let codes = parse_codes(str)?;675 let mut out = String::new();676677 for code in codes {678 match code {679 Element::String(s) => {680 out.push_str(s);681 }682 Element::Code(c) => {683 // TODO: Operate on ref684 let f: IStr = c.mkey.into();685 let width = match c.width {686 Width::Star => {687 throw!(CannotUseStarWidthWithObject);688 }689 Width::Fixed(n) => n,690 };691 let precision = match c.precision {692 Some(Width::Star) => {693 throw!(CannotUseStarWidthWithObject);694 }695 Some(Width::Fixed(n)) => Some(n),696 None => None,697 };698699 let value = if c.convtype == ConvTypeV::Percent {700 Val::Null701 } else {702 if f.is_empty() {703 throw!(MappingKeysRequired);704 }705 if let Some(v) = values.get(s.clone(), f.clone())? {706 v707 } else {708 throw!(NoSuchFormatField(f));709 }710 };711712 format_code(s.clone(), &mut out, &value, &c, width, precision)?;713 }714 }715 }716717 Ok(out)718}719720#[cfg(test)]721pub mod test_format {722 use super::*;723724 #[test]725 fn parse() {726 assert_eq!(727 parse_codes(728 "How much error budget is left looking at our %.3f%% availability gurantees?"729 )730 .unwrap()731 .len(),732 4733 );734 }735736 #[test]737 fn octals() {738 assert_eq!(format_arr("%#o", &[Val::Num(8.0)]).unwrap(), "010");739 assert_eq!(format_arr("%#4o", &[Val::Num(8.0)]).unwrap(), " 010");740 assert_eq!(format_arr("%4o", &[Val::Num(8.0)]).unwrap(), " 10");741 assert_eq!(format_arr("%04o", &[Val::Num(8.0)]).unwrap(), "0010");742 assert_eq!(format_arr("%+4o", &[Val::Num(8.0)]).unwrap(), " +10");743 assert_eq!(format_arr("%+04o", &[Val::Num(8.0)]).unwrap(), "+010");744 assert_eq!(format_arr("%-4o", &[Val::Num(8.0)]).unwrap(), "10 ");745 assert_eq!(format_arr("%+-4o", &[Val::Num(8.0)]).unwrap(), "+10 ");746 assert_eq!(format_arr("%+-04o", &[Val::Num(8.0)]).unwrap(), "+10 ");747 }748749 #[test]750 fn percent_doesnt_consumes_values() {751 assert_eq!(752 format_arr(753 "How much error budget is left looking at our %.3f%% availability gurantees?",754 &[Val::Num(4.0)]755 )756 .unwrap(),757 "How much error budget is left looking at our 4.000% availability gurantees?"758 );759 }760}crates/jrsonnet-evaluator/src/builtin/manifest.rsdiffbeforeafterboth--- 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<String> {
+pub fn manifest_json_ex(s: State, val: &Val, options: &ManifestJsonOptions<'_>) -> Result<String> {
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::<f64>().is_ok()
}
-pub fn manifest_yaml_ex(val: &Val, options: &ManifestYamlOptions<'_>) -> Result<String> {
+pub fn manifest_yaml_ex(s: State, val: &Val, options: &ManifestYamlOptions<'_>) -> Result<String> {
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);
}
}
crates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth--- 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<String> {
- push_frame(
+pub fn std_format(s: State, str: IStr, vals: Val) -> Result<String> {
+ 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<VecVal> {
+fn builtin_make_array(s: State, sz: usize, func: FuncVal) -> Result<VecVal> {
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<Any> {
- let value: serde_json::Value = serde_json::from_str(&s)
+fn builtin_parse_json(st: State, s: IStr) -> Result<Any> {
+ 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<Any> {
+fn builtin_parse_yaml(st: State, s: IStr) -> Result<Any> {
+ 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<bool> {
- equals(&a.0, &b.0)
+fn builtin_equals(s: State, a: Any, b: Any) -> Result<bool> {
+ 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<Any> {
+fn builtin_mod(s: State, a: Either![f64, IStr], b: Any) -> Result<Any> {
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<Any> {
- Ok(Any(with_state(|s| s.settings().ext_vars.get(&x).cloned())
+fn builtin_ext_var(s: State, x: IStr) -> Result<Any> {
+ Ok(Any(s
+ .settings()
+ .ext_vars
+ .get(&x)
+ .cloned()
.ok_or(UndefinedExternalVariable(x))?))
}
#[jrsonnet_macros::builtin]
-fn builtin_native(name: IStr) -> Result<FuncVal> {
- Ok(with_state(|s| s.settings().ext_natives.get(&name).cloned())
+fn builtin_native(s: State, name: IStr) -> Result<FuncVal> {
+ 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<ArrValue> {
- arr.filter(|val| bool::try_from(func.evaluate_simple(&[Any(val.clone())].as_slice())?))
+fn builtin_filter(s: State, func: FuncVal, arr: ArrValue) -> Result<ArrValue> {
+ 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<ArrValue> {
- arr.map(|val| func.evaluate_simple(&[Any(val)].as_slice()))
+fn builtin_map(s: State, func: FuncVal, arr: ArrValue) -> Result<ArrValue> {
+ 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<IndexableVal> {
+fn builtin_flatmap(s: State, func: FuncVal, arr: IndexableVal) -> Result<IndexableVal> {
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<Any> {
+fn builtin_foldl(s: State, func: FuncVal, arr: ArrValue, init: Any) -> Result<Any> {
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<Any> {
+fn builtin_foldr(s: State, func: FuncVal, arr: ArrValue, init: Any) -> Result<Any> {
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<FuncVal>) -> Result<ArrValue> {
+fn builtin_sort(s: State, arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {
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<String> {
- std_format(str, vals.0)
+fn builtin_format(s: State, str: IStr, vals: Any) -> Result<String> {
+ 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<Any> {
+fn builtin_trace(s: State, loc: CallLocation, str: IStr, rest: Any) -> Result<Any> {
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<Any>
@@ -526,26 +539,25 @@
}
#[jrsonnet_macros::builtin]
-fn builtin_join(sep: IndexableVal, arr: ArrValue) -> Result<IndexableVal> {
+fn builtin_join(s: State, sep: IndexableVal, arr: ArrValue) -> Result<IndexableVal> {
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<IStr>,
@@ -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<bool>,
quote_keys: Option<bool>,
#[cfg(feature = "exp-preserve-order")] preserve_order: Option<bool>,
) -> Result<String> {
manifest_yaml_ex(
+ s,
&value.0,
&ManifestYamlOptions {
padding: " ",
@@ -670,16 +686,16 @@
}
#[jrsonnet_macros::builtin]
-fn builtin_member(arr: IndexableVal, x: Any) -> Result<bool> {
+fn builtin_member(s: State, arr: IndexableVal, x: Any) -> Result<bool> {
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<Any>, v: Any) -> Result<usize> {
+fn builtin_count(s: State, arr: Vec<Any>, v: Any) -> Result<usize> {
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<bool> {
- for v in arr.iter() {
- let v: bool = v?.try_into()?;
+fn builtin_any(s: State, arr: ArrValue) -> Result<bool> {
+ 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<bool> {
- for v in arr.iter() {
- let v: bool = v?.try_into()?;
+fn builtin_all(s: State, arr: ArrValue) -> Result<bool> {
+ for v in arr.iter(s.clone()) {
+ let v = bool::from_untyped(v?, s.clone())?;
if !v {
return Ok(false);
}
crates/jrsonnet-evaluator/src/builtin/sort.rsdiffbeforeafterboth--- 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<Vec<Val>>, key_getter: Option<&FuncVal>) -> Result<Cc<Vec<Val>>> {
+pub fn sort(s: State, values: Cc<Vec<Val>>, key_getter: Option<&FuncVal>) -> Result<Cc<Vec<Val>>> {
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)?;
crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth--- 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<GcHashMap<IStr, LazyBinding>>);
impl ContextCreator {
- pub fn create(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<Context> {
+ pub fn create(
+ &self,
+ s: State,
+ this: Option<ObjValue>,
+ super_obj: Option<ObjValue>,
+ ) -> Result<Context> {
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<IStr, LazyBinding>,
new_dollar: Option<ObjValue>,
new_this: Option<ObjValue>,
@@ -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))
}
crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth--- 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<Context>,
-) -> LazyVal {
+pub fn evaluate_binding_in_future(b: &BindSpec, fctx: FutureWrapper<Context>) -> LazyVal {
let b = b.clone();
if let Some(params) = &b.params {
let params = params.clone();
#[derive(Trace)]
struct LazyMethodBinding {
- context_creator: FutureWrapper<Context>,
+ fctx: FutureWrapper<Context>,
name: IStr,
params: ParamsDesc,
value: LocExpr,
}
impl LazyValValue for LazyMethodBinding {
- fn get(self: Box<Self>) -> Result<Val> {
+ fn get(self: Box<Self>, _: State) -> Result<Val> {
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<Context>,
+ fctx: FutureWrapper<Context>,
name: IStr,
value: LocExpr,
}
impl LazyValValue for LazyNamedBinding {
- fn get(self: Box<Self>) -> Result<Val> {
- evaluate_named(self.context_creator.unwrap(), &self.value, self.name)
+ fn get(self: Box<Self>, s: State) -> Result<Val> {
+ 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<ObjValue>,
super_obj: Option<ObjValue>,
- context_creator: ContextCreator,
+ cctx: ContextCreator,
name: IStr,
params: ParamsDesc,
value: LocExpr,
}
impl LazyValValue for BindableMethodLazyVal {
- fn get(self: Box<Self>) -> Result<Val> {
+ fn get(self: Box<Self>, s: State) -> Result<Val> {
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<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal> {
+ fn bind(
+ &self,
+ _: State,
+ this: Option<ObjValue>,
+ super_obj: Option<ObjValue>,
+ ) -> Result<LazyVal> {
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<ObjValue>,
super_obj: Option<ObjValue>,
- context_creator: ContextCreator,
+ cctx: ContextCreator,
name: IStr,
value: LocExpr,
}
impl LazyValValue for BindableNamedLazyVal {
- fn get(self: Box<Self>) -> Result<Val> {
+ fn get(self: Box<Self>, s: State) -> Result<Val> {
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<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal> {
+ fn bind(
+ &self,
+ _: State,
+ this: Option<ObjValue>,
+ super_obj: Option<ObjValue>,
+ ) -> Result<LazyVal> {
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<Option<IStr>> {
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<ObjValue> {
+pub fn evaluate_member_list_object(s: State, ctx: Context, members: &[Member]) -> Result<ObjValue> {
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<IStr, LazyBinding> = 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<ObjValue>,
super_obj: Option<ObjValue>,
) -> Result<LazyVal> {
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<ObjValue>,
super_obj: Option<ObjValue>,
) -> Result<LazyVal> {
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<ObjValue>,
super_obj: Option<ObjValue>,
) -> 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<ObjValue> {
+pub fn evaluate_object(s: State, ctx: Context, object: &ObjBody) -> Result<ObjValue> {
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<IStr, LazyBinding> =
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<ObjValue>,
_super_obj: Option<ObjValue>,
) -> Result<LazyVal> {
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<Val> {
- 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<Val> {
+pub fn evaluate_named(s: State, ctx: Context, lexpr: &LocExpr, name: IStr) -> Result<Val> {
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<Val> {
+pub fn evaluate(s: State, ctx: Context, expr: &LocExpr) -> Result<Val> {
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<IStr, LazyVal> =
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<Self>) -> Result<Val> {
- evaluate(self.context, &self.item)
+ fn get(self: Box<Self>, s: State) -> Result<Val> {
+ 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<const MIN: usize>(
+ fn parse_idx<T: Typed>(
loc: CallLocation,
- context: &Context,
+ s: State,
+ ctx: &Context,
expr: &Option<LocExpr>,
desc: &'static str,
- ) -> Result<Option<BoundedUsize<MIN, { i32::MAX as usize }>>> {
+ ) -> Result<Option<T>> {
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))
}
})
crates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth--- 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<Val> {
@@ -17,7 +16,7 @@
})
}
-pub fn evaluate_add_op(a: &Val, b: &Val) -> Result<Val> {
+pub fn evaluate_add_op(s: State, a: &Val, b: &Val) -> Result<Val> {
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<Val> {
+pub fn evaluate_mod_op(s: State, a: &Val, b: &Val) -> Result<Val> {
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<Val> {
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<Val> {
+pub fn evaluate_binary_op_normal(s: State, a: &Val, op: BinaryOpType, b: &Val) -> Result<Val> {
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()),
crates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth--- 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<Self>) -> Result<Val> {
- evaluate(self.context, &self.expr)
+ fn get(self: Box<Self>, s: State) -> Result<Val> {
+ evaluate(s, self.ctx, &self.expr)
}
}
#[derive(Trace)]
struct EvaluateNamedLazyVal {
- future_context: FutureWrapper<Context>,
+ ctx: FutureWrapper<Context>,
name: IStr,
value: LocExpr,
}
impl LazyValValue for EvaluateNamedLazyVal {
- fn get(self: Box<Self>) -> Result<Val> {
- evaluate_named(self.future_context.unwrap(), &self.value, self.name)
+ fn get(self: Box<Self>, s: State) -> Result<Val> {
+ evaluate_named(s, self.ctx.unwrap(), &self.value, self.name)
}
}
pub trait ArgLike {
- fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<LazyVal>;
+ fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<LazyVal>;
}
impl ArgLike for &LocExpr {
- fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<LazyVal> {
+ fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<LazyVal> {
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<T> ArgLike for T
where
T: Typed + Clone,
- Val: TryFrom<T, Error = LocError>,
{
- fn evaluate_arg(&self, _ctx: Context, _tailstrict: bool) -> Result<LazyVal> {
- let val: Val = Val::try_from(self.clone())?;
+ fn evaluate_arg(&self, s: State, _ctx: Context, _tailstrict: bool) -> Result<LazyVal> {
+ 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<LazyVal> {
+ fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<LazyVal> {
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<Val>;
+ fn call(&self, s: State, ctx: Context, loc: CallLocation, args: &dyn ArgsLike) -> Result<Val>;
}
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<Self>) -> Result<Val> {
+ fn get(self: Box<Self>, _: State) -> Result<Val> {
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)
}
crates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth--- 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<Self> {
- 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<Val> {
+ 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<Val> = 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<Self> {
+ 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<Val> for Value {
- type Error = LocError;
-
- fn try_from(value: Val) -> Result<Self, Self::Error> {
- <Self as TryFrom<&Val>>::try_from(&value)
- }
-}
-
-impl TryFrom<&Value> for Val {
- type Error = LocError;
- fn try_from(v: &Value) -> Result<Self> {
- 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<Self> = 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<Value> for Val {
- type Error = LocError;
-
- fn try_from(value: Value) -> Result<Self, Self::Error> {
- <Self as TryFrom<&Value>>::try_from(&value)
}
}
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- 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<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal>;
+ fn bind(
+ &self,
+ s: State,
+ this: Option<ObjValue>,
+ super_obj: Option<ObjValue>,
+ ) -> Result<LazyVal>;
}
#[derive(Clone, Trace)]
@@ -62,9 +67,14 @@
}
}
impl LazyBinding {
- pub fn evaluate(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal> {
+ pub fn evaluate(
+ &self,
+ s: State,
+ this: Option<ObjValue>,
+ super_obj: Option<ObjValue>,
+ ) -> Result<LazyVal> {
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<EvaluationSettings>,
}
-thread_local! {
- /// Contains the state for a currently executed file.
- /// Global state is fine here.
- pub(crate) static EVAL_STATE: RefCell<Option<EvaluationState>> = RefCell::new(None)
-}
-
-pub(crate) fn with_state<T>(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<T>(
- e: CallLocation,
- frame_desc: impl FnOnce() -> String,
- f: impl FnOnce() -> Result<T>,
-) -> Result<T> {
- 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<Val>,
-) -> Result<Val> {
- with_state(|s| s.push_val(e, frame_desc, f))
-}
-#[allow(dead_code)]
-pub fn push_description_frame<T>(
- frame_desc: impl FnOnce() -> String,
- f: impl FnOnce() -> Result<T>,
-) -> Result<T> {
- with_state(|s| s.push_description(frame_desc, f))
-}
-
/// Maintains stack trace and import resolution
#[derive(Default, Clone)]
-pub struct EvaluationState(Rc<EvaluationStateInternals>);
+pub struct State(Rc<EvaluationStateInternals>);
-impl EvaluationState {
+impl State {
/// Parses and adds file as loaded
pub fn add_file(&self, path: Rc<Path>, source_code: IStr) -> Result<LocExpr> {
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<Path> = 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<T>(&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<Breakpoint>,
- 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<IStr> {
- 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<Vec<(IStr, IStr)>> {
- 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<Vec<IStr>> {
- 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<Val> {
- 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<EvaluationData> {
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<Val> {
- 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<Val> {
- 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<Path>, code: IStr) -> Result<Val> {
@@ -580,12 +515,12 @@
}
/// Evaluates the parsed expression
pub fn evaluate_expr_raw(&self, code: LocExpr) -> Result<Val> {
- 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::<Vec<_>>());
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::<Vec<_>>());
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(
crates/jrsonnet-evaluator/src/native.rsdiffbeforeafterboth--- 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<Val> {
- let args = parse_builtin_call(context, &self.params, args, true)?;
+ fn call(&self, s: State, ctx: Context, loc: CallLocation, args: &dyn ArgsLike) -> Result<Val> {
+ 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<Rc<Path>>, args: &[Val]) -> Result<Val>;
+ fn call(&self, s: State, from: Option<Rc<Path>>, args: &[Val]) -> Result<Val>;
}
crates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth--- 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<ObjValue>, super_obj: Option<ObjValue>) -> Result<()>;
+ fn run(&self, s: State, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<()>;
}
// Field => This
@@ -360,14 +360,14 @@
.unwrap_or(false)
}
- pub fn get(&self, key: IStr) -> Result<Option<Val>> {
- self.run_assertions()?;
- self.get_raw(key, self.0.this_obj.as_ref())
+ pub fn get(&self, s: State, key: IStr) -> Result<Option<Val>> {
+ 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<Option<Val>> {
+ fn get_raw(&self, s: State, key: IStr, real_this: Option<&Self>) -> Result<Option<Val>> {
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<Val> {
+ fn evaluate_this(&self, s: State, v: &ObjMember, real_this: &Self) -> Result<Val> {
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<ValueBuilder<'v>> {
- 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<dyn Bindable>) -> Result<()> {
- self.binding(LazyBinding::Bindable(Cc::new(bindable)))
+ pub fn bindable(self, s: State, bindable: TraceBox<dyn Bindable>) -> 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())),
crates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth--- 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],
crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth--- 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<Val, Error = LocError> + TryInto<Val, Error = LocError> {
+pub trait Typed: Sized {
const TYPE: &'static ComplexValType;
+ fn into_untyped(typed: Self, s: State) -> Result<Val>;
+ fn from_untyped(untyped: Val, s: State) -> Result<Self>;
}
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<Val> for $ty {
- type Error = LocError;
-
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
+ <Self as Typed>::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<Self> {
- Ok(Self::Num(value as f64))
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ Ok(Val::Num(value as f64))
}
}
)*};
@@ -100,12 +90,9 @@
Some(MIN as f64),
Some(MAX as f64),
);
- }
- impl<const MIN: $ty, const MAX: $ty> TryFrom<Val> for $name<MIN, MAX> {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
+ <Self as Typed>::TYPE.check(s, &value)?;
match value {
Val::Num(n) => {
if n.trunc() != n {
@@ -122,12 +109,9 @@
_ => unreachable!(),
}
}
- }
- impl<const MIN: $ty, const MAX: $ty> TryFrom<$name<MIN, MAX>> for Val {
- type Error = LocError;
- fn try_from(value: $name<MIN, MAX>) -> Result<Self> {
- Ok(Self::Num(value.0 as f64))
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ 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<Val> for f64 {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ Ok(Val::Num(value))
+ }
+
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
+ <Self as Typed>::TYPE.check(s, &value)?;
match value {
Val::Num(n) => Ok(n),
_ => unreachable!(),
}
}
}
-impl TryFrom<f64> for Val {
- type Error = LocError;
-
- fn try_from(value: f64) -> Result<Self> {
- 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<Val> for PositiveF64 {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ Ok(Val::Num(value.0))
+ }
+
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
+ <Self as Typed>::TYPE.check(s, &value)?;
match value {
Val::Num(n) => Ok(Self(n)),
_ => unreachable!(),
}
}
}
-impl TryFrom<PositiveF64> for Val {
- type Error = LocError;
-
- fn try_from(value: PositiveF64) -> Result<Self> {
- 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<Val> for usize {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ 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<Self> {
+ <Self as Typed>::TYPE.check(s, &value)?;
match value {
Val::Num(n) => {
if n.trunc() != n {
@@ -209,127 +184,81 @@
}
}
}
-impl TryFrom<usize> for Val {
- type Error = LocError;
- fn try_from(value: usize) -> Result<Self> {
- 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<Val> for IStr {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ Ok(Val::Str(value))
+ }
+
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
+ <Self as Typed>::TYPE.check(s, &value)?;
match value {
Val::Str(s) => Ok(s),
_ => unreachable!(),
}
- }
-}
-impl TryFrom<IStr> for Val {
- type Error = LocError;
-
- fn try_from(value: IStr) -> Result<Self> {
- Ok(Self::Str(value))
}
}
impl Typed for String {
const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);
-}
-impl TryFrom<Val> for String {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ Ok(Val::Str(value.into()))
+ }
+
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
+ <Self as Typed>::TYPE.check(s, &value)?;
match value {
Val::Str(s) => Ok(s.to_string()),
_ => unreachable!(),
}
- }
-}
-impl TryFrom<String> for Val {
- type Error = LocError;
-
- fn try_from(value: String) -> Result<Self> {
- Ok(Self::Str(value.into()))
}
}
impl Typed for char {
const TYPE: &'static ComplexValType = &ComplexValType::Char;
-}
-impl TryFrom<Val> for char {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ Ok(Val::Str(value.to_string().into()))
+ }
+
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
+ <Self as Typed>::TYPE.check(s, &value)?;
match value {
Val::Str(s) => Ok(s.chars().next().unwrap()),
_ => unreachable!(),
}
}
}
-impl TryFrom<char> for Val {
- type Error = LocError;
- fn try_from(value: char) -> Result<Self> {
- Ok(Self::Str(value.to_string().into()))
- }
-}
-
impl<T> Typed for Vec<T>
where
T: Typed,
- T: TryFrom<Val, Error = LocError>,
- T: TryInto<Val, Error = LocError>,
{
const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE);
-}
-impl<T> TryFrom<Val> for Vec<T>
-where
- T: Typed,
- T: TryFrom<Val, Error = LocError>,
- T: TryInto<Val, Error = LocError>,
-{
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
+ fn into_untyped(value: Self, s: State) -> Result<Val> {
+ 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<Self> {
+ <Self as Typed>::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<T> TryFrom<Vec<T>> for Val
-where
- T: Typed,
- T: TryFrom<Self, Error = LocError>,
- T: TryInto<Self, Error = LocError>,
-{
- type Error = LocError;
-
- fn try_from(value: Vec<T>) -> Result<Self> {
- 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<Val> for Any {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- Ok(Self(value))
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ Ok(value.0)
}
-}
-impl TryFrom<Any> for Val {
- type Error = LocError;
- fn try_from(value: Any) -> Result<Self> {
- Ok(value.0)
+ fn from_untyped(value: Val, _: State) -> Result<Self> {
+ Ok(Self(value))
}
}
@@ -361,47 +284,42 @@
impl Typed for VecVal {
const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);
-}
-impl TryFrom<Val> for VecVal {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ Ok(Val::Arr(ArrValue::Eager(value.0)))
+ }
+
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
+ <Self as Typed>::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<VecVal> for Val {
- type Error = LocError;
- fn try_from(value: VecVal) -> Result<Self> {
- 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<Val> for Bytes {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ Ok(Val::Arr(ArrValue::Bytes(value.0)))
+ }
+
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
match value {
Val::Arr(ArrValue::Bytes(bytes)) => Ok(Self(bytes)),
_ => {
- <Self as Typed>::TYPE.check(&value)?;
+ <Self as Typed>::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<Bytes> for Val {
- type Error = LocError;
-
- fn try_from(value: Bytes) -> Result<Self> {
- 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<Val> for M1 {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
- Ok(Self)
+ fn into_untyped(_: Self, _: State) -> Result<Val> {
+ Ok(Val::Num(-1.0))
}
-}
-impl TryFrom<M1> for Val {
- type Error = LocError;
- fn try_from(_: M1) -> Result<Self> {
- Ok(Self::Num(-1.0))
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
+ <Self as Typed>::TYPE.check(s, &value)?;
+ Ok(Self)
}
}
@@ -449,33 +354,22 @@
$($id: Typed,)*
{
const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]);
- }
- impl<$($id),*> TryFrom<Val> for $name<$($id),*>
- where
- $($id: Typed,)*
- {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
+ fn into_untyped(value: Self, s: State) -> Result<Val> {
+ match value {$(
+ $name::$id(v) => $id::into_untyped(v, s)
+ ),*}
+ }
+
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
$(
- 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
)* {
- <Self as Typed>::TYPE.check(&value)?;
+ <Self as Typed>::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<Self> {
- 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<Val> for ArrValue {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ Ok(Val::Arr(value))
+ }
+
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
+ <Self as Typed>::TYPE.check(s, &value)?;
match value {
Val::Arr(a) => Ok(a),
_ => unreachable!(),
}
}
}
-impl TryFrom<ArrValue> for Val {
- type Error = LocError;
- fn try_from(value: ArrValue) -> Result<Self> {
- Ok(Self::Arr(value))
- }
-}
-
impl Typed for FuncVal {
const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);
-}
-impl TryFrom<Val> for FuncVal {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ Ok(Val::Func(value))
+ }
+
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
+ <Self as Typed>::TYPE.check(s, &value)?;
match value {
Val::Func(a) => Ok(a),
_ => unreachable!(),
}
}
}
-impl TryFrom<FuncVal> for Val {
- type Error = LocError;
- fn try_from(value: FuncVal) -> Result<Self> {
- Ok(Self::Func(value))
- }
-}
-
impl Typed for Cc<FuncDesc> {
const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);
-}
-impl TryFrom<Val> for Cc<FuncDesc> {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self, Self::Error> {
- <Self as Typed>::TYPE.check(&value)?;
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ Ok(Val::Func(FuncVal::Normal(value)))
+ }
+
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
+ <Self as Typed>::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<Cc<FuncDesc>> for Val {
- type Error = LocError;
-
- fn try_from(value: Cc<FuncDesc>) -> Result<Self, Self::Error> {
- Ok(Self::Func(FuncVal::Normal(value)))
}
}
impl Typed for ObjValue {
const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Obj);
-}
-impl TryFrom<Val> for ObjValue {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ Ok(Val::Obj(value))
+ }
+
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
+ <Self as Typed>::TYPE.check(s, &value)?;
match value {
Val::Obj(a) => Ok(a),
_ => unreachable!(),
}
}
}
-impl TryFrom<ObjValue> for Val {
- type Error = LocError;
- fn try_from(value: ObjValue) -> Result<Self> {
- Ok(Self::Obj(value))
- }
-}
-
impl Typed for bool {
const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool);
-}
-impl TryFrom<Val> for bool {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ Ok(Val::Bool(value))
+ }
+
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
+ <Self as Typed>::TYPE.check(s, &value)?;
match value {
Val::Bool(a) => Ok(a),
_ => unreachable!(),
}
}
}
-impl TryFrom<bool> for Val {
- type Error = LocError;
-
- fn try_from(value: bool) -> Result<Self> {
- Ok(Self::Bool(value))
- }
-}
-
impl Typed for IndexableVal {
const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[
&ComplexValType::Simple(ValType::Arr),
&ComplexValType::Simple(ValType::Str),
]);
-}
-impl TryFrom<Val> for IndexableVal {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
- value.into_indexable()
+ fn into_untyped(value: Self, _: State) -> Result<Val> {
+ match value {
+ IndexableVal::Str(s) => Ok(Val::Str(s)),
+ IndexableVal::Arr(a) => Ok(Val::Arr(a)),
+ }
}
-}
-impl TryFrom<IndexableVal> for Val {
- type Error = LocError;
- fn try_from(value: IndexableVal) -> Result<Self> {
- match value {
- IndexableVal::Str(s) => Ok(Self::Str(s)),
- IndexableVal::Arr(a) => Ok(Self::Arr(a)),
- }
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
+ <Self as Typed>::TYPE.check(s, &value)?;
+ value.into_indexable()
}
}
pub struct Null;
impl Typed for Null {
const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null);
-}
-impl TryFrom<Val> for Null {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
- Ok(Self)
+ fn into_untyped(_: Self, _: State) -> Result<Val> {
+ Ok(Val::Null)
}
-}
-impl TryFrom<Null> for Val {
- type Error = LocError;
- fn try_from(_: Null) -> Result<Self> {
- Ok(Self::Null)
+ fn from_untyped(value: Val, s: State) -> Result<Self> {
+ <Self as Typed>::TYPE.check(s, &value)?;
+ Ok(Self)
}
}
crates/jrsonnet-evaluator/src/typed/mod.rsdiffbeforeafterboth--- 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(())
}
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth--- 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<Self>) -> Result<Val>;
+ fn get(self: Box<Self>, s: State) -> Result<Val>;
}
#[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<Val> {
+ pub fn evaluate(&self, s: State) -> Result<Val> {
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<Context> {
- 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<Val> {
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<Val> {
- self.evaluate(Context::default(), CallLocation::native(), args, true)
+ pub fn evaluate_simple(&self, s: State, args: &dyn ArgsLike) -> Result<Val> {
+ self.evaluate(s, Context::default(), CallLocation::native(), args, true)
}
}
@@ -276,14 +285,14 @@
self.len() == 0
}
- pub fn get(&self, index: usize) -> Result<Option<Val>> {
+ pub fn get(&self, s: State, index: usize) -> Result<Option<Val>> {
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<Cc<Vec<Val>>> {
+ pub fn evaluated(&self, s: State) -> Result<Cc<Vec<Val>>> {
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<Item = Result<Val>> + '_ {
+ pub fn iter(&self, s: State) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {
(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<Val>) -> Result<Self> {
+ pub fn map(self, s: State, mapper: impl Fn(Val) -> Result<Val>) -> Result<Self> {
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<bool>) -> Result<Self> {
+ pub fn filter(self, s: State, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {
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<IStr> {
+ pub fn to_string(&self, s: State) -> Result<IStr> {
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<Vec<(IStr, IStr)>> {
+ pub fn manifest_multi(&self, s: State, ty: &ManifestFormat) -> Result<Vec<(IStr, IStr)>> {
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<Vec<IStr>> {
+ pub fn manifest_stream(&self, s: State, ty: &ManifestFormat) -> Result<Vec<IStr>> {
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<IStr> {
+ pub fn manifest(&self, s: State, ty: &ManifestFormat) -> Result<IStr> {
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<IStr> {
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<Rc<str>> {
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<IStr> {
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<bool> {
+pub fn equals(s: State, val_a: &Val, val_b: &Val) -> Result<bool> {
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);
}
}
crates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth--- 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<Val> {
- let parsed = parse_builtin_call(context, &PARAMS, args, false)?;
+ fn call(&self, s: State, ctx: Context, location: CallLocation, args: &dyn ArgsLike) -> Result<Val> {
+ 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<Self> {
+ let obj = value.as_obj().expect("shape is correct");
+ Self::parse(&obj)
+ }
+
+ fn into_untyped(value: Self, s: State) -> Result<Val> {
+ let mut out = ObjValueBuilder::new();
+ value.serialize(&mut out)?;
+ Ok(Val::Obj(out.build()))
+ }
+
}
}
};
@@ -567,25 +603,8 @@
Ok(Self {
#(#fields_parse)*
})
- }
- }
-
- impl TryFrom<Val> for #ident {
- type Error = LocError;
- fn try_from(value: Val) -> Result<Self, Self::Error> {
- let obj = value.as_obj().expect("shape is correct");
- Self::parse(&obj)
- }
- }
- impl TryInto<Val> for #ident {
- type Error = LocError;
- fn try_into(self) -> Result<Val, Self::Error> {
- let mut out = ObjValueBuilder::new();
- self.serialize(&mut out)?;
- Ok(Val::Obj(out.build()))
}
}
- ()
};
})
}