pprust.rs 48.8 KB
Newer Older
1

2
import std::ivec;
3
import std::int;
4
import std::ioivec;
5 6
import std::str;
import std::uint;
7
import std::option;
8 9 10
import parse::lexer;
import syntax::codemap::codemap;
import ast;
11 12
import option::some;
import option::none;
G
Graydon Hoare 已提交
13 14
import pp::printer;
import pp::break_offset;
G
Graydon Hoare 已提交
15
import pp::word;
16
import pp::huge_word;
17
import pp::zero_word;
G
Graydon Hoare 已提交
18
import pp::space;
G
Graydon Hoare 已提交
19
import pp::zerobreak;
G
Graydon Hoare 已提交
20
import pp::hardbreak;
21 22 23
import pp::breaks;
import pp::consistent;
import pp::inconsistent;
G
Graydon Hoare 已提交
24
import pp::eof;
25

26 27 28
// The ps is stored here to prevent recursive type.
// FIXME use a nominal tag instead
tag ann_node {
29
    node_block(ps, ast::blk);
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
    node_item(ps, @ast::item);
    node_expr(ps, @ast::expr);
    node_pat(ps, @ast::pat);
}
type pp_ann = rec(fn(&ann_node node) pre,
                  fn(&ann_node node) post);

fn no_ann() -> pp_ann {
    fn ignore(&ann_node node) {}
    ret rec(pre=ignore, post=ignore);
}

type ps =
    @rec(pp::printer s,
         option::t[codemap] cm,
45 46
         option::t[lexer::cmnt[]] comments,
         option::t[lexer::lit[]] literals,
47 48
         mutable uint cur_cmnt,
         mutable uint cur_lit,
49
         mutable pp::breaks[] boxes,
50 51 52
         pp_ann ann);

fn ibox(&ps s, uint u) {
53
    s.boxes += ~[pp::inconsistent];
54 55 56
    pp::ibox(s.s, u);
}

57
fn end(&ps s) { ivec::pop(s.boxes); pp::end(s.s); }
58

59
fn rust_printer(ioivec::writer writer) -> ps {
60
    let pp::breaks[] boxes = ~[];
61 62
    ret @rec(s=pp::mk_printer(writer, default_columns),
             cm=none[codemap],
63 64
             comments=none[lexer::cmnt[]],
             literals=none[lexer::lit[]],
65 66 67 68 69 70 71
             mutable cur_cmnt=0u,
             mutable cur_lit=0u,
             mutable boxes=boxes,
             ann=no_ann());
}

const uint indent_unit = 4u;
72
const uint alt_indent_unit = 2u;
73 74 75

const uint default_columns = 78u;

76 77 78 79 80
// Requires you to pass an input filename and reader so that
// it can scan the input text for comments and literals to
// copy forward.
fn print_crate(&codemap cm, @ast::crate crate,
               str filename, ioivec::reader in,
81
               ioivec::writer out, &pp_ann ann) {
82
    let pp::breaks[] boxes = ~[];
83
    auto r = lexer::gather_comments_and_literals(cm, filename, in);
84 85
    auto s =
        @rec(s=pp::mk_printer(out, default_columns),
86
             cm=some(cm),
87 88 89 90 91
             comments=some(r.cmnts),
             literals=some(r.lits),
             mutable cur_cmnt=0u,
             mutable cur_lit=0u,
             mutable boxes=boxes,
92
             ann=ann);
93
    print_mod(s, crate.node.module, crate.node.attrs);
94
    print_remaining_comments(s);
G
Graydon Hoare 已提交
95
    eof(s.s);
M
Marijn Haverbeke 已提交
96 97
}

98
fn ty_to_str(&ast::ty ty) -> str { be to_str(ty, print_type); }
99

T
Tim Chevalier 已提交
100
fn pat_to_str(&@ast::pat pat) -> str { be to_str(pat, print_pat); }
101

T
Tim Chevalier 已提交
102
fn expr_to_str(&@ast::expr e) -> str { be to_str(e, print_expr); }
103

T
Tim Chevalier 已提交
104
fn stmt_to_str(&ast::stmt s) -> str { be to_str(s, print_stmt); }
105

T
Tim Chevalier 已提交
106
fn item_to_str(&@ast::item i) -> str { be to_str(i, print_item); }
107

T
Tim Chevalier 已提交
108
fn path_to_str(&ast::path p) -> str { be to_str(p, print_path); }
109

110
fn fun_to_str(&ast::_fn f, str name, &ast::ty_param[] params) -> str {
111
    auto writer = ioivec::string_writer();
112
    auto s = rust_printer(writer.get_writer());
G
Graydon Hoare 已提交
113
    print_fn(s, f.decl, f.proto, name, params);
G
Graydon Hoare 已提交
114
    eof(s.s);
115
    ret writer.get_str();
116 117
}

118
fn block_to_str(&ast::blk blk) -> str {
119
    auto writer = ioivec::string_writer();
120
    auto s = rust_printer(writer.get_writer());
G
Graydon Hoare 已提交
121 122
    // containing cbox, will be closed by print-block at }

123
    cbox(s, indent_unit);
G
Graydon Hoare 已提交
124
    // head-ibox, will be closed by print-block after {
125

126
    ibox(s, 0u);
127
    print_block(s, blk);
G
Graydon Hoare 已提交
128
    eof(s.s);
129 130 131
    ret writer.get_str();
}

132 133 134 135
fn meta_item_to_str(&ast::meta_item mi) -> str {
    ret to_str(@mi, print_meta_item);
}

136 137 138 139
fn attribute_to_str(&ast::attribute attr) -> str {
    be to_str(attr, print_attribute);
}

140
fn cbox(&ps s, uint u) {
141
    s.boxes += ~[pp::consistent];
142 143 144 145
    pp::cbox(s.s, u);
}

fn box(&ps s, uint u, pp::breaks b) {
146
    s.boxes += ~[b];
147 148 149
    pp::box(s.s, u, b);
}

150 151 152
fn nbsp(&ps s) { word(s.s, " "); }

fn word_nbsp(&ps s, str w) { word(s.s, w); nbsp(s); }
G
Graydon Hoare 已提交
153

154
fn word_space(&ps s, str w) { word(s.s, w); space(s.s); }
G
Graydon Hoare 已提交
155

156
fn popen(&ps s) { word(s.s, "("); }
G
Graydon Hoare 已提交
157

158
fn pclose(&ps s) { word(s.s, ")"); }
G
Graydon Hoare 已提交
159

160
fn head(&ps s, str w) {
G
Graydon Hoare 已提交
161
    // outer-box is consistent
162
    cbox(s, indent_unit);
G
Graydon Hoare 已提交
163
    // head-box is inconsistent
164
    ibox(s, str::char_len(w) + 1u);
G
Graydon Hoare 已提交
165
    // keyword that starts the head
G
Graydon Hoare 已提交
166
    word_nbsp(s, w);
G
Graydon Hoare 已提交
167 168
}

169
fn bopen(&ps s) {
G
Graydon Hoare 已提交
170
    word(s.s, "{");
171
    end(s); // close the head-box
172

173
}
G
Graydon Hoare 已提交
174

175
fn bclose_(&ps s, codemap::span span, uint indented) {
176
    maybe_print_comment(s, span.hi);
177
    break_offset_if_not_bol(s, 1u, -(indented as int));
G
Graydon Hoare 已提交
178
    word(s.s, "}");
179
    end(s); // close the outer-box
180 181 182
}
fn bclose(&ps s, codemap::span span) {
    bclose_(s, span, indent_unit);
M
Marijn Haverbeke 已提交
183
}
G
Graydon Hoare 已提交
184

185 186 187
fn is_bol(&ps s) -> bool {
    ret (s.s.last_token() == pp::EOF ||
         s.s.last_token() == pp::hardbreak_tok());
188 189
}

190 191 192 193 194 195
fn hardbreak_if_not_bol(&ps s) { if ! is_bol(s) { hardbreak(s.s); } }
fn space_if_not_bol(&ps s) { if ! is_bol(s) { space(s.s); } }
fn break_offset_if_not_bol(&ps s, uint n, int off) {
    if ! is_bol(s) {
        break_offset(s.s, n, off);
    } else {
G
Graydon Hoare 已提交
196
        if off != 0 &&
197 198 199 200 201 202
            s.s.last_token() == pp::hardbreak_tok() {
            // We do something pretty sketchy here: tuck the nonzero
            // offset-adjustment we were going to deposit along with the
            // break into the previous hardbreak.
            s.s.replace_last_token(pp::hardbreak_tok_offset(off));
        }
203 204
    }
}
205

