NeilFraser/JS-Interpreter

How to warp non native functions

krishyadav007 opened this issue · 5 comments

#191

I was running the following code when I too got the same error.

        var initFunc = function(interpreter, globalObject) {
            
            var display_wrapper = function display(text) {
                return window.alert("HELLO WORLD");
            };
            
            interpreter.setProperty(globalObject, 'display', interpreter.createNativeFunction(display_wrapper));
        };

        var Interpreter_js = new Interpreter(code, initFunc);
        Interpreter_js.run();

From what I understood, since display function is not a native function it will give the error.
So what is the correct way to wrap and use non-native custom functions?

That code should work fine. In the interpreter you should now have a global function named 'display' that alerts "HELLO WORLD". What's the problem?

Ok, so this is the correct way for non-native custom functions.
So how to use outside variables inside that function.

Cuz I tried

SENTENCE = ["Hello", "World"]
code="display(SENTENCE[1])";
var initFunc = function(interpreter, globalObject) {
  interpreter.setProperty(globalObject, 'SENTENCE', SENTENCE);
  var display_wrapper = function display(text) {
                return window.alert(text);
  };
  interpreter.setProperty(globalObject, 'display', interpreter.createNativeFunction(display_wrapper));
};

var Interpreter_js = new Interpreter(code, initFunc);
Interpreter_js.run();

I felt I am wrongly using the function, as the error says

acorn_interpreter.js:111 Uncaught TypeError: Expecting native value or pseudo object
at t.p.D (acorn_interpreter.js:111:219)
at t.stepMemberExpression (acorn_interpreter.js:147:283)
at t.p.fb (acorn_interpreter.js:47:178)
at t.p.xb (acorn_interpreter.js:47:449)

interpreter.setProperty(globalObject, 'SENTENCE', SENTENCE);

Native objects (in this case an array) can't be passed straight into the interpreter. You'd want:

var pseudoSentance = interpreter.nativeToPseudo(SENTENCE);
interpreter.setProperty(globalObject, 'SENTENCE', pseudoSentance);

This injects a copy of the array into the interpreter at the moment of initialization. If you want live access to the real array (so that changes to the original array are reflected inside the interpreter, then you'd need a getter:

var initFunc = function(interpreter, globalObject) {
  var getSentenceWrapper = function getSentence() {
                return interpreter.nativeToPseudo(SENTENCE);
  };
  interpreter.setProperty(globalObject, 'getSentence', interpreter.createNativeFunction(getSentenceWrapper));

And likewise, if you want two-way live access (so that the interpreter can change the array), then you'd need a getter and a setter. As expected there's a pseudoToNative function which takes an object in the interpreter and creates an equivalent native JavaScript object.

I'm going to close this issue for now since it looks like the question has been answered—but @NeilFraser's answer above does suggest to me that something like nativeToPseudo, but which returns something like a Proxy of the native object, and which would return similar proxies of object-valued properties on the proxied object, would be very useful. (It would need to have some restrictions on auto-wrapping of functions, however, to prevent sandbox escapes.)

Oh sure, you can close it, the issue is resolved, and I would suggest, you can add this to documentation too