Skip to content

Commit 04f9925

Browse files
committed
---
yaml --- r: 4830 b: refs/heads/master c: 84fb821 h: refs/heads/master v: v3
1 parent 7c25de7 commit 04f9925

File tree

3 files changed

+140
-16
lines changed

3 files changed

+140
-16
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
refs/heads/master: 4d03b7b1fbb970320aff049b5135fecc81a24fdd
2+
refs/heads/master: 84fb821e4036a65f78db1821d75b95526ed3fd76

trunk/src/comp/syntax/print/pprust.rs

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import std::uint;
77
import std::option;
88
import parse::lexer;
99
import syntax::codemap::codemap;
10+
import syntax::visit;
1011
import ast;
1112
import option::some;
1213
import option::none;
@@ -596,13 +597,13 @@ fn print_possibly_embedded_block(s: &ps, blk: &ast::blk, embedded: embed_type,
596597

597598
let last_stmt = option::none;
598599
for st: @ast::stmt in blk.node.stmts {
599-
maybe_protect_unop(s, last_stmt, stmt_(st));
600+
maybe_protect_block(s, last_stmt, stmt_(st));
600601
print_stmt(s, *st);
601602
last_stmt = option::some(st);
602603
}
603604
alt blk.node.expr {
604605
some(expr) {
605-
maybe_protect_unop(s, last_stmt, expr_(expr));
606+
maybe_protect_block(s, last_stmt, expr_(expr));
606607
space_if_not_bol(s);
607608
print_expr(s, expr);
608609
maybe_print_trailing_comment(s, expr.span, some(blk.span.hi));
@@ -615,11 +616,10 @@ fn print_possibly_embedded_block(s: &ps, blk: &ast::blk, embedded: embed_type,
615616
tag expr_or_stmt { stmt_(@ast::stmt); expr_(@ast::expr); }
616617

617618
// The Rust syntax has an ambiguity when an if, alt, or block statement is
618-
// followed by a unary op statement. In those cases we have to add an
619-
// extra semi to make sure the unop is not parsed as a binop with the
620-
// if/alt/block expression.
621-
fn maybe_protect_unop(s: &ps, last: &option::t<@ast::stmt>,
622-
next: &expr_or_stmt) {
619+
// followed by a unary op or paren. In those cases we have to add an
620+
// extra semi to make sure the output retains the same meaning.
621+
fn maybe_protect_block(s: &ps, last: &option::t<@ast::stmt>,
622+
next: &expr_or_stmt) {
623623
let last_expr_is_block = alt last {
624624
option::some(@{node: ast::stmt_expr(e, _), _}) {
625625
alt e.node {
@@ -632,20 +632,74 @@ fn print_possibly_embedded_block(s: &ps, blk: &ast::blk, embedded: embed_type,
632632
}
633633
_ { false }
634634
};
635-
let next_expr_is_unnop = alt next {
636-
expr_(@{node: ast::expr_unary(_, _), _}) { true }
635+
636+
if !last_expr_is_block { ret; }
637+
638+
let next_expr_is_ambig = alt next {
639+
expr_(e) { expr_is_ambig(e) }
637640
stmt_(@{node: ast::stmt_expr(e, _), _}) {
638-
alt e.node {
639-
ast::expr_unary(_, _) { true }
640-
_ { false }
641-
}
641+
expr_is_ambig(e)
642642
}
643643
_ { false }
644644
};
645645

646-
if last_expr_is_block && next_expr_is_unnop {
646+
if last_expr_is_block && next_expr_is_ambig {
647647
word(s.s, ";");
648648
}
649+
650+
fn expr_is_ambig(ex: @ast::expr) -> bool {
651+
// We're going to walk the expression to the 'left' looking for
652+
// various properties that might indicate ambiguity
653+
654+
type env = @mutable bool;
655+
let visitor = visit::mk_vt(@{
656+
visit_expr: visit_expr
657+
with *visit::default_visitor()
658+
});
659+
let env = @mutable false;
660+
visit_expr(ex, env, visitor);
661+
ret *env;
662+
663+
fn visit_expr(ex: &@ast::expr, e: &env, v: &visit::vt<env>) {
664+
assert *e == false;
665+
666+
if expr_is_ambig(ex) {
667+
*e = true;
668+
ret;
669+
}
670+
671+
alt ex.node {
672+
ast::expr_assign(x, _) { v.visit_expr(x, e, v); }
673+
ast::expr_assign_op(_, x, _) { visit_expr(x, e, v); }
674+
ast::expr_move(x, _) { v.visit_expr(x, e, v); }
675+
ast::expr_field(x, _) { v.visit_expr(x, e, v); }
676+
ast::expr_index(x, _) { v.visit_expr(x, e, v); }
677+
ast::expr_binary(op, x, _) {
678+
if need_parens(x, operator_prec(op)) {
679+
*e = true;
680+
ret;
681+
}
682+
v.visit_expr(x, e, v);
683+
}
684+
ast::expr_cast(x, _) {
685+
if need_parens(x, parse::parser::as_prec) {
686+
*e = true;
687+
ret;
688+
}
689+
}
690+
ast::expr_ternary(x, _, _) { v.visit_expr(x, e, v); }
691+
_ { }
692+
}
693+
}
694+
695+
fn expr_is_ambig(ex: @ast::expr) -> bool {
696+
alt ex.node {
697+
ast::expr_unary(_, _) { true }
698+
ast::expr_tup(_) { true }
699+
_ { false }
700+
}
701+
}
702+
}
649703
}
650704
}
651705

@@ -1307,7 +1361,7 @@ fn operator_prec(op: ast::binop) -> int {
13071361
fail;
13081362
}
13091363

1310-
fn print_maybe_parens(s: &ps, expr: &@ast::expr, outer_prec: int) {
1364+
fn need_parens(expr: &@ast::expr, outer_prec: int) -> bool {
13111365
let add_them;
13121366
alt expr.node {
13131367
ast::expr_binary(op, _, _) {
@@ -1319,6 +1373,11 @@ fn print_maybe_parens(s: &ps, expr: &@ast::expr, outer_prec: int) {
13191373
}
13201374
_ { add_them = false; }
13211375
}
1376+
ret add_them;
1377+
}
1378+
1379+
fn print_maybe_parens(s: &ps, expr: &@ast::expr, outer_prec: int) {
1380+
let add_them = need_parens(expr, outer_prec);
13221381
if add_them { popen(s); }
13231382
print_expr(s, expr);
13241383
if add_them { pclose(s); }
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Tests that the pretty printer correctly disambiguates various scenarios
2+
// involving block statements by ending them with a semi-colon
3+
fn test1() {
4+
let val = @0;
5+
{};
6+
*val;
7+
}
8+
9+
fn test2() -> int {
10+
let val = @0;
11+
{};
12+
*val
13+
}
14+
15+
fn test3() {
16+
let regs = @{mutable eax: 0};
17+
alt true {
18+
true { }
19+
};
20+
(*regs).eax = 1;
21+
}
22+
23+
fn test4() -> bool {
24+
let regs = @true;
25+
if true { };
26+
*regs || false
27+
}
28+
29+
fn test5() -> (int, int) {
30+
{};
31+
(0, 1)
32+
}
33+
34+
fn test6() -> bool {
35+
{};
36+
(true || false) && true
37+
}
38+
39+
fn test7() -> uint {
40+
let regs = @0;
41+
alt true { true { } };
42+
(*regs < 2) as uint
43+
}
44+
45+
fn test8() -> int {
46+
let val = @0;
47+
alt true { true { } };
48+
*val < 1 ? 0 : 1
49+
}
50+
51+
fn test9() {
52+
let regs = @mutable 0;
53+
alt true {
54+
true { }
55+
};
56+
*regs += 1;
57+
}
58+
59+
fn test10() -> int {
60+
let regs = @mutable [0];
61+
alt true {
62+
true { }
63+
};
64+
(*regs).(0)
65+
}

0 commit comments

Comments
 (0)