pprust.rs 47.3 KB
Newer Older
1

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

27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
// The ps is stored here to prevent recursive type.
// FIXME use a nominal tag instead
tag ann_node {
    node_block(ps, ast::block);
    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,
         option::t[vec[lexer::cmnt]] comments,
         option::t[vec[lexer::lit]] literals,
         mutable uint cur_cmnt,
         mutable uint cur_lit,
         mutable vec[pp::breaks] boxes,
         pp_ann ann);

fn ibox(&ps s, uint u) {
    vec::push(s.boxes, pp::inconsistent);
    pp::ibox(s.s, u);
}

fn end(&ps s) { vec::pop(s.boxes); pp::end(s.s); }

fn rust_printer(io::writer writer) -> ps {
    let vec[pp::breaks] boxes = [];
    ret @rec(s=pp::mk_printer(writer, default_columns),
             cm=none[codemap],
             comments=none[vec[lexer::cmnt]],
             literals=none[vec[lexer::lit]],
             mutable cur_cmnt=0u,
             mutable cur_lit=0u,
             mutable boxes=boxes,
             ann=no_ann());
}

const uint indent_unit = 4u;

const uint default_columns = 78u;

fn print_crate(&codemap cm, @ast::crate crate, str filename,
77
               io::writer out, &pp_ann ann) {
78
    let vec[pp::breaks] boxes = [];
79
    auto r = lexer::gather_comments_and_literals(cm, filename);
80 81
    auto s =
        @rec(s=pp::mk_printer(out, default_columns),
82
             cm=some(cm),
83 84 85 86 87
             comments=some(r.cmnts),
             literals=some(r.lits),
             mutable cur_cmnt=0u,
             mutable cur_lit=0u,
             mutable boxes=boxes,
88
             ann=ann);
89
    print_mod(s, crate.node.module, crate.node.attrs);
90
    print_remaining_comments(s);
G
Graydon Hoare 已提交
91
    eof(s.s);
M
Marijn Haverbeke 已提交
92 93
}

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

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

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

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

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

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

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

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

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

122
    ibox(s, 0u);
123
    print_block(s, blk);
G
Graydon Hoare 已提交
124
    eof(s.s);
125 126 127
    ret writer.get_str();
}

128 129 130 131
fn meta_item_to_str(&ast::meta_item mi) -> str {
    ret to_str(@mi, print_meta_item);
}

132 133 134 135
fn attribute_to_str(&ast::attribute attr) -> str {
    be to_str(attr, print_attribute);
}

136 137 138 139 140 141 142 143 144 145
fn cbox(&ps s, uint u) {
    vec::push(s.boxes, pp::consistent);
    pp::cbox(s.s, u);
}

fn box(&ps s, uint u, pp::breaks b) {
    vec::push(s.boxes, b);
    pp::box(s.s, u, b);
}

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

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

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

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

154
fn head(&ps s, str w) {
G
Graydon Hoare 已提交
155
    // outer-box is consistent
156
    cbox(s, indent_unit);
G
Graydon Hoare 已提交
157
    // head-box is inconsistent
158
    ibox(s, str::char_len(w) + 1u);
G
Graydon Hoare 已提交
159
    // keyword that starts the head
G
Graydon Hoare 已提交
160
    word_nbsp(s, w);
G
Graydon Hoare 已提交
161 162
}

163
fn bopen(&ps s) {
G
Graydon Hoare 已提交
164
    word(s.s, "{");
165
    end(s); // close the head-box
166

167
}
G
Graydon Hoare 已提交
168

169
fn bclose(&ps s, codemap::span span) {
170
    maybe_print_comment(s, span.hi);
G
Graydon Hoare 已提交
171
    break_offset(s.s, 1u, -(indent_unit as int));
G
Graydon Hoare 已提交
172
    word(s.s, "}");
173
    end(s); // close the outer-box
174

M
Marijn Haverbeke 已提交
175
}
G
Graydon Hoare 已提交
176

177 178 179
fn hardbreak_if_not_bol(&ps s) {
    if (s.s.last_token() != pp::EOF &&
        s.s.last_token() != pp::hardbreak_tok()) {
180 181 182 183
        hardbreak(s.s);
    }
}

184 185 186 187 188
fn space_if_not_hardbreak(&ps s) {
    if (s.s.last_token() != pp::hardbreak_tok()) {
        space(s.s);
    }
}
189

190 191 192 193 194 195 196 197 198 199
// 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, "*/");
}

200
fn commasep[IN](&ps s, breaks b, vec[IN] elts, fn(&ps, &IN)  op) {
201
    box(s, 0u, b);
202 203
    auto first = true;
    for (IN elt in elts) {
204
        if (first) { first = false; } else { word_space(s, ","); }
205 206
        op(s, elt);
    }
207
    end(s);
M
Marijn Haverbeke 已提交
208
}
G
Graydon Hoare 已提交
209

210 211 212 213 214 215 216 217 218 219 220
fn commasep_ivec[IN](&ps s, breaks b, &IN[] elts, fn(&ps, &IN)  op) {
    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);
}


221
fn commasep_cmnt[IN](&ps s, breaks b, vec[IN] elts, fn(&ps, &IN)  op,
222
                     fn(&IN) -> codemap::span  get_span) {
223
    box(s, 0u, b);
224
    auto len = vec::len[IN](elts);
225 226
    auto i = 0u;
    for (IN elt in elts) {
227
        maybe_print_comment(s, get_span(elt).hi);
228 229 230
        op(s, elt);
        i += 1u;
        if (i < len) {
G
Graydon Hoare 已提交
231
            word(s.s, ",");
232 233
            maybe_print_trailing_comment(s, get_span(elt),
                                         some(get_span(elts.(i)).hi));
234
            space_if_not_hardbreak(s);
235 236
        }
    }
237
    end(s);
238
}
G
Graydon Hoare 已提交
239