206 207 208 209 210 211 212 213 214 215
// Synthesizes a comment that was not textually present in the original source
// file.
fn synth_comment(&ps s, str text) {
    word(s.s, "/*");
    space(s.s);
    word(s.s, text);
    space(s.s);
    word(s.s, "*/");
}

216
fn commasep[IN](&ps s, breaks b, &IN[] elts, fn(&ps, &IN)  op) {
217 218 219 220 221 222 223 224 225 226
    box(s, 0u, b);
    auto first = true;
    for (IN elt in elts) {
        if (first) { first = false; } else { word_space(s, ","); }
        op(s, elt);
    }
    end(s);
}


227
fn commasep_cmnt[IN](&ps s, breaks b, &IN[] elts, fn(&ps, &IN)  op,
228
                     fn(&IN) -> codemap::span  get_span) {
229
    box(s, 0u, b);
230 231 232 233 234 235 236 237 238 239
    auto len = ivec::len[IN](elts);
    auto i = 0u;
    for (IN elt in elts) {
        maybe_print_comment(s, get_span(elt).hi);
        op(s, elt);
        i += 1u;
        if (i < len) {
            word(s.s, ",");
            maybe_print_trailing_comment(s, get_span(elt),
                                         some(get_span(elts.(i)).hi));
240
            space_if_not_bol(s);
241 242 243 244 245
        }
    }
    end(s);
}

246
fn commasep_exprs(&ps s, breaks b, &(@ast::expr)[] exprs) {
247
    fn expr_span(&@ast::expr expr) -> codemap::span { ret expr.span; }
248
    commasep_cmnt(s, b, exprs, print_expr, expr_span);
249
}
M
Marijn Haverbeke 已提交
250

251
fn print_mod(&ps s, &ast::_mod _mod, &ast::attribute[] attrs) {
252
    print_inner_attributes(s, attrs);
253 254 255
    for (@ast::view_item vitem in _mod.view_items) {
        print_view_item(s, vitem);
    }
G
Graydon Hoare 已提交
256 257 258
    for (@ast::item item in _mod.items) {
        print_item(s, item);
    }
259 260
}

261 262 263 264 265 266 267 268 269 270 271
fn print_native_mod(&ps s, &ast::native_mod nmod,
                    &ast::attribute[] attrs) {
    print_inner_attributes(s, attrs);
    for (@ast::view_item vitem in nmod.view_items) {
        print_view_item(s, vitem);
    }
    for (@ast::native_item item in nmod.items) {
        print_native_item(s, item);
    }
}

272
fn print_boxed_type(&ps s, &@ast::ty ty) { print_type(s, *ty); }
G
Graydon Hoare 已提交
273

274
fn print_type(&ps s, &ast::ty ty) {
275
    maybe_print_comment(s, ty.span.lo);
276
    ibox(s, 0u);
277
    alt (ty.node) {
278 279 280 281 282 283
        case (ast::ty_nil) { word(s.s, "()"); }
        case (ast::ty_bool) { word(s.s, "bool"); }
        case (ast::ty_bot) { word(s.s, "!"); }
        case (ast::ty_int) { word(s.s, "int"); }
        case (ast::ty_uint) { word(s.s, "uint"); }
        case (ast::ty_float) { word(s.s, "float"); }
284
        case (ast::ty_machine(?tm)) { word(s.s, ast::ty_mach_to_str(tm)); }
285 286
        case (ast::ty_char) { word(s.s, "char"); }
        case (ast::ty_str) { word(s.s, "str"); }
G
Graydon Hoare 已提交
287
        case (ast::ty_istr) { word(s.s, "istr"); }
288
        case (ast::ty_box(?mt)) { word(s.s, "@"); print_mt(s, mt); }
289
        case (ast::ty_vec(?mt)) {
290 291 292
            word(s.s, "vec[");
            print_mt(s, mt);
            word(s.s, "]");
293
        }
294
        case (ast::ty_ivec(?mt)) {
295 296 297 298 299 300 301
            auto parens = alt mt.ty.node {
              ast::ty_box(_) | ast::ty_vec(_) | ast::ty_ptr(_) |
              ast::ty_port(_) | ast::ty_chan(_) { true }
              ast::ty_path(?pt, _) { ivec::len(pt.node.types) > 0u }
              _ { false }
            };
            if parens { popen(s); }
302
            print_type(s, *mt.ty);
303
            if parens { pclose(s); }
304 305 306 307
            word(s.s, "[");
            print_mutability(s, mt.mut);
            word(s.s, "]");
        }
G
Graydon Hoare 已提交
308 309 310 311 312 313 314
        case (ast::ty_ptr(?mt)) {
            word(s.s, "*");
            print_mt(s, mt);
        }
        case (ast::ty_task) {
            word(s.s, "task");
        }
315
        case (ast::ty_port(?t)) {
316 317 318
            word(s.s, "port[");
            print_type(s, *t);
            word(s.s, "]");
319
        }
320
        case (ast::ty_chan(?t)) {
321 322 323
            word(s.s, "chan[");
            print_type(s, *t);
            word(s.s, "]");
324
        }
325
        case (ast::ty_rec(?fields)) {
326
            word(s.s, "{");
327
            fn print_field(&ps s, &ast::ty_field f) {
328
                cbox(s, indent_unit);
329
                print_mutability(s, f.node.mt.mut);
330
                word(s.s, f.node.ident);
331 332
                word_space(s, ":");
                print_type(s, *f.node.mt.ty);
333
                end(s);
334
            }
335
            fn get_span(&ast::ty_field f) -> codemap::span { ret f.span; }
336
            commasep_cmnt(s, consistent, fields, print_field, get_span);
337
            word(s.s, "}");
338
        }
G
Graydon Hoare 已提交
339 340 341
        case (ast::ty_fn(?proto, ?inputs, ?output, ?cf, ?constrs)) {
            print_ty_fn(s, proto, none[str], inputs, output, cf, constrs);
        }
342
        case (ast::ty_obj(?methods)) {
G
Graydon Hoare 已提交
343
            head(s, "obj");
344
            bopen(s);
345
            for (ast::ty_method m in methods) {
346
                hardbreak_if_not_bol(s);
347
                cbox(s, indent_unit);
348 349
                maybe_print_comment(s, m.span.lo);
                print_ty_fn(s, m.node.proto, some(m.node.ident),
350 351
                            m.node.inputs, m.node.output, m.node.cf,
                            m.node.constrs);
G
Graydon Hoare 已提交
352
                word(s.s, ";");
353
                end(s);
354
            }
G
Graydon Hoare 已提交
355
            bclose(s, ty.span);
356
        }
357
        case (ast::ty_path(?path, _)) { print_path(s, path); }
G
Graydon Hoare 已提交
358 359 360 361 362 363
        case (ast::ty_type) { word(s.s, "type"); }
        case (ast::ty_constr(?t, ?cs)) {
            print_type(s, *t);
            space(s.s);
            word(s.s, ":");
            space(s.s);
364
            word(s.s, ast_ty_constrs_str(cs));
G
Graydon Hoare 已提交
365
        }
M
Marijn Haverbeke 已提交
366
    }
367
    end(s);
M
Marijn Haverbeke 已提交
368 369
}

370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
fn print_native_item(&ps s, &@ast::native_item item) {
    hardbreak_if_not_bol(s);
    maybe_print_comment(s, item.span.lo);
    print_outer_attributes(s, item.attrs);
    alt (item.node) {
      ast::native_item_ty {
        ibox(s, indent_unit);
        ibox(s, 0u);
        word_nbsp(s, "type");
        word(s.s, item.ident);
        end(s); // end the inner ibox
        word(s.s, ";");
        end(s); // end the outer ibox

      }

      ast::native_item_fn(?lname, ?decl, ?typarams) {
        print_fn(s, decl, ast::proto_fn, item.ident,
                 typarams);
        alt (lname) {
          none { }
          some(?ss) {
            space(s.s);
            word_space(s, "=");
            print_string(s, ss);
          }
        }
        end(s); // end head-ibox
        word(s.s, ";");
        end(s); // end the outer fn box
      }
    }
}

