CertainLach/jrsonnet

Ext variables are not working while adding methods in global

redoC-A2k opened this issue · 2 comments

Jsonnet make

pub 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(),
    ));
    add_namespace(&state); // **here we are adding our global methods**
    Box::into_raw(Box::new(VM {
        state,
        manifest_format: Box::new(JsonFormat::default()),
        trace_format: Box::new(CompactFormat::default()),
        tla_args: GcHashMap::default(),
    }))
}

add_namespace function

fn add_namespace(state: &State) {
    let mut bobj = ObjValueBuilder::new();
    bobj.method("join", join::INST);
    bobj.method("regexMatch", regex_match::INST);
    state.add_global("arakoo".into(), Thunk::evaluated(Val::Obj(bobj.build())))
}
pub fn main() {
        let vm = jsonnet_make();
        // let filename = CString::new("filename").unwrap();
        let filename = "filename";

        let snippet = r#"
    local username = std.extVar('name');
    local Person(name='Alice') = {
      name: name,
      welcome: 'Hello ' + name + '!',
    };
    {
      person1: Person(username),
      person2: Person('Bob'),
    }"#;
        unsafe {
            ext_string(
                &mut *vm, // name.as_ptr() as *const c_char,
                "name",   // value.as_ptr() as *const c_char,
                "afshan",
            );
        }

        let result = unsafe { jsonnet_evaluate_snippet(&mut *vm, filename, snippet) };
        println!("{}", result);
}
    
pub fn ext_string(vm: *mut VM, key: &str, value: &str) {
    let vm = unsafe { &mut *vm };
    let any_initializer = vm.state.context_initializer();
    any_initializer
        .as_any()
        .downcast_ref::<jrsonnet_stdlib::ContextInitializer>()
        .expect("only stdlib context initializer supported")
        .add_ext_var(key.into(), Val::Str(value.into()));
}

Issue : We want to call regex_match and join method under arakoo namespace , it is working but when are trying to get value from external variable then we get panic as "only stdlib context initializer supported"
Expected : We should be able to call arakoo.regex_match and arakoo.join and also getting value from external variable should work .
VM struct is same as -> https://github.com/CertainLach/jrsonnet/blob/master/bindings/jsonnet/src/lib.rs#L75

This isn't obvious, but add_global and stdlib initializer are orthogonal,

    any_initializer
        .as_any()
        .downcast_ref::<jrsonnet_stdlib::ContextInitializer>()
        .expect("only stdlib context initializer supported")

Panics, because initializer here is not jrsonnet_stdlib::ContextInitializer, but GlobalsCtx defined here:
https://github.com/CertainLach/jrsonnet/blob/master/crates/jrsonnet-evaluator/src/lib.rs#L418-L454

In the future I want to drop those global initialization methods, but for now it is as it is, you need to set ext_strings before you add globals using add_global, or you need to implement your own ContextInitializer which will provide your own variables, as well as forward control to jrsonnet_stdlib.

It is also possible to chain two initializers,
state.set_context_initializer((jrsonnet_stdlib::ContextInitializer, ArakooContextInitializer))

Where ArakooContextInitializer will provide arakoo global.

Example of ContextInitializer initialization:
https://github.com/UniqueNetwork/chainql/blob/master/crates/chainql-core/src/lib.rs#L1657-L1688

And how to use it:
https://github.com/UniqueNetwork/chainql/blob/master/cmds/chainql/src/main.rs#L28-L32

Thanks a lot for helping , I have implemented ArakooContext and then managed jrsonnet_stdlib::Context from there