240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
// TODO: Remove me.
fn commasep_cmnt_ivec[IN](&ps s, breaks b, &IN[] elts, fn(&ps, &IN)  op,
                          fn(&IN) -> codemap::span  get_span) {
    box(s, 0u, b);
    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));
            space_if_not_hardbreak(s);
        }
    }
    end(s);
}

260
fn commasep_exprs(&ps s, breaks b, &(@ast::expr)[] exprs) {
261
    fn expr_span(&@ast::expr expr) -> codemap::span { ret expr.span; }
262
    commasep_cmnt_ivec(s, b, exprs, print_expr, expr_span);
263
}
M
Marijn Haverbeke 已提交
264

265
fn print_mod(&ps s, ast::_mod _mod, &ast::attribute[] attrs) {
266
    print_inner_attributes(s, attrs);
267 268 269
    for (@ast::view_item vitem in _mod.view_items) {
        print_view_item(s, vitem);
    }
G
Graydon Hoare 已提交
270
    for (@ast::item item in _mod.items) {
271
        hardbreak_if_not_bol(s);
G
Graydon Hoare 已提交
272 273
        print_item(s, item);
    }
274 275
}

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

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

372
fn print_item(&ps s, &@ast::item item) {
373
    hardbreak_if_not_bol(s);
374
    maybe_print_comment(s, item.span.lo);
375
    print_outer_attributes(s, item.attrs);
376 377
    auto ann_node = node_item(s, item);
    s.ann.pre(ann_node);
378
    alt (item.node) {
379
        case (ast::item_const(?ty, ?expr)) {
G
Graydon Hoare 已提交
380
            head(s, "const");
381
            print_type(s, *ty);
382
            space(s.s);
383
            word_space(s, item.ident);
384
            end(s); // end the head-ibox
385

G
Graydon Hoare 已提交
386
            word_space(s, "=");
387
            print_expr(s, expr);
G
Graydon Hoare 已提交
388
            word(s.s, ";");
389
            end(s); // end the outer cbox
390

391
        }
392 393
        case (ast::item_fn(?_fn, ?typarams)) {
            print_fn(s, _fn.decl, _fn.proto, item.ident, typarams);
G
Graydon Hoare 已提交
394
            word(s.s, " ");
395 396
            print_block(s, _fn.body);
        }
397
        case (ast::item_mod(?_mod)) {
G
Graydon Hoare 已提交
398
            head(s, "mod");
399
            word_nbsp(s, item.ident);
400
            bopen(s);
401
            print_mod(s, _mod, item.attrs);
G
Graydon Hoare 已提交
402
            bclose(s, item.span);
403
        }
404
        case (ast::item_native_mod(?nmod)) {
G
Graydon Hoare 已提交
405
            head(s, "native");
406
            alt (nmod.abi) {
407
                case (ast::native_abi_llvm) { word_nbsp(s, "\"llvm\""); }
408 409
                case (ast::native_abi_rust) { word_nbsp(s, "\"rust\""); }
                case (ast::native_abi_cdecl) { word_nbsp(s, "\"cdecl\""); }
410
                case (ast::native_abi_rust_intrinsic) {
G
Graydon Hoare 已提交
411
                    word_nbsp(s, "\"rust-intrinsic\"");
412
                }
413
            }
G
Graydon Hoare 已提交
414
            word_nbsp(s, "mod");
415
            word_nbsp(s, item.ident);
416
            bopen(s);
417
            print_inner_attributes(s, item.attrs);
418
            for (@ast::native_item item in nmod.items) {
419
                hardbreak_if_not_bol(s);
420
                print_outer_attributes(s, item.attrs);
421
                ibox(s, indent_unit);
422 423
                maybe_print_comment(s, item.span.lo);
                alt (item.node) {
424
                    case (ast::native_item_ty) {
G
Graydon Hoare 已提交
425
                        word_nbsp(s, "type");
426
                        word(s.s, item.ident);
427
                    }
428 429 430
                    case (ast::native_item_fn(?lname, ?decl, ?typarams)) {
                        print_fn(s, decl, ast::proto_fn, item.ident,
                                 typarams);
431
                        alt (lname) {
432
                            case (none) { }
433 434 435 436 437
                            case (some(?ss)) {
                                space(s.s);
                                word_space(s, "=");
                                print_string(s, ss);
                            }
438
                        }
G
Graydon Hoare 已提交
439
                        end(s); // end head-ibox
440

G
Graydon Hoare 已提交
441
                        end(s); // end the outer fn box
442

443 444
                    }
                }
G
Graydon Hoare 已提交
445
                word(s.s, ";");
446
                end(s);
447
            }
G
Graydon Hoare 已提交
448
            bclose(s, item.span);
449
        }
450
        case (ast::item_ty(?ty, ?params)) {
451 452
            ibox(s, indent_unit);
            ibox(s, 0u);
G
Graydon Hoare 已提交
453
            word_nbsp(s, "type");
454
            word(s.s, item.ident);
455
            print_type_params(s, params);
456
            end(s); // end the inner ibox
457

458
            space(s.s);
G
Graydon Hoare 已提交
459
            word_space(s, "=");
460
            print_type(s, *ty);
G
Graydon Hoare 已提交
461
            word(s.s, ";");
462
            end(s); // end the outer ibox
463

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

558
fn print_outer_attributes(&ps s, &ast::attribute[] attrs) {
559 560 561
    auto count = 0;
    for (ast::attribute attr in attrs) {
        alt (attr.node.style) {
562 563
            case (ast::attr_outer) { print_attribute(s, attr); count += 1; }
            case (_) {/* fallthrough */ }
564 565
        }
    }
566
    if (count > 0) { hardbreak_if_not_bol(s); }
567 568
}

569
fn print_inner_attributes(&ps s, &ast::attribute[] attrs) {
570 571 572 573 574 575 576 577 578 579 580
    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 */ }
        }
    }
581
    if (count > 0) { hardbreak_if_not_bol(s); }
582 583
}

