From 1da990e653890f6c85779f8556b8b095b0aabce9 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Wed, 09 Nov 2022 23:35:23 +0000 Subject: [PATCH] fix: upgrade libjsonnet to new apis --- --- a/bindings/jsonnet/src/import.rs +++ b/bindings/jsonnet/src/import.rs @@ -13,11 +13,13 @@ use jrsonnet_evaluator::{ error::{Error::*, Result}, - throw, FileImportResolver, ImportResolver, State, + throw, FileImportResolver, ImportResolver, }; use jrsonnet_gcmodule::Trace; use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath}; +use crate::VM; + pub type JsonnetImportCallback = unsafe extern "C" fn( ctx: *mut c_void, base: *const c_char, @@ -100,25 +102,26 @@ /// It should be safe to call `cb` using valid values with passed `ctx` #[no_mangle] pub unsafe extern "C" fn jsonnet_import_callback( - vm: &State, + vm: &VM, cb: JsonnetImportCallback, ctx: *mut c_void, ) { - vm.set_import_resolver(Box::new(CallbackImportResolver { - cb, - ctx, - out: RefCell::new(HashMap::new()), - })) + vm.state + .set_import_resolver(Box::new(CallbackImportResolver { + cb, + ctx, + out: RefCell::new(HashMap::new()), + })) } /// # Safety /// /// `path` should be a NUL-terminated string #[no_mangle] -pub unsafe extern "C" fn jsonnet_jpath_add(vm: &State, path: *const c_char) { +pub unsafe extern "C" fn jsonnet_jpath_add(vm: &VM, path: *const c_char) { let cstr = CStr::from_ptr(path); let path = PathBuf::from(cstr.to_str().unwrap()); - let any_resolver = vm.import_resolver(); + let any_resolver = vm.state.import_resolver(); let resolver = any_resolver .as_any() .downcast_ref::() --- 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::{State, Val}; +use jrsonnet_evaluator::Val; use crate::{import::jsonnet_import_callback, native::jsonnet_native_callback}; @@ -28,14 +28,14 @@ /// # Safety #[no_mangle] -pub unsafe extern "C" fn jrsonnet_apply_static_import_callback(vm: &State, ctx: *mut c_void) { +pub unsafe extern "C" fn jrsonnet_apply_static_import_callback(vm: &VM, 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: &State, + vm: &VM, name: *const c_char, ctx: *mut c_void, raw_params: *const *const c_char, @@ -44,7 +44,7 @@ } #[no_mangle] -pub extern "C" fn jrsonnet_set_trace_format(vm: &State, format: u8) { +pub extern "C" fn jrsonnet_set_trace_format(vm: &VM, format: u8) { use jrsonnet_evaluator::trace::JsFormat; match format { 1 => vm.set_trace_format(Box::new(JsFormat)), --- a/bindings/jsonnet/src/lib.rs +++ b/bindings/jsonnet/src/lib.rs @@ -17,7 +17,14 @@ }; use jrsonnet_evaluator::{ - tb, trace::PathResolver, FileImportResolver, IStr, ManifestFormat, State, Val, + apply_tla, + function::TlaArg, + gc::GcHashMap, + stack::set_stack_depth_limit, + stdlib::manifest::{JsonFormat, ToStringFormat}, + tb, throw, + trace::{CompactFormat, PathResolver, TraceFormat}, + FileImportResolver, IStr, ManifestFormat, Result, State, Val, }; /// WASM stub @@ -63,56 +70,64 @@ } } +pub struct VM { + state: State, + manifest_format: Box, + trace_format: Box, + tla_args: GcHashMap, +} + /// Creates a new Jsonnet virtual machine. #[no_mangle] #[allow(clippy::box_default)] -pub extern "C" fn jsonnet_make() -> *mut State { +pub extern "C" fn jsonnet_make() -> *mut VM { let state = State::default(); state.settings_mut().import_resolver = tb!(FileImportResolver::default()); state.settings_mut().context_initializer = tb!(jrsonnet_stdlib::ContextInitializer::new( state.clone(), PathResolver::new_cwd_fallback(), )); - Box::into_raw(Box::new(state)) + Box::into_raw(Box::new(VM { + state, + manifest_format: Box::new(JsonFormat::default()), + trace_format: Box::new(CompactFormat::default()), + tla_args: GcHashMap::new(), + })) } /// Complement of [`jsonnet_vm_make`]. #[no_mangle] #[allow(clippy::boxed_local)] -pub extern "C" fn jsonnet_destroy(vm: Box) { +pub extern "C" fn jsonnet_destroy(vm: Box) { drop(vm); } /// Set the maximum stack depth. #[no_mangle] -pub extern "C" fn jsonnet_max_stack(_vm: &State, _v: c_uint) { - todo!() +pub extern "C" fn jsonnet_max_stack(_vm: &VM, v: c_uint) { + set_stack_depth_limit(v as usize) } /// Set the number of objects required before a garbage collection cycle is allowed. /// /// No-op for now #[no_mangle] -pub extern "C" fn jsonnet_gc_min_objects(_vm: &State, _v: c_uint) {} +pub extern "C" fn jsonnet_gc_min_objects(_vm: &VM, _v: c_uint) {} /// Run the garbage collector after this amount of growth in the number of objects /// /// No-op for now #[no_mangle] -pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &State, _v: c_double) {} +pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &VM, _v: c_double) {} /// Expect a string as output and don't JSON encode it. #[no_mangle] -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 { - padding: 4, - #[cfg(feature = "exp-preserve-order")] - preserve_order: false, - }), +pub extern "C" fn jsonnet_string_output(vm: &mut VM, v: c_int) { + vm.manifest_format = match v { + 0 => Box::new(JsonFormat::default()), + 1 => Box::new(ToStringFormat), _ => panic!("incorrect output format"), - } + }; } /// Allocate, resize, or free a buffer. This will abort if the memory cannot be allocated. It will @@ -124,7 +139,7 @@ /// /// This function is most definitely broken, but it works somehow, see TODO inside #[no_mangle] -pub unsafe extern "C" fn jsonnet_realloc(_vm: &State, buf: *mut u8, sz: usize) -> *mut u8 { +pub unsafe extern "C" fn jsonnet_realloc(_vm: &VM, buf: *mut u8, sz: usize) -> *mut u8 { if buf.is_null() { if sz == 0 { return std::ptr::null_mut(); @@ -148,14 +163,18 @@ /// This is useful if you want to abort with an error mid-way through building a complex value. #[no_mangle] #[allow(clippy::boxed_local)] -pub extern "C" fn jsonnet_json_destroy(_vm: &State, v: Box) { +pub extern "C" fn jsonnet_json_destroy(_vm: &VM, v: Box) { drop(v); } /// Set the number of lines of stack trace to display (0 for all of them). #[no_mangle] -pub extern "C" fn jsonnet_max_trace(vm: &State, v: c_uint) { - vm.set_max_trace(v as usize) +pub extern "C" fn jsonnet_max_trace(vm: &mut VM, v: c_uint) { + if let Some(format) = vm.trace_format.as_any_mut().downcast_mut::() { + format.max_trace = v as usize + } else { + panic!("max_trace is not supported by current tracing format") + } } /// Evaluate a file containing Jsonnet code, return a JSON string. @@ -167,15 +186,16 @@ /// `filename` should be a NUL-terminated string #[no_mangle] pub unsafe extern "C" fn jsonnet_evaluate_file( - vm: &State, + vm: &VM, filename: *const c_char, error: &mut c_int, ) -> *const c_char { let filename = parse_path(CStr::from_ptr(filename)); match vm + .state .import(&filename) - .and_then(|v| vm.with_tla(v)) - .and_then(|v| vm.manifest(v)) + .and_then(|val| apply_tla(vm.state.clone(), &vm.tla_args, val)) + .and_then(|val| val.manifest(&vm.manifest_format)) { Ok(v) => { *error = 0; @@ -183,7 +203,8 @@ } Err(e) => { *error = 1; - let out = vm.stringify_err(&e); + let mut out = String::new(); + vm.trace_format.write_trace(&mut out, &e).unwrap(); CString::new(&out as &str).unwrap().into_raw() } } @@ -198,7 +219,7 @@ /// `filename`, `snippet` should be a NUL-terminated strings #[no_mangle] pub unsafe extern "C" fn jsonnet_evaluate_snippet( - vm: &State, + vm: &VM, filename: *const c_char, snippet: *const c_char, error: &mut c_int, @@ -206,9 +227,10 @@ let filename = CStr::from_ptr(filename); let snippet = CStr::from_ptr(snippet); match vm + .state .evaluate_snippet(filename.to_str().unwrap(), snippet.to_str().unwrap()) - .and_then(|v| vm.with_tla(v)) - .and_then(|v| vm.manifest(v)) + .and_then(|val| apply_tla(vm.state.clone(), &vm.tla_args, val)) + .and_then(|val| val.manifest(&vm.manifest_format)) { Ok(v) => { *error = 0; @@ -216,12 +238,27 @@ } Err(e) => { *error = 1; - let out = vm.stringify_err(&e); + let mut out = String::new(); + vm.trace_format.write_trace(&mut out, &e).unwrap(); CString::new(&out as &str).unwrap().into_raw() } } } +fn val_to_multi(val: Val, format: &dyn ManifestFormat) -> Result> { + let Val::Obj(val) = val else { + throw!("expected object as multi output") + }; + let mut out = Vec::new(); + for (k, v) in val.iter( + #[cfg(feature = "exp-preserve-order")] + false, + ) { + out.push((k, v?.manifest(format)?.into())); + } + Ok(out) +} + fn multi_to_raw(multi: Vec<(IStr, IStr)>) -> *const c_char { let mut out = Vec::new(); for (i, (k, v)) in multi.iter().enumerate() { @@ -242,15 +279,16 @@ /// # Safety #[no_mangle] pub unsafe extern "C" fn jsonnet_evaluate_file_multi( - vm: &State, + vm: &VM, filename: *const c_char, error: &mut c_int, ) -> *const c_char { let filename = parse_path(CStr::from_ptr(filename)); match vm + .state .import(&filename) - .and_then(|v| vm.with_tla(v)) - .and_then(|v| vm.manifest_multi(v)) + .and_then(|val| apply_tla(vm.state.clone(), &vm.tla_args, val)) + .and_then(|val| val_to_multi(val, &vm.manifest_format)) { Ok(v) => { *error = 0; @@ -258,7 +296,8 @@ } Err(e) => { *error = 1; - let out = vm.stringify_err(&e); + let mut out = String::new(); + vm.trace_format.write_trace(&mut out, &e).unwrap(); CString::new(&out as &str).unwrap().into_raw() } } @@ -267,7 +306,7 @@ /// # Safety #[no_mangle] pub unsafe extern "C" fn jsonnet_evaluate_snippet_multi( - vm: &State, + vm: &VM, filename: *const c_char, snippet: *const c_char, error: &mut c_int, @@ -275,9 +314,10 @@ let filename = CStr::from_ptr(filename); let snippet = CStr::from_ptr(snippet); match vm + .state .evaluate_snippet(filename.to_str().unwrap(), snippet.to_str().unwrap()) - .and_then(|v| vm.with_tla(v)) - .and_then(|v| vm.manifest_multi(v)) + .and_then(|val| apply_tla(vm.state.clone(), &vm.tla_args, val)) + .and_then(|val| val_to_multi(val, &vm.manifest_format)) { Ok(v) => { *error = 0; @@ -285,12 +325,24 @@ } Err(e) => { *error = 1; - let out = vm.stringify_err(&e); + let mut out = String::new(); + vm.trace_format.write_trace(&mut out, &e).unwrap(); CString::new(&out as &str).unwrap().into_raw() } } } +fn val_to_stream(val: Val, format: &dyn ManifestFormat) -> Result> { + let Val::Arr(val) = val else { + throw!("expected array as stream output") + }; + let mut out = Vec::new(); + for item in val.iter() { + out.push(item?.manifest(format)?.into()); + } + Ok(out) +} + fn stream_to_raw(multi: Vec) -> *const c_char { let mut out = Vec::new(); for (i, v) in multi.iter().enumerate() { @@ -309,15 +361,16 @@ /// # Safety #[no_mangle] pub unsafe extern "C" fn jsonnet_evaluate_file_stream( - vm: &State, + vm: &VM, filename: *const c_char, error: &mut c_int, ) -> *const c_char { let filename = parse_path(CStr::from_ptr(filename)); match vm - .import(&filename) - .and_then(|v| vm.with_tla(v)) - .and_then(|v| vm.manifest_stream(v)) + .state + .import(filename) + .and_then(|val| apply_tla(vm.state.clone(), &vm.tla_args, val)) + .and_then(|val| val_to_stream(val, &vm.manifest_format)) { Ok(v) => { *error = 0; @@ -325,10 +378,9 @@ } Err(e) => { *error = 1; - let out = vm.stringify_err(&e); - CString::new(&out as &str) - .expect("there should be no \\0 in the error string") - .into_raw() + let mut out = String::new(); + vm.trace_format.write_trace(&mut out, &e).unwrap(); + CString::new(&out as &str).unwrap().into_raw() } } } @@ -336,7 +388,7 @@ /// # Safety #[no_mangle] pub unsafe extern "C" fn jsonnet_evaluate_snippet_stream( - vm: &State, + vm: &VM, filename: *const c_char, snippet: *const c_char, error: &mut c_int, @@ -344,12 +396,10 @@ let filename = CStr::from_ptr(filename); let snippet = CStr::from_ptr(snippet); match vm - .evaluate_snippet( - filename.to_str().expect("filename is not utf-8"), - snippet.to_str().expect("snippet is not utf-8"), - ) - .and_then(|v| vm.with_tla(v)) - .and_then(|v| vm.manifest_stream(v)) + .state + .evaluate_snippet(filename.to_str().unwrap(), snippet.to_str().unwrap()) + .and_then(|val| apply_tla(vm.state.clone(), &vm.tla_args, val)) + .and_then(|val| val_to_stream(val, &vm.manifest_format)) { Ok(v) => { *error = 0; @@ -357,10 +407,9 @@ } Err(e) => { *error = 1; - let out = vm.stringify_err(&e); - CString::new(&out as &str) - .expect("there should be no \\0 in the error string") - .into_raw() + let mut out = String::new(); + vm.trace_format.write_trace(&mut out, &e).unwrap(); + CString::new(&out as &str).unwrap().into_raw() } } } --- a/bindings/jsonnet/src/native.rs +++ b/bindings/jsonnet/src/native.rs @@ -9,10 +9,12 @@ function::builtin::{NativeCallback, NativeCallbackHandler}, tb, typed::Typed, - IStr, State, Val, + IStr, Val, }; use jrsonnet_gcmodule::Cc; +use crate::VM; + /// The returned `JsonnetJsonValue*` should be allocated with `jsonnet_realloc`. It will be cleaned up /// along with the objects rooted at `argv` by `libjsonnet` when no-longer needed. Return a string upon /// failure, which will appear in Jsonnet as an error. The `argv` pointer is an array whose size @@ -70,7 +72,7 @@ /// `raw_params` should point to a NULL-terminated array of NUL-terminated strings #[no_mangle] pub unsafe extern "C" fn jsonnet_native_callback( - vm: &State, + vm: &VM, name: *const c_char, cb: JsonnetNativeCallback, ctx: *const c_void, @@ -92,7 +94,7 @@ raw_params = raw_params.offset(1); } - let any_resolver = vm.context_initializer(); + let any_resolver = vm.state.context_initializer(); any_resolver .as_any() .downcast_ref::() --- a/bindings/jsonnet/src/val_extract.rs +++ b/bindings/jsonnet/src/val_extract.rs @@ -5,11 +5,13 @@ os::raw::{c_char, c_double, c_int}, }; -use jrsonnet_evaluator::{State, Val}; +use jrsonnet_evaluator::Val; + +use crate::VM; /// If the value is a string, return it as UTF-8, otherwise return `NULL`. #[no_mangle] -pub extern "C" fn jsonnet_json_extract_string(_vm: &State, v: &Val) -> *mut c_char { +pub extern "C" fn jsonnet_json_extract_string(_vm: &VM, v: &Val) -> *mut c_char { match v { Val::Str(s) => CString::new(s as &str).unwrap().into_raw(), _ => std::ptr::null_mut(), @@ -18,7 +20,7 @@ /// If the value is a number, return `1` and store the number in out, otherwise return `0`. #[no_mangle] -pub extern "C" fn jsonnet_json_extract_number(_vm: &State, v: &Val, out: &mut c_double) -> c_int { +pub extern "C" fn jsonnet_json_extract_number(_vm: &VM, v: &Val, out: &mut c_double) -> c_int { match v { Val::Num(n) => { *out = *n; @@ -30,7 +32,7 @@ /// Return `0` if the value is `false`, `1` if it is `true`, and `2` if it is not a `bool`. #[no_mangle] -pub extern "C" fn jsonnet_json_extract_bool(_vm: &State, v: &Val) -> c_int { +pub extern "C" fn jsonnet_json_extract_bool(_vm: &VM, v: &Val) -> c_int { match v { Val::Bool(false) => 0, Val::Bool(true) => 1, @@ -40,7 +42,7 @@ /// Return `1` if the value is `null`, otherwise return `0`. #[no_mangle] -pub extern "C" fn jsonnet_json_extract_null(_vm: &State, v: &Val) -> c_int { +pub extern "C" fn jsonnet_json_extract_null(_vm: &VM, v: &Val) -> c_int { match v { Val::Null => 1, _ => 0, --- a/bindings/jsonnet/src/val_make.rs +++ b/bindings/jsonnet/src/val_make.rs @@ -5,16 +5,18 @@ os::raw::{c_char, c_double, c_int}, }; -use jrsonnet_evaluator::{val::ArrValue, ObjValue, State, Val}; +use jrsonnet_evaluator::{val::ArrValue, ObjValue, Val}; use jrsonnet_gcmodule::Cc; +use crate::VM; + /// Convert the given `UTF-8` string to a `JsonnetJsonValue`. /// /// # Safety /// /// `v` should be a NUL-terminated string #[no_mangle] -pub unsafe extern "C" fn jsonnet_json_make_string(_vm: &State, val: *const c_char) -> *mut Val { +pub unsafe extern "C" fn jsonnet_json_make_string(_vm: &VM, val: *const c_char) -> *mut Val { let val = CStr::from_ptr(val); let val = val.to_str().expect("string is not utf-8"); Box::into_raw(Box::new(Val::Str(val.into()))) @@ -22,20 +24,20 @@ /// Convert the given double to a `JsonnetJsonValue`. #[no_mangle] -pub extern "C" fn jsonnet_json_make_number(_vm: &State, v: c_double) -> *mut Val { +pub extern "C" fn jsonnet_json_make_number(_vm: &VM, v: c_double) -> *mut Val { Box::into_raw(Box::new(Val::Num(v))) } /// Convert the given `bool` (`1` or `0`) to a `JsonnetJsonValue`. #[no_mangle] -pub extern "C" fn jsonnet_json_make_bool(_vm: &State, v: c_int) -> *mut Val { +pub extern "C" fn jsonnet_json_make_bool(_vm: &VM, v: c_int) -> *mut Val { assert!(v == 0 || v == 1, "bad boolean value"); Box::into_raw(Box::new(Val::Bool(v == 1))) } /// Make a `JsonnetJsonValue` representing `null`. #[no_mangle] -pub extern "C" fn jsonnet_json_make_null(_vm: &State) -> *mut Val { +pub extern "C" fn jsonnet_json_make_null(_vm: &VM) -> *mut Val { Box::into_raw(Box::new(Val::Null)) } @@ -43,12 +45,12 @@ /// /// Assign elements with [`jsonnet_json_array_append`]. #[no_mangle] -pub extern "C" fn jsonnet_json_make_array(_vm: &State) -> *mut Val { +pub extern "C" fn jsonnet_json_make_array(_vm: &VM) -> *mut Val { Box::into_raw(Box::new(Val::Arr(ArrValue::Eager(Cc::new(Vec::new()))))) } /// Make a `JsonnetJsonValue` representing an object. #[no_mangle] -pub extern "C" fn jsonnet_json_make_object(_vm: &State) -> *mut Val { +pub extern "C" fn jsonnet_json_make_object(_vm: &VM) -> *mut Val { Box::into_raw(Box::new(Val::Obj(ObjValue::new_empty()))) } --- a/bindings/jsonnet/src/val_modify.rs +++ b/bindings/jsonnet/src/val_modify.rs @@ -4,9 +4,11 @@ use std::{ffi::CStr, os::raw::c_char}; -use jrsonnet_evaluator::{val::ArrValue, State, Thunk, Val}; +use jrsonnet_evaluator::{val::ArrValue, Thunk, Val}; use jrsonnet_gcmodule::Cc; +use crate::VM; + /// Adds value to the end of the array `arr`. /// /// # Safety @@ -14,7 +16,7 @@ /// `arr` should be a pointer to array value allocated by make_array, or returned by other library call /// `val` should be a pointer to value allocated using this library #[no_mangle] -pub unsafe extern "C" fn jsonnet_json_array_append(_vm: &State, arr: &mut Val, val: &Val) { +pub unsafe extern "C" fn jsonnet_json_array_append(_vm: &VM, arr: &mut Val, val: &Val) { match arr { Val::Arr(old) => { let mut new = Vec::new(); @@ -39,7 +41,7 @@ /// `name` should be NUL-terminated string #[no_mangle] pub unsafe extern "C" fn jsonnet_json_object_append( - _vm: &State, + _vm: &VM, obj: &mut Val, name: *const c_char, val: &Val, --- a/bindings/jsonnet/src/vars_tlas.rs +++ b/bindings/jsonnet/src/vars_tlas.rs @@ -2,7 +2,10 @@ use std::{ffi::CStr, os::raw::c_char}; -use jrsonnet_evaluator::State; +use jrsonnet_evaluator::{function::TlaArg, IStr}; +use jrsonnet_parser::{ParserSettings, Source}; + +use crate::VM; /// Binds a Jsonnet external variable to the given string. /// @@ -12,11 +15,11 @@ /// /// `name`, `code` should be a NUL-terminated strings #[no_mangle] -pub unsafe extern "C" fn jsonnet_ext_var(vm: &State, name: *const c_char, value: *const c_char) { +pub unsafe extern "C" fn jsonnet_ext_var(vm: &VM, name: *const c_char, value: *const c_char) { let name = CStr::from_ptr(name); let value = CStr::from_ptr(value); - let any_initializer = vm.context_initializer(); + let any_initializer = vm.state.context_initializer(); any_initializer .as_any() .downcast_ref::() @@ -35,11 +38,11 @@ /// /// `name`, `code` should be a NUL-terminated strings #[no_mangle] -pub unsafe extern "C" fn jsonnet_ext_code(vm: &State, name: *const c_char, code: *const c_char) { +pub unsafe extern "C" fn jsonnet_ext_code(vm: &VM, name: *const c_char, code: *const c_char) { let name = CStr::from_ptr(name); let code = CStr::from_ptr(code); - let any_initializer = vm.context_initializer(); + let any_initializer = vm.state.context_initializer(); any_initializer .as_any() .downcast_ref::() @@ -59,13 +62,13 @@ /// /// `name`, `value` should be a NUL-terminated strings #[no_mangle] -pub unsafe extern "C" fn jsonnet_tla_var(vm: &State, name: *const c_char, value: *const c_char) { +pub unsafe extern "C" fn jsonnet_tla_var(vm: &mut VM, name: *const c_char, value: *const c_char) { let name = CStr::from_ptr(name); let value = CStr::from_ptr(value); - vm.add_tla_str( + vm.tla_args.insert( name.to_str().expect("name is not utf-8").into(), - value.to_str().expect("value is not utf-8").into(), - ) + TlaArg::String(value.to_str().expect("value is not utf-8").into()), + ); } /// Binds a top-level code argument for a top-level parameter. @@ -76,12 +79,19 @@ /// /// `name`, `code` should be a NUL-terminated strings #[no_mangle] -pub unsafe extern "C" fn jsonnet_tla_code(vm: &State, name: *const c_char, code: *const c_char) { +pub unsafe extern "C" fn jsonnet_tla_code(vm: &mut VM, name: *const c_char, code: *const c_char) { let name = CStr::from_ptr(name); let code = CStr::from_ptr(code); - vm.add_tla_code( - name.to_str().expect("name is not utf-8").into(), - code.to_str().expect("code is not utf-8"), + + let name: IStr = name.to_str().expect("name is not utf-8").into(); + let code: IStr = code.to_str().expect("code is not utf-8").into(); + let code = jrsonnet_parser::parse( + &code, + &ParserSettings { + source: Source::new_virtual(format!("").into(), code.clone()), + }, ) - .expect("can't parse tla code") + .expect("can't parse TLA code"); + + vm.tla_args.insert(name, TlaArg::Code(code)); } -- gitstuff