Cómo generar y ejecutar JavaScript

Las aplicaciones de Blockly a menudo generan JavaScript como su lenguaje de salida Generalmente para ejecutarse en una página web (posiblemente la misma o en un WebView incorporado). Como cualquier generador, el primer paso es incluir el generador de JavaScript.

import {javascriptGenerator} from 'blockly/javascript';

Para generar JavaScript desde el espacio de trabajo, llama a lo siguiente:

javascriptGenerator.addReservedWords('code');
var code = javascriptGenerator.workspaceToCode(workspace);

El código resultante se puede ejecutar directamente en la página web de destino:

try {
  eval(code);
} catch (e) {
  alert(e);
}

Básicamente, el fragmento anterior solo genera el código y lo evalúa. Sin embargo, hay un par de mejoras. Una mejora es que la evaluación se envuelve una try/catch para que se puedan ver los errores de tiempo de ejecución, en lugar de fallar en silencio. Otra mejora es que code se agregó a la lista de reservas. palabras para que, si el código del usuario contiene una variable con ese nombre, será cambiarles el nombre automáticamente en lugar de colisionar. Todas las variables locales se deben reservaron de esta manera.

Destacar bloques

Destacar el bloque que se está ejecutando a medida que se ejecuta el código ayuda a los usuarios a comprender el comportamiento de su programa. El resaltado se puede realizar en un nivel de declaración por declaración estableciendo STATEMENT_PREFIX antes de generar el código JavaScript:

javascriptGenerator.STATEMENT_PREFIX = 'highlightBlock(%1);\n';
javascriptGenerator.addReservedWords('highlightBlock');

Define highlightBlock para marcar el bloque en el lugar de trabajo.

function highlightBlock(id) {
  workspace.highlightBlock(id);
}

Como resultado, se agrega la sentencia highlightBlock('123'); antes de cada instrucción, donde 123 es el número de serie del bloque que se va a destacado.

Bucles infinitos

Aunque se garantiza que el código resultante sea sintácticamente correcto en absoluto varias veces, puede contener bucles infinitos. Desde que se resolvió el El problema de detención va más allá El alcance de Blockly (!) el mejor enfoque para tratar estos casos es mantener un contador y disminuirlo cada vez que se realiza una iteración. Para ello, simplemente establece javascriptGenerator.INFINITE_LOOP_TRAP en un código que se insertará en cada bucle y función. Este es un ejemplo:

window.LoopTrap = 1000;
javascriptGenerator.INFINITE_LOOP_TRAP = 'if(--window.LoopTrap == 0) throw "Infinite loop.";\n';
var code = javascriptGenerator.workspaceToCode(workspace);

Ejemplo

Aquí tienes una demostración en vivo de generar y ejecutar JavaScript.

Intérprete de JS

Si realmente quieres ejecutar los bloques del usuario correctamente, el JS-Interpreter project es la mejor opción. Este proyecto es independiente de Blockly, pero se escribió específicamente para Blockly.

  • Ejecuta código a cualquier velocidad.
  • Pausar, reanudar o realizar una ejecución paso a paso
  • Destaca los bloques a medida que se ejecutan.
  • Completamente aislado del JavaScript del navegador.

Cómo ejecutar el intérprete

Primero, descarga el JS-Interpreter de GitHub:

Descargar archivo ZIP Descargar TAR Ball Ver en GitHub

Luego, agrégalo a tu página:

<script src="acorn_interpreter.js"></script>

El método más simple para llamarlo es generar el código JavaScript, crear el y ejecuta el código:

var code = javascriptGenerator.workspaceToCode(workspace);
var myInterpreter = new Interpreter(code);
myInterpreter.run();

Sé el intérprete

Para ejecutar el código de forma más lenta, o de una forma más controlada, reemplaza el llamada a run con un bucle que avanza (en este caso, un paso cada 10 ms):

function nextStep() {
  if (myInterpreter.step()) {
    setTimeout(nextStep, 10);
  }
}
nextStep();

Ten en cuenta que cada paso no es una línea o un bloque, es una unidad semántica en JavaScript, que puede ser muy detallado.

Agregar una API

JS-Interpreter es una zona de pruebas completamente aislada del navegador. Cualquier bloque que realice acciones con el mundo exterior requiere que se agregue una API el intérprete. Para ver una descripción completa, consulta la Documentación de JS-Interpreter. Pero, para comenzar, esta es la API que se necesita para admitir los bloques de instrucciones y alertas:

function initApi(interpreter, globalObject) {
  // Add an API function for the alert() block.
  var wrapper = function(text) {
    return alert(arguments.length ? text : '');
  };
  interpreter.setProperty(globalObject, 'alert',
      interpreter.createNativeFunction(wrapper));

  // Add an API function for the prompt() block.
  wrapper = function(text) {
    return prompt(text);
  };
  interpreter.setProperty(globalObject, 'prompt',
      interpreter.createNativeFunction(wrapper));
}

Luego, modifica la inicialización de tu intérprete para pasar la función initApi:

var myInterpreter = new Interpreter(code, initApi);

Los bloques de alertas y mensajes son los únicos dos bloques del conjunto predeterminado de bloques. que requieren una API personalizada para el intérprete.

Conectando highlightBlock()

Cuando se ejecuta en JS-Interpreter, se debe ejecutar highlightBlock(). inmediatamente, fuera de la zona de pruebas, a medida que el usuario recorre el programa. Tareas pendientes esto, crea una función wrapper highlightBlock() para capturar la función de registro y registrarlo como una función nativa.

function initApi(interpreter, globalObject) {
  // Add an API function for highlighting blocks.
  var wrapper = function(id) {
    return workspace.highlightBlock(id);
  };
  interpreter.setProperty(globalObject, 'highlightBlock',
      interpreter.createNativeFunction(wrapper));
}

Las aplicaciones más sofisticadas podrían querer ejecutar pasos de forma repetida sin pausa hasta que se alcance un comando de resaltado y, luego, pausa. Esta estrategia simula línea por línea. En el siguiente ejemplo, se usa este enfoque.

Ejemplo de JS-Interpreter

Aquí tienes una demostración en vivo de interpretar JavaScript paso a paso. Y esta demostración incluye un bloque "wait" (esperar), un buen ejemplo para usar en otros comportamientos asíncronos (p.ej., voz o audio, o entrada del usuario).