Skip to content

Commit 7f203b6

Browse files
klutzyalexcrichton
authored andcommitted
pprust: Add parentheses to some Expr
Some `Expr` needs parentheses when printed. For example, without parentheses, `ExprUnary(UnNeg, ExprBinary(BiAdd, ..))` becomes `-lhs + rhs` which is wrong. Those cases don't appear in ordinary code (since parentheses are explicitly added) but they can appear in manually crafted ast by extensions.
1 parent 6d535b5 commit 7f203b6

File tree

1 file changed

+45
-3
lines changed

1 file changed

+45
-3
lines changed

src/libsyntax/print/pprust.rs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,15 @@ pub fn visibility_qualified(vis: ast::Visibility, s: &str) -> StrBuf {
247247
}
248248
}
249249

250+
fn needs_parentheses(expr: &ast::Expr) -> bool {
251+
match expr.node {
252+
ast::ExprAssign(..) | ast::ExprBinary(..) |
253+
ast::ExprFnBlock(..) | ast::ExprProc(..) |
254+
ast::ExprAssignOp(..) | ast::ExprCast(..) => true,
255+
_ => false,
256+
}
257+
}
258+
250259
impl<'a> State<'a> {
251260
pub fn ibox(&mut self, u: uint) -> IoResult<()> {
252261
self.boxes.push(pp::Inconsistent);
@@ -1136,6 +1145,18 @@ impl<'a> State<'a> {
11361145
self.pclose()
11371146
}
11381147

1148+
pub fn print_expr_maybe_paren(&mut self, expr: &ast::Expr) -> IoResult<()> {
1149+
let needs_par = needs_parentheses(expr);
1150+
if needs_par {
1151+
try!(self.popen());
1152+
}
1153+
try!(self.print_expr(expr));
1154+
if needs_par {
1155+
try!(self.pclose());
1156+
}
1157+
Ok(())
1158+
}
1159+
11391160
pub fn print_expr(&mut self, expr: &ast::Expr) -> IoResult<()> {
11401161
try!(self.maybe_print_comment(expr.span.lo));
11411162
try!(self.ibox(indent_unit));
@@ -1209,7 +1230,7 @@ impl<'a> State<'a> {
12091230
try!(self.pclose());
12101231
}
12111232
ast::ExprCall(func, ref args) => {
1212-
try!(self.print_expr(func));
1233+
try!(self.print_expr_maybe_paren(func));
12131234
try!(self.print_call_post(args.as_slice()));
12141235
}
12151236
ast::ExprMethodCall(ident, ref tys, ref args) => {
@@ -1233,17 +1254,38 @@ impl<'a> State<'a> {
12331254
}
12341255
ast::ExprUnary(op, expr) => {
12351256
try!(word(&mut self.s, ast_util::unop_to_str(op)));
1236-
try!(self.print_expr(expr));
1257+
try!(self.print_expr_maybe_paren(expr));
12371258
}
12381259
ast::ExprAddrOf(m, expr) => {
12391260
try!(word(&mut self.s, "&"));
1261+
1262+
// `ExprAddrOf(ExprLit("str"))` should be `&&"str"` instead of `&"str"`
1263+
// since `&"str"` is `ExprVstore(ExprLit("str"))` which has same meaning to
1264+
// `"str"`.
1265+
// In many cases adding parentheses (`&("str")`) would help, but it become invalid
1266+
// if expr is in `PatLit()`.
1267+
let needs_extra_amp = match expr.node {
1268+
ast::ExprLit(lit) => {
1269+
match lit.node {
1270+
ast::LitStr(..) => true,
1271+
_ => false,
1272+
}
1273+
}
1274+
ast::ExprVec(..) => true,
1275+
_ => false,
1276+
};
1277+
if needs_extra_amp {
1278+
try!(word(&mut self.s, "&"));
1279+
}
1280+
12401281
try!(self.print_mutability(m));
12411282
// Avoid `& &e` => `&&e`.
12421283
match (m, &expr.node) {
12431284
(ast::MutImmutable, &ast::ExprAddrOf(..)) => try!(space(&mut self.s)),
12441285
_ => { }
12451286
}
1246-
try!(self.print_expr(expr));
1287+
1288+
try!(self.print_expr_maybe_paren(expr));
12471289
}
12481290
ast::ExprLit(lit) => try!(self.print_literal(lit)),
12491291
ast::ExprCast(expr, ty) => {

0 commit comments

Comments
 (0)