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:
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).