difftreelog
refactor split libjsonnet code into modules
in: master
11 files changed
bindings/c/.gitignorediffbeforeafterboth--- /dev/null
+++ b/bindings/c/.gitignore
@@ -0,0 +1 @@
+libjsonnet_test_file
bindings/js/index.jsdiffbeforeafterboth--- a/bindings/js/index.js
+++ b/bindings/js/index.js
@@ -1,16 +1,48 @@
const fs = require('fs');
+const path = require('path');
const { WASI } = require('wasi');
const wasi = new WASI({
args: process.argv,
env: process.env,
preopens: {},
});
-const importObject = { wasi_snapshot_preview1: wasi.wasiImport };
class JsonnetVM {
constructor(wasm, vm) {
this.wasm = wasm;
this.vm = vm;
+ this.wasm.exports.jrsonnet_set_trace_format(this.vm, 1);
+
+ this.setImportCallback((from, to) => {
+ const resolved = path.resolve(from, to);
+ return {
+ value: fs.readFileSync(resolved).toString('utf-8'),
+ foundHere: resolved,
+ };
+ })
+ }
+
+ /**
+ * @param {(from: string, to: string) => {foundHere: string, value: string}} cb
+ */
+ setImportCallback(cb) {
+ this.wasm.importCbs.set(this.vm, (base, rel, foundHere, success) => {
+ const baseStr = this.wasm.readString(base);
+ const relStr = this.wasm.readString(rel);
+ try {
+ const value = cb(baseStr, relStr);
+ this.wasm.memorySlice32Len(foundHere, 1)[0] = this.allocateString(value.foundHere);
+ this.wasm.memorySlice32Len(success, 1)[0] = 1;
+ return this.allocateString(value.value);
+ } catch (e) {
+ this.wasm.memorySlice32Len(success, 1)[0] = 0;
+ return this.allocateString(e.stack)
+ }
+ });
+ this.wasm.exports.jrsonnet_apply_static_import_callback(
+ this.vm,
+ this.vm,
+ );
}
alloc(length) {
@@ -18,7 +50,7 @@
}
allocateString(string) {
const byteLength = new TextEncoder().encode(string).length;
- const addr = this.alloc(byteLength);
+ const addr = this.alloc(byteLength + 1);
this.wasm.writeString(addr, string);
return addr;
}
@@ -36,7 +68,7 @@
const result = this.wasm.readString(resultAddr).trim();
this.dealloc(resultAddr);
if (resultCode[0] === 1) {
- const error = new Error(this.normalizeErrorString(result));
+ const error = new Error(result);
throw error;
} else {
return result;
@@ -54,31 +86,46 @@
const result = this.wasm.readString(resultAddr);
this.dealloc(resultAddr);
if (resultCode[0] === 1) {
- const error = new Error(this.normalizeErrorString(result));
+ const error = new Error(result);
throw error;
} else {
return result;
}
}
- normalizeErrorString(str) {
- str = str.trim();
- const newLine = str.indexOf('\n');
- if (newLine === -1) return str;
- let message = str.slice(0, newLine);
- let trace = str.slice(newLine + 1).split('\n').map(s => s.split(' ---- ')).map(([p, v]) => ` at ${v} (${p})`).join('\n');
- return `${message}\n${trace}`;
+
+ /**
+ * Destroys vm, any future call to this object will fail, and all resources will be freed
+ */
+ destroy() {
+ this.wasm.exports.jsonnet_destroy(this.vm);
+ this.wasm.importCbs.delete(this.vm);
}
}
class JsonnetWASM {
- constructor() { }
+ constructor() {
+ this.importCbs = new Map();
+ }
async init(buf) {
const wasm = await WebAssembly.compile(buf);
- const instance = await WebAssembly.instantiate(wasm, importObject);
+ const instance = await WebAssembly.instantiate(wasm, {
+ wasi_snapshot_preview1: wasi.wasiImport,
+ env: {
+ _jrsonnet_static_import_callback: (ctx, base, rel, found_here, success) => {
+ if (!this.importCbs.has(ctx)) {
+ throw new Error(`Got unknown ctx callback: ${ctx}`);
+ }
+ return this.importCbs.get(ctx)(base, rel, found_here, success);
+ }
+ }
+ });
wasi.start(instance);
this.instance = instance;
}
+ /**
+ * @type Record<string, WebAssembly.ExportValue>
+ */
get exports() {
return this.instance.exports;
}
@@ -91,6 +138,9 @@
memorySliceLen(start, length) {
return new Uint8Array(this.memoryBuffer, start, length);
}
+ memorySlice32Len(start, length) {
+ return new Uint32Array(this.memoryBuffer, start, length);
+ }
memorySlice(start, end) {
return new Uint8Array(this.memoryBuffer, start, start && end && (end - start));
}
@@ -119,15 +169,13 @@
(async () => {
try {
const jsonnet = new JsonnetWASM();
- await jsonnet.init(fs.readFileSync(`${__dirname}/../../target/wasm32-wasi/release/jsonnet.wasi.wasm`));
+ await jsonnet.init(fs.readFileSync(`${__dirname}/../../target/wasm32-wasi/release/jsonnet.wasm`));
console.log(`Version = ${jsonnet.version()}`);
const vm = jsonnet.newVM();
console.log(vm.evaluateSnippet('./snip.jsonnet', `
- local a(b) = error "sad" + b;
- local c() = a(2 + 2);
- c()
- `))
+ 2+2
+ `));
console.log(vm.evaluateFile('./test.jsonnet'));
} catch (e) {
console.log(e.stack);
bindings/jsonnet/Cargo.tomldiffbeforeafterboth--- a/bindings/jsonnet/Cargo.toml
+++ b/bindings/jsonnet/Cargo.toml
@@ -9,7 +9,6 @@
[dependencies]
jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "1.0.0" }
jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "1.0.0" }
-libc = "0.2.71"
[lib]
crate-type = ["cdylib"]
bindings/jsonnet/src/interop.rsdiffbeforeafterboth--- /dev/null
+++ b/bindings/jsonnet/src/interop.rs
@@ -0,0 +1,36 @@
+//! Jrsonnet specific additional binding helpers
+
+use crate::import::jsonnet_import_callback;
+use jrsonnet_evaluator::EvaluationState;
+use std::{
+ ffi::c_void,
+ os::raw::{c_char, c_int},
+};
+
+extern "C" {
+ pub fn _jrsonnet_static_import_callback(
+ ctx: *mut c_void,
+ base: *const c_char,
+ rel: *const c_char,
+ found_here: *mut *const c_char,
+ success: &mut c_int,
+ ) -> *const c_char;
+}
+
+/// # Safety
+#[no_mangle]
+pub unsafe extern "C" fn jrsonnet_apply_static_import_callback(
+ vm: &EvaluationState,
+ ctx: *mut c_void,
+) {
+ jsonnet_import_callback(vm, _jrsonnet_static_import_callback, ctx)
+}
+
+#[no_mangle]
+pub extern "C" fn jrsonnet_set_trace_format(vm: &EvaluationState, format: u8) {
+ use jrsonnet_evaluator::trace::JSFormat;
+ match format {
+ 1 => vm.set_trace_format(Box::new(JSFormat)),
+ _ => panic!("unknown trace format"),
+ }
+}
bindings/jsonnet/src/lib.rsdiffbeforeafterboth--- a/bindings/jsonnet/src/lib.rs
+++ b/bindings/jsonnet/src/lib.rs
@@ -1,23 +1,24 @@
-use jrsonnet_evaluator::{
- create_error, create_error_result, Error, EvaluationState, ImportResolver, LazyBinding,
- LazyVal, ObjMember, ObjValue, Result, Val,
-};
-use jrsonnet_parser::Visibility;
-use libc::{c_char, c_double, c_int, c_uint};
+#![feature(custom_inner_attributes)]
+
+pub mod import;
+pub mod interop;
+pub mod val_extract;
+pub mod val_make;
+pub mod val_modify;
+pub mod vars_tlas;
+
+use import::NativeImportResolver;
+use jrsonnet_evaluator::{EvaluationState, ManifestFormat, Val};
use std::{
alloc::Layout,
- any::Any,
- cell::RefCell,
- collections::HashMap,
ffi::{CStr, CString},
- fs::File,
- io::Read,
+ os::raw::{c_char, c_double, c_int, c_uint},
path::PathBuf,
rc::Rc,
};
+/// WASM stub
#[no_mangle]
-#[cfg(target = "wasm32-wasi")]
pub extern "C" fn _start() {}
#[no_mangle]
@@ -25,45 +26,6 @@
b"v0.16.0\0"
}
-#[derive(Default)]
-struct NativeImportResolver {
- library_paths: RefCell<Vec<PathBuf>>,
-}
-impl NativeImportResolver {
- fn add_jpath(&self, path: PathBuf) {
- self.library_paths.borrow_mut().push(path);
- }
-}
-impl ImportResolver for NativeImportResolver {
- fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>> {
- let mut new_path = from.clone();
- new_path.push(path);
- if new_path.exists() {
- Ok(Rc::new(new_path))
- } else {
- for library_path in self.library_paths.borrow().iter() {
- let mut cloned = library_path.clone();
- cloned.push(path);
- if cloned.exists() {
- return Ok(Rc::new(cloned));
- }
- }
- create_error_result(Error::ImportFileNotFound(from.clone(), path.clone()))
- }
- }
- fn load_file_contents(&self, id: &PathBuf) -> Result<Rc<str>> {
- let mut file =
- File::open(id).map_err(|_e| create_error(Error::ResolvedFileNotFound(id.clone())))?;
- let mut out = String::new();
- file.read_to_string(&mut out)
- .map_err(|_e| create_error(Error::ImportBadFileUtf8(id.clone())))?;
- Ok(out.into())
- }
- unsafe fn as_any(&self) -> &dyn Any {
- self
- }
-}
-
#[no_mangle]
pub extern "C" fn jsonnet_make() -> *mut EvaluationState {
let state = EvaluationState::default();
@@ -89,134 +51,18 @@
pub extern "C" fn jsonnet_gc_min_objects(_vm: &EvaluationState, _v: c_uint) {}
#[no_mangle]
pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &EvaluationState, _v: c_double) {}
-
-// TODO
-#[no_mangle]
-pub extern "C" fn jsonnet_string_output(_vm: &EvaluationState, _v: c_int) {
- todo!()
-}
#[no_mangle]
-pub extern "C" fn jsonnet_json_extract_string(_vm: &EvaluationState, v: &Val) -> *mut c_char {
- match v.unwrap_if_lazy().unwrap() {
- 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 {
- match v.unwrap_if_lazy().unwrap() {
- Val::Num(n) => {
- *out = n;
- 1
- }
- _ => 0,
- }
-}
-#[no_mangle]
-pub extern "C" fn jsonnet_json_extract_bool(_vm: &EvaluationState, v: &Val) -> c_int {
- match v.unwrap_if_lazy().unwrap() {
- Val::Bool(false) => 0,
- Val::Bool(true) => 1,
- _ => 2,
- }
-}
-#[no_mangle]
-pub extern "C" fn jsonnet_json_extract_null(_vm: &EvaluationState, v: &Val) -> c_int {
- match v.unwrap_if_lazy().unwrap() {
- Val::Null => 1,
- _ => 0,
- }
-}
-
-/// # 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 {
- 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 {
- 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 {
- 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 {
- Box::into_raw(Box::new(Val::Null))
-}
-
-#[no_mangle]
-pub extern "C" fn jsonnet_json_make_array(_vm: &EvaluationState) -> *mut Val {
- Box::into_raw(Box::new(Val::Arr(Rc::new(Vec::new()))))
-}
-
-#[no_mangle]
-pub extern "C" fn jsonnet_json_array_append(_vm: &EvaluationState, arr: &mut Val, val: &Val) {
- match arr {
- Val::Arr(old) => {
- // TODO: Mutate array, instead of recreating them
- let mut new = Vec::new();
- new.extend(old.iter().cloned());
- new.push(val.clone());
- *arr = Val::Arr(Rc::new(new));
- }
- _ => panic!("should receive array"),
+pub extern "C" fn jsonnet_string_output(vm: &EvaluationState, v: c_int) {
+ match v {
+ 1 => vm.set_manifest_format(ManifestFormat::None),
+ 0 => vm.set_manifest_format(ManifestFormat::Json(4)),
+ _ => panic!("incorrect output format"),
}
-}
-
-#[no_mangle]
-pub extern "C" fn jsonnet_json_make_object(_vm: &EvaluationState) -> *mut Val {
- Box::into_raw(Box::new(Val::Obj(ObjValue::new_empty())))
}
/// # Safety
///
-/// This function is safe if passed name is ok
-#[no_mangle]
-pub unsafe extern "C" fn jsonnet_json_object_append(
- _vm: &EvaluationState,
- obj: &mut Val,
- name: *const c_char,
- val: &Val,
-) {
- match obj {
- Val::Obj(old) => {
- let mut new = HashMap::new();
- new.insert(
- CStr::from_ptr(name).to_str().unwrap().into(),
- ObjMember {
- add: false,
- visibility: Visibility::Normal,
- invoke: LazyBinding::Bound(LazyVal::new_resolved(val.clone())),
- location: None,
- },
- );
- let new_obj = ObjValue::new(Some(old.clone()), Rc::new(new));
- *obj = Val::Obj(new_obj);
- }
- _ => panic!("should receive array"),
- }
-}
-
-/// # Safety
-///
/// This function is most definitely broken, but it works somehow, see TODO inside
#[no_mangle]
pub unsafe extern "C" fn jsonnet_realloc(
@@ -247,48 +93,14 @@
Box::from_raw(v);
}
-#[no_mangle]
-pub extern "C" fn jsonnet_import_callback() {
- todo!()
-}
#[no_mangle]
pub extern "C" fn jsonnet_native_callback() {
- todo!()
-}
-#[no_mangle]
-pub extern "C" fn jsonnet_ext_var() {
todo!()
}
-#[no_mangle]
-pub extern "C" fn jsonnet_ext_code() {
- todo!()
-}
-#[no_mangle]
-pub extern "C" fn jsonnet_tla_var() {
- todo!()
-}
-#[no_mangle]
-pub extern "C" fn jsonnet_tla_code() {
- todo!()
-}
-#[no_mangle]
-pub extern "C" fn jsonnet_max_trace() {
- todo!()
-}
-/// # Safety
-///
-/// 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) {
- let cstr = CStr::from_ptr(v);
- let path = PathBuf::from(cstr.to_str().unwrap());
- let any_resolver = &vm.settings().import_resolver;
- let resolver = any_resolver
- .as_any()
- .downcast_ref::<NativeImportResolver>()
- .unwrap();
- resolver.add_jpath(path);
+pub extern "C" fn jsonnet_max_trace(vm: &EvaluationState, v: c_uint) {
+ vm.set_max_trace(v as usize)
}
/// # Safety
@@ -301,20 +113,19 @@
error: &mut c_int,
) -> *const c_char {
vm.run_in_state(|| {
- use std::fmt::Write;
let filename = CStr::from_ptr(filename);
- match vm.evaluate_file_to_json(&PathBuf::from(filename.to_str().unwrap())) {
+ 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 mut out = String::new();
- writeln!(out, "{:?}", e.0).unwrap();
- for i in (e.1).0.iter() {
- writeln!(out, "{:?}", i.0).unwrap();
- }
+ let out = vm.stringify_err(&e);
CString::new(&out as &str).unwrap().into_raw()
}
}
@@ -332,24 +143,23 @@
error: &mut c_int,
) -> *const c_char {
vm.run_in_state(|| {
- use std::fmt::Write;
let filename = CStr::from_ptr(filename);
let snippet = CStr::from_ptr(snippet);
- match vm.evaluate_snippet_to_json(
- &PathBuf::from(filename.to_str().unwrap()),
- &snippet.to_str().unwrap(),
- ) {
+ match vm
+ .evaluate_snippet_raw(
+ Rc::new(PathBuf::from(filename.to_str().unwrap())),
+ 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 mut out = String::new();
- writeln!(out, "{:?}", e.0).unwrap();
- for i in (e.1).0.iter() {
- writeln!(out, "{:?} ---- {}", i.0, i.1).unwrap();
- }
+ let out = vm.stringify_err(&e);
CString::new(&out as &str).unwrap().into_raw()
}
}
bindings/jsonnet/src/val_extract.rsdiffbeforeafterboth--- /dev/null
+++ b/bindings/jsonnet/src/val_extract.rs
@@ -0,0 +1,45 @@
+//! Extract values from VM
+
+use jrsonnet_evaluator::{EvaluationState, Val};
+
+use std::{
+ ffi::CString,
+ os::raw::{c_char, c_double, c_int},
+};
+
+#[no_mangle]
+pub extern "C" fn jsonnet_json_extract_string(_vm: &EvaluationState, v: &Val) -> *mut c_char {
+ match v.unwrap_if_lazy().unwrap() {
+ 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 {
+ match v.unwrap_if_lazy().unwrap() {
+ Val::Num(n) => {
+ *out = n;
+ 1
+ }
+ _ => 0,
+ }
+}
+#[no_mangle]
+pub extern "C" fn jsonnet_json_extract_bool(_vm: &EvaluationState, v: &Val) -> c_int {
+ match v.unwrap_if_lazy().unwrap() {
+ Val::Bool(false) => 0,
+ Val::Bool(true) => 1,
+ _ => 2,
+ }
+}
+#[no_mangle]
+pub extern "C" fn jsonnet_json_extract_null(_vm: &EvaluationState, v: &Val) -> c_int {
+ match v.unwrap_if_lazy().unwrap() {
+ Val::Null => 1,
+ _ => 0,
+ }
+}
bindings/jsonnet/src/val_make.rsdiffbeforeafterboth--- /dev/null
+++ b/bindings/jsonnet/src/val_make.rs
@@ -0,0 +1,47 @@
+//! Create values in VM
+
+use jrsonnet_evaluator::{EvaluationState, ObjValue, Val};
+use std::{
+ ffi::CStr,
+ os::raw::{c_char, c_double, c_int},
+ rc::Rc,
+};
+
+/// # 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 {
+ 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 {
+ 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 {
+ 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 {
+ Box::into_raw(Box::new(Val::Null))
+}
+
+#[no_mangle]
+pub extern "C" fn jsonnet_json_make_array(_vm: &EvaluationState) -> *mut Val {
+ Box::into_raw(Box::new(Val::Arr(Rc::new(Vec::new()))))
+}
+
+#[no_mangle]
+pub extern "C" fn jsonnet_json_make_object(_vm: &EvaluationState) -> *mut Val {
+ Box::into_raw(Box::new(Val::Obj(ObjValue::new_empty())))
+}
bindings/jsonnet/src/val_modify.rsdiffbeforeafterbothno changes
bindings/jsonnet/src/vars_tlas.rsdiffbeforeafterboth--- /dev/null
+++ b/bindings/jsonnet/src/vars_tlas.rs
@@ -0,0 +1,64 @@
+//! Manipulate external variables and top level arguments
+
+use jrsonnet_evaluator::EvaluationState;
+use std::{ffi::CStr, os::raw::c_char};
+
+/// # Safety
+#[no_mangle]
+pub unsafe extern "C" fn jsonnet_ext_var(
+ vm: &EvaluationState,
+ name: *const c_char,
+ value: *const c_char,
+) {
+ let name = CStr::from_ptr(name);
+ let value = CStr::from_ptr(value);
+ vm.add_ext_str(
+ name.to_str().unwrap().into(),
+ value.to_str().unwrap().into(),
+ )
+}
+
+/// # Safety
+#[no_mangle]
+pub unsafe extern "C" fn jsonnet_ext_code(
+ vm: &EvaluationState,
+ name: *const c_char,
+ value: *const c_char,
+) {
+ let name = CStr::from_ptr(name);
+ let value = CStr::from_ptr(value);
+ vm.add_ext_code(
+ name.to_str().unwrap().into(),
+ value.to_str().unwrap().into(),
+ )
+ .unwrap()
+}
+/// # Safety
+#[no_mangle]
+pub unsafe extern "C" fn jsonnet_tla_var(
+ vm: &EvaluationState,
+ name: *const c_char,
+ value: *const c_char,
+) {
+ let name = CStr::from_ptr(name);
+ let value = CStr::from_ptr(value);
+ vm.add_tla_str(
+ name.to_str().unwrap().into(),
+ value.to_str().unwrap().into(),
+ )
+}
+/// # Safety
+#[no_mangle]
+pub unsafe extern "C" fn jsonnet_tla_code(
+ vm: &EvaluationState,
+ name: *const c_char,
+ value: *const c_char,
+) {
+ let name = CStr::from_ptr(name);
+ let value = CStr::from_ptr(value);
+ vm.add_tla_code(
+ name.to_str().unwrap().into(),
+ value.to_str().unwrap().into(),
+ )
+ .unwrap()
+}
bindings/test.jsonnetdiffbeforeafterboth--- a/bindings/test.jsonnet
+++ /dev/null
@@ -1 +0,0 @@
-2 + 2
crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/error.rs
+++ b/crates/jrsonnet-evaluator/src/error.rs
@@ -56,10 +56,17 @@
StackOverflow,
FractionalIndex,
DivisionByZero,
+
+ StringManifestOutputIsNotAString,
+
+ ImportCallbackError(String),
}
#[derive(Clone, Debug)]
-pub struct StackTraceElement(pub ExprLocation, pub String);
+pub struct StackTraceElement {
+ pub location: ExprLocation,
+ pub desc: String,
+}
#[derive(Debug, Clone)]
pub struct StackTrace(pub Vec<StackTraceElement>);