Armazenamento em cache de argumentos de bloco de valor

Às vezes, o gerador de código de bloco precisa referenciar o código do bloco interno várias vezes.

Por exemplo, se você tiver um bloco que recebe o último elemento de uma lista, vai precisar acessar o código da lista várias vezes:

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

Mas isso pode causar problemas se o valor resultante do código do bloco interno for inconsistente ou tiver efeitos colaterais. Por exemplo, se o código interno for, na verdade, uma chamada de função, esse código específico poderá acabar com uma condição fora do intervalo:

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

O uso de funções utilitárias permite garantir que o código dos blocos internos seja avaliado apenas uma vez.

Funções do utilitário

Uma função utilitária é uma função definida pelo desenvolvedor e incluída como parte da string de código gerada. Você pode usá-los para garantir que o código de bloco interno seja avaliado apenas uma vez e, em seguida, o valor possa ser referenciado várias vezes.

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

Fornecer a função

É possível definir funções utilitárias dentro de geradores de código de bloco usando provideFunction_. Ela recebe o nome que você quer para a função utilitária e uma matriz de strings de código que definem o que a função faz. Ele retorna o nome resultante da função de utilitário depois de (possivelmente) modificá-la para não entrar em conflito com as funções definidas pelo usuário.

provideFunction_ também elimina as definições de função utilitária, para que cada função utilitária exista apenas uma vez, mesmo que o tipo de bloco que a define exista várias vezes.

Atualizar precedências

Ao definir uma função de utilitário, você também precisa atualizar as precedências (que definem como os parênteses são inseridos) incluídas no gerador de código de bloco.

A precedência é sempre baseada na string de código retornada pelo gerador de código de bloco. Ele não se importa com operadores dentro das funções utilitárias. Portanto, no exemplo anterior, a chamada valueToCode foi alterada para Order.NONE e a tupla de retorno foi alterada para Order.FUNCTION_CALL.