404
fn print_item(&ps s, &@ast::item item) {
405
    hardbreak_if_not_bol(s);
406
    maybe_print_comment(s, item.span.lo);
407
    print_outer_attributes(s, item.attrs);
408 409
    auto ann_node = node_item(s, item);
    s.ann.pre(ann_node);
410
    alt (item.node) {
411
        case (ast::item_const(?ty, ?expr)) {
G
Graydon Hoare 已提交
412
            head(s, "const");
413
            word_space(s, item.ident + ":");
414
            print_type(s, *ty);
415
            space(s.s);
416
            end(s); // end the head-ibox
417

G
Graydon Hoare 已提交
418
            word_space(s, "=");
419
            print_expr(s, expr);
G
Graydon Hoare 已提交
420
            word(s.s, ";");
421
            end(s); // end the outer cbox
422

423
        }
424 425
        case (ast::item_fn(?_fn, ?typarams)) {
            print_fn(s, _fn.decl, _fn.proto, item.ident, typarams);
G
Graydon Hoare 已提交
426
            word(s.s, " ");
427 428
            print_block(s, _fn.body);
        }
429
        case (ast::item_mod(?_mod)) {
G
Graydon Hoare 已提交
430
            head(s, "mod");
431
            word_nbsp(s, item.ident);
432
            bopen(s);
433
            print_mod(s, _mod, item.attrs);
G
Graydon Hoare 已提交
434
            bclose(s, item.span);
435
        }
436
        case (ast::item_native_mod(?nmod)) {
G
Graydon Hoare 已提交
437
            head(s, "native");
438
            alt (nmod.abi) {
439
                case (ast::native_abi_llvm) { word_nbsp(s, "\"llvm\""); }
440 441
                case (ast::native_abi_rust) { word_nbsp(s, "\"rust\""); }
                case (ast::native_abi_cdecl) { word_nbsp(s, "\"cdecl\""); }
442
                case (ast::native_abi_rust_intrinsic) {
G
Graydon Hoare 已提交
443
                    word_nbsp(s, "\"rust-intrinsic\"");
444
                }
445 446 447
                case (ast::native_abi_x86stdcall) {
                    word_nbsp(s, "\"x86stdcall\"");
                }
448
            }
G
Graydon Hoare 已提交
449
            word_nbsp(s, "mod");
450
            word_nbsp(s, item.ident);
451 452 453 454 455
            if !str::eq(nmod.native_name, item.ident) {
                word_space(s, "=");
                print_string(s, nmod.native_name);
                nbsp(s);
            }
456
            bopen(s);
457
            print_native_mod(s, nmod, item.attrs);
G
Graydon Hoare 已提交
458
            bclose(s, item.span);
459
        }
460
        case (ast::item_ty(?ty, ?params)) {
461 462
            ibox(s, indent_unit);
            ibox(s, 0u);
G
Graydon Hoare 已提交
463
            word_nbsp(s, "type");
464
            word(s.s, item.ident);
465
            print_type_params(s, params);
466
            end(s); // end the inner ibox
467

468
            space(s.s);
G
Graydon Hoare 已提交
469
            word_space(s, "=");
470
            print_type(s, *ty);
G
Graydon Hoare 已提交
471
            word(s.s, ";");
472
            end(s); // end the outer ibox
473
        }
474
        case (ast::item_tag(?variants, ?params)) {
475
            auto newtype = ivec::len(variants) == 1u &&
476
                str::eq(item.ident, variants.(0).node.name) &&
477
                ivec::len(variants.(0).node.args) == 1u;
478 479 480 481 482 483
            if (newtype) {
                ibox(s, indent_unit);
                word_space(s, "tag");
            } else {
                head(s, "tag");
            }
484
            word(s.s, item.ident);
485 486
            print_type_params(s, params);
            space(s.s);
487 488 489 490 491 492 493 494 495 496 497
            if (newtype) {
                word_space(s, "=");
                print_type(s, *variants.(0).node.args.(0).ty);
                word(s.s, ";");
                end(s);
            } else {
                bopen(s);
                for (ast::variant v in variants) {
                    space(s.s);
                    maybe_print_comment(s, v.span.lo);
                    word(s.s, v.node.name);
498
                    if (ivec::len(v.node.args) > 0u) {
499 500 501 502
                        popen(s);
                        fn print_variant_arg(&ps s, &ast::variant_arg arg) {
                            print_type(s, *arg.ty);
                        }
503
                        commasep(s, consistent, v.node.args,
504
                                      print_variant_arg);
505
                        pclose(s);
506
                    }
507 508
                    word(s.s, ";");
                    maybe_print_trailing_comment(s, v.span, none[uint]);
509
                }
510
                bclose(s, item.span);
511
            }
M
Marijn Haverbeke 已提交
512
        }
513
        case (ast::item_obj(?_obj, ?params, _)) {
G
Graydon Hoare 已提交
514
            head(s, "obj");
515
            word(s.s, item.ident);
516 517
            print_type_params(s, params);
            popen(s);
518
            fn print_field(&ps s, &ast::obj_field field) {
519
                ibox(s, indent_unit);
G
Graydon Hoare 已提交
520
                print_mutability(s, field.mut);
521
                word_space(s, field.ident + ":");
522
                print_type(s, *field.ty);
523
                end(s);
524
            }
525
            fn get_span(&ast::obj_field f) -> codemap::span { ret f.ty.span; }
526
            commasep_cmnt(s, consistent, _obj.fields, print_field,
527
                               get_span);
528 529 530
            pclose(s);
            space(s.s);
            bopen(s);
531
            for (@ast::method meth in _obj.methods) {
532
                let ast::ty_param[] typarams = ~[];
533
                hardbreak_if_not_bol(s);
534
                maybe_print_comment(s, meth.span.lo);
G
Graydon Hoare 已提交
535 536
                print_fn(s, meth.node.meth.decl, meth.node.meth.proto,
                         meth.node.ident, typarams);
G
Graydon Hoare 已提交
537
                word(s.s, " ");
538 539 540
                print_block(s, meth.node.meth.body);
            }
            alt (_obj.dtor) {
541
                case (some(?dtor)) {
G
Graydon Hoare 已提交
542
                    head(s, "drop");
543
                    print_block(s, dtor.node.meth.body);
544
                }
545
                case (_) { }
546
            }
G
Graydon Hoare 已提交
547
            bclose(s, item.span);
M
Marijn Haverbeke 已提交
548
        }
549
        case (ast::item_res(?dt, ?dt_id, ?tps, ?ct_id)) {
550
            head(s, "resource");
551 552 553
            word(s.s, item.ident);
            print_type_params(s, tps);
            popen(s);
554
            word_space(s, dt.decl.inputs.(0).ident + ":");
555 556 557 558 559
            print_type(s, *dt.decl.inputs.(0).ty);
            pclose(s);
            space(s.s);
            print_block(s, dt.body);
        }
M
Marijn Haverbeke 已提交
560
    }
561
    s.ann.post(ann_node);
M
Marijn Haverbeke 已提交
562 563
}

564
fn print_outer_attributes(&ps s, &ast::attribute[] attrs) {
565 566 567
    auto count = 0;
    for (ast::attribute attr in attrs) {
        alt (attr.node.style) {
568 569
            case (ast::attr_outer) { print_attribute(s, attr); count += 1; }
            case (_) {/* fallthrough */ }
570 571
        }
    }
572
    if (count > 0) { hardbreak_if_not_bol(s); }
573 574
}

575
fn print_inner_attributes(&ps s, &ast::attribute[] attrs) {
576 577 578 579 580 581 582 583 584 585 586
    auto count = 0;
    for (ast::attribute attr in attrs) {
        alt (attr.node.style) {
            case (ast::attr_inner) {
                print_attribute(s, attr);
                word(s.s, ";");
                count += 1;
            }
            case (_) { /* fallthrough */ }
        }
    }
587
    if (count > 0) { hardbreak_if_not_bol(s); }
588 589
}

590
fn print_attribute(&ps s, &ast::attribute attr) {
591
    hardbreak_if_not_bol(s);
592 593 594 595 596 597
    maybe_print_comment(s, attr.span.lo);
    word(s.s, "#[");
    print_meta_item(s, @attr.node.value);
    word(s.s, "]");
}

