Os blocos sugerem parênteses. Por exemplo, ao ver os blocos a seguir, você
supõe que significa -(5 + 2)
, e não -5 + 2
, porque 5
e 2
fazem parte de
um bloco, e o -
faz parte de outro.
No entanto, se você colocar parênteses em cada bloco, o código ficará muito menos legível. Compare (((5) * (2)) + (3))
com 5 * 2 + 3
. As duas
expressões avaliam a mesma coisa (13
), mas a segunda é muito mais fácil
de ler.
As regras de precedência de operadores do Blockly ajudam a gerar o código com o número mínimo de parênteses, para maior legibilidade.
Gerar uma saída "correta"
Se você não precisa que o código gerado seja legível, não é necessário se preocupar com a minimização dos parênteses. Envolver todos os blocos é uma boa abordagem e garante que o código gerado seja sempre avaliado corretamente.
Para garantir a exatidão, sempre transmita Order.ATOMIC
para chamadas valueToCode
e
sempre retorne Order.NONE
do gerador de código de bloco.
Gerar parênteses ideais
Os parênteses só precisam ser inseridos se o código gerado estiver incorreto sem eles. Isso acontece quando a precedência de um operador no bloco externo é mais forte que a precedência de um operador no bloco interno.
Por exemplo, nos blocos a seguir, há um operador de negação unário e um operador de adição. A negação unária tem uma precedência mais forte do que o operador de adição.
Portanto, se você não adicionar parênteses, o resultado será -5 + 2
, e o -
será avaliado
antes de +
, o que não corresponde aos blocos.
Você pode informar ao gerador quando inserir parênteses, informando a intensidade dos diferentes operadores. Se ele notar que o operador externo é mais forte que o interno, ele insere parênteses para proteger o operador interno.
valueToCode
tem a precedência do operador externo, e a tupla de retorno especifica a precedência do operador interno.
Aqui está um exemplo de um bloco que inclui dois operadores:
import {javascriptGenerator, Order} from 'blockly/javascript';
javascriptGenerator.forBlock['negate_plus_two'] = function(block, generator) {
// valueToCode takes in the precedence of the outer operator.
const innerCode = generator.valueToCode(block, 'INNER', Order.UNARY_NEGATION);
const code = `-${innerCode} + 2`;
// The return tuple specifies the precedence of the inner operator.
return [code, Order.ADDITION];
}
Precedência de valueToCode
Ao chamar valueToCode
para gerar o código de um bloco interno, você transmite a ele
a precedência do operador mais forte que atua no código do bloco
interno. Esse é o operador do qual o código do bloco interno precisa ser protegido.
Por exemplo, nos blocos a seguir, o operador de negação unário e o
operador de adição atuam no código do bloco interno. A negação unária
é mais forte, então essa é a precedência que você precisa transmitir para valueToCode
.
// The - is the strongest operator acting on the inner code.
const innerCode = generator.valueToCode(block, 'INNER', Order.UNARY_NEGATION);
const code = `-${innerCode} + 2`;
Precedência de devolução
Quando você retornar uma precedência do seu gerador de código de bloco, retorne a precedência do operador mais fraco no código do bloco. Esse é o operador que precisa de proteção.
Por exemplo, o bloco a seguir contém um operador de negação unário e um operador de adição. A adição é mais fraca, então essa é a precedência que você precisa retornar do gerador de código de bloco.
const code = `-${innerCode} + 2`;
// The + is the weakest operator in the block.
return [code, Order.ADDITION];
enumeração do pedido
Cada módulo de gerador de idioma define um tipo enumerado Order
que inclui todas
as precedências desse idioma.
Precedências mais fortes têm valores de apoio menores e precedências mais fracas têm valores de apoio mais altos. Pense em precedências fortes como uma "classificação mais alta" em força e nas precedências mais fracas como sendo "classificadas em menor nível", como se fossem lutadores competitivos.
Veja onde você encontra os tipos enumerados Order
para todos os idiomas integrados:
Precedências especiais
A maioria das precedências nos tipos enumerados Order
dos geradores corresponde às precedências
definidas pelos respectivos idiomas baseados em texto. Mas há duas precedências
especiais, Order.ATOMIC
e Order.NONE
.
Order.ATOMIC
é a precedência mais forte. Ela é usada quando:
- Para garantir que o código fique sempre entre parênteses,
transmita-o para
valueToCode
. - Seu bloco não inclui operadores, então você o retorna do gerador de código de bloco.
Order.NONE
é a precedência mais fraca. Ela é usada quando:
- Você quer garantir que o código fique sempre entre parênteses, então você o retorna do gerador de código de bloco.
- Não há operadores atuando em um bloco interno, então você o transmite para
valueToCode
.