584
fn print_attribute(&ps s, &ast::attribute attr) {
585
    hardbreak_if_not_bol(s);
586 587 588 589 590 591
    maybe_print_comment(s, attr.span.lo);
    word(s.s, "#[");
    print_meta_item(s, @attr.node.value);
    word(s.s, "]");
}

592 593 594
fn print_stmt(&ps s, &ast::stmt st) {
    maybe_print_comment(s, st.span.lo);
    alt (st.node) {
595
        case (ast::stmt_decl(?decl, _)) { print_decl(s, decl); }
596 597 598 599
        case (ast::stmt_expr(?expr, _)) {
            space_if_not_hardbreak(s);
            print_expr(s, expr);
        }
600
    }
601
    if (parse::parser::stmt_ends_with_semi(st)) { word(s.s, ";"); }
602
    maybe_print_trailing_comment(s, st.span, none[uint]);
603 604 605
}

fn print_block(&ps s, ast::block blk) {
606
    maybe_print_comment(s, blk.span.lo);
607 608
    auto ann_node = node_block(s, blk);
    s.ann.pre(ann_node);
609
    bopen(s);
610
    for (@ast::stmt st in blk.node.stmts) { print_stmt(s, *st) }
611
    alt (blk.node.expr) {
612
        case (some(?expr)) {
613
            space_if_not_hardbreak(s);
614
            print_expr(s, expr);
615
            maybe_print_trailing_comment(s, expr.span, some(blk.span.hi));
616
        }
617
        case (_) { }
M
Marijn Haverbeke 已提交
618
    }
G
Graydon Hoare 已提交
619
    bclose(s, blk.span);
620
    s.ann.post(ann_node);
M
Marijn Haverbeke 已提交
621 622
}

T
Tim Chevalier 已提交
623
fn print_if(&ps s, &@ast::expr test, &ast::block block,
624
            &option::t[@ast::expr] elseopt, bool chk) {
T
Tim Chevalier 已提交
625
    head(s, "if");
626 627 628
    if (chk) {
        word_nbsp(s, "check");
    }
T
Tim Chevalier 已提交
629 630 631 632 633 634 635 636 637
    popen(s);
    print_expr(s, test);
    pclose(s);
    space(s.s);
    print_block(s, block);
    fn do_else(&ps s, option::t[@ast::expr] els) {
        alt (els) {
            case (some(?_else)) {
                alt (_else.node) {
638 639
                    // "another else-if"
                    case (ast::expr_if(?i, ?t, ?e)) {
T
Tim Chevalier 已提交
640 641 642 643 644 645 646 647 648 649
                        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);
                    }
650 651
                    // "final else"
                    case (ast::expr_block(?b)) {
T
Tim Chevalier 已提交
652 653 654 655 656 657 658 659 660 661 662 663 664
                        cbox(s, indent_unit - 1u);
                        ibox(s, 0u);
                        word(s.s, " else ");
                        print_block(s, b);
                    }
                }
            }
            case (_) {/* fall through */ }
        }
    }
    do_else(s, elseopt);
}