598 599 600
fn print_stmt(&ps s, &ast::stmt st) {
    maybe_print_comment(s, st.span.lo);
    alt (st.node) {
601
        case (ast::stmt_decl(?decl, _)) { print_decl(s, decl); }
602
        case (ast::stmt_expr(?expr, _)) {
603
            space_if_not_bol(s);
604 605
            print_expr(s, expr);
        }
606
    }
607
    if (parse::parser::stmt_ends_with_semi(st)) { word(s.s, ";"); }
608
    maybe_print_trailing_comment(s, st.span, none[uint]);
609 610
}

611
fn print_block(&ps s, &ast::blk blk) {
612
    print_possibly_embedded_block(s, blk, false, indent_unit);
613
}
614

615
fn print_possibly_embedded_block(&ps s, &ast::blk blk, bool embedded,
616
                                 uint indented) {
617
    maybe_print_comment(s, blk.span.lo);
618 619
    auto ann_node = node_block(s, blk);
    s.ann.pre(ann_node);
620 621 622 623 624
    if (embedded) {
        word(s.s, "#{"); end(s);
    } else {
        bopen(s);
    }
625
    for (@ast::stmt st in blk.node.stmts) { print_stmt(s, *st) }
626
    alt (blk.node.expr) {
627
        case (some(?expr)) {
628
            space_if_not_bol(s);
629
            print_expr(s, expr);
630
            maybe_print_trailing_comment(s, expr.span, some(blk.span.hi));
631
        }
632
        case (_) { }
M
Marijn Haverbeke 已提交
633
    }
634
    bclose_(s, blk.span, indented);
635
    s.ann.post(ann_node);
M
Marijn Haverbeke 已提交
636 637
}

638
fn print_if(&ps s, &@ast::expr test, &ast::blk blk,
639
            &option::t[@ast::expr] elseopt, bool chk) {
T
Tim Chevalier 已提交
640
    head(s, "if");
641 642 643
    if (chk) {
        word_nbsp(s, "check");
    }
T
Tim Chevalier 已提交
644 645
    print_expr(s, test);
    space(s.s);
646
    print_block(s, blk);
T
Tim Chevalier 已提交
647 648 649 650
    fn do_else(&ps s, option::t[@ast::expr] els) {
        alt (els) {
            case (some(?_else)) {
                alt (_else.node) {
651 652
                    // "another else-if"
                    case (ast::expr_if(?i, ?t, ?e)) {
T
Tim Chevalier 已提交
653 654 655 656 657 658 659 660 661 662
                        cbox(s, indent_unit - 1u);
                        ibox(s, 0u);
                        word(s.s, " else if ");
                        popen(s);
                        print_expr(s, i);
                        pclose(s);
                        space(s.s);
                        print_block(s, t);
                        do_else(s, e);
                    }
663 664
                    // "final else"
                    case (ast::expr_block(?b)) {
T
Tim Chevalier 已提交
665 666 667 668 669 670 671 672 673 674 675 676 677
                        cbox(s, indent_unit - 1u);
                        ibox(s, 0u);
                        word(s.s, " else ");
                        print_block(s, b);
                    }
                }
            }
            case (_) {/* fall through */ }
        }
    }
    do_else(s, elseopt);
}

678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
fn print_mac(&ps s, &ast::mac m) {
    alt (m.node) {
        case (ast::mac_invoc(?path, ?args, ?body)) {
            word(s.s, "#");
            print_path(s, path);
            if (ivec::len(args) > 0u) {
                popen(s);
                commasep_exprs(s, inconsistent, args);
                pclose(s);
            }
            // FIXME: extension 'body'

        }
        case (ast::mac_embed_type(?ty)) {
            word(s.s, "#<");
            print_type(s, *ty);
            word(s.s, ">");
        }
        case (ast::mac_embed_block(?blk)) {
697
            print_possibly_embedded_block(s, blk, true, indent_unit);
698
        }
P
Paul Stansifer 已提交
699
        case (ast::mac_ellipsis) {
700 701 702 703 704
            word(s.s, "...");
        }
    }
}

