Mise en cache des arguments du bloc de valeurs

Parfois, votre générateur de code en bloc doit référencer plusieurs fois le code de son bloc interne.

Par exemple, si un bloc récupère le dernier élément d'une liste, vous devez accéder au code de la liste plusieurs fois:

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

Toutefois, cela peut entraîner des problèmes si la valeur résultante du code du bloc interne est incohérente ou si elle a des effets secondaires. Par exemple, si le code interne est en réalité un appel de fonction, ce code peut se retrouver avec une condition hors plage:

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

L'utilisation de fonctions utilitaires vous permet de vous assurer que le code des blocs internes n'est évalué qu'une seule fois.

Fonctions utilitaires

Une fonction utilitaire est une fonction définie par le développeur et incluse dans la chaîne de code générée. Vous pouvez les utiliser pour vous assurer que le code du bloc interne n'est évalué qu'une seule fois. La valeur peut ensuite être référencée plusieurs fois.

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

Fournir la fonction

Vous pouvez définir des fonctions utilitaires dans des générateurs de code en bloc à l'aide de provideFunction_. Il utilise le nom que vous souhaitez pour votre fonction utilitaire et un tableau de chaînes de code définissant sa fonction. Elle renvoie le nom de votre fonction utilitaire, après l'avoir modifiée (éventuellement) pour éviter tout conflit avec les fonctions définies par l'utilisateur.

provideFunction_ déduplique également les définitions des fonctions utilitaires, de sorte que chaque fonction utilitaire n'existe qu'une seule fois, même si le type de bloc qui la définit existe plusieurs fois.

Priorités de mise à jour

Lorsque vous définissez une fonction utilitaire, vous devez également mettre à jour les priorités (qui définissent la façon dont les parenthèses sont insérées) incluses dans le générateur de code de bloc.

La priorité est toujours basée sur la chaîne de code renvoyée par le générateur de code en bloc. Il ne se soucie pas des opérateurs dans les fonctions utilitaires. Ainsi, dans l'exemple précédent, l'appel valueToCode a été remplacé par Order.NONE et le tuple de retour a été remplacé par Order.FUNCTION_CALL.