Como gerar e executar o JavaScript

Os aplicativos Blockly geram JavaScript como linguagem de saída, em geral para execução em uma página da Web (possivelmente a mesma ou um WebView incorporado). Como qualquer gerador, a primeira etapa é incluir o gerador JavaScript.

import {javascriptGenerator} from 'blockly/javascript';

Para gerar JavaScript do espaço de trabalho, chame:

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

O código resultante pode ser executado diretamente na página da Web de destino:

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

Basicamente, o snippet acima apenas gera o código e o avalia. No entanto, você precisa fazer algumas melhorias. Um refinamento é que a avaliação está envolvida uma try/catch para que todos os erros de execução fiquem visíveis, em vez de falhar em silêncio. Outro refinamento é que code é adicionado à lista de objetos palavras para que, se o código do usuário tiver uma variável com o mesmo nome, ela será automaticamente renomeadas em vez de colidirem. Todas as variáveis locais devem ser reservados dessa forma.

Blocos de destaque

Destacar o bloco em execução durante a execução do código ajuda os usuários a entender o comportamento do programa. O destaque pode ser feito instrução por instrução, definindo STATEMENT_PREFIX antes de o código JavaScript:

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

Defina highlightBlock para marcar o bloco no espaço de trabalho.

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

Isso resulta na adição da instrução highlightBlock('123'); antes todas as instruções, em que 123 é o número de série do bloco a ser em destaque.

Repetições infinitas

Embora o código resultante tenha a garantia de estar sintaticamente correto pode conter loops infinitos. Como resolver O problema de interrupção está além escopo (!) de Blockly. A melhor abordagem para lidar com esses casos é manter um contador e diminuí-lo toda vez que uma iteração for realizada. Para fazer isso, basta definir javascriptGenerator.INFINITE_LOOP_TRAP como um código que será inserido em cada loop e em cada função. Veja um exemplo:

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

Exemplo

Aqui está uma demonstração ao vivo de gerar e executar JavaScript.

JS-Intérprete

Se você levar a sério a execução correta dos bloqueios do usuário, o O Projeto JS-Interpreter é o caminho a seguir. Este projeto é separado do Blockly, mas foi elaborado especificamente para a empresa.

  • Execute código a qualquer velocidade.
  • Pausar/retomar/fazer a execução das etapas.
  • Destaque os blocos conforme eles são executados.
  • Completamente isolado do JavaScript do navegador.

Executar o intérprete

Primeiro, faça o download do JS-Interpreter no GitHub:

Baixar o arquivo ZIP Baixar TAR Ball Ver no GitHub

Em seguida, adicione-o à sua página:

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

O método mais simples de chamá-lo é gerar o JavaScript, criar a interpretador e execute o código:

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

Etapas para o intérprete

Para executar o código mais lentamente ou de forma mais controlada, substitua a classe chamada a run com uma repetição que realiza etapas (neste caso, uma etapa a cada 10 ms):

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

Observe que cada etapa não é uma linha ou um bloco, é uma unidade semântica em JavaScript, que pode ser extremamente refinado.

Adicionar uma API

O JS-Interpreter é um sandbox totalmente isolado do navegador. Quaisquer blocos que realizem ações com o mundo externo exigem a adição de uma API ao o intérprete. Para uma descrição completa, consulte a Documentação do JS-Interpreter. Mas, para começar, aqui está a API necessária para oferecer suporte aos blocos de alertas e comandos:

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));
}

Em seguida, modifique a inicialização do interpretador para transmitir a função initApi:

var myInterpreter = new Interpreter(code, initApi);

Os blocos de alerta e prompt são os únicos dois no conjunto padrão de blocos que exigem uma API personalizada para o intérprete.

Conectando o provedor highlightBlock()

Ao ser executado no JS-Interpreter, highlightBlock() precisa ser executado imediatamente, fora da sandbox, à medida que o usuário percorre o programa. Afazeres Isso, crie uma função wrapper highlightBlock() para capturar a função. e registrá-lo como uma função 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));
}

Aplicativos mais sofisticados podem executar etapas repetidamente sem até que um comando de destaque seja alcançado. Em seguida, pare. Essa estratégia simula a execução linha por linha. O exemplo abaixo usa essa abordagem.

Exemplo de intérprete de JS

Aqui está uma demonstração ao vivo de interpretar JavaScript passo a passo. E nesta demonstração inclui um bloco de espera, um bom exemplo para usar para outros comportamentos assíncronos (por exemplo, fala ou áudio, entrada do usuário).