705
fn print_expr(&ps s, &@ast::expr expr) {
706
    maybe_print_comment(s, expr.span.lo);
707
    ibox(s, indent_unit);
708 709
    auto ann_node = node_expr(s, expr);
    s.ann.pre(ann_node);
710
    alt (expr.node) {
711
        case (ast::expr_vec(?exprs, ?mut, ?kind)) {
712
            ibox(s, indent_unit);
713 714 715 716
            alt (kind) {
                case (ast::sk_rc) { word(s.s, "["); }
                case (ast::sk_unique) { word(s.s, "~["); }
            }
717
            if (mut == ast::mut) { word_nbsp(s, "mutable"); }
718
            commasep_exprs(s, inconsistent, exprs);
G
Graydon Hoare 已提交
719
            word(s.s, "]");
720
            end(s);
721
        }
722
        case (ast::expr_rec(?fields, ?wth)) {
723
            fn print_field(&ps s, &ast::field field) {
724
                ibox(s, indent_unit);
725
                if (field.node.mut == ast::mut) { word_nbsp(s, "mutable"); }
726
                word(s.s, field.node.ident);
727
                word_space(s, ":");
728
                print_expr(s, field.node.expr);
729
                end(s);
730
            }
731 732 733
            fn get_span(&ast::field field) -> codemap::span {
                ret field.span;
            }
734
            word(s.s, "{");
735
            commasep_cmnt(s, consistent, fields, print_field, get_span);
736
            alt (wth) {
737
                case (some(?expr)) {
738
                    if (ivec::len(fields) > 0u) { space(s.s); }
739
                    ibox(s, indent_unit);
G
Graydon Hoare 已提交
740
                    word_space(s, "with");
741
                    print_expr(s, expr);
742
                    end(s);
743
                }
744
                case (_) { }
745
            }
746
            word(s.s, "}");
747
        }
748
        case (ast::expr_call(?func, ?args)) {
749
            print_expr_parens_if_unary(s, func);
750
            popen(s);
751
            commasep_exprs(s, inconsistent, args);
752 753
            pclose(s);
        }
754
        case (ast::expr_self_method(?ident)) {
G
Graydon Hoare 已提交
755
            word(s.s, "self.");
756
            print_ident(s, ident);
757
        }
758
        case (ast::expr_bind(?func, ?args)) {
759
            fn print_opt(&ps s, &option::t[@ast::expr] expr) {
760
                alt (expr) {
761 762
                    case (some(?expr)) { print_expr(s, expr); }
                    case (_) { word(s.s, "_"); }
763 764
                }
            }
G
Graydon Hoare 已提交
765
            word_nbsp(s, "bind");
766 767
            print_expr(s, func);
            popen(s);
768
            commasep(s, inconsistent, args, print_opt);
769 770
            pclose(s);
        }
771
        case (ast::expr_spawn(_, _, ?e, ?es)) {
772 773 774 775 776
            word_nbsp(s, "spawn");
            print_expr(s, e);
            popen(s);
            commasep_exprs(s, inconsistent, es);
            pclose(s);
777
        }
778
        case (ast::expr_binary(?op, ?lhs, ?rhs)) {
779 780 781
            auto prec = operator_prec(op);
            print_maybe_parens(s, lhs, prec);
            space(s.s);
G
Graydon Hoare 已提交
782
            word_space(s, ast::binop_to_str(op));
783 784
            print_maybe_parens(s, rhs, prec + 1);
        }
785
        case (ast::expr_unary(?op, ?expr)) {
G
Graydon Hoare 已提交
786
            word(s.s, ast::unop_to_str(op));
787
            print_maybe_parens(s, expr, parse::parser::unop_prec);
M
Marijn Haverbeke 已提交
788
        }
789 790
        case (ast::expr_lit(?lit)) { print_literal(s, lit); }
        case (ast::expr_cast(?expr, ?ty)) {
791
            print_maybe_parens(s, expr, parse::parser::as_prec);
792
            space(s.s);
G
Graydon Hoare 已提交
793
            word_space(s, "as");
794
            print_type(s, *ty);
795
        }
796 797
        case (ast::expr_if(?test, ?blk, ?elseopt)) {
            print_if(s, test, blk, elseopt, false);
T
Tim Chevalier 已提交
798
        }
799 800
        case (ast::expr_if_check(?test, ?blk, ?elseopt)) {
            print_if(s, test, blk, elseopt, true);
801
        }
802 803 804 805 806 807 808 809 810
        case (ast::expr_ternary(?test, ?then, ?els)) {
            print_expr(s, test);
            space(s.s);
            word_space(s, "?");
            print_expr(s, then);
            space(s.s);
            word_space(s, ":");
            print_expr(s, els);
        }
811
        case (ast::expr_while(?test, ?blk)) {
G
Graydon Hoare 已提交
812
            head(s, "while");
813 814
            print_expr(s, test);
            space(s.s);
815
            print_block(s, blk);
816
        }
817
        case (ast::expr_for(?decl, ?expr, ?blk)) {
G
Graydon Hoare 已提交
818
            head(s, "for");
819 820
            print_for_decl(s, decl);
            space(s.s);
G
Graydon Hoare 已提交
821
            word_space(s, "in");
822 823
            print_expr(s, expr);
            space(s.s);
824
            print_block(s, blk);
825
        }
826
        case (ast::expr_for_each(?decl, ?expr, ?blk)) {
G
Graydon Hoare 已提交
827
            head(s, "for each");
828 829
            print_for_decl(s, decl);
            space(s.s);
G
Graydon Hoare 已提交
830
            word_space(s, "in");
831 832
            print_expr(s, expr);
            space(s.s);
833
            print_block(s, blk);
834
        }
835
        case (ast::expr_do_while(?blk, ?expr)) {
G
Graydon Hoare 已提交
836
            head(s, "do");
837
            space(s.s);
838
            print_block(s, blk);
839
            space(s.s);
G
Graydon Hoare 已提交
840
            word_space(s, "while");
841 842
            print_expr(s, expr);
        }
843
        case (ast::expr_alt(?expr, ?arms)) {
844 845 846
            cbox(s, alt_indent_unit);
            ibox(s, 4u);
            word_nbsp(s, "alt");
847 848 849
            print_expr(s, expr);
            space(s.s);
            bopen(s);
850
            for (ast::arm arm in arms) {
G
Graydon Hoare 已提交
851
                space(s.s);
852 853
                cbox(s, alt_indent_unit);
                ibox(s, 0u);
854 855 856 857 858 859
                auto first = true;
                for (@ast::pat p in arm.pats) {
                    if (first) { first = false; }
                    else { space(s.s); word_space(s, "|"); }
                    print_pat(s, p);
                }
860
                space(s.s);
861 862
                print_possibly_embedded_block(s, arm.block, false,
                                              alt_indent_unit);
863
            }
864
            bclose_(s, expr.span, alt_indent_unit);
865
        }
866
        case (ast::expr_fn(?f)) {
867
            head(s, proto_to_str(f.proto));
868 869 870 871
            print_fn_args_and_ret(s, f.decl);
            space(s.s);
            print_block(s, f.body);
        }
872
        case (ast::expr_block(?blk)) {
G
Graydon Hoare 已提交
873
            // containing cbox, will be closed by print-block at }
874
            cbox(s, indent_unit);
G
Graydon Hoare 已提交
875
            // head-box, will be closed by print-block after {
876
            ibox(s, 0u);
877
            print_block(s, blk);
878
        }
879
        case (ast::expr_move(?lhs, ?rhs)) {
880 881
            print_expr(s, lhs);
            space(s.s);
M
Michael Sullivan 已提交
882
            word_space(s, "<-");
883 884
            print_expr(s, rhs);
        }
885
        case (ast::expr_assign(?lhs, ?rhs)) {
886 887
            print_expr(s, lhs);
            space(s.s);
G
Graydon Hoare 已提交
888
            word_space(s, "=");
889 890
            print_expr(s, rhs);
        }
891
        case (ast::expr_swap(?lhs, ?rhs)) {
892 893 894 895 896
            print_expr(s, lhs);
            space(s.s);
            word_space(s, "<->");
            print_expr(s, rhs);
        }
897
        case (ast::expr_assign_op(?op, ?lhs, ?rhs)) {
898 899
            print_expr(s, lhs);
            space(s.s);
G
Graydon Hoare 已提交
900
            word(s.s, ast::binop_to_str(op));
G
Graydon Hoare 已提交
901
            word_space(s, "=");
902 903
            print_expr(s, rhs);
        }
904
        case (ast::expr_send(?lhs, ?rhs)) {
905 906
            print_expr(s, lhs);
            space(s.s);
G
Graydon Hoare 已提交
907
            word_space(s, "<|");
908 909
            print_expr(s, rhs);
        }
910
        case (ast::expr_recv(?lhs, ?rhs)) {
911
            print_expr(s, lhs);
912
            space(s.s);
G
Graydon Hoare 已提交
913
            word_space(s, "|>");
914
            print_expr(s, rhs);
915
        }
916
        case (ast::expr_field(?expr, ?id)) {
917
            print_expr_parens_if_unary(s, expr);
G
Graydon Hoare 已提交
918 919
            word(s.s, ".");
            word(s.s, id);
920
        }
921
        case (ast::expr_index(?expr, ?index)) {
922
            print_expr_parens_if_unary(s, expr);
G
Graydon Hoare 已提交
923
            word(s.s, ".");
G
Graydon Hoare 已提交
924
            popen(s);
925 926 927
            print_expr(s, index);
            pclose(s);
        }
928
        case (ast::expr_path(?path)) { print_path(s, path); }
929
        case (ast::expr_fail(?maybe_fail_val)) {
G
Graydon Hoare 已提交
930
            word(s.s, "fail");
931 932
            alt (maybe_fail_val) {
                case (some(?expr)) { word(s.s, " "); print_expr(s, expr); }
933
                case (_) { }
J
Josh Matthews 已提交
934
            }
935
        }
936 937 938
        case (ast::expr_break) { word(s.s, "break"); }
        case (ast::expr_cont) { word(s.s, "cont"); }
        case (ast::expr_ret(?result)) {
G
Graydon Hoare 已提交
939
            word(s.s, "ret");
940
            alt (result) {
941 942
                case (some(?expr)) { word(s.s, " "); print_expr(s, expr); }
                case (_) { }
943 944
            }
        }
945
        case (ast::expr_put(?result)) {
G
Graydon Hoare 已提交
946
            word(s.s, "put");
947
            alt (result) {
948 949
                case (some(?expr)) { word(s.s, " "); print_expr(s, expr); }
                case (_) { }
950 951
            }
        }
952
        case (ast::expr_be(?result)) {
G
Graydon Hoare 已提交
953
            word_nbsp(s, "be");
954 955
            print_expr(s, result);
        }
956
        case (ast::expr_log(?lvl, ?expr)) {
M
Marijn Haverbeke 已提交
957
            alt (lvl) {
958 959
                case (1) { word_nbsp(s, "log"); }
                case (0) { word_nbsp(s, "log_err"); }
M
Marijn Haverbeke 已提交
960
            }
961 962
            print_expr(s, expr);
        }
T
Tim Chevalier 已提交
963 964 965 966 967 968 969 970 971
        case (ast::expr_check(?m, ?expr)) {
            alt (m) {
                case (ast::unchecked) {
                    word_nbsp(s, "claim");
                }
                case (ast::checked) {
                    word_nbsp(s, "check");
                }
            }
G
Graydon Hoare 已提交
972
            popen(s);
973 974 975
            print_expr(s, expr);
            pclose(s);
        }
976
        case (ast::expr_assert(?expr)) {
G
Graydon Hoare 已提交
977 978
            word_nbsp(s, "assert");
            popen(s);
979 980 981
            print_expr(s, expr);
            pclose(s);
        }
982 983
        case (ast::expr_mac(?m)) {
            print_mac(s, m);
984
        }
985
        case (ast::expr_port(?ot)) {
G
Graydon Hoare 已提交
986
            word(s.s, "port");
987 988 989 990 991 992 993 994
            alt(ot) {
                case(some(?t)) {
                    word(s.s, "[");
                    print_type(s, *t);
                    word(s.s, "]");
                }
                case(none) {}
            }
G
Graydon Hoare 已提交
995
            popen(s); pclose(s);
996
        }
997
        case (ast::expr_chan(?expr)) {
G
Graydon Hoare 已提交
998
            word(s.s, "chan");
G
Graydon Hoare 已提交
999
            popen(s);
1000 1001
            print_expr(s, expr);
            pclose(s);
M
Marijn Haverbeke 已提交
1002
        }
1003
        case (ast::expr_anon_obj(?anon_obj)) {
1004 1005 1006 1007 1008 1009 1010
            head(s, "obj");

            // Fields
            popen(s);
            fn print_field(&ps s, &ast::anon_obj_field field) {
                ibox(s, indent_unit);
                print_mutability(s, field.mut);
1011
                word_space(s, field.ident + ":");
1012 1013 1014 1015 1016 1017
                print_type(s, *field.ty);
                space(s.s);
                word_space(s, "=");
                print_expr(s, field.expr);
                end(s);
            }
1018 1019
            fn get_span(&ast::anon_obj_field f) -> codemap::span {
                ret f.ty.span;
1020 1021 1022 1023
            }
            alt (anon_obj.fields) {
                case (none) { }
                case (some(?fields)) {
1024
                    commasep_cmnt(s, consistent, fields, print_field,
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
                                       get_span);
                }
            }
            pclose(s);
            space(s.s);
            bopen(s);

            // Methods
            for (@ast::method meth in anon_obj.methods) {
                let ast::ty_param[] typarams = ~[];
                hardbreak_if_not_bol(s);
                maybe_print_comment(s, meth.span.lo);
                print_fn(s, meth.node.meth.decl, meth.node.meth.proto,
                         meth.node.ident, typarams);
                word(s.s, " ");
                print_block(s, meth.node.meth.body);
            }
            space(s.s);
1043

1044 1045 1046 1047 1048 1049 1050 1051 1052
            // With object
            alt (anon_obj.with_obj) {
                case (none) { }
                case (some(?e)) {
                    word_space(s, "with");
                    print_expr(s, e);
                }
            }
            bclose(s, expr.span);
1053
        }
1054
    }
1055
    s.ann.post(ann_node);
1056
    end(s);
M
Marijn Haverbeke 已提交
1057 1058
}

