fix(codegen): add parenthesis in binary expression by precedence (#2067)

related ESBuild code:
f5f8ff895c/internal/js_printer/js_printer.go (L3348-L3371)
This commit is contained in:
Wenzhe Wang 2024-01-17 23:01:42 +08:00 committed by GitHub
parent 32349af691
commit 29dc5e69ff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 57 additions and 8 deletions

View file

@ -1393,15 +1393,25 @@ impl<'a, const MINIFY: bool> GenExpr<MINIFY> for UnaryExpression<'a> {
impl<'a, const MINIFY: bool> GenExpr<MINIFY> for BinaryExpression<'a> {
fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) {
let wrap_in = self.operator == BinaryOperator::In && !ctx.has_in();
let wrap = precedence > self.precedence() || wrap_in;
let wrap = precedence >= self.precedence() || wrap_in;
p.wrap(wrap, |p| {
self.left.gen_expr(p, self.precedence(), ctx);
let left_precedence = if self.precedence().is_right_associative() {
self.precedence()
} else {
self.operator.lower_precedence()
};
self.left.gen_expr(p, left_precedence, ctx);
if self.operator.is_keyword() {
p.print_space_before_identifier();
}
self.operator.gen(p, ctx);
p.print_soft_space();
self.right.gen_expr(p, self.precedence(), ctx.union_in_if(wrap));
let right_precedence = if self.precedence().is_left_associative() {
self.precedence()
} else {
self.operator.lower_precedence()
};
self.right.gen_expr(p, right_precedence, ctx.union_in_if(wrap));
});
}
}

View file

@ -110,7 +110,7 @@ fn logical_and() {
fn bitwise_or() {
test("a | b | c", "a|b|c;");
test("(a | b) | c", "a|b|c;");
test("a | (b | c)", "a|b|c;");
test("a | (b | c)", "a|(b|c);");
test("a | b ^ c", "a|b^c;");
test("a | (b ^ c)", "a|b^c;");
test("a | (b && c)", "a|(b&&c);");
@ -124,7 +124,7 @@ fn bitwise_or() {
fn bitwise_xor() {
test("a ^ b ^ c", "a^b^c;");
test("(a ^ b) ^ c", "a^b^c;");
test("a ^ (b ^ c)", "a^b^c;");
test("a ^ (b ^ c)", "a^(b^c);");
test("a | b & c", "a|b&c;");
test("a | (b & c)", "a|b&c;");
test("a | (b || c)", "a|(b||c);");
@ -138,7 +138,7 @@ fn bitwise_xor() {
fn bitwise_and() {
test("a & b & c", "a&b&c;");
test("((a & b) & c) & d", "a&b&c&d;");
test("a & (b & (c & d))", "a&b&c&d;");
test("a & (b & (c & d))", "a&(b&(c&d));");
test("a & b == c", "a&b==c;");
test("a & (b == c)", "a&b==c;");
test("a == b & c", "a==b&c;");
@ -152,7 +152,7 @@ fn bitwise_and() {
#[test]
fn equality() {
test("a == b != c === d !== e", "a==b!=c===d!==e;");
test("a == (b != (c === (d !== e)))", "a==b!=c===d!==e;");
test("a == (b != (c === (d !== e)))", "a==(b!=(c===(d!==e)));");
test("(((a == b) != c) === d) !== e", "a==b!=c===d!==e;");
test("a > b == c < d", "a>b==c<d;");
test("(a > b) == (c < d)", "a>b==c<d;");

View file

@ -222,6 +222,26 @@ impl BinaryOperator {
Self::Exponential => "**",
}
}
pub fn lower_precedence(&self) -> Precedence {
match self {
Self::BitwiseOR => Precedence::LogicalAnd,
Self::BitwiseXOR => Precedence::BitwiseOr,
Self::BitwiseAnd => Precedence::BitwiseXor,
Self::Equality | Self::Inequality | Self::StrictEquality | Self::StrictInequality => {
Precedence::BitwiseAnd
}
Self::LessThan
| Self::LessEqualThan
| Self::GreaterThan
| Self::GreaterEqualThan
| Self::Instanceof
| Self::In => Precedence::Equality,
Self::ShiftLeft | Self::ShiftRight | Self::ShiftRightZeroFill => Precedence::Relational,
Self::Addition | Self::Subtraction => Precedence::Shift,
Self::Multiplication | Self::Remainder | Self::Division => Precedence::Add,
Self::Exponential => Precedence::Multiply,
}
}
}
impl GetPrecedence for BinaryOperator {

View file

@ -44,6 +44,25 @@ impl Precedence {
}
pub fn is_right_associative(&self) -> bool {
matches!(self, Self::Exponential)
matches!(self, Self::Exponential | Self::Conditional | Self::Arrow | Self::Assign)
}
pub fn is_left_associative(&self) -> bool {
matches!(
self,
Self::Member
| Self::Multiply
| Self::Add
| Self::Shift
| Self::Relational
| Self::Equality
| Self::BitwiseAnd
| Self::BitwiseXor
| Self::BitwiseOr
| Self::LogicalAnd
| Self::LogicalOr
| Self::Coalesce
| Self::Comma
)
}
}