Skip to content

Commit 6c341b9

Browse files
committed
Preserve parenthesis when necessary.
1 parent aef9632 commit 6c341b9

File tree

5 files changed

+49
-4
lines changed

5 files changed

+49
-4
lines changed

core/src/codegen.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,9 @@ impl Code for Expression {
439439
ref right,
440440
..
441441
} => {
442-
if left.binding_power() < self.binding_power() {
442+
let bp = self.binding_power();
443+
444+
if left.binding_power() < bp {
443445
gen.write_byte(b'(');
444446
gen.write(left);
445447
gen.write_byte(b')');
@@ -449,7 +451,14 @@ impl Code for Expression {
449451
gen.write_min(b" ", b"");
450452
gen.write(operator);
451453
gen.write_min(b" ", b"");
452-
gen.write(right);
454+
455+
if right.needs_parens(bp) {
456+
gen.write_byte(b'(');
457+
gen.write(right);
458+
gen.write_byte(b')');
459+
} else {
460+
gen.write(right);
461+
}
453462
},
454463

455464
Expression::Prefix {

core/src/grammar.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,30 @@ impl Expression {
343343
arguments: arguments,
344344
}
345345
}
346+
347+
#[inline]
348+
pub fn parenthesize(mut self) -> Expression {
349+
if let Expression::Binary {
350+
ref mut parenthesized,
351+
..
352+
} = self {
353+
*parenthesized = true;
354+
}
355+
356+
self
357+
}
358+
359+
#[inline]
360+
pub fn needs_parens(&self, bp: u8) -> bool {
361+
match *self {
362+
Expression::Binary {
363+
ref parenthesized,
364+
ref operator,
365+
..
366+
} => *parenthesized && bp >= operator.binding_power(),
367+
_ => false
368+
}
369+
}
346370
}
347371

348372
impl From<&'static str> for Expression {

core/src/parser.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ impl<'a> Parser<'a> {
453453

454454
expect!(self, ParenClose);
455455

456-
Ok(expression)
456+
Ok(expression.parenthesize())
457457
}
458458
}
459459
}

core/src/transformer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ impl Transformable for Expression {
344344
left = Expression::binary(
345345
left,
346346
Addition,
347-
expression
347+
expression.parenthesize()
348348
);
349349

350350
if quasi.len() == 0 {

core/tests/codegen.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,22 @@ fn template_strings_plain() {
3939
assert_compile!("`foo\nbar`;", "\"foo\\nbar\";");
4040
}
4141

42+
#[test]
43+
fn operator_precedence_and_parens() {
44+
// Preserve parens when necessary
45+
assert_compile!("'foo'+(1+2);", r#"'foo'+(1+2);"#);
46+
47+
// Should strip parens when not necessary
48+
assert_compile!("(1+2)+'foo';", r#"1+2+'foo';"#);
49+
assert_compile!("'foo'+(1*2);", r#"'foo'+1*2;"#);
50+
assert_compile!("(1*2)+'foo';", r#"1*2+'foo';"#);
51+
}
52+
4253
#[test]
4354
fn template_strings_interpolation() {
4455
assert_compile!("`foo${1}bar`;", r#""foo"+1+"bar";"#);
4556
assert_compile!("`foo${1+2}bar`;", r#""foo"+(1+2)+"bar";"#);
57+
assert_compile!("`foo${1*2}bar`;", r#""foo"+1*2+"bar";"#);
4658
assert_compile!("`foo${1}${2**2}bar`;", r#""foo"+1+Math.pow(2,2)+"bar";"#);
4759
assert_compile!("`foo${1}bar${2**2}`;", r#""foo"+1+"bar"+Math.pow(2,2);"#);
4860
}

0 commit comments

Comments
 (0)