JS-Interpreter icon indicating copy to clipboard operation
JS-Interpreter copied to clipboard

A couple of helper functions proposal

Open Passiday opened this issue 9 years ago • 2 comments

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?.

Passiday avatar Dec 16 '15 07:12 Passiday

+1

I think createNativeFunction should unwrap all arguments before calling the function being created.

bioball avatar Feb 05 '16 00:02 bioball

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!

Gb42 avatar Nov 26 '17 20:11 Gb42