665
fn print_expr(&ps s, &@ast::expr expr) {
666
    maybe_print_comment(s, expr.span.lo);
667
    ibox(s, indent_unit);
668 669
    auto ann_node = node_expr(s, expr);
    s.ann.pre(ann_node);
670
    alt (expr.node) {
671
        case (ast::expr_vec(?exprs, ?mut, ?kind)) {
672
            ibox(s, indent_unit);
673 674 675 676
            alt (kind) {
                case (ast::sk_rc) { word(s.s, "["); }
                case (ast::sk_unique) { word(s.s, "~["); }
            }
677
            if (mut == ast::mut) { word_nbsp(s, "mutable"); }
678
            commasep_exprs(s, inconsistent, exprs);
G
Graydon Hoare 已提交
679
            word(s.s, "]");
680
            end(s);
681
        }
682
        case (ast::expr_tup(?exprs)) {
683
            fn printElt(&ps s, &ast::elt elt) {
684
                ibox(s, indent_unit);
685
                if (elt.mut == ast::mut) { word_nbsp(s, "mutable"); }
686
                print_expr(s, elt.expr);
687
                end(s);
688
            }
689
            fn get_span(&ast::elt elt) -> codemap::span { ret elt.expr.span; }
G
Graydon Hoare 已提交
690
            word(s.s, "tup");
691
            popen(s);
692
            commasep_cmnt_ivec(s, inconsistent, exprs, printElt, get_span);
693 694
            pclose(s);
        }
695
        case (ast::expr_rec(?fields, ?wth)) {
696
            fn print_field(&ps s, &ast::field field) {
697
                ibox(s, indent_unit);
698
                if (field.node.mut == ast::mut) { word_nbsp(s, "mutable"); }
699
                word(s.s, field.node.ident);
G
Graydon Hoare 已提交
700
                word(s.s, "=");
701
                print_expr(s, field.node.expr);
702
                end(s);
703
            }
704 705 706
            fn get_span(&ast::field field) -> codemap::span {
                ret field.span;
            }
G
Graydon Hoare 已提交
707
            word(s.s, "rec");
708
            popen(s);
709
            commasep_cmnt_ivec(s, consistent, fields, print_field, get_span);
710
            alt (wth) {
711
                case (some(?expr)) {
712
                    if (ivec::len(fields) > 0u) { space(s.s); }
713
                    ibox(s, indent_unit);
G
Graydon Hoare 已提交
714
                    word_space(s, "with");
715
                    print_expr(s, expr);
716
                    end(s);
717
                }
718
                case (_) { }
719 720 721
            }
            pclose(s);
        }
722
        case (ast::expr_call(?func, ?args)) {
723 724
            print_expr(s, func);
            popen(s);
725
            commasep_exprs(s, inconsistent, args);
726 727
            pclose(s);
        }
728
        case (ast::expr_self_method(?ident)) {
G
Graydon Hoare 已提交
729
            word(s.s, "self.");
730
            print_ident(s, ident);
731
        }
732
        case (ast::expr_bind(?func, ?args)) {
733
            fn print_opt(&ps s, &option::t[@ast::expr] expr) {
734
                alt (expr) {
735 736
                    case (some(?expr)) { print_expr(s, expr); }
                    case (_) { word(s.s, "_"); }
737 738
                }
            }
G
Graydon Hoare 已提交
739
            word_nbsp(s, "bind");
740 741
            print_expr(s, func);
            popen(s);
742
            commasep_ivec(s, inconsistent, args, print_opt);
743 744
            pclose(s);
        }
745
        case (ast::expr_spawn(_, _, ?e, ?es)) {
746 747 748 749 750
            word_nbsp(s, "spawn");
            print_expr(s, e);
            popen(s);
            commasep_exprs(s, inconsistent, es);
            pclose(s);
751
        }
752
        case (ast::expr_binary(?op, ?lhs, ?rhs)) {
753 754 755
            auto prec = operator_prec(op);
            print_maybe_parens(s, lhs, prec);
            space(s.s);
G
Graydon Hoare 已提交
756
            word_space(s, ast::binop_to_str(op));
757 758
            print_maybe_parens(s, rhs, prec + 1);
        }
759
        case (ast::expr_unary(?op, ?expr)) {
G
Graydon Hoare 已提交
760
            word(s.s, ast::unop_to_str(op));
761
            print_maybe_parens(s, expr, parse::parser::unop_prec);
M
Marijn Haverbeke 已提交
762
        }
763 764
        case (ast::expr_lit(?lit)) { print_literal(s, lit); }
        case (ast::expr_cast(?expr, ?ty)) {
765
            print_maybe_parens(s, expr, parse::parser::as_prec);
766
            space(s.s);
G
Graydon Hoare 已提交
767
            word_space(s, "as");
768
            print_type(s, *ty);
769
        }
770
        case (ast::expr_if(?test, ?block, ?elseopt)) {
771
            print_if(s, test, block, elseopt, false);
T
Tim Chevalier 已提交
772
        }
773
        case (ast::expr_if_check(?test, ?block, ?elseopt)) {
774
            print_if(s, test, block, elseopt, true);
775
        }
776 777 778 779 780 781 782 783 784
        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);
        }
785
        case (ast::expr_while(?test, ?block)) {
G
Graydon Hoare 已提交
786 787
            head(s, "while");
            popen(s);
788 789 790 791 792
            print_expr(s, test);
            pclose(s);
            space(s.s);
            print_block(s, block);
        }
793
        case (ast::expr_for(?decl, ?expr, ?block)) {
G
Graydon Hoare 已提交
794 795
            head(s, "for");
            popen(s);
796 797
            print_for_decl(s, decl);
            space(s.s);
G
Graydon Hoare 已提交
798
            word_space(s, "in");
799 800 801 802 803
            print_expr(s, expr);
            pclose(s);
            space(s.s);
            print_block(s, block);
        }
804
        case (ast::expr_for_each(?decl, ?expr, ?block)) {
G
Graydon Hoare 已提交
805 806
            head(s, "for each");
            popen(s);
807 808
            print_for_decl(s, decl);
            space(s.s);
G
Graydon Hoare 已提交
809
            word_space(s, "in");
810 811 812 813 814
            print_expr(s, expr);
            pclose(s);
            space(s.s);
            print_block(s, block);
        }
815
        case (ast::expr_do_while(?block, ?expr)) {
G
Graydon Hoare 已提交
816
            head(s, "do");
817 818 819
            space(s.s);
            print_block(s, block);
            space(s.s);
G
Graydon Hoare 已提交
820 821
            word_space(s, "while");
            popen(s);
822 823 824
            print_expr(s, expr);
            pclose(s);
        }
825
        case (ast::expr_alt(?expr, ?arms)) {
G
Graydon Hoare 已提交
826 827
            head(s, "alt");
            popen(s);
828 829 830 831
            print_expr(s, expr);
            pclose(s);
            space(s.s);
            bopen(s);
832
            for (ast::arm arm in arms) {
G
Graydon Hoare 已提交
833 834
                space(s.s);
                head(s, "case");
835 836 837 838 839 840
                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);
                }
841 842 843
                space(s.s);
                print_block(s, arm.block);
            }
G
Graydon Hoare 已提交
844
            bclose(s, expr.span);
845
        }
846
        case (ast::expr_fn(?f)) {
847 848 849 850 851
            head(s, "fn");
            print_fn_args_and_ret(s, f.decl);
            space(s.s);
            print_block(s, f.body);
        }
852
        case (ast::expr_block(?block)) {
G
Graydon Hoare 已提交
853 854
            // containing cbox, will be closed by print-block at }

855
            cbox(s, indent_unit);
G
Graydon Hoare 已提交
856
            // head-box, will be closed by print-block after {
857

858
            ibox(s, 0u);
859 860
            print_block(s, block);
        }
861
        case (ast::expr_move(?lhs, ?rhs)) {
862 863
            print_expr(s, lhs);
            space(s.s);
M
Michael Sullivan 已提交
864
            word_space(s, "<-");
865 866
            print_expr(s, rhs);
        }
