@@ -7,6 +7,7 @@ import std::uint;
7
7
import std:: option;
8
8
import parse:: lexer;
9
9
import syntax:: codemap:: codemap;
10
+ import syntax:: visit;
10
11
import ast;
11
12
import option:: some;
12
13
import option:: none;
@@ -596,13 +597,13 @@ fn print_possibly_embedded_block(s: &ps, blk: &ast::blk, embedded: embed_type,
596
597
597
598
let last_stmt = option:: none;
598
599
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) ) ;
600
601
print_stmt ( s, * st) ;
601
602
last_stmt = option:: some ( st) ;
602
603
}
603
604
alt blk. node . expr {
604
605
some ( expr) {
605
- maybe_protect_unop ( s, last_stmt, expr_ ( expr) ) ;
606
+ maybe_protect_block ( s, last_stmt, expr_ ( expr) ) ;
606
607
space_if_not_bol ( s) ;
607
608
print_expr ( s, expr) ;
608
609
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,
615
616
tag expr_or_stmt { stmt_( @ast:: stmt) ; expr_ ( @ast:: expr) ; }
616
617
617
618
// 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 ) {
623
623
let last_expr_is_block = alt last {
624
624
option : : some( @{ node: ast:: stmt_expr ( e, _) , _} ) {
625
625
alt e. node {
@@ -632,20 +632,74 @@ fn print_possibly_embedded_block(s: &ps, blk: &ast::blk, embedded: embed_type,
632
632
}
633
633
_ { false }
634
634
} ;
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) }
637
640
stmt_ ( @{ node: ast:: stmt_expr ( e, _) , _} ) {
638
- alt e. node {
639
- ast:: expr_unary ( _, _) { true }
640
- _ { false }
641
- }
641
+ expr_is_ambig ( e)
642
642
}
643
643
_ { false }
644
644
} ;
645
645
646
- if last_expr_is_block && next_expr_is_unnop {
646
+ if last_expr_is_block && next_expr_is_ambig {
647
647
word ( s. s , ";" ) ;
648
648
}
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
+ }
649
703
}
650
704
}
651
705
@@ -1307,7 +1361,7 @@ fn operator_prec(op: ast::binop) -> int {
1307
1361
fail;
1308
1362
}
1309
1363
1310
- fn print_maybe_parens ( s : & ps , expr : & @ast:: expr , outer_prec : int ) {
1364
+ fn need_parens ( expr : & @ast:: expr , outer_prec : int ) -> bool {
1311
1365
let add_them;
1312
1366
alt expr. node {
1313
1367
ast:: expr_binary ( op, _, _) {
@@ -1319,6 +1373,11 @@ fn print_maybe_parens(s: &ps, expr: &@ast::expr, outer_prec: int) {
1319
1373
}
1320
1374
_ { add_them = false ; }
1321
1375
}
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) ;
1322
1381
if add_them { popen ( s) ; }
1323
1382
print_expr ( s, expr) ;
1324
1383
if add_them { pclose ( s) ; }
0 commit comments