git.delta.rocks / jrsonnet / refs/commits / dc0a0bacae12

difftreelog

refactor split libjsonnet code into modules

Лач2020-07-19parent: #3943cce.patch.diff
in: master

11 files changed

addedbindings/c/.gitignorediffbeforeafterboth

no changes

modifiedbindings/js/index.jsdiffbeforeafterboth
1const fs = require('fs');1const fs = require('fs');
2const path = require('path');
2const { WASI } = require('wasi');3const { WASI } = require('wasi');
3const wasi = new WASI({4const wasi = new WASI({
4 args: process.argv,5 args: process.argv,
5 env: process.env,6 env: process.env,
6 preopens: {},7 preopens: {},
7});8});
8const importObject = { wasi_snapshot_preview1: wasi.wasiImport };
99
10class JsonnetVM {10class JsonnetVM {
11 constructor(wasm, vm) {11 constructor(wasm, vm) {
12 this.wasm = wasm;12 this.wasm = wasm;
13 this.vm = vm;13 this.vm = vm;
14 this.wasm.exports.jrsonnet_set_trace_format(this.vm, 1);
15
16 this.setImportCallback((from, to) => {
17 const resolved = path.resolve(from, to);
18 return {
19 value: fs.readFileSync(resolved).toString('utf-8'),
20 foundHere: resolved,
21 };
22 })
14 }23 }
24
25 /**
26 * @param {(from: string, to: string) => {foundHere: string, value: string}} cb
27 */
28 setImportCallback(cb) {
29 this.wasm.importCbs.set(this.vm, (base, rel, foundHere, success) => {
30 const baseStr = this.wasm.readString(base);
31 const relStr = this.wasm.readString(rel);
32 try {
33 const value = cb(baseStr, relStr);
34 this.wasm.memorySlice32Len(foundHere, 1)[0] = this.allocateString(value.foundHere);
35 this.wasm.memorySlice32Len(success, 1)[0] = 1;
36 return this.allocateString(value.value);
37 } catch (e) {
38 this.wasm.memorySlice32Len(success, 1)[0] = 0;
39 return this.allocateString(e.stack)
40 }
41 });
42 this.wasm.exports.jrsonnet_apply_static_import_callback(
43 this.vm,
44 this.vm,
45 );
46 }
1547
16 alloc(length) {48 alloc(length) {
17 return this.wasm.exports.jsonnet_realloc(this.vm, 0, length);49 return this.wasm.exports.jsonnet_realloc(this.vm, 0, length);
18 }50 }
19 allocateString(string) {51 allocateString(string) {
20 const byteLength = new TextEncoder().encode(string).length;52 const byteLength = new TextEncoder().encode(string).length;
21 const addr = this.alloc(byteLength);53 const addr = this.alloc(byteLength + 1);
22 this.wasm.writeString(addr, string);54 this.wasm.writeString(addr, string);
23 return addr;55 return addr;
24 }56 }
36 const result = this.wasm.readString(resultAddr).trim();68 const result = this.wasm.readString(resultAddr).trim();
37 this.dealloc(resultAddr);69 this.dealloc(resultAddr);
38 if (resultCode[0] === 1) {70 if (resultCode[0] === 1) {
39 const error = new Error(this.normalizeErrorString(result));71 const error = new Error(result);
40 throw error;72 throw error;
41 } else {73 } else {
42 return result;74 return result;
54 const result = this.wasm.readString(resultAddr);86 const result = this.wasm.readString(resultAddr);
55 this.dealloc(resultAddr);87 this.dealloc(resultAddr);
56 if (resultCode[0] === 1) {88 if (resultCode[0] === 1) {
57 const error = new Error(this.normalizeErrorString(result));89 const error = new Error(result);
58 throw error;90 throw error;
59 } else {91 } else {
60 return result;92 return result;
61 }93 }
62 }94 }
95
96 /**
97 * Destroys vm, any future call to this object will fail, and all resources will be freed
98 */
63 normalizeErrorString(str) {99 destroy() {
64 str = str.trim();100 this.wasm.exports.jsonnet_destroy(this.vm);
65 const newLine = str.indexOf('\n');
66 if (newLine === -1) return str;
67 let message = str.slice(0, newLine);
68 let trace = str.slice(newLine + 1).split('\n').map(s => s.split(' ---- ')).map(([p, v]) => ` at ${v} (${p})`).join('\n');101 this.wasm.importCbs.delete(this.vm);
69 return `${message}\n${trace}`;
70 }102 }
71}103}
72104
73class JsonnetWASM {105class JsonnetWASM {
74 constructor() { }106 constructor() {
107 this.importCbs = new Map();
108 }
75109
76 async init(buf) {110 async init(buf) {
77 const wasm = await WebAssembly.compile(buf);111 const wasm = await WebAssembly.compile(buf);
78 const instance = await WebAssembly.instantiate(wasm, importObject);112 const instance = await WebAssembly.instantiate(wasm, {
113 wasi_snapshot_preview1: wasi.wasiImport,
114 env: {
115 _jrsonnet_static_import_callback: (ctx, base, rel, found_here, success) => {
116 if (!this.importCbs.has(ctx)) {
117 throw new Error(`Got unknown ctx callback: ${ctx}`);
118 }
119 return this.importCbs.get(ctx)(base, rel, found_here, success);
120 }
121 }
122 });
79 wasi.start(instance);123 wasi.start(instance);
80 this.instance = instance;124 this.instance = instance;
81 }125 }
126 /**
127 * @type Record<string, WebAssembly.ExportValue>
128 */
82 get exports() {129 get exports() {
83 return this.instance.exports;130 return this.instance.exports;
84 }131 }
91 memorySliceLen(start, length) {138 memorySliceLen(start, length) {
92 return new Uint8Array(this.memoryBuffer, start, length);139 return new Uint8Array(this.memoryBuffer, start, length);
93 }140 }
141 memorySlice32Len(start, length) {
142 return new Uint32Array(this.memoryBuffer, start, length);
143 }
94 memorySlice(start, end) {144 memorySlice(start, end) {
95 return new Uint8Array(this.memoryBuffer, start, start && end && (end - start));145 return new Uint8Array(this.memoryBuffer, start, start && end && (end - start));
96 }146 }
119(async () => {169(async () => {
120 try {170 try {
121 const jsonnet = new JsonnetWASM();171 const jsonnet = new JsonnetWASM();
122 await jsonnet.init(fs.readFileSync(`${__dirname}/../../target/wasm32-wasi/release/jsonnet.wasi.wasm`));172 await jsonnet.init(fs.readFileSync(`${__dirname}/../../target/wasm32-wasi/release/jsonnet.wasm`));
123 console.log(`Version = ${jsonnet.version()}`);173 console.log(`Version = ${jsonnet.version()}`);
124174
125 const vm = jsonnet.newVM();175 const vm = jsonnet.newVM();
126 console.log(vm.evaluateSnippet('./snip.jsonnet', `176 console.log(vm.evaluateSnippet('./snip.jsonnet', `
127 local a(b) = error "sad" + b;177 2+2
128 local c() = a(2 + 2);
129 c()
130 `))178 `));
131 console.log(vm.evaluateFile('./test.jsonnet'));179 console.log(vm.evaluateFile('./test.jsonnet'));
132 } catch (e) {180 } catch (e) {
133 console.log(e.stack);181 console.log(e.stack);
modifiedbindings/jsonnet/Cargo.tomldiffbeforeafterboth
9[dependencies]9[dependencies]
10jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "1.0.0" }10jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "1.0.0" }
11jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "1.0.0" }11jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "1.0.0" }
12libc = "0.2.71"
1312
14[lib]13[lib]
15crate-type = ["cdylib"]14crate-type = ["cdylib"]
addedbindings/jsonnet/src/interop.rsdiffbeforeafterboth

no changes

modifiedbindings/jsonnet/src/lib.rsdiffbeforeafterboth
1use jrsonnet_evaluator::{1#![feature(custom_inner_attributes)]
2 create_error, create_error_result, Error, EvaluationState, ImportResolver, LazyBinding,2
3 LazyVal, ObjMember, ObjValue, Result, Val,3pub mod import;
4};4pub mod interop;
5pub mod val_extract;
6pub mod val_make;
7pub mod val_modify;
8pub mod vars_tlas;
9
5use jrsonnet_parser::Visibility;10use import::NativeImportResolver;
6use libc::{c_char, c_double, c_int, c_uint};11use jrsonnet_evaluator::{EvaluationState, ManifestFormat, Val};
7use std::{12use std::{
8 alloc::Layout,13 alloc::Layout,
9 any::Any,
10 cell::RefCell,
11 collections::HashMap,
12 ffi::{CStr, CString},14 ffi::{CStr, CString},
13 fs::File,15 os::raw::{c_char, c_double, c_int, c_uint},
14 io::Read,
15 path::PathBuf,16 path::PathBuf,
16 rc::Rc,17 rc::Rc,
17};18};
1819
20/// WASM stub
19#[no_mangle]21#[no_mangle]
20#[cfg(target = "wasm32-wasi")]
21pub extern "C" fn _start() {}22pub extern "C" fn _start() {}
2223
23#[no_mangle]24#[no_mangle]
24pub extern "C" fn jsonnet_version() -> &'static [u8; 8] {25pub extern "C" fn jsonnet_version() -> &'static [u8; 8] {
25 b"v0.16.0\0"26 b"v0.16.0\0"
26}27}
27
28#[derive(Default)]
29struct NativeImportResolver {
30 library_paths: RefCell<Vec<PathBuf>>,
31}
32impl NativeImportResolver {
33 fn add_jpath(&self, path: PathBuf) {
34 self.library_paths.borrow_mut().push(path);
35 }
36}
37impl ImportResolver for NativeImportResolver {
38 fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>> {
39 let mut new_path = from.clone();
40 new_path.push(path);
41 if new_path.exists() {
42 Ok(Rc::new(new_path))
43 } else {
44 for library_path in self.library_paths.borrow().iter() {
45 let mut cloned = library_path.clone();
46 cloned.push(path);
47 if cloned.exists() {
48 return Ok(Rc::new(cloned));
49 }
50 }
51 create_error_result(Error::ImportFileNotFound(from.clone(), path.clone()))
52 }
53 }
54 fn load_file_contents(&self, id: &PathBuf) -> Result<Rc<str>> {
55 let mut file =
56 File::open(id).map_err(|_e| create_error(Error::ResolvedFileNotFound(id.clone())))?;
57 let mut out = String::new();
58 file.read_to_string(&mut out)
59 .map_err(|_e| create_error(Error::ImportBadFileUtf8(id.clone())))?;
60 Ok(out.into())
61 }
62 unsafe fn as_any(&self) -> &dyn Any {
63 self
64 }
65}
6628
67#[no_mangle]29#[no_mangle]
68pub extern "C" fn jsonnet_make() -> *mut EvaluationState {30pub extern "C" fn jsonnet_make() -> *mut EvaluationState {
90#[no_mangle]52#[no_mangle]
91pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &EvaluationState, _v: c_double) {}53pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &EvaluationState, _v: c_double) {}
9254
93// TODO
94#[no_mangle]55#[no_mangle]
95pub extern "C" fn jsonnet_string_output(_vm: &EvaluationState, _v: c_int) {56pub extern "C" fn jsonnet_string_output(vm: &EvaluationState, v: c_int) {
96 todo!()
97}
98
99#[no_mangle]
100pub extern "C" fn jsonnet_json_extract_string(_vm: &EvaluationState, v: &Val) -> *mut c_char {
101 match v.unwrap_if_lazy().unwrap() {
102 Val::Str(s) => CString::new(&*s as &str).unwrap().into_raw(),
103 _ => std::ptr::null_mut(),
104 }
105}
106#[no_mangle]
107pub extern "C" fn jsonnet_json_extract_number(
108 _vm: &EvaluationState,
109 v: &Val,
110 out: &mut c_double,
111) -> c_int {
112 match v.unwrap_if_lazy().unwrap() {
113 Val::Num(n) => {
114 *out = n;
115 1
116 }
117 _ => 0,
118 }
119}
120#[no_mangle]
121pub extern "C" fn jsonnet_json_extract_bool(_vm: &EvaluationState, v: &Val) -> c_int {
122 match v.unwrap_if_lazy().unwrap() {
123 Val::Bool(false) => 0,
124 Val::Bool(true) => 1,
125 _ => 2,
126 }
127}
128#[no_mangle]
129pub extern "C" fn jsonnet_json_extract_null(_vm: &EvaluationState, v: &Val) -> c_int {
130 match v.unwrap_if_lazy().unwrap() {
131 Val::Null => 1,
132 _ => 0,
133 }
134}
135
136/// # Safety
137///
138/// This function is safe, if received v is a pointer to normal C string
139#[no_mangle]
140pub unsafe extern "C" fn jsonnet_json_make_string(
141 _vm: &EvaluationState,
142 v: *const c_char,
143) -> *mut Val {
144 let cstr = CStr::from_ptr(v);
145 let str = cstr.to_str().unwrap();
146 Box::into_raw(Box::new(Val::Str(str.into())))
147}
148
149#[no_mangle]
150pub extern "C" fn jsonnet_json_make_number(_vm: &EvaluationState, v: c_double) -> *mut Val {
151 Box::into_raw(Box::new(Val::Num(v)))
152}
153
154#[no_mangle]
155pub extern "C" fn jsonnet_json_make_bool(_vm: &EvaluationState, v: c_int) -> *mut Val {
156 assert!(v == 0 || v == 1);
157 Box::into_raw(Box::new(Val::Bool(v == 1)))
158}
159
160#[no_mangle]
161pub extern "C" fn jsonnet_json_make_null(_vm: &EvaluationState) -> *mut Val {
162 Box::into_raw(Box::new(Val::Null))
163}
164
165#[no_mangle]
166pub extern "C" fn jsonnet_json_make_array(_vm: &EvaluationState) -> *mut Val {
167 Box::into_raw(Box::new(Val::Arr(Rc::new(Vec::new()))))
168}
169
170#[no_mangle]
171pub extern "C" fn jsonnet_json_array_append(_vm: &EvaluationState, arr: &mut Val, val: &Val) {
172 match arr {
173 Val::Arr(old) => {
174 // TODO: Mutate array, instead of recreating them
175 let mut new = Vec::new();
176 new.extend(old.iter().cloned());
177 new.push(val.clone());
178 *arr = Val::Arr(Rc::new(new));
179 }
180 _ => panic!("should receive array"),
181 }
182}
183
184#[no_mangle]
185pub extern "C" fn jsonnet_json_make_object(_vm: &EvaluationState) -> *mut Val {
186 Box::into_raw(Box::new(Val::Obj(ObjValue::new_empty())))
187}
188
189/// # Safety
190///
191/// This function is safe if passed name is ok
192#[no_mangle]
193pub unsafe extern "C" fn jsonnet_json_object_append(
194 _vm: &EvaluationState,
195 obj: &mut Val,
196 name: *const c_char,
197 val: &Val,
198) {
199 match obj {57 match v {
58 1 => vm.set_manifest_format(ManifestFormat::None),
200 Val::Obj(old) => {59 0 => vm.set_manifest_format(ManifestFormat::Json(4)),
201 let mut new = HashMap::new();
202 new.insert(
203 CStr::from_ptr(name).to_str().unwrap().into(),
204 ObjMember {
205 add: false,
206 visibility: Visibility::Normal,
207 invoke: LazyBinding::Bound(LazyVal::new_resolved(val.clone())),
208 location: None,
209 },
210 );
211 let new_obj = ObjValue::new(Some(old.clone()), Rc::new(new));
212 *obj = Val::Obj(new_obj);
213 }
214 _ => panic!("should receive array"),60 _ => panic!("incorrect output format"),
215 }61 }
216}62}
21763
247 Box::from_raw(v);93 Box::from_raw(v);
248}94}
24995
250#[no_mangle]
251pub extern "C" fn jsonnet_import_callback() {
252 todo!()
253}
254#[no_mangle]96#[no_mangle]
255pub extern "C" fn jsonnet_native_callback() {97pub extern "C" fn jsonnet_native_callback() {
256 todo!()98 todo!()
257}99}
100
258#[no_mangle]101#[no_mangle]
259pub extern "C" fn jsonnet_ext_var() {102pub extern "C" fn jsonnet_max_trace(vm: &EvaluationState, v: c_uint) {
260 todo!()
261}
262#[no_mangle]
263pub extern "C" fn jsonnet_ext_code() {
264 todo!()
265}
266#[no_mangle]
267pub extern "C" fn jsonnet_tla_var() {
268 todo!()
269}
270#[no_mangle]
271pub extern "C" fn jsonnet_tla_code() {
272 todo!()
273}
274#[no_mangle]
275pub extern "C" fn jsonnet_max_trace() {
276 todo!()
277}
278
279/// # Safety
280///
281/// This function is safe, if received v is a pointer to normal C string
282#[no_mangle]
283pub unsafe extern "C" fn jsonnet_jpath_add(vm: &EvaluationState, v: *const c_char) {
284 let cstr = CStr::from_ptr(v);
285 let path = PathBuf::from(cstr.to_str().unwrap());
286 let any_resolver = &vm.settings().import_resolver;103 vm.set_max_trace(v as usize)
287 let resolver = any_resolver
288 .as_any()
289 .downcast_ref::<NativeImportResolver>()
290 .unwrap();
291 resolver.add_jpath(path);
292}104}
293105
294/// # Safety106/// # Safety
301 error: &mut c_int,113 error: &mut c_int,
302) -> *const c_char {114) -> *const c_char {
303 vm.run_in_state(|| {115 vm.run_in_state(|| {
304 use std::fmt::Write;
305 let filename = CStr::from_ptr(filename);116 let filename = CStr::from_ptr(filename);
306 match vm.evaluate_file_to_json(&PathBuf::from(filename.to_str().unwrap())) {117 match vm
118 .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap()))
119 .and_then(|v| vm.with_tla(v))
120 .and_then(|v| vm.manifest(v))
121 {
307 Ok(v) => {122 Ok(v) => {
308 *error = 0;123 *error = 0;
309 CString::new(&*v as &str).unwrap().into_raw()124 CString::new(&*v as &str).unwrap().into_raw()
310 }125 }
311 Err(e) => {126 Err(e) => {
312 *error = 1;127 *error = 1;
313 let mut out = String::new();128 let out = vm.stringify_err(&e);
314 writeln!(out, "{:?}", e.0).unwrap();
315 for i in (e.1).0.iter() {
316 writeln!(out, "{:?}", i.0).unwrap();
317 }
318 CString::new(&out as &str).unwrap().into_raw()129 CString::new(&out as &str).unwrap().into_raw()
319 }130 }
320 }131 }
332 error: &mut c_int,143 error: &mut c_int,
333) -> *const c_char {144) -> *const c_char {
334 vm.run_in_state(|| {145 vm.run_in_state(|| {
335 use std::fmt::Write;
336 let filename = CStr::from_ptr(filename);146 let filename = CStr::from_ptr(filename);
337 let snippet = CStr::from_ptr(snippet);147 let snippet = CStr::from_ptr(snippet);
338 match vm.evaluate_snippet_to_json(148 match vm
149 .evaluate_snippet_raw(
339 &PathBuf::from(filename.to_str().unwrap()),150 Rc::new(PathBuf::from(filename.to_str().unwrap())),
340 &snippet.to_str().unwrap(),151 snippet.to_str().unwrap().into(),
341 ) {152 )
153 .and_then(|v| vm.with_tla(v))
154 .and_then(|v| vm.manifest(v))
155 {
342 Ok(v) => {156 Ok(v) => {
343 *error = 0;157 *error = 0;
344 CString::new(&*v as &str).unwrap().into_raw()158 CString::new(&*v as &str).unwrap().into_raw()
345 }159 }
346 Err(e) => {160 Err(e) => {
347 *error = 1;161 *error = 1;
348 let mut out = String::new();162 let out = vm.stringify_err(&e);
349 writeln!(out, "{:?}", e.0).unwrap();
350 for i in (e.1).0.iter() {
351 writeln!(out, "{:?} ---- {}", i.0, i.1).unwrap();
352 }
353 CString::new(&out as &str).unwrap().into_raw()163 CString::new(&out as &str).unwrap().into_raw()
354 }164 }
355 }165 }
addedbindings/jsonnet/src/val_extract.rsdiffbeforeafterboth

no changes

addedbindings/jsonnet/src/val_make.rsdiffbeforeafterboth

no changes

addedbindings/jsonnet/src/val_modify.rsdiffbeforeafterboth

no changes

addedbindings/jsonnet/src/vars_tlas.rsdiffbeforeafterboth

no changes

deletedbindings/test.jsonnetdiffbeforeafterboth

no changes

modifiedcrates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth
57 FractionalIndex,57 FractionalIndex,
58 DivisionByZero,58 DivisionByZero,
59
60 StringManifestOutputIsNotAString,
61
62 ImportCallbackError(String),
59}63}
6064
61#[derive(Clone, Debug)]65#[derive(Clone, Debug)]
62pub struct StackTraceElement(pub ExprLocation, pub String);66pub struct StackTraceElement {
67 pub location: ExprLocation,
68 pub desc: String,
69}
63#[derive(Debug, Clone)]70#[derive(Debug, Clone)]
64pub struct StackTrace(pub Vec<StackTraceElement>);71pub struct StackTrace(pub Vec<StackTraceElement>);
6572