867
        case (ast::expr_assign(?lhs, ?rhs)) {
868 869
            print_expr(s, lhs);
            space(s.s);
G
Graydon Hoare 已提交
870
            word_space(s, "=");
871 872
            print_expr(s, rhs);
        }
873
        case (ast::expr_swap(?lhs, ?rhs)) {
874 875 876 877 878
            print_expr(s, lhs);
            space(s.s);
            word_space(s, "<->");
            print_expr(s, rhs);
        }
879
        case (ast::expr_assign_op(?op, ?lhs, ?rhs)) {
880 881
            print_expr(s, lhs);
            space(s.s);
G
Graydon Hoare 已提交
882
            word(s.s, ast::binop_to_str(op));
G
Graydon Hoare 已提交
883
            word_space(s, "=");
884 885
            print_expr(s, rhs);
        }
886
        case (ast::expr_send(?lhs, ?rhs)) {
887 888
            print_expr(s, lhs);
            space(s.s);
G
Graydon Hoare 已提交
889
            word_space(s, "<|");
890 891
            print_expr(s, rhs);
        }
892
        case (ast::expr_recv(?lhs, ?rhs)) {
893
            print_expr(s, lhs);
894
            space(s.s);
G
Graydon Hoare 已提交
895
            word_space(s, "|>");
896
            print_expr(s, rhs);
897
        }
898
        case (ast::expr_field(?expr, ?id)) {
899
            print_expr(s, expr);
G
Graydon Hoare 已提交
900 901
            word(s.s, ".");
            word(s.s, id);
902
        }
903
        case (ast::expr_index(?expr, ?index)) {
904
            print_expr(s, expr);
G
Graydon Hoare 已提交
905
            word(s.s, ".");
G
Graydon Hoare 已提交
906
            popen(s);
907 908 909
            print_expr(s, index);
            pclose(s);
        }
910
        case (ast::expr_path(?path)) { print_path(s, path); }
911
        case (ast::expr_fail(?maybe_fail_val)) {
G
Graydon Hoare 已提交
912
            word(s.s, "fail");
913 914
            alt (maybe_fail_val) {
                case (some(?expr)) { word(s.s, " "); print_expr(s, expr); }
915
                case (_) { }
J
Josh Matthews 已提交
916
            }
917
        }
918 919 920
        case (ast::expr_break) { word(s.s, "break"); }
        case (ast::expr_cont) { word(s.s, "cont"); }
        case (ast::expr_ret(?result)) {
G
Graydon Hoare 已提交
921
            word(s.s, "ret");
922
            alt (result) {
923 924
                case (some(?expr)) { word(s.s, " "); print_expr(s, expr); }
                case (_) { }
925 926
            }
        }
927
        case (ast::expr_put(?result)) {
G
Graydon Hoare 已提交
928
            word(s.s, "put");
929
            alt (result) {
930 931
                case (some(?expr)) { word(s.s, " "); print_expr(s, expr); }
                case (_) { }
932 933
            }
        }
934
        case (ast::expr_be(?result)) {
G
Graydon Hoare 已提交
935
            word_nbsp(s, "be");
936 937
            print_expr(s, result);
        }
938
        case (ast::expr_log(?lvl, ?expr)) {
M
Marijn Haverbeke 已提交
939
            alt (lvl) {
940 941
                case (1) { word_nbsp(s, "log"); }
                case (0) { word_nbsp(s, "log_err"); }
M
Marijn Haverbeke 已提交
942
            }
943 944
            print_expr(s, expr);
        }
T
Tim Chevalier 已提交
945 946 947 948 949 950 951 952 953
        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 已提交
954
            popen(s);
955 956 957
            print_expr(s, expr);
            pclose(s);
        }
958
        case (ast::expr_assert(?expr)) {
G
Graydon Hoare 已提交
959 960
            word_nbsp(s, "assert");
            popen(s);
961 962 963
            print_expr(s, expr);
            pclose(s);
        }
964
        case (ast::expr_ext(?path, ?args, ?body, _)) {
G
Graydon Hoare 已提交
965
            word(s.s, "#");
966
            print_path(s, path);
967
            if (ivec::len(args) > 0u) {
968
                popen(s);
969
                commasep_exprs(s, inconsistent, args);
970 971 972
                pclose(s);
            }
            // FIXME: extension 'body'
973

974
        }
975
        case (ast::expr_port(?ot)) {
G
Graydon Hoare 已提交
976
            word(s.s, "port");
977 978 979 980 981 982 983 984
            alt(ot) {
                case(some(?t)) {
                    word(s.s, "[");
                    print_type(s, *t);
                    word(s.s, "]");
                }
                case(none) {}
            }
G
Graydon Hoare 已提交
985
            popen(s); pclose(s);
986
        }
987
        case (ast::expr_chan(?expr)) {
G
Graydon Hoare 已提交
988
            word(s.s, "chan");
G
Graydon Hoare 已提交
989
            popen(s);
990 991
            print_expr(s, expr);
            pclose(s);
M
Marijn Haverbeke 已提交
992
        }
993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
        case (ast::expr_anon_obj(?anon_obj, ?tps)) {
            head(s, "obj");
            print_type_params(s, tps);

            // Fields
            popen(s);
            fn print_field(&ps s, &ast::anon_obj_field field) {
                ibox(s, indent_unit);
                print_mutability(s, field.mut);
                print_type(s, *field.ty);
                space(s.s);
                word(s.s, field.ident);
                word_space(s, "=");
                print_expr(s, field.expr);
                end(s);
            }
            fn get_span(&ast::anon_obj_field f) -> codemap::span { 
                ret f.ty.span; 
            }
            alt (anon_obj.fields) {
                case (none) { }
                case (some(?fields)) {
                    commasep_cmnt_ivec(s, consistent, fields, print_field, 
                                       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);
1034

1035 1036 1037 1038 1039 1040 1041 1042 1043
            // With object
            alt (anon_obj.with_obj) {
                case (none) { }
                case (some(?e)) {
                    word_space(s, "with");
                    print_expr(s, e);
                }
            }
            bclose(s, expr.span);
1044
        }
1045
    }
1046
    s.ann.post(ann_node);
1047
    end(s);
M
Marijn Haverbeke 已提交
1048 1049
}

