Consider the following assembly of blocks.
alert(2 * 3 + 4);
This is obviously incorrect, since the multiplication operator rips apart the addition, grabbing the '3' for itself. One solution is to wrap the result of every value block in parentheses:
alert(((2) * ((3) + (4)));
This solution works perfectly, but it results in extremely messy code with large numbers of redundant parentheses. For some use cases this is not an issue. If human eyes are never going to see the generated code, then this is acceptable. However, Blockly is often used as an educational tool to introduce programming, a use case which relies on generating human-readable code.
ORDER_ATOMIC = 0; // 0 "" ... ORDER_NEW = 1.1; // new ORDER_MEMBER = 1.2; // .  ORDER_FUNCTION_CALL = 2; // () ORDER_INCREMENT = 3; // ++ ORDER_DECREMENT = 3; // -- ORDER_BITWISE_NOT = 4.1; // ~ ORDER_UNARY_PLUS = 4.2; // + ORDER_UNARY_NEGATION = 4.3; // - ORDER_LOGICAL_NOT = 4.4; // ! ORDER_TYPEOF = 4.5; // typeof ORDER_VOID = 4.6; // void ORDER_DELETE = 4.7; // delete ORDER_AWAIT = 4.8; // await ORDER_EXPONENTIATION = 5.0; // ** ORDER_MULTIPLICATION = 5.1; // * ORDER_DIVISION = 5.2; // / ORDER_MODULUS = 5.3; // % ORDER_SUBTRACTION = 6.1; // - ORDER_ADDITION = 6.2; // + ORDER_BITWISE_SHIFT = 7; // << >> >>> ORDER_RELATIONAL = 8; // < <= > >= ORDER_IN = 8; // in ORDER_INSTANCEOF = 8; // instanceof ORDER_EQUALITY = 9; // == != === !== ORDER_BITWISE_AND = 10; // & ORDER_BITWISE_XOR = 11; // ^ ORDER_BITWISE_OR = 12; // | ORDER_LOGICAL_AND = 13; // && ORDER_LOGICAL_OR = 14; // || ORDER_CONDITIONAL = 15; // ?: ORDER_ASSIGNMENT = 16; // = += -= **= *= /= %= <<= >>= ... ORDER_YIELD = 16.5; // yield ORDER_COMMA = 17; // , ORDER_NONE = 99; // (...)
ORDER_ATOMIC added to the start and
ORDER_NONE added to the end.
Applying these orders occurs in two places within each block's generator. The first place is when fetching generated code from a connected value block. In this case we pass the constant which represents the maximum binding strength of any operators adjacent to the sub-block's generated code. For example:
The second place is when returning generated code from a value block. In this case we pass the constant which represents the minimum binding strength of any operators in the block's generated code. For example:
If the order value returned by the sub-block is weaker than or equal to the
order value for the order argument of the parent block, then the
function will automatically wrap the contents of the sub-block's code in
parentheses to prevent it from being ripped apart by the parent block's code.
Below are some more examples. In each case the block has one connected sub-block which is represented as 'X' (the contents of 'X' is unknown and doesn't matter). The second column lists the strongest operator which might split 'X'. The third column lists the weakest operator in the final code for the block.
|Generated Code||Max strength against X||Min strength of block|
Math is hard
Still don't understand? No problem. Just use
ORDER_ATOMIC as the order on
every call to
valueToCode, and use
ORDER_NONE as the order for the final
return statement on every value block. The resulting code will be infested with
needless parentheses, but is guaranteed to be correct.