Кэширование аргументов блока значений

Иногда вашему генератору блочного кода необходимо несколько раз ссылаться на код своего внутреннего блока.

Например, если у вас есть блок, который получает последний элемент списка, вам нужно получить доступ к коду списка несколько раз:

// Incorrect block-code generator.
javascriptGenerator.forBlock['last_element'] = function(block, generator) {
  const listCode = generator.valueToCode(block, 'LIST', Order.MEMBER);

  // listCode gets referenced twice.
  const code = `${listCode}[${listCode}.length - 1]`;

  return [code, Order.MEMBER];
}

Но это может вызвать проблемы, если результирующее значение кода внутреннего блока противоречиво или имеет побочные эффекты. Например, если внутренний код на самом деле является вызовом функции, этот конкретный код может закончиться состоянием выхода за пределы диапазона:

randomList()[randomList().length - 1]

Использование служебных функций позволяет гарантировать, что код внутренних блоков вычисляется только один раз.

Вспомогательные функции

Вспомогательная функция — это определенная разработчиком функция, включенная как часть сгенерированной строки кода. Вы можете использовать их, чтобы гарантировать, что код внутреннего блока оценивается только один раз, а затем на значение можно ссылаться несколько раз.

import {javascriptGenerator, Order} from 'blockly/javascript';

// Correct block-code generator.
javascriptGenerator.forBlock['last_element'] = function(block, generator) {
  const listCode = generator.valueToCode(block, 'LIST', Order.NONE);
  const functionName = generator.provideFunction_(
      'list_lastElement',
      [
        `function ${generator.FUNCTION_NAME_PLACEHOLDER_}(list) {`,
        `  return list[list.length - 1];`,
        `}`
      ]
  );

  // listCode only gets evaluated once.
  const code = `${functionName}(${listCode})`;
  return [code, Order.FUNCTION_CALL];
}

Предоставьте функцию

Вы можете определить служебные функции внутри генераторов блочного кода, используя provideFunction_ . Он принимает имя, которое вы хотите для своей служебной функции, и массив строк кода, определяющих, что делает функция. Он возвращает результирующее имя вашей служебной функции после (возможно) изменения его, чтобы оно не конфликтовало с пользовательскими функциями.

provideFunction_ также выполняет дедупликацию определений служебных функций, так что каждая служебная функция существует только один раз, даже если тип блока, который ее определяет, существует несколько раз.

Обновить приоритеты

Когда вы определяете вспомогательную функцию, вам также следует обновить приоритеты (которые определяют способ вставки скобок ), включенные в генератор блочного кода.

Приоритет всегда основан на кодовой строке, возвращаемой генератором блочного кода. Его не волнуют операторы внутри служебных функций. Итак, в предыдущем примере вызов valueToCode был изменен на Order.NONE , а возвращаемый кортеж был изменен на Order.FUNCTION_CALL .