單元 23 · 自訂目標語言生成器

CodeGenerator 子類別、JSON codelab、DSL/硬體指令

23.1 內建語言生成器

Blockly 內建 5 種語言生成器,每個都是「語言通用規則 + 一組積木生成器」:

語言import 方式適用
JavaScript ES5blockly/javascript瀏覽器/Node.js
Python 3blockly/python教學、資料、後端
Lua 5.1blockly/lua遊戲引擎、嵌入式
Dart 2blockly/dartFlutter/App
PHP 7blockly/php網頁後端
核心:每個積木要支援哪種語言,就要為那塊積木寫一個 forBlock['type'] 生成器。內建積木已備齊,自訂積木需自己補。

23.2 為什麼要自訂生成器

實際案例
Blockly 用在:
  MakeCode → 輸出 JavaScript + MicroPython
  App Inventor → 輸出 .aia(內部 JSON)
  自製 IoT 工具 → 輸出 JSON 設定檔給韌體
  機器人教學 → 輸出「前進/右轉/角度」指令序列

23.3 寫一個自訂 CodeGenerator(JSON 為例)

官方 codelab 以「JSON 語言生成器」示範:積木拼成巢狀 JSON 物件。

CodeGenerator 子類別
import {CodeGenerator} from 'blockly';
import {javascriptGenerator} from 'blockly/javascript';

class JsonGenerator extends CodeGenerator {
  constructor() {
    super('JSON');                 // 名稱
    this.isInitialized = false;    // 後續 init() 中初始化
  }
  // 可覆寫語言通用規則,例如縮排
  // this.INDENT = '  ';
}

const jsonGenerator = new JsonGenerator();
// 註冊積木生成器
jsonGenerator.forBlock['json_setting'] = function(block, generator) {
  const key = block.getFieldValue('KEY');
  const value = generator.valueToCode(block, 'VALUE', 0);
  return '\n  "' + key + '": ' + value + ',';
};
重點:自訂生成器也是「CodeGenerator 子類別 + forBlock 生成器」。語言規則(縮排/字串)寫在類別裡,積木轉換寫在 forBlock 裡——與內建生成器完全同一套模型。

23.4 dropdown 值轉換:語言中立 → 目標語法

範例
// 積木的 dropdown 存的是語言中立值
options: [['不等於', 'NOT_EQUAL'], ['大於', 'GREATER']]

// 目標語言是 JavaScript → 對照表
const OP = {NOT_EQUAL: '!==', GREATER: '>'};
const op = OP[block.getFieldValue('OPERATOR')];   // '!=='

// 目標語言是 C → 另一張表
const OP_C = {NOT_EQUAL: '!=', GREATER: '>'};
const opC = OP_C[block.getFieldValue('OPERATOR')]; // '!='

// 同一塊積木,不同生成器 → 不同語言!
設計原則:欄位值要「語言中立」,翻譯交給生成器。這樣同一塊積木才能自由輸出多種語言。

23.5 Worked Example:把積木輸出成 JSON 設定

範例
目標:使用者拼「溫度警報」積木 → 輸出韌體能讀的 JSON

積木:alarm_when (SENSOR dropdown) (THRESHOLD number) (ACTION dropdown)

JsonGenerator.forBlock['alarm_when'] = function(block, generator) {
  const sensor = block.getFieldValue('SENSOR');      // 'temperature'
  const action = block.getFieldValue('ACTION');      // 'sound'
  const threshold = generator.valueToCode(block, 'THRESHOLD', 0);
  return '{\n  "sensor": "' + sensor + '",\n  "threshold": ' +
         threshold + ',\n  "action": "' + action + '"\n}';
};

// 輸出:
// {
//   "sensor": "temperature",
//   "threshold": 40,
//   "action": "sound"
// }
// 韌體拿到 JSON → 直接套用設定!這就是「積木 → 你要的格式」。

23.6 練習

  1. 說出「語言生成器」與「積木生成器」的分工。
  2. 為你的積木寫一個輸出「C 語言」的生成器片段。
  3. 設計一個輸出「JSON 設定檔」的積木並試拼。
看完這單元你應該能說出:
  • 說出 Blockly 內建 5 種語言生成器。
  • 為「目標語言」寫一個自訂 CodeGenerator 子類別。
  • 把積木輸出成非程式語言格式(JSON/DSL/硬體指令)。

延伸閱讀