Almacenamiento en caché de argumentos de bloque de valores

En ocasiones, el generador de código de bloque necesita hacer referencia al código de su bloque interno varias veces.

Por ejemplo, si tienes un bloque que obtiene el último elemento de una lista, debes acceder al código de la lista varias veces:

// 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];
}

Sin embargo, esto puede causar problemas si el valor resultante del código del bloque interno no es coherente o si tiene efectos secundarios. Por ejemplo, si el código interno es en realidad una llamada a función, este código en particular puede terminar con una condición de fuera de rango:

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

Usar funciones de utilidad te permite asegurarte de que el código de los bloques internos solo se evalúe una vez.

Funciones de utilidad

Una función de utilidad es una función definida por el desarrollador que se incluye como parte de la string de código generada. Puedes usarlos para asegurarte de que el código del bloque interno solo se evalúe una vez y, luego, se pueda hacer referencia al valor varias veces.

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

Proporciona la función

Puedes definir funciones de utilidad dentro de generadores de código de bloque con provideFunction_. Toma el nombre que deseas para tu función de utilidad y un array de cadenas de código que definen lo que hace la función. Muestra el nombre resultante de la función de utilidad, después de modificarlo (posiblemente) para que no entre en conflicto con las funciones definidas por el usuario.

provideFunction_ también anula la duplicación de las definiciones de las funciones de utilidad, de modo que cada función de utilidad solo exista una vez, incluso si el tipo de bloque que la define existe varias veces.

Actualizar prioridades

Cuando defines una función de utilidad, también debes actualizar las prioridades (que definen cómo se insertan los paréntesis) que se incluyen en el generador de códigos de bloque.

La prioridad siempre se basa en la string de código que muestra el generador de códigos de bloque. No le interesan los operadores dentro de las funciones de utilidad. Por lo tanto, en el ejemplo anterior, la llamada a valueToCode se cambió a Order.NONE y la tupla de retorno se cambió a Order.FUNCTION_CALL.