1050
fn print_decl(&ps s, &@ast::decl decl) {
1051 1052
    maybe_print_comment(s, decl.span.lo);
    alt (decl.node) {
1053
        case (ast::decl_local(?loc)) {
1054
            space_if_not_hardbreak(s);
1055
            ibox(s, indent_unit);
P
Paul Stansifer 已提交
1056
            alt (loc.node.ty) {
1057
                case (some(?ty)) {
G
Graydon Hoare 已提交
1058
                    word_nbsp(s, "let");
1059
                    print_type(s, *ty);
1060 1061 1062
                    space(s.s);
                }
                case (_) {
G
Graydon Hoare 已提交
1063
                    word_nbsp(s, "auto");
1064
                }
1065
            }
P
Paul Stansifer 已提交
1066 1067
            word(s.s, loc.node.ident);
            alt (loc.node.init) {
1068
                case (some(?init)) {
1069 1070
                    space(s.s);
                    alt (init.op) {
1071 1072 1073
                        case (ast::init_assign) { word_space(s, "="); }
                        case (ast::init_move) { word_space(s, "<-"); }
                        case (ast::init_recv) { word_space(s, "|>"); }
1074 1075 1076
                    }
                    print_expr(s, init.expr);
                }
1077
                case (_) { }
1078
            }
1079
            end(s);
M
Marijn Haverbeke 已提交
1080
        }
1081
        case (ast::decl_item(?item)) { print_item(s, item); }
M
Marijn Haverbeke 已提交
1082
    }
1083 1084
}

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

1087
fn print_for_decl(&ps s, @ast::local loc) {
1088
    print_type(s, *option::get(loc.node.ty));
1089 1090
    space(s.s);
    word(s.s, loc.node.ident);
M
Marijn Haverbeke 已提交
1091 1092
}

1093
fn print_path(&ps s, &ast::path path) {
1094 1095 1096
    maybe_print_comment(s, path.span.lo);
    auto first = true;
    for (str id in path.node.idents) {
1097
        if (first) { first = false; } else { word(s.s, "::"); }
G
Graydon Hoare 已提交
1098
        word(s.s, id);
1099
    }
1100
    if (ivec::len(path.node.types) > 0u) {
G
Graydon Hoare 已提交
1101
        word(s.s, "[");
1102
        commasep_ivec(s, inconsistent, path.node.types, print_boxed_type);
G
Graydon Hoare 已提交
1103
        word(s.s, "]");
1104
    }
M
Marijn Haverbeke 已提交
1105 1106
}

1107
fn print_pat(&ps s, &@ast::pat pat) {
1108
    maybe_print_comment(s, pat.span.lo);
1109 1110
    auto ann_node = node_pat(s, pat);
    s.ann.pre(ann_node);
1111
    alt (pat.node) {
1112 1113 1114 1115
        case (ast::pat_wild) { word(s.s, "_"); }
        case (ast::pat_bind(?id)) { word(s.s, "?" + id); }
        case (ast::pat_lit(?lit)) { print_literal(s, lit); }
        case (ast::pat_tag(?path, ?args)) {
1116
            print_path(s, path);
1117
            if (ivec::len(args) > 0u) {
G
Graydon Hoare 已提交
1118
                popen(s);
1119
                commasep_ivec(s, inconsistent, args, print_pat);
1120 1121 1122
                pclose(s);
            }
        }
M
Marijn Haverbeke 已提交
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
        case (ast::pat_rec(?fields, ?etc)) {
            bopen(s);
            fn print_field(&ps s, &ast::field_pat f) {
                cbox(s, indent_unit);
                word(s.s, f.ident);
                word(s.s, ":");
                print_pat(s, f.pat);
                end(s);
            }
            fn get_span(&ast::field_pat f) -> codemap::span {
                ret f.pat.span;
            }
            commasep_cmnt_ivec(s, consistent, fields, print_field, get_span);
            if (etc) { space(s.s); word(s.s, "..."); }
            bclose(s, pat.span);
        }
M
Marijn Haverbeke 已提交
1139
    }
1140
    s.ann.post(ann_node);
M
Marijn Haverbeke 已提交
1141 1142
}

G
Graydon Hoare 已提交
1143
fn print_fn(&ps s, ast::fn_decl decl, ast::proto proto, str name,
1144
            &ast::ty_param[] typarams) {
1145
    alt (decl.purity) {
1146
        case (ast::impure_fn) {
G
Graydon Hoare 已提交
1147 1148
            if (proto == ast::proto_iter) {
                head(s, "iter");
1149
            } else { head(s, "fn"); }
1150
        }
1151
        case (_) { head(s, "pred"); }
1152
    }
G
Graydon Hoare 已提交
1153
    word(s.s, name);
1154
    print_type_params(s, typarams);
1155 1156 1157 1158
    print_fn_args_and_ret(s, decl);
}

