JS-Interpreter
JS-Interpreter copied to clipboard
A couple of helper functions proposal
I was implementing custom blocks in my Blockly project, and quickly filled my init function with boilerplate code consisting from this (for each function):
var wrapper = function(text) {
text = text ? text.toString() : '';
return interpreter.createPrimitive(alert(text));
};
interpreter.setProperty(scope, 'alert',
interpreter.createNativeFunction(wrapper));
So, I created a couple of functions to make this binding easier:
function extractJavaScriptValue(valueObject) {
if (valueObject.isPrimitive) {
return valueObject.data;
}
if ("length" in valueObject) {
// This probably is a list
var output = [];
for (var i = 0; i < valueObject.length; i++)
{
output.push(extractJavaScriptValue(valueObject.properties[i]));
}
return output;
}
}
function bindJavaScriptFn(interpreter, scope, fnName, fn) {
var wrapper = function(arg) {
var argValues = [];
for (var i = 0; i < arguments.length; i++) {
argValues[i] = extractJavaScriptValue(arguments[i]);
}
return interpreter.createPrimitive(fn.apply(window, argValues));
};
interpreter.setProperty(scope, fnName,
interpreter.createNativeFunction(wrapper));
}
Now, the function binding is simple one-liner:
bindJavaScriptFn(interpreter, scope, 'alert', alert);
I have not studied the JS-Interpreter internals too deeply, maybe this approach has issues? Or maybe I have created something that already exists but is not particularly documented?.
+1
I think createNativeFunction should unwrap all arguments before calling the function being created.
Hi @Passiday , I was using what you wrote and I even did a little improvment by supporting functions that take object as arguments, and that return object too (without passying by JSON.parse ;))
function extractJavaScriptValue(valueObject) {
if (typeof(valueObject) === 'undefined')
return undefined;
if (valueObject.isPrimitive)
return valueObject.data;
if ("length" in valueObject) {
var output = [];
for (var i = 0; i < valueObject.length; i++)
output.push(extractJavaScriptValue(valueObject.properties[i]));
return output;
}
if ("properties" in valueObject) {
var obj = {};
for (var property in valueObject.properties)
obj[property] = extractJavaScriptValue(valueObject.properties[property]);
return obj;
}
}
function bindJavaScriptFn(interpreter, scope, fnName, fn) {
var wrapper = function(arg) {
var argValues = [];
for (var i = 0; i < arguments.length; i++)
argValues[i] = extractJavaScriptValue(arguments[i]);
var result = fn.apply(window, argValues);
if (typeof result !== 'object')
return interpreter.createPrimitive(result);
var obj = interpreter.createObject(interpreter.OBJECT);
for (var property in result)
interpreter.setProperty(obj, property, interpreter.createPrimitive(result[property]));
return obj;
};
interpreter.setProperty(scope, fnName, interpreter.createNativeFunction(wrapper));
}
I hope it would help someone else than us!