Summary
Python's bitwise & has higher precedence than comparison operators (!=, ==), so flags & FLAG != 0 means (flags & FLAG) != 0. In JavaScript and Java, & has lower precedence than !==/!=, so the same expression means flags & (FLAG !== 0) = flags & 1, which is wrong.
Tongues correctly parenthesizes for Perl (($flags & $FLAG) != 0) but not for JS or Java.
Reproduction
Python:
flags & FLAG != 0 # → (flags & FLAG) != 0 → correct
Transpiled JS:
flags & FLAG !== 0 // → flags & (FLAG !== 0) → flags & 1 → WRONG
Expected JS:
(flags & FLAG) !== 0 // → correct
Verification
>>> 6 & 2 != 0 # True (because (6 & 2) = 2, 2 != 0)
> 6 & 2 !== 0 // 0 (because 2 !== 0 = true, 6 & 1 = 0)
Impact
9 instances in the Parable JS transpilation, all in _parse_matched_pair and _subst_matched_pair. This causes the DOLBRACE, ALLOWESC, EXTGLOB, ARITH, and DQUOTE flag checks to silently return wrong results, leading to incorrect brace/quote matching in parameter expansions.
This is the root cause of ~24 "unexpected EOF" errors in the JS backend (e.g., ${x:-a{b} fails because the DOLBRACE flag isn't detected, so the { inside the default value is incorrectly counted as opening a new brace group).
Ruby and Perl are not affected — Ruby's & has higher precedence than != (like Python), and Perl's transpilation already includes parentheses.
Java has the same precedence rules as JS and will have the same bug.
Discovered via ldayton/Parable#413.
Summary
Python's bitwise
&has higher precedence than comparison operators (!=,==), soflags & FLAG != 0means(flags & FLAG) != 0. In JavaScript and Java,&has lower precedence than!==/!=, so the same expression meansflags & (FLAG !== 0)=flags & 1, which is wrong.Tongues correctly parenthesizes for Perl (
($flags & $FLAG) != 0) but not for JS or Java.Reproduction
Python:
Transpiled JS:
Expected JS:
Verification
Impact
9 instances in the Parable JS transpilation, all in
_parse_matched_pairand_subst_matched_pair. This causes the DOLBRACE, ALLOWESC, EXTGLOB, ARITH, and DQUOTE flag checks to silently return wrong results, leading to incorrect brace/quote matching in parameter expansions.This is the root cause of ~24 "unexpected EOF" errors in the JS backend (e.g.,
${x:-a{b}fails because the DOLBRACE flag isn't detected, so the{inside the default value is incorrectly counted as opening a new brace group).Ruby and Perl are not affected — Ruby's
&has higher precedence than!=(like Python), and Perl's transpilation already includes parentheses.Java has the same precedence rules as JS and will have the same bug.
Discovered via ldayton/Parable#413.