fn print_fn_args_and_ret(&ps s, &ast::fn_decl decl) {
1159
    popen(s);
1160
    fn print_arg(&ps s, &ast::arg x) {
1161
        ibox(s, indent_unit);
1162
        print_alias(s, x.mode);
1163
        print_type(s, *x.ty);
1164
        space(s.s);
G
Graydon Hoare 已提交
1165
        word(s.s, x.ident);
1166
        end(s);
1167
    }
1168
    commasep_ivec(s, inconsistent, decl.inputs, print_arg);
1169 1170
    pclose(s);
    maybe_print_comment(s, decl.output.span.lo);
1171
    if (decl.output.node != ast::ty_nil) {
1172
        space_if_not_hardbreak(s);
G
Graydon Hoare 已提交
1173
        word_space(s, "->");
1174
        print_type(s, *decl.output);
1175
    }
M
Marijn Haverbeke 已提交
1176 1177
}

1178 1179 1180 1181
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, "&"); }
1182
        case (ast::val) { }
1183 1184 1185
    }
}

1186 1187
fn print_type_params(&ps s, &ast::ty_param[] params) {
    if (ivec::len(params) > 0u) {
G
Graydon Hoare 已提交
1188
        word(s.s, "[");
1189
        fn printParam(&ps s, &ast::ty_param param) { word(s.s, param); }
1190
        commasep_ivec(s, inconsistent, params, printParam);
G
Graydon Hoare 已提交
1191
        word(s.s, "]");
1192
    }
M
Marijn Haverbeke 已提交
1193 1194
}

1195 1196
fn print_meta_item(&ps s, &@ast::meta_item item) {
    ibox(s, indent_unit);
1197
    alt (item.node) {
1198 1199 1200 1201 1202
        case (ast::meta_word(?name)) {
            word(s.s, name);
        }
        case (ast::meta_name_value(?name, ?value)) {
            word_space(s, name);
1203
            word_space(s, "=");
1204
            print_literal(s, @value);
1205
        }
1206 1207 1208
        case (ast::meta_list(?name, ?items)) {
            word(s.s, name);
            popen(s);
1209
            commasep_ivec(s, consistent, items, print_meta_item);
1210
            pclose(s);
1211 1212
        }
    }
1213 1214 1215
    end(s);
}

1216
fn print_view_item(&ps s, &@ast::view_item item) {
1217
    hardbreak_if_not_bol(s);
1218 1219
    maybe_print_comment(s, item.span.lo);
    alt (item.node) {
1220
        case (ast::view_item_use(?id, ?mta, _)) {
G
Graydon Hoare 已提交
1221
            head(s, "use");
G
Graydon Hoare 已提交
1222
            word(s.s, id);
1223
            if (ivec::len(mta) > 0u) {
1224
                popen(s);
1225
                commasep_ivec(s, consistent, mta, print_meta_item);
1226 1227 1228
                pclose(s);
            }
        }
1229
        case (ast::view_item_import(?id, ?ids, _)) {
G
Graydon Hoare 已提交
1230
            head(s, "import");
1231
            if (!str::eq(id, ids.(ivec::len(ids) - 1u))) {
G
Graydon Hoare 已提交
1232 1233
                word_space(s, id);
                word_space(s, "=");
1234 1235 1236
            }
            auto first = true;
            for (str elt in ids) {
1237
                if (first) { first = false; } else { word(s.s, "::"); }
G
Graydon Hoare 已提交
1238
                word(s.s, elt);
1239 1240
            }
        }
1241
        case (ast::view_item_import_glob(?ids, _)) {
G
Graydon Hoare 已提交
1242 1243 1244
            head(s, "import");
            auto first = true;
            for (str elt in ids) {
1245
                if (first) { first = false; } else { word(s.s, "::"); }
G
Graydon Hoare 已提交
1246 1247 1248 1249
                word(s.s, elt);
            }
            word(s.s, "::*");
        }
1250
        case (ast::view_item_export(?id, _)) {
G
Graydon Hoare 已提交
1251
            head(s, "export");
G
Graydon Hoare 已提交
1252
            word(s.s, id);
1253
        }
M
Marijn Haverbeke 已提交
1254
    }
G
Graydon Hoare 已提交
1255
    word(s.s, ";");
1256
    end(s); // end inner head-block
1257

1258
    end(s); // end outer head-block
1259

M
Marijn Haverbeke 已提交
1260 1261
}

1262

M
Marijn Haverbeke 已提交
1263 1264
// FIXME: The fact that this builds up the table anew for every call is
// not good. Eventually, table should be a const.
1265
fn operator_prec(ast::binop op) -> int {
1266
    for (parse::parser::op_spec spec in parse::parser::prec_table()) {
1267
        if (spec.op == op) { ret spec.prec; }
1268 1269
    }
    fail;
M
Marijn Haverbeke 已提交
1270 1271
}

1272
fn print_maybe_parens(&ps s, &@ast::expr expr, int outer_prec) {
1273 1274
    auto add_them;
    alt (expr.node) {
1275
        case (ast::expr_binary(?op, _, _)) {
1276 1277
            add_them = operator_prec(op) < outer_prec;
        }
1278
        case (ast::expr_cast(_, _)) {
1279
            add_them = parse::parser::as_prec < outer_prec;
1280
        }
1281
        case (ast::expr_ternary(_, _, _)) {
1282
            add_them = parse::parser::ternary_prec < outer_prec;
1283
        }
1284
        case (_) { add_them = false; }
M
Marijn Haverbeke 已提交
1285
    }
1286
    if (add_them) { popen(s); }
1287
    print_expr(s, expr);
1288
    if (add_them) { pclose(s); }
M
Marijn Haverbeke 已提交
1289 1290
}

G
Graydon Hoare 已提交
1291 1292
fn print_mutability(&ps s, &ast::mutability mut) {
    alt (mut) {
1293
        case (ast::mut) { word_nbsp(s, "mutable"); }
G
Graydon Hoare 已提交
1294
        case (ast::maybe_mut) { word_nbsp(s, "mutable?"); }
1295
        case (ast::imm) {/* nothing */ }
1296
    }
G
Graydon Hoare 已提交
1297 1298 1299 1300
}

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

