Code generation

Code generation is the process of turning the blocks on a workspace into a string of code that can be executed.

Code generation is extremely important, because it is what allows your blocks to actually do things, like evaluate arithmetic expressions, move a character through a maze, or configure an online shop!

You can't "run" blocks directly. Instead you generate code strings, and then execute those.

Code generators

To generate code, you have to pick what text-based language you want to generate.

A code generator is a class that handles the rules for generating code that are specific to a given language, but not specific to an individual block. For example, it handles things like formatting comments, indenting statements, and quoting strings.

// javascriptGenerator is a code generator that makes javascript strings.
import {javascriptGenerator} from 'blockly/javascript';

const code = javascriptGenerator.workspaceToCode(myWorkspace);

Blockly provides 5 built-in code generators:

  • JavaScript ES5
  • Python 3
  • Lua 5.1
  • Dart 2
  • PHP 7

You can import and use the generators using one of the following methods.

Modules

import {javascriptGenerator} from 'blockly/javascript';
import {pythonGenerator} from 'blockly/python';
import {phpGenerator} from 'blockly/php';
import {luaGenerator} from 'blockly/lua';
import {dartGenerator} from 'blockly/dart';

const jsCode = javascriptGenerator.workspaceToCode(workspace);
const pythonCode = pythonGenerator.workspaceToCode(workspace);
const phpCode = phpGenerator.workspaceToCode(workspace);
const luaCode = luaGenerator.workspaceToCode(workspace);
const dartCode = dartGenerator.workspaceToCode(workspace);

Unpkg

You must include the generator after you include Blockly.

<script src="https://unpkg.com/blockly"></script>
<script src="https://unpkg.com/blockly/javascript_compressed"></script>
<script src="https://unpkg.com/blockly/python_compressed"></script>
<script src="https://unpkg.com/blockly/php_compressed"></script>
<script src="https://unpkg.com/blockly/lua_compressed"></script>
<script src="https://unpkg.com/blockly/dart_compressed"></script>
const jsCode = javascript.javascriptGenerator.workspaceToCode(workspace);
const pythonCode = python.pythonGenerator.workspaceToCode(workspace);
const phpCode = php.phpGenerator.workspaceToCode(workspace);
const luaCode = lua.luaGenerator.workspaceToCode(workspace);
const dartCode = dart.dartGenerator.workspaceToCode(workspace);

Local scripts

You must include the generator after you include Blockly.

<script src="blockly_compressed.js"></script>
<script src="javascript_compressed.js"></script>
<script src="python_compressed.js"></script>
<script src="php_compressed.js"></script>
<script src="lua_compressed.js"></script>
<script src="dart_compressed.js"></script>
const jsCode = javascript.javascriptGenerator.workspaceToCode(workspace);
const pythonCode = python.pythonGenerator.workspaceToCode(workspace);
const phpCode = php.phpGenerator.workspaceToCode(workspace);
const luaCode = lua.luaGenerator.workspaceToCode(workspace);
const dartCode = dart.dartGenerator.workspaceToCode(workspace);

If this list doesn't include the language you want to generate code for, you can also create a custom code generator.

Block-code generators

The second part of generating code is defining what code individual blocks generate. This has to be done for each block, for each individual language you want to generate.

javascriptGenerator.forBlock['my_custom_block'] = function(block, generator) { /* ... */ }

How code generators work is different for different types of blocks:

But they all require collecting the values from fields, collect inner blocks' code, and then then concatenating those strings.

Generation

Generation can be done when the end-user requests it (for example, when they click a button), or it can be done continuously.

Continuous updates allow you to show or run the code whenever the user makes a change. Generating code is a fast operation, so there's little performance impact for doing this. This is done using an event listener.

const supportedEvents = new Set([
  Blockly.Events.BLOCK_CHANGE,
  Blockly.Events.BLOCK_CREATE,
  Blockly.Events.BLOCK_DELETE,
  Blockly.Events.BLOCK_MOVE,
]);

function updateCode(event) {
  if (workspace.isDragging()) return; // Don't update while changes are happening.
  if (!supportedEvents.has(event.type)) return;

  const code = javascriptGenerator.workspaceToCode(workspace);
  document.getElementById('textarea').value = code;
}

workspace.addChangeListener(updateCode);

Preamble or postscript code

After you've generated your code you can including (optional) preamble or preamble code at the beginning or end of the generated code.

let code = javascriptGenerator.workspaceToCode(workspace);
// Add a preamble and a postscript to the code.
code = `const def = 'some value';\n${code}\nkickOffSomeFunction();\n`;

Preamble code is usually used to include external definitions at the beginning of the code. Postscript code is usually used to call functions to kick off behavior at the end of the code.

If your generated code is runnable as-is, then there's no need to include a preamble or a postscript.

Execution

After you've generated the code, you need to figure out how to execute it. Deciding how to execute it is very application-specific, and outside the scope of Blockly.

For JavaScript code the Blockly team recommends using the JSInterpreter. Other languages require other tools.