1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
fn print_expr_parens_if_unary(&ps s, &@ast::expr ex) {
    auto parens = alt ex.node {
      ast::expr_unary(_, _) { true }
      _ { false }
    };
    if parens { popen(s); }
    print_expr(s, ex);
    if parens { pclose(s); }
}

1069
fn print_decl(&ps s, &@ast::decl decl) {
1070 1071
    maybe_print_comment(s, decl.span.lo);
    alt (decl.node) {
1072
        case (ast::decl_local(?locs)) {
1073
            space_if_not_bol(s);
1074
            ibox(s, indent_unit);
1075
            word_nbsp(s, "let");
1076
            fn print_local(&ps s, &@ast::local loc) {
1077
                alt loc.node.ty {
1078
                  some(?ty) {
1079
                    ibox(s, indent_unit);
1080
                    word_space(s, loc.node.ident + ":");
1081
                    print_type(s, *ty);
1082 1083 1084 1085
                    end(s);
                  }
                  _ {
                    word(s.s, loc.node.ident);
1086 1087
                  }
                }
1088 1089
                alt loc.node.init {
                  some(?init) {
1090
                    nbsp(s);
1091 1092 1093 1094
                    alt init.op {
                      ast::init_assign { word_space(s, "="); }
                      ast::init_move { word_space(s, "<-"); }
                      ast::init_recv { word_space(s, "|>"); }
1095 1096
                    }
                    print_expr(s, init.expr);
1097 1098
                  }
                  _ { }
1099
                }
1100
            }
1101 1102
            fn local_span(&@ast::local loc) -> codemap::span { ret loc.span; }
            commasep_cmnt(s, consistent, locs, print_local, local_span);
1103
            end(s);
M
Marijn Haverbeke 已提交
1104
        }
1105
        case (ast::decl_item(?item)) { print_item(s, item); }
M
Marijn Haverbeke 已提交
1106
    }
1107 1108
}

1109
fn print_ident(&ps s, &ast::ident ident) { word(s.s, ident); }
1110

1111
fn print_for_decl(&ps s, @ast::local loc) {
1112
    word(s.s, loc.node.ident);
1113
    alt (loc.node.ty) {
1114 1115 1116 1117 1118
      some (?t) {
        word_space(s, ":");
        print_type(s, *t);
      }
      none {}
1119
    }
1120
    space(s.s);
M
Marijn Haverbeke 已提交
1121 1122
}

1123
fn print_path(&ps s, &ast::path path) {
1124
    maybe_print_comment(s, path.span.lo);
1125
    if path.node.global { word(s.s, "::"); }
1126 1127
    auto first = true;
    for (str id in path.node.idents) {
1128
        if (first) { first = false; } else { word(s.s, "::"); }
G
Graydon Hoare 已提交
1129
        word(s.s, id);
1130
    }
1131
    if (ivec::len(path.node.types) > 0u) {
G
Graydon Hoare 已提交
1132
        word(s.s, "[");
1133
        commasep(s, inconsistent, path.node.types, print_boxed_type);
G
Graydon Hoare 已提交
1134
        word(s.s, "]");
1135
    }
M
Marijn Haverbeke 已提交
1136 1137
}

1138
fn print_pat(&ps s, &@ast::pat pat) {
1139
    maybe_print_comment(s, pat.span.lo);
1140 1141
    auto ann_node = node_pat(s, pat);
    s.ann.pre(ann_node);
1142
    alt (pat.node) {
1143
        case (ast::pat_wild) { word(s.s, "_"); }
1144
        case (ast::pat_bind(?id)) { word(s.s, id); }
1145 1146
        case (ast::pat_lit(?lit)) { print_literal(s, lit); }
        case (ast::pat_tag(?path, ?args)) {
1147
            print_path(s, path);
1148
            if (ivec::len(args) > 0u) {
G
Graydon Hoare 已提交
1149
                popen(s);
1150
                commasep(s, inconsistent, args, print_pat);
1151
                pclose(s);
1152 1153
            } else {
                word(s.s, ".");
1154 1155
            }
        }
M
Marijn Haverbeke 已提交
1156
        case (ast::pat_rec(?fields, ?etc)) {
1157
            word(s.s, "{");
M
Marijn Haverbeke 已提交
1158 1159 1160
            fn print_field(&ps s, &ast::field_pat f) {
                cbox(s, indent_unit);
                word(s.s, f.ident);
1161
                word_space(s, ":");
M
Marijn Haverbeke 已提交
1162 1163 1164 1165 1166 1167
                print_pat(s, f.pat);
                end(s);
            }
            fn get_span(&ast::field_pat f) -> codemap::span {
                ret f.pat.span;
            }
1168
            commasep_cmnt(s, consistent, fields, print_field, get_span);
1169 1170 1171 1172
            if (etc) {
                if (ivec::len(fields) != 0u) { word_space(s, ","); }
                word(s.s, "_");
            }
1173
            word(s.s, "}");
M
Marijn Haverbeke 已提交
1174
        }
1175 1176 1177 1178
        case (ast::pat_box(?inner)) {
            word(s.s, "@");
            print_pat(s, inner);
        }
M
Marijn Haverbeke 已提交
1179
    }
1180
    s.ann.post(ann_node);
M
Marijn Haverbeke 已提交
1181 1182
}

G
Graydon Hoare 已提交
1183
fn print_fn(&ps s, ast::fn_decl decl, ast::proto proto, str name,
1184
            &ast::ty_param[] typarams) {
1185
    alt (decl.purity) {
1186
        case (ast::impure_fn) {
1187
            head(s, proto_to_str(proto));
1188
        }
1189
        case (_) { head(s, "pred"); }
1190
    }
G
Graydon Hoare 已提交
1191
    word(s.s, name);
1192
    print_type_params(s, typarams);
1193 1194 1195 1196
    print_fn_args_and_ret(s, decl);
}

fn print_fn_args_and_ret(&ps s, &ast::fn_decl decl) {
1197
    popen(s);
1198
    fn print_arg(&ps s, &ast::arg x) {
1199
        ibox(s, indent_unit);
1200
        word_space(s, x.ident + ":");
1201
        print_alias(s, x.mode);
1202
        print_type(s, *x.ty);
1203
        end(s);
1204
    }
1205
    commasep(s, inconsistent, decl.inputs, print_arg);
1206 1207
    pclose(s);
    maybe_print_comment(s, decl.output.span.lo);
1208
    if (decl.output.node != ast::ty_nil) {
1209
        space_if_not_bol(s);
G
Graydon Hoare 已提交
1210
        word_space(s, "->");
1211
        print_type(s, *decl.output);
1212
    }
M
Marijn Haverbeke 已提交
1213 1214
}

