ExtendScript gives && and || equal precedence
The below is from u/Ales-78 on Reddit:
"I found this while debugging something that made no sense, and because I once reported a "bug" to Adobe that turned out to be my own syntax error, I checked it on several versions before posting.
ExtendScript evaluates && and || at the same precedence level, left to right. So a || b && c is parsed as (a || b) && c instead of the correct a || (b && c). ECMAScript requires && to bind tighter.
Two lines, no document needed:
alert(true || false && false);
// prints "false", should print "true"
Confirmed on:
Illustrator 30.8.1, ExtendScript 4.5.6, Windows
Illustrator CS6 16.0.0, ExtendScript 4.2.12, Windows
Illustrator 30.8.2, macOS (confirmed by Monika Gause)
Line for line identical across all three. Other precedences are fine, I tested ternary, arithmetic, bitwise, typeof, in and instanceof. It really is just these two operators.
Both readings agree almost all the time. They diverge only when the first operand is truthy and the last one is falsy, which is how it can sit in a codebase for years without surfacing.
What made it visible for me was minification. I write a || (b && c) in the source. Closure Compiler ADVANCED removes those parentheses, because in standard JavaScript they genuinely are redundant, and its output is correct JS. ExtendScript then reads it the other way round and the conditional logic silently inverts.
So Closure is not at fault either. Two individually correct things meeting in the wrong place.
My workaround is a post-compile pass that re-adds parentheses around any && that is a direct operand of ||, then verifies the standard JS AST has not changed.
If you ship minified ExtendScript, this is worth checking."
-
Ales Ulrych
commented
I'm the one who found this. A few details that did not make it into the original post:
Other precedence levels are fine. I tested ternary, arithmetic, bitwise, comma, typeof, in and instanceof, all correct. It really is only these two operators sharing a level.
The two readings differ only when the first operand is truthy and the last one is falsy, which is why it can sit in a codebase unnoticed for years.
I have a test script with 24 cases for the logical operators and another with 31 for the remaining precedences. In Node they pass clean, in ExtendScript it is 7 out of 24. Happy to attach them if that helps.