1304
fn print_ty_fn(&ps s, &ast::proto proto, &option::t[str] id,
1305
               &ast::ty_arg[] inputs, &@ast::ty output,
1306
               &ast::controlflow cf, &(@ast::constr)[] constrs) {
1307
    ibox(s, indent_unit);
1308 1309 1310
    if (proto == ast::proto_fn) {
        word(s.s, "fn");
    } else { word(s.s, "iter"); }
1311
    alt (id) {
1312 1313
        case (some(?id)) { word(s.s, " "); word(s.s, id); }
        case (_) { }
1314
    }
G
Graydon Hoare 已提交
1315
    zerobreak(s.s);
G
Graydon Hoare 已提交
1316
    popen(s);
1317
    fn print_arg(&ps s, &ast::ty_arg input) {
1318
        print_alias(s, input.node.mode);
1319
        print_type(s, *input.node.ty);
1320
    }
1321
    commasep_ivec(s, inconsistent, inputs, print_arg);
1322 1323
    pclose(s);
    maybe_print_comment(s, output.span.lo);
1324
    if (output.node != ast::ty_nil) {
1325
        space_if_not_hardbreak(s);
1326
        ibox(s, indent_unit);
G
Graydon Hoare 已提交
1327
        word_space(s, "->");
1328
        alt (cf) {
1329 1330
            case (ast::return) { print_type(s, *output); }
            case (ast::noreturn) { word_nbsp(s, "!"); }
1331
        }
1332
        end(s);
1333
    }
1334
    word_space(s, ast_constrs_str(constrs));
1335
    end(s);
1336 1337
}

1338
fn maybe_print_trailing_comment(&ps s, codemap::span span,
1339
                                option::t[uint] next_pos) {
1340
    auto cm;
1341
    alt (s.cm) { case (some(?ccm)) { cm = ccm; } case (_) { ret; } }
1342
    alt (next_comment(s)) {
1343
        case (some(?cmnt)) {
1344
            if (cmnt.style != lexer::trailing) { ret; }
1345 1346
            auto span_line = codemap::lookup_pos(cm, span.hi);
            auto comment_line = codemap::lookup_pos(cm, cmnt.pos);
1347
            auto next = cmnt.pos + 1u;
1348 1349
            alt (next_pos) { case (none) { } case (some(?p)) { next = p; } }
            if (span.hi < cmnt.pos && cmnt.pos < next &&
G
Graydon Hoare 已提交
1350
                span_line.line == comment_line.line) {
G
Graydon Hoare 已提交
1351
                print_comment(s, cmnt);
1352 1353 1354
                s.cur_cmnt += 1u;
            }
        }
1355
        case (_) { }
1356 1357 1358
    }
}

1359
fn print_remaining_comments(&ps s) {
1360 1361
    while (true) {
        alt (next_comment(s)) {
1362 1363
            case (some(?cmnt)) { print_comment(s, cmnt); s.cur_cmnt += 1u; }
            case (_) { break; }
1364 1365 1366 1367
        }
    }
}

1368 1369 1370
fn in_cbox(&ps s) -> bool {
    auto len = vec::len(s.boxes);
    if (len == 0u) { ret false; }
1371
    ret s.boxes.(len - 1u) == pp::consistent;
1372
}
1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394

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]), '\'') + "'");
        }
1395 1396
        case (ast::lit_int(?val)) { word(s.s, int::str(val)); }
        case (ast::lit_uint(?val)) { word(s.s, uint::str(val) + "u"); }
1397 1398
        case (ast::lit_float(?fstr)) { word(s.s, fstr); }
        case (ast::lit_mach_int(?mach, ?val)) {
1399
            word(s.s, int::str(val as int));
1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 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
            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)) {
            if (s.cur_lit < vec::len(lits)) {
                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) {
            assert (vec::len(cmnt.lines) == 1u);
            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, " ");
            if (vec::len(cmnt.lines) == 1u) {
                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 {
    auto writer = io::string_writer();
    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)) {
            if (s.cur_cmnt < vec::len(cmnts)) {
                ret some(cmnts.(s.cur_cmnt));
            } else { ret none[lexer::cmnt]; }
        }
        case (_) { ret none[lexer::cmnt]; }
    }
}

1522 1523 1524
// 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,
1525
                         &(@ast::constr_arg_general[T])[] args) -> str {
1526 1527 1528 1529 1530 1531 1532 1533 1534 1535
    auto comma = false;
    auto s = "(";
    for (@ast::constr_arg_general[T] a in args) {
        if (comma) { s += ", "; } else { comma = true; }
        s += constr_arg_to_str[T](f, a.node);
    }
    s += ")";
    ret s;
}

1536
fn constr_arg_to_str[T](&fn(&T) -> str f, &ast::constr_arg_general_[T] c) ->
1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547
   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)
1548
fn uint_to_str(&uint i) -> str { ret uint::str(i); }
1549 1550

fn ast_constr_to_str(&@ast::constr c) -> str {
1551 1552 1553 1554 1555
    // TODO: Remove this vec->ivec conversion.
    auto cag_ivec = ~[];
    for (@ast::constr_arg_general[uint] cag in c.node.args) {
        cag_ivec += ~[cag];
    }
1556
    ret ast::path_to_str(c.node.path) +
1557
            constr_args_to_str(uint_to_str, cag_ivec);
1558 1559
}

1560
fn ast_constrs_str(&(@ast::constr)[] constrs) -> str {
1561 1562 1563 1564 1565 1566 1567 1568 1569
    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;
}

1570 1571 1572 1573 1574 1575 1576 1577 1578 1579
//
// 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:
//