1215 1216 1217 1218
fn print_alias(&ps s, ast::mode m) {
    alt (m) {
        case (ast::alias(true)) { word_space(s, "&mutable"); }
        case (ast::alias(false)) { word(s.s, "&"); }
1219
        case (ast::val) { }
1220 1221 1222
    }
}

1223 1224
fn print_type_params(&ps s, &ast::ty_param[] params) {
    if (ivec::len(params) > 0u) {
G
Graydon Hoare 已提交
1225
        word(s.s, "[");
1226
        fn printParam(&ps s, &ast::ty_param param) { word(s.s, param); }
1227
        commasep(s, inconsistent, params, printParam);
G
Graydon Hoare 已提交
1228
        word(s.s, "]");
1229
    }
M
Marijn Haverbeke 已提交
1230 1231
}

1232 1233
fn print_meta_item(&ps s, &@ast::meta_item item) {
    ibox(s, indent_unit);
1234
    alt (item.node) {
1235 1236 1237 1238 1239
        case (ast::meta_word(?name)) {
            word(s.s, name);
        }
        case (ast::meta_name_value(?name, ?value)) {
            word_space(s, name);
1240
            word_space(s, "=");
1241
            print_literal(s, @value);
1242
        }
1243 1244 1245
        case (ast::meta_list(?name, ?items)) {
            word(s.s, name);
            popen(s);
1246
            commasep(s, consistent, items, print_meta_item);
1247
            pclose(s);
1248 1249
        }
    }
1250 1251 1252
    end(s);
}

1253
fn print_view_item(&ps s, &@ast::view_item item) {
1254
    hardbreak_if_not_bol(s);
1255 1256
    maybe_print_comment(s, item.span.lo);
    alt (item.node) {
1257
        case (ast::view_item_use(?id, ?mta, _)) {
G
Graydon Hoare 已提交
1258
            head(s, "use");
G
Graydon Hoare 已提交
1259
            word(s.s, id);
1260
            if (ivec::len(mta) > 0u) {
1261
                popen(s);
1262
                commasep(s, consistent, mta, print_meta_item);
1263 1264 1265
                pclose(s);
            }
        }
1266
        case (ast::view_item_import(?id, ?ids, _)) {
G
Graydon Hoare 已提交
1267
            head(s, "import");
1268
            if (!str::eq(id, ids.(ivec::len(ids) - 1u))) {
G
Graydon Hoare 已提交
1269 1270
                word_space(s, id);
                word_space(s, "=");
1271 1272 1273
            }
            auto first = true;
            for (str elt in ids) {
1274
                if (first) { first = false; } else { word(s.s, "::"); }
G
Graydon Hoare 已提交
1275
                word(s.s, elt);
1276 1277
            }
        }
1278
        case (ast::view_item_import_glob(?ids, _)) {
G
Graydon Hoare 已提交
1279 1280 1281
            head(s, "import");
            auto first = true;
            for (str elt in ids) {
1282
                if (first) { first = false; } else { word(s.s, "::"); }
G
Graydon Hoare 已提交
1283 1284 1285 1286
                word(s.s, elt);
            }
            word(s.s, "::*");
        }
1287
        case (ast::view_item_export(?id, _)) {
G
Graydon Hoare 已提交
1288
            head(s, "export");
G
Graydon Hoare 已提交
1289
            word(s.s, id);
1290
        }
M
Marijn Haverbeke 已提交
1291
    }
G
Graydon Hoare 已提交
1292
    word(s.s, ";");
1293
    end(s); // end inner head-block
1294

1295
    end(s); // end outer head-block
1296

M
Marijn Haverbeke 已提交
1297 1298
}

1299

M
Marijn Haverbeke 已提交
1300 1301
// FIXME: The fact that this builds up the table anew for every call is
// not good. Eventually, table should be a const.
1302
fn operator_prec(ast::binop op) -> int {
1303
    for (parse::parser::op_spec spec in *parse::parser::prec_table()) {
1304
        if (spec.op == op) { ret spec.prec; }
1305 1306
    }
    fail;
M
Marijn Haverbeke 已提交
1307 1308
}

1309
fn print_maybe_parens(&ps s, &@ast::expr expr, int outer_prec) {
1310 1311
    auto add_them;
    alt (expr.node) {
1312
        case (ast::expr_binary(?op, _, _)) {
1313 1314
            add_them = operator_prec(op) < outer_prec;
        }
1315
        case (ast::expr_cast(_, _)) {
1316
            add_them = parse::parser::as_prec < outer_prec;
1317
        }
1318
        case (ast::expr_ternary(_, _, _)) {
1319
            add_them = parse::parser::ternary_prec < outer_prec;
1320
        }
1321
        case (_) { add_them = false; }
M
Marijn Haverbeke 已提交
1322
    }
1323
    if (add_them) { popen(s); }
1324
    print_expr(s, expr);
1325
    if (add_them) { pclose(s); }
M
Marijn Haverbeke 已提交
1326 1327
}

G
Graydon Hoare 已提交
1328 1329
fn print_mutability(&ps s, &ast::mutability mut) {
    alt (mut) {
1330
        case (ast::mut) { word_nbsp(s, "mutable"); }
G
Graydon Hoare 已提交
1331
        case (ast::maybe_mut) { word_nbsp(s, "mutable?"); }
1332
        case (ast::imm) {/* nothing */ }
1333
    }
G
Graydon Hoare 已提交
1334 1335 1336 1337
}

fn print_mt(&ps s, &ast::mt mt) {
    print_mutability(s, mt.mut);
1338
    print_type(s, *mt.ty);
M
Marijn Haverbeke 已提交
1339 1340
}

1341
fn print_ty_fn(&ps s, &ast::proto proto, &option::t[str] id,
1342
               &ast::ty_arg[] inputs, &@ast::ty output,
1343
               &ast::controlflow cf, &(@ast::constr)[] constrs) {
1344
    ibox(s, indent_unit);
1345
    word(s.s, proto_to_str(proto));
1346
    alt (id) {
1347 1348
        case (some(?id)) { word(s.s, " "); word(s.s, id); }
        case (_) { }
1349
    }
G
Graydon Hoare 已提交
1350
    zerobreak(s.s);
G
Graydon Hoare 已提交
1351
    popen(s);
1352
    fn print_arg(&ps s, &ast::ty_arg input) {
1353
        print_alias(s, input.node.mode);
1354
        print_type(s, *input.node.ty);
1355
    }
1356
    commasep(s, inconsistent, inputs, print_arg);
1357 1358
    pclose(s);
    maybe_print_comment(s, output.span.lo);
1359
    if (output.node != ast::ty_nil) {
1360
        space_if_not_bol(s);
1361
        ibox(s, indent_unit);
G
Graydon Hoare 已提交
1362
        word_space(s, "->");
1363
        alt (cf) {
1364 1365
            case (ast::return) { print_type(s, *output); }
            case (ast::noreturn) { word_nbsp(s, "!"); }
1366
        }
1367
        end(s);
1368
    }
1369
    word_space(s, ast_constrs_str(constrs));
1370
    end(s);
1371 1372
}

1373
fn maybe_print_trailing_comment(&ps s, codemap::span span,
1374
                                option::t[uint] next_pos) {
1375
    auto cm;
1376
    alt (s.cm) { case (some(?ccm)) { cm = ccm; } case (_) { ret; } }
1377
    alt (next_comment(s)) {
1378
        case (some(?cmnt)) {
1379
            if (cmnt.style != lexer::trailing) { ret; }
1380 1381
            auto span_line = codemap::lookup_char_pos(cm, span.hi);
            auto comment_line = codemap::lookup_char_pos(cm, cmnt.pos);
1382
            auto next = cmnt.pos + 1u;
1383 1384
            alt (next_pos) { case (none) { } case (some(?p)) { next = p; } }
            if (span.hi < cmnt.pos && cmnt.pos < next &&
G
Graydon Hoare 已提交
1385
                span_line.line == comment_line.line) {
G
Graydon Hoare 已提交
1386
                print_comment(s, cmnt);
1387 1388 1389
                s.cur_cmnt += 1u;
            }
        }
1390
        case (_) { }
1391 1392 1393
    }
}

1394
fn print_remaining_comments(&ps s) {
1395 1396
    while (true) {
        alt (next_comment(s)) {
1397 1398
            case (some(?cmnt)) { print_comment(s, cmnt); s.cur_cmnt += 1u; }
            case (_) { break; }
1399 1400 1401 1402
        }
    }
}

1403
fn in_cbox(&ps s) -> bool {
1404
    auto len = ivec::len(s.boxes);
1405
    if (len == 0u) { ret false; }
1406
    ret s.boxes.(len - 1u) == pp::consistent;
1407
}
1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429

fn print_literal(&ps s, &@ast::lit lit) {
    maybe_print_comment(s, lit.span.lo);
    alt (next_lit(s)) {
        case (some(?lt)) {
            if (lt.pos == lit.span.lo) {
                word(s.s, lt.lit);
                s.cur_lit += 1u;
                ret;
            }
        }
        case (_) { }
    }
    alt (lit.node) {
        case (ast::lit_str(?st, ?kind)) {
            if (kind == ast::sk_unique) { word(s.s, "~"); }
            print_string(s, st);
        }
        case (ast::lit_char(?ch)) {
            word(s.s,
                 "'" + escape_str(str::from_bytes([ch as u8]), '\'') + "'");
        }
1430 1431
        case (ast::lit_int(?val)) { word(s.s, int::str(val)); }
        case (ast::lit_uint(?val)) { word(s.s, uint::str(val) + "u"); }
1432 1433
        case (ast::lit_float(?fstr)) { word(s.s, fstr); }
        case (ast::lit_mach_int(?mach, ?val)) {
1434
            word(s.s, int::str(val as int));
1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453
            word(s.s, ast::ty_mach_to_str(mach));
        }
        case (ast::lit_mach_float(?mach, ?val)) {
            // val is already a str
            word(s.s, val);
            word(s.s, ast::ty_mach_to_str(mach));
        }
        case (ast::lit_nil) { word(s.s, "()"); }
        case (ast::lit_bool(?val)) {
            if (val) { word(s.s, "true"); } else { word(s.s, "false"); }
        }
    }
}

fn lit_to_str(&@ast::lit l) -> str { be to_str(l, print_literal); }

fn next_lit(&ps s) -> option::t[lexer::lit] {
    alt (s.literals) {
        case (some(?lits)) {
1454
            if (s.cur_lit < ivec::len(lits)) {
1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478
                ret some(lits.(s.cur_lit));
            } else { ret none[lexer::lit]; }
        }
        case (_) { ret none[lexer::lit]; }
    }
}

fn maybe_print_comment(&ps s, uint pos) {
    while (true) {
        alt (next_comment(s)) {
            case (some(?cmnt)) {
                if (cmnt.pos < pos) {
                    print_comment(s, cmnt);
                    s.cur_cmnt += 1u;
                } else { break; }
            }
            case (_) { break; }
        }
    }
}

fn print_comment(&ps s, lexer::cmnt cmnt) {
    alt (cmnt.style) {
        case (lexer::mixed) {
1479
            assert (ivec::len(cmnt.lines) == 1u);
1480 1481 1482 1483 1484 1485 1486 1487 1488 1489
            zerobreak(s.s);
            word(s.s, cmnt.lines.(0));
            zerobreak(s.s);
        }
        case (lexer::isolated) {
            pprust::hardbreak_if_not_bol(s);
            for (str line in cmnt.lines) { word(s.s, line); hardbreak(s.s); }
        }
        case (lexer::trailing) {
            word(s.s, " ");
1490
            if (ivec::len(cmnt.lines) == 1u) {
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538
                word(s.s, cmnt.lines.(0));
                hardbreak(s.s);
            } else {
                ibox(s, 0u);
                for (str line in cmnt.lines) {
                    word(s.s, line);
                    hardbreak(s.s);
                }
                end(s);
            }
        }
        case (lexer::blank_line) {
            // We need to do at least one, possibly two hardbreaks.
            pprust::hardbreak_if_not_bol(s);
            hardbreak(s.s);
        }
    }
}

fn print_string(&ps s, &str st) {
    word(s.s, "\"");
    word(s.s, escape_str(st, '"'));
    word(s.s, "\"");
}

fn escape_str(str st, char to_escape) -> str {
    let str out = "";
    auto len = str::byte_len(st);
    auto i = 0u;
    while (i < len) {
        alt (st.(i) as char) {
            case ('\n') { out += "\\n"; }
            case ('\t') { out += "\\t"; }
            case ('\r') { out += "\\r"; }
            case ('\\') { out += "\\\\"; }
            case (?cur) {
                if (cur == to_escape) { out += "\\"; }
                // FIXME some (or all?) non-ascii things should be escaped

                str::push_char(out, cur);
            }
        }
        i += 1u;
    }
    ret out;
}

fn to_str[T](&T t, fn(&ps, &T)  f) -> str {
1539
    auto writer = ioivec::string_writer();
1540 1541 1542 1543 1544 1545 1546 1547 1548
    auto s = rust_printer(writer.get_writer());
    f(s, t);
    eof(s.s);
    ret writer.get_str();
}

fn next_comment(&ps s) -> option::t[lexer::cmnt] {
    alt (s.comments) {
        case (some(?cmnts)) {
1549
            if (s.cur_cmnt < ivec::len(cmnts)) {
1550 1551 1552 1553 1554 1555 1556
                ret some(cmnts.(s.cur_cmnt));
            } else { ret none[lexer::cmnt]; }
        }
        case (_) { ret none[lexer::cmnt]; }
    }
}

1557 1558 1559
// Removing the aliases from the type of f in the next two functions
// triggers memory corruption, but I haven't isolated the bug yet. FIXME
fn constr_args_to_str[T](&fn(&T) -> str f,
1560
                         &(@ast::sp_constr_arg[T])[] args) -> str {
1561 1562
    auto comma = false;
    auto s = "(";
1563
    for (@ast::sp_constr_arg[T] a in args) {
1564 1565 1566 1567 1568 1569 1570
        if (comma) { s += ", "; } else { comma = true; }
        s += constr_arg_to_str[T](f, a.node);
    }
    s += ")";
    ret s;
}

1571
fn constr_arg_to_str[T](&fn(&T) -> str f, &ast::constr_arg_general_[T] c) ->
1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582
   str {
    alt (c) {
        case (ast::carg_base) { ret "*"; }
        case (ast::carg_ident(?i)) { ret f(i); }
        case (ast::carg_lit(?l)) { ret lit_to_str(l); }
    }
}

// needed b/c constr_args_to_str needs
// something that takes an alias
// (argh)
1583
fn uint_to_str(&uint i) -> str { ret uint::str(i); }
1584 1585

fn ast_constr_to_str(&@ast::constr c) -> str {
1586 1587
    ret path_to_str(c.node.path) +
          constr_args_to_str(uint_to_str, c.node.args);
1588 1589
}

1590
// FIXME: fix repeated code
1591
fn ast_constrs_str(&(@ast::constr)[] constrs) -> str {
1592 1593 1594 1595 1596 1597 1598 1599 1600
    auto s = "";
    auto colon = true;
    for (@ast::constr c in constrs) {
        if (colon) { s += " : "; colon = false; } else { s += ", "; }
        s += ast_constr_to_str(c);
    }
    ret s;
}

1601 1602 1603 1604
fn proto_to_str(&ast::proto p) -> str {
    ret alt (p) {
        ast::proto_fn { "fn" }
        ast::proto_iter { "iter" }
1605 1606
        ast::proto_block { "block" }
        ast::proto_closure { "lambda" }
1607 1608 1609
    };
}

1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625
fn ty_constr_to_str(&@ast::ty_constr c) -> str {
    ret path_to_str(c.node.path) +
          constr_args_to_str[ast::path](path_to_str, c.node.args);
}


fn ast_ty_constrs_str(&(@ast::ty_constr)[] constrs) -> str {
    auto s = "";
    auto colon = true;
    for (@ast::ty_constr c in constrs) {
        if (colon) { s += " : "; colon = false; } else { s += ", "; }
        s += ty_constr_to_str(c);
    }
    ret s;
}

1626 1627 1628 1629 1630 1631 1632 1633 1634 1635
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//