pprust.rs 49.5 KB
Newer Older
1

B
Brian Anderson 已提交
2
import std::vec;
3
import std::int;
B
Brian Anderson 已提交
4
import std::io;
5 6
import std::str;
import std::uint;
7
import std::option;
8 9
import parse::lexer;
import syntax::codemap::codemap;
10
import syntax::visit;
11
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
// The ps is stored here to prevent recursive type.
// FIXME use a nominal tag instead
tag ann_node {
30
    node_block(ps, ast::blk);
31 32 33 34
    node_item(ps, @ast::item);
    node_expr(ps, @ast::expr);
    node_pat(ps, @ast::pat);
}
B
Brian Anderson 已提交
35
type pp_ann = {pre: fn(&ann_node), post: fn(&ann_node)};
36 37

fn no_ann() -> pp_ann {
38
    fn ignore(_node: &ann_node) { }
M
Marijn Haverbeke 已提交
39
    ret {pre: ignore, post: ignore};
40 41 42
}

type ps =
M
Marijn Haverbeke 已提交
43
    @{s: pp::printer,
44 45 46
      cm: option::t<codemap>,
      comments: option::t<[lexer::cmnt]>,
      literals: option::t<[lexer::lit]>,
M
Marijn Haverbeke 已提交
47 48
      mutable cur_cmnt: uint,
      mutable cur_lit: uint,
49
      mutable boxes: [pp::breaks],
M
Marijn Haverbeke 已提交
50
      ann: pp_ann};
51

B
Brian Anderson 已提交
52
fn ibox(s: &ps, u: uint) { s.boxes += [pp::inconsistent]; pp::ibox(s.s, u); }
53

B
Brian Anderson 已提交
54
fn end(s: &ps) { vec::pop(s.boxes); pp::end(s.s); }
55

B
Brian Anderson 已提交
56
fn rust_printer(writer: io::writer) -> ps {
B
Brian Anderson 已提交
57
    let boxes: [pp::breaks] = [];
M
Marijn Haverbeke 已提交
58
    ret @{s: pp::mk_printer(writer, default_columns),
59 60 61
          cm: none::<codemap>,
          comments: none::<[lexer::cmnt]>,
          literals: none::<[lexer::lit]>,
M
Marijn Haverbeke 已提交
62 63 64 65
          mutable cur_cmnt: 0u,
          mutable cur_lit: 0u,
          mutable boxes: boxes,
          ann: no_ann()};
66 67
}

M
Marijn Haverbeke 已提交
68 69
const indent_unit: uint = 4u;
const alt_indent_unit: uint = 2u;
70

M
Marijn Haverbeke 已提交
71
const default_columns: uint = 78u;
72

73 74 75
// Requires you to pass an input filename and reader so that
// it can scan the input text for comments and literals to
// copy forward.
M
Marijn Haverbeke 已提交
76
fn print_crate(cm: &codemap, crate: @ast::crate, filename: str,
B
Brian Anderson 已提交
77
               in: io::reader, out: io::writer, ann: &pp_ann) {
B
Brian Anderson 已提交
78
    let boxes: [pp::breaks] = [];
M
Marijn Haverbeke 已提交
79 80 81 82 83 84 85 86 87 88
    let r = lexer::gather_comments_and_literals(cm, filename, in);
    let s =
        @{s: pp::mk_printer(out, default_columns),
          cm: some(cm),
          comments: some(r.cmnts),
          literals: some(r.lits),
          mutable cur_cmnt: 0u,
          mutable cur_lit: 0u,
          mutable boxes: boxes,
          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(ty: &@ast::ty) -> str { be to_str(ty, print_type); }
95

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

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

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

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

104 105 106
fn path_to_str(p: &ast::path) -> str {
    be to_str(p, bind print_path(_, _, false));
}
107

108
fn fun_to_str(f: &ast::_fn, name: str, params: &[ast::ty_param]) -> str {
B
Brian Anderson 已提交
109
    let writer = io::string_writer();
M
Marijn Haverbeke 已提交
110
    let s = rust_printer(writer.get_writer());
111
    print_fn(s, f.decl, f.proto, name, params, f.decl.constraints);
G
Graydon Hoare 已提交
112
    eof(s.s);
113
    ret writer.get_str();
114 115
}

M
Marijn Haverbeke 已提交
116
fn block_to_str(blk: &ast::blk) -> str {
B
Brian Anderson 已提交
117
    let writer = io::string_writer();
M
Marijn Haverbeke 已提交
118
    let s = rust_printer(writer.get_writer());
G
Graydon Hoare 已提交
119 120
    // containing cbox, will be closed by print-block at }

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

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

M
Marijn Haverbeke 已提交
130
fn meta_item_to_str(mi: &ast::meta_item) -> str {
131 132 133
    ret to_str(@mi, print_meta_item);
}

M
Marijn Haverbeke 已提交
134
fn attribute_to_str(attr: &ast::attribute) -> str {
135 136 137
    be to_str(attr, print_attribute);
}

B
Brian Anderson 已提交
138
fn cbox(s: &ps, u: uint) { s.boxes += [pp::consistent]; pp::cbox(s.s, u); }
139

B
Brian Anderson 已提交
140
fn box(s: &ps, u: uint, b: pp::breaks) { s.boxes += [b]; pp::box(s.s, u, b); }
141

M
Marijn Haverbeke 已提交
142
fn nbsp(s: &ps) { word(s.s, " "); }
143

M
Marijn Haverbeke 已提交
144
fn word_nbsp(s: &ps, w: str) { word(s.s, w); nbsp(s); }
G
Graydon Hoare 已提交
145

M
Marijn Haverbeke 已提交
146
fn word_space(s: &ps, w: str) { word(s.s, w); space(s.s); }
G
Graydon Hoare 已提交
147

M
Marijn Haverbeke 已提交
148
fn popen(s: &ps) { word(s.s, "("); }
G
Graydon Hoare 已提交
149

M
Marijn Haverbeke 已提交
150
fn pclose(s: &ps) { word(s.s, ")"); }
G
Graydon Hoare 已提交
151

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

M
Marijn Haverbeke 已提交
161
fn bopen(s: &ps) {
G
Graydon Hoare 已提交
162
    word(s.s, "{");
163
    end(s); // close the head-box
164
}
G
Graydon Hoare 已提交
165

M
Marijn Haverbeke 已提交
166
fn bclose_(s: &ps, span: codemap::span, indented: uint) {
167
    maybe_print_comment(s, span.hi);
168
    break_offset_if_not_bol(s, 1u, -(indented as int));
G
Graydon Hoare 已提交
169
    word(s.s, "}");
170
    end(s); // close the outer-box
171
}
M
Marijn Haverbeke 已提交
172
fn bclose(s: &ps, span: codemap::span) { bclose_(s, span, indent_unit); }
G
Graydon Hoare 已提交
173

174
fn is_begin(s: &ps) -> bool {
B
Brian Anderson 已提交
175
    alt s.s.last_token() { pp::BEGIN(_) { true } _ { false } }
176 177 178
}

fn is_end(s: &ps) -> bool {
B
Brian Anderson 已提交
179
    alt s.s.last_token() { pp::END. { true } _ { false } }
180 181
}

M
Marijn Haverbeke 已提交
182 183
fn is_bol(s: &ps) -> bool {
    ret s.s.last_token() == pp::EOF ||
B
Brian Anderson 已提交
184
            s.s.last_token() == pp::hardbreak_tok();
185 186
}

M
Marijn Haverbeke 已提交
187 188 189 190
fn hardbreak_if_not_bol(s: &ps) { if !is_bol(s) { hardbreak(s.s); } }
fn space_if_not_bol(s: &ps) { if !is_bol(s) { space(s.s); } }
fn break_offset_if_not_bol(s: &ps, n: uint, off: int) {
    if !is_bol(s) {
191 192
        break_offset(s.s, n, off);
    } else {
M
Marijn Haverbeke 已提交
193
        if off != 0 && s.s.last_token() == pp::hardbreak_tok() {
194 195 196 197 198
            // 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));
        }
199 200
    }
}
201

202 203
// Synthesizes a comment that was not textually present in the original source
// file.
M
Marijn Haverbeke 已提交
204
fn synth_comment(s: &ps, text: str) {
205 206 207 208 209 210 211
    word(s.s, "/*");
    space(s.s);
    word(s.s, text);
    space(s.s);
    word(s.s, "*/");
}

B
Brian Anderson 已提交
212
fn commasep<IN>(s: &ps, b: breaks, elts: &[IN], op: fn(&ps, &IN)) {
213
    box(s, 0u, b);
M
Marijn Haverbeke 已提交
214
    let first = true;
215
    for elt: IN in elts {
M
Marijn Haverbeke 已提交
216
        if first { first = false; } else { word_space(s, ","); }
217 218 219 220 221 222
        op(s, elt);
    }
    end(s);
}


B
Brian Anderson 已提交
223 224
fn commasep_cmnt<IN>(s: &ps, b: breaks, elts: &[IN], op: fn(&ps, &IN),
                     get_span: fn(&IN) -> codemap::span) {
225
    box(s, 0u, b);
226
    let len = vec::len::<IN>(elts);
M
Marijn Haverbeke 已提交
227
    let i = 0u;
228
    for elt: IN in elts {
229 230 231
        maybe_print_comment(s, get_span(elt).hi);
        op(s, elt);
        i += 1u;
M
Marijn Haverbeke 已提交
232
        if i < len {
233 234
            word(s.s, ",");
            maybe_print_trailing_comment(s, get_span(elt),
B
Brian Anderson 已提交
235
                                         some(get_span(elts[i]).hi));
236
            space_if_not_bol(s);
237 238 239 240 241
        }
    }
    end(s);
}

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

247
fn print_mod(s: &ps, _mod: &ast::_mod, attrs: &[ast::attribute]) {
248
    print_inner_attributes(s, attrs);
249
    for vitem: @ast::view_item in _mod.view_items {
250 251
        print_view_item(s, vitem);
    }
252
    for item: @ast::item in _mod.items { print_item(s, item); }
253 254
}

M
Marijn Haverbeke 已提交
255
fn print_native_mod(s: &ps, nmod: &ast::native_mod,
256
                    attrs: &[ast::attribute]) {
257
    print_inner_attributes(s, attrs);
258
    for vitem: @ast::view_item in nmod.view_items {
259 260
        print_view_item(s, vitem);
    }
261
    for item: @ast::native_item in nmod.items { print_native_item(s, item); }
262 263
}

264
fn print_type(s: &ps, ty: &@ast::ty) {
265
    maybe_print_comment(s, ty.span.lo);
266
    ibox(s, 0u);
M
Marijn Haverbeke 已提交
267 268 269 270 271 272 273 274 275 276 277 278
    alt ty.node {
      ast::ty_nil. { word(s.s, "()"); }
      ast::ty_bool. { word(s.s, "bool"); }
      ast::ty_bot. { word(s.s, "!"); }
      ast::ty_int. { word(s.s, "int"); }
      ast::ty_uint. { word(s.s, "uint"); }
      ast::ty_float. { word(s.s, "float"); }
      ast::ty_machine(tm) { word(s.s, ast::ty_mach_to_str(tm)); }
      ast::ty_char. { word(s.s, "char"); }
      ast::ty_str. { word(s.s, "str"); }
      ast::ty_istr. { word(s.s, "istr"); }
      ast::ty_box(mt) { word(s.s, "@"); print_mt(s, mt); }
279
      ast::ty_vec(mt) {
M
Marijn Haverbeke 已提交
280
        word(s.s, "[");
281
        alt mt.mut {
282 283
          ast::mut. { word_space(s, "mutable"); }
          ast::maybe_mut. { word_space(s, "mutable?"); }
B
Brian Anderson 已提交
284
          ast::imm. { }
285
        }
286
        print_type(s, mt.ty);
M
Marijn Haverbeke 已提交
287 288 289 290 291
        word(s.s, "]");
      }
      ast::ty_ptr(mt) { word(s.s, "*"); print_mt(s, mt); }
      ast::ty_task. { word(s.s, "task"); }
      ast::ty_port(t) {
292
        word(s.s, "port<");
293
        print_type(s, t);
294
        word(s.s, ">");
M
Marijn Haverbeke 已提交
295 296
      }
      ast::ty_chan(t) {
297
        word(s.s, "chan<");
298
        print_type(s, t);
299
        word(s.s, ">");
M
Marijn Haverbeke 已提交
300 301 302 303 304 305 306 307
      }
      ast::ty_rec(fields) {
        word(s.s, "{");
        fn print_field(s: &ps, f: &ast::ty_field) {
            cbox(s, indent_unit);
            print_mutability(s, f.node.mt.mut);
            word(s.s, f.node.ident);
            word_space(s, ":");
308
            print_type(s, f.node.mt.ty);
M
Marijn Haverbeke 已提交
309
            end(s);
310
        }
M
Marijn Haverbeke 已提交
311 312 313 314
        fn get_span(f: &ast::ty_field) -> codemap::span { ret f.span; }
        commasep_cmnt(s, consistent, fields, print_field, get_span);
        word(s.s, "}");
      }
315
      ast::ty_tup(elts) {
B
Brian Anderson 已提交
316 317 318
        popen(s);
        commasep(s, inconsistent, elts, print_type);
        pclose(s);
319
      }
M
Marijn Haverbeke 已提交
320
      ast::ty_fn(proto, inputs, output, cf, constrs) {
321
        print_ty_fn(s, proto, none::<str>, inputs, output, cf, constrs);
M
Marijn Haverbeke 已提交
322 323 324 325
      }
      ast::ty_obj(methods) {
        head(s, "obj");
        bopen(s);
326
        for m: ast::ty_method in methods {
M
Marijn Haverbeke 已提交
327 328 329 330 331 332 333
            hardbreak_if_not_bol(s);
            cbox(s, indent_unit);
            maybe_print_comment(s, m.span.lo);
            print_ty_fn(s, m.node.proto, some(m.node.ident), m.node.inputs,
                        m.node.output, m.node.cf, m.node.constrs);
            word(s.s, ";");
            end(s);
G
Graydon Hoare 已提交
334
        }
M
Marijn Haverbeke 已提交
335 336
        bclose(s, ty.span);
      }
337
      ast::ty_path(path, _) { print_path(s, path, false); }
M
Marijn Haverbeke 已提交
338 339
      ast::ty_type. { word(s.s, "type"); }
      ast::ty_constr(t, cs) {
340
        print_type(s, t);
M
Marijn Haverbeke 已提交
341 342 343
        space(s.s);
        word(s.s, ast_ty_constrs_str(cs));
      }
M
Marijn Haverbeke 已提交
344
    }
345
    end(s);
M
Marijn Haverbeke 已提交
346 347
}

M
Marijn Haverbeke 已提交
348
fn print_native_item(s: &ps, item: &@ast::native_item) {
349 350 351
    hardbreak_if_not_bol(s);
    maybe_print_comment(s, item.span.lo);
    print_outer_attributes(s, item.attrs);
M
Marijn Haverbeke 已提交
352 353
    alt item.node {
      ast::native_item_ty. {
354 355 356 357 358 359 360 361 362 363
        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

      }

M
Marijn Haverbeke 已提交
364

B
Brian Anderson 已提交
365

M
Marijn Haverbeke 已提交
366
      ast::native_item_fn(lname, decl, typarams) {
367 368
        print_fn(s, decl, ast::proto_fn, item.ident, typarams,
                 decl.constraints);
M
Marijn Haverbeke 已提交
369 370 371
        alt lname {
          none. { }
          some(ss) { space(s.s); word_space(s, "="); print_string(s, ss); }
372 373 374 375 376 377 378 379
        }
        end(s); // end head-ibox
        word(s.s, ";");
        end(s); // end the outer fn box
      }
    }
}

M
Marijn Haverbeke 已提交
380
fn print_item(s: &ps, item: &@ast::item) {
381
    hardbreak_if_not_bol(s);
382
    maybe_print_comment(s, item.span.lo);
383
    print_outer_attributes(s, item.attrs);
M
Marijn Haverbeke 已提交
384
    let ann_node = node_item(s, item);
385
    s.ann.pre(ann_node);
M
Marijn Haverbeke 已提交
386 387 388 389
    alt item.node {
      ast::item_const(ty, expr) {
        head(s, "const");
        word_space(s, item.ident + ":");
390
        print_type(s, ty);
M
Marijn Haverbeke 已提交
391 392 393 394 395 396 397
        space(s.s);
        end(s); // end the head-ibox

        word_space(s, "=");
        print_expr(s, expr);
        word(s.s, ";");
        end(s); // end the outer cbox
398

M
Marijn Haverbeke 已提交
399 400
      }
      ast::item_fn(_fn, typarams) {
401 402
        print_fn(s, _fn.decl, _fn.proto, item.ident, typarams,
                 _fn.decl.constraints);
M
Marijn Haverbeke 已提交
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
        word(s.s, " ");
        print_block(s, _fn.body);
      }
      ast::item_mod(_mod) {
        head(s, "mod");
        word_nbsp(s, item.ident);
        bopen(s);
        print_mod(s, _mod, item.attrs);
        bclose(s, item.span);
      }
      ast::item_native_mod(nmod) {
        head(s, "native");
        alt nmod.abi {
          ast::native_abi_llvm. { word_nbsp(s, "\"llvm\""); }
          ast::native_abi_rust. { word_nbsp(s, "\"rust\""); }
          ast::native_abi_cdecl. { word_nbsp(s, "\"cdecl\""); }
          ast::native_abi_rust_intrinsic. {
            word_nbsp(s, "\"rust-intrinsic\"");
          }
          ast::native_abi_x86stdcall. { word_nbsp(s, "\"x86stdcall\""); }
423
        }
M
Marijn Haverbeke 已提交
424 425 426
        word_nbsp(s, "mod");
        word_nbsp(s, item.ident);
        if !str::eq(nmod.native_name, item.ident) {
G
Graydon Hoare 已提交
427
            word_space(s, "=");
M
Marijn Haverbeke 已提交
428 429
            print_string(s, nmod.native_name);
            nbsp(s);
430
        }
M
Marijn Haverbeke 已提交
431 432 433 434 435 436 437 438 439 440 441 442 443 444
        bopen(s);
        print_native_mod(s, nmod, item.attrs);
        bclose(s, item.span);
      }
      ast::item_ty(ty, params) {
        ibox(s, indent_unit);
        ibox(s, 0u);
        word_nbsp(s, "type");
        word(s.s, item.ident);
        print_type_params(s, params);
        end(s); // end the inner ibox

        space(s.s);
        word_space(s, "=");
445
        print_type(s, ty);
M
Marijn Haverbeke 已提交
446 447 448 449 450
        word(s.s, ";");
        end(s); // end the outer ibox
      }
      ast::item_tag(variants, params) {
        let newtype =
B
Brian Anderson 已提交
451
            vec::len(variants) == 1u &&
B
Brian Anderson 已提交
452 453
                str::eq(item.ident, variants[0].node.name) &&
                vec::len(variants[0].node.args) == 1u;
M
Marijn Haverbeke 已提交
454 455 456 457 458 459 460 461 462
        if newtype {
            ibox(s, indent_unit);
            word_space(s, "tag");
        } else { head(s, "tag"); }
        word(s.s, item.ident);
        print_type_params(s, params);
        space(s.s);
        if newtype {
            word_space(s, "=");
B
Brian Anderson 已提交
463
            print_type(s, variants[0].node.args[0].ty);
M
Marijn Haverbeke 已提交
464 465 466
            word(s.s, ";");
            end(s);
        } else {
467
            bopen(s);
468
            for v: ast::variant in variants {
469
                space_if_not_bol(s);
M
Marijn Haverbeke 已提交
470 471
                maybe_print_comment(s, v.span.lo);
                word(s.s, v.node.name);
B
Brian Anderson 已提交
472
                if vec::len(v.node.args) > 0u {
M
Marijn Haverbeke 已提交
473 474
                    popen(s);
                    fn print_variant_arg(s: &ps, arg: &ast::variant_arg) {
475
                        print_type(s, arg.ty);
M
Marijn Haverbeke 已提交
476 477 478
                    }
                    commasep(s, consistent, v.node.args, print_variant_arg);
                    pclose(s);
479
                }
M
Marijn Haverbeke 已提交
480
                word(s.s, ";");
481
                maybe_print_trailing_comment(s, v.span, none::<uint>);
482
            }
G
Graydon Hoare 已提交
483
            bclose(s, item.span);
M
Marijn Haverbeke 已提交
484
        }
M
Marijn Haverbeke 已提交
485 486 487 488 489 490 491 492 493 494
      }
      ast::item_obj(_obj, params, _) {
        head(s, "obj");
        word(s.s, item.ident);
        print_type_params(s, params);
        popen(s);
        fn print_field(s: &ps, field: &ast::obj_field) {
            ibox(s, indent_unit);
            print_mutability(s, field.mut);
            word_space(s, field.ident + ":");
495
            print_type(s, field.ty);
M
Marijn Haverbeke 已提交
496
            end(s);
497
        }
M
Marijn Haverbeke 已提交
498 499 500 501 502
        fn get_span(f: &ast::obj_field) -> codemap::span { ret f.ty.span; }
        commasep_cmnt(s, consistent, _obj.fields, print_field, get_span);
        pclose(s);
        space(s.s);
        bopen(s);
503
        for meth: @ast::method in _obj.methods {
B
Brian Anderson 已提交
504
            let typarams: [ast::ty_param] = [];
M
Marijn Haverbeke 已提交
505 506 507
            hardbreak_if_not_bol(s);
            maybe_print_comment(s, meth.span.lo);
            print_fn(s, meth.node.meth.decl, meth.node.meth.proto,
B
Brian Anderson 已提交
508
                     meth.node.ident, typarams, []);
M
Marijn Haverbeke 已提交
509 510 511 512 513 514 515 516 517 518
            word(s.s, " ");
            print_block(s, meth.node.meth.body);
        }
        bclose(s, item.span);
      }
      ast::item_res(dt, dt_id, tps, ct_id) {
        head(s, "resource");
        word(s.s, item.ident);
        print_type_params(s, tps);
        popen(s);
B
Brian Anderson 已提交
519 520
        word_space(s, dt.decl.inputs[0].ident + ":");
        print_type(s, dt.decl.inputs[0].ty);
M
Marijn Haverbeke 已提交
521 522 523 524
        pclose(s);
        space(s.s);
        print_block(s, dt.body);
      }
M
Marijn Haverbeke 已提交
525
    }
526
    s.ann.post(ann_node);
M
Marijn Haverbeke 已提交
527 528
}

529
fn print_outer_attributes(s: &ps, attrs: &[ast::attribute]) {
M
Marijn Haverbeke 已提交
530
    let count = 0;
531
    for attr: ast::attribute in attrs {
M
Marijn Haverbeke 已提交
532 533 534
        alt attr.node.style {
          ast::attr_outer. { print_attribute(s, attr); count += 1; }
          _ {/* fallthrough */ }
535 536
        }
    }
M
Marijn Haverbeke 已提交
537
    if count > 0 { hardbreak_if_not_bol(s); }
538 539
}

540
fn print_inner_attributes(s: &ps, attrs: &[ast::attribute]) {
M
Marijn Haverbeke 已提交
541
    let count = 0;
542
    for attr: ast::attribute in attrs {
M
Marijn Haverbeke 已提交
543 544 545 546 547 548 549
        alt attr.node.style {
          ast::attr_inner. {
            print_attribute(s, attr);
            word(s.s, ";");
            count += 1;
          }
          _ {/* fallthrough */ }
550 551
        }
    }
M
Marijn Haverbeke 已提交
552
    if count > 0 { hardbreak_if_not_bol(s); }
553 554
}

M
Marijn Haverbeke 已提交
555
fn print_attribute(s: &ps, attr: &ast::attribute) {
556
    hardbreak_if_not_bol(s);
557 558 559 560 561 562
    maybe_print_comment(s, attr.span.lo);
    word(s.s, "#[");
    print_meta_item(s, @attr.node.value);
    word(s.s, "]");
}

M
Marijn Haverbeke 已提交
563
fn print_stmt(s: &ps, st: &ast::stmt) {
564
    maybe_print_comment(s, st.span.lo);
M
Marijn Haverbeke 已提交
565 566 567
    alt st.node {
      ast::stmt_decl(decl, _) { print_decl(s, decl); }
      ast::stmt_expr(expr, _) { space_if_not_bol(s); print_expr(s, expr); }
568
    }
M
Marijn Haverbeke 已提交
569
    if parse::parser::stmt_ends_with_semi(st) { word(s.s, ";"); }
570
    maybe_print_trailing_comment(s, st.span, none::<uint>);
571 572
}

M
Marijn Haverbeke 已提交
573
fn print_block(s: &ps, blk: &ast::blk) {
M
Michael Sullivan 已提交
574
    print_possibly_embedded_block(s, blk, block_normal, indent_unit);
575
}
576

M
Michael Sullivan 已提交
577 578 579
tag embed_type { block_macro; block_block_fn; block_normal; }

fn print_possibly_embedded_block(s: &ps, blk: &ast::blk, embedded: embed_type,
M
Marijn Haverbeke 已提交
580
                                 indented: uint) {
581
    maybe_print_comment(s, blk.span.lo);
M
Marijn Haverbeke 已提交
582
    let ann_node = node_block(s, blk);
583
    s.ann.pre(ann_node);
M
Michael Sullivan 已提交
584 585 586 587 588
    alt embedded {
      block_macro. { word(s.s, "#{"); end(s); }
      block_block_fn. { end(s); }
      block_normal. { bopen(s); }
    }
589 590

    let last_stmt = option::none;
591
    for st: @ast::stmt in blk.node.stmts {
592
        maybe_protect_block(s, last_stmt, stmt_(st));
593 594 595
        print_stmt(s, *st);
        last_stmt = option::some(st);
    }
M
Marijn Haverbeke 已提交
596 597
    alt blk.node.expr {
      some(expr) {
598
        maybe_protect_block(s, last_stmt, expr_(expr));
M
Marijn Haverbeke 已提交
599 600 601 602 603
        space_if_not_bol(s);
        print_expr(s, expr);
        maybe_print_trailing_comment(s, expr.span, some(blk.span.hi));
      }
      _ { }
M
Marijn Haverbeke 已提交
604
    }
605
    bclose_(s, blk.span, indented);
606
    s.ann.post(ann_node);
607 608 609 610

    tag expr_or_stmt { stmt_(@ast::stmt); expr_(@ast::expr); }

    // The Rust syntax has an ambiguity when an if, alt, or block statement is
611 612 613 614
    // followed by a unary op or paren. In those cases we have to add an
    // extra semi to make sure the output retains the same meaning.
    fn maybe_protect_block(s: &ps, last: &option::t<@ast::stmt>,
                           next: &expr_or_stmt) {
B
Brian Anderson 已提交
615 616 617 618 619 620 621 622 623 624 625 626
        let last_expr_is_block =
            alt last {
              option::some(@{node: ast::stmt_expr(e, _), _}) {
                alt e.node {
                  ast::expr_if(_, _, _) | ast::expr_alt(_, _) |
                  ast::expr_block(_) {
                    true
                  }
                  _ { false }
                }
                true
              }
627
              _ { false }
B
Brian Anderson 已提交
628
            };
629 630 631

        if !last_expr_is_block { ret; }

B
Brian Anderson 已提交
632 633 634 635 636 637
        let next_expr_is_ambig =
            alt next {
              expr_(e) { expr_is_ambig(e) }
              stmt_(@{node: ast::stmt_expr(e, _), _}) { expr_is_ambig(e) }
              _ { false }
            };
638

B
Brian Anderson 已提交
639
        if last_expr_is_block && next_expr_is_ambig { word(s.s, ";"); }
640 641

        fn expr_is_ambig(ex: @ast::expr) -> bool {
B
Brian Anderson 已提交
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
            // We're going to walk the expression to the 'left' looking for
            // various properties that might indicate ambiguity

            type env = @mutable bool;
            let visitor =
                visit::mk_vt(@{visit_expr: visit_expr
                                  with *visit::default_visitor()});
            let env = @mutable false;
            visit_expr(ex, env, visitor);
            ret *env;

            fn visit_expr(ex: &@ast::expr, e: &env, v: &visit::vt<env>) {
                assert (*e == false);

                if expr_is_ambig(ex) { *e = true; ret; }

                alt ex.node {
                  ast::expr_assign(x, _) { v.visit_expr(x, e, v); }
                  ast::expr_assign_op(_, x, _) { visit_expr(x, e, v); }
                  ast::expr_move(x, _) { v.visit_expr(x, e, v); }
                  ast::expr_field(x, _) { v.visit_expr(x, e, v); }
                  ast::expr_index(x, _) { v.visit_expr(x, e, v); }
                  ast::expr_binary(op, x, _) {
                    if need_parens(x, operator_prec(op)) { *e = true; ret; }
                    v.visit_expr(x, e, v);
667
                  }
B
Brian Anderson 已提交
668 669 670 671 672
                  ast::expr_cast(x, _) {
                    if need_parens(x, parse::parser::as_prec) {
                        *e = true;
                        ret;
                    }
673
                  }
B
Brian Anderson 已提交
674 675
                  ast::expr_ternary(x, _, _) { v.visit_expr(x, e, v); }
                  _ { }
676
                }
B
Brian Anderson 已提交
677
            }
678

B
Brian Anderson 已提交
679 680 681 682 683 684 685
            fn expr_is_ambig(ex: @ast::expr) -> bool {
                alt ex.node {
                  ast::expr_unary(_, _) { true }
                  ast::expr_tup(_) { true }
                  _ { false }
                }
            }
686
        }
687
    }
M
Marijn Haverbeke 已提交
688 689
}

690 691 692
// ret and fail, without arguments cannot appear is the discriminant of if,
// alt, do, & while unambiguously without being parenthesized
fn print_maybe_parens_discrim(s: &ps, e: &@ast::expr) {
B
Brian Anderson 已提交
693 694
    let disambig =
        alt e.node { ast::expr_ret(option::none.) { true } _ { false } };
695 696 697 698 699
    if disambig { popen(s) }
    print_expr(s, e);
    if disambig { pclose(s) }
}

M
Marijn Haverbeke 已提交
700
fn print_if(s: &ps, test: &@ast::expr, blk: &ast::blk,
701
            elseopt: &option::t<@ast::expr>, chk: bool) {
T
Tim Chevalier 已提交
702
    head(s, "if");
M
Marijn Haverbeke 已提交
703
    if chk { word_nbsp(s, "check"); }
704
    print_maybe_parens_discrim(s, test);
T
Tim Chevalier 已提交
705
    space(s.s);
706
    print_block(s, blk);
707
    fn do_else(s: &ps, els: option::t<@ast::expr>) {
M
Marijn Haverbeke 已提交
708 709 710 711
        alt els {
          some(_else) {
            alt _else.node {

B
Brian Anderson 已提交
712

M
Marijn Haverbeke 已提交
713 714 715 716 717 718 719 720 721 722 723
              // "another else-if"
              ast::expr_if(i, t, e) {
                cbox(s, indent_unit - 1u);
                ibox(s, 0u);
                word(s.s, " else if ");
                print_expr(s, i);
                space(s.s);
                print_block(s, t);
                do_else(s, e);
              }

B
Brian Anderson 已提交
724

M
Marijn Haverbeke 已提交
725 726 727 728 729 730 731
              // "final else"
              ast::expr_block(b) {
                cbox(s, indent_unit - 1u);
                ibox(s, 0u);
                word(s.s, " else ");
                print_block(s, b);
              }
T
Tim Chevalier 已提交
732
            }
M
Marijn Haverbeke 已提交
733 734
          }
          _ {/* fall through */ }
T
Tim Chevalier 已提交
735 736 737 738 739
        }
    }
    do_else(s, elseopt);
}

M
Marijn Haverbeke 已提交
740 741
fn print_mac(s: &ps, m: &ast::mac) {
    alt m.node {
742
      ast::mac_invoc(path, arg, body) {
M
Marijn Haverbeke 已提交
743
        word(s.s, "#");
744
        print_path(s, path, false);
B
Brian Anderson 已提交
745
        alt arg.node { ast::expr_vec(_, _) { } _ { word(s.s, " "); } }
746
        print_expr(s, arg);
M
Marijn Haverbeke 已提交
747 748 749 750
        // FIXME: extension 'body'
      }
      ast::mac_embed_type(ty) {
        word(s.s, "#<");
751
        print_type(s, ty);
M
Marijn Haverbeke 已提交
752 753 754
        word(s.s, ">");
      }
      ast::mac_embed_block(blk) {
M
Michael Sullivan 已提交
755
        print_possibly_embedded_block(s, blk, block_normal, indent_unit);
M
Marijn Haverbeke 已提交
756 757
      }
      ast::mac_ellipsis. { word(s.s, "..."); }
758 759 760
    }
}

M
Marijn Haverbeke 已提交
761
fn print_expr(s: &ps, expr: &@ast::expr) {
762
    maybe_print_comment(s, expr.span.lo);
763
    ibox(s, indent_unit);
M
Marijn Haverbeke 已提交
764
    let ann_node = node_expr(s, expr);
765
    s.ann.pre(ann_node);
M
Marijn Haverbeke 已提交
766
    alt expr.node {
767
      ast::expr_vec(exprs, mut) {
M
Marijn Haverbeke 已提交
768
        ibox(s, indent_unit);
B
Brian Anderson 已提交
769
        word(s.s, "[");
770 771
        if mut == ast::mut {
            word(s.s, "mutable");
B
Brian Anderson 已提交
772
            if vec::len(exprs) > 0u { nbsp(s); }
773
        }
M
Marijn Haverbeke 已提交
774 775 776 777 778 779 780 781 782
        commasep_exprs(s, inconsistent, exprs);
        word(s.s, "]");
        end(s);
      }
      ast::expr_rec(fields, wth) {
        fn print_field(s: &ps, field: &ast::field) {
            ibox(s, indent_unit);
            if field.node.mut == ast::mut { word_nbsp(s, "mutable"); }
            word(s.s, field.node.ident);
783
            word_space(s, ":");
M
Marijn Haverbeke 已提交
784 785
            print_expr(s, field.node.expr);
            end(s);
786
        }
M
Marijn Haverbeke 已提交
787 788 789 790 791
        fn get_span(field: &ast::field) -> codemap::span { ret field.span; }
        word(s.s, "{");
        commasep_cmnt(s, consistent, fields, print_field, get_span);
        alt wth {
          some(expr) {
B
Brian Anderson 已提交
792
            if vec::len(fields) > 0u { space(s.s); }
M
Marijn Haverbeke 已提交
793 794
            ibox(s, indent_unit);
            word_space(s, "with");
795
            print_expr(s, expr);
M
Marijn Haverbeke 已提交
796 797 798
            end(s);
          }
          _ { }
799
        }
M
Marijn Haverbeke 已提交
800 801
        word(s.s, "}");
      }
802 803
      ast::expr_tup(exprs) {
        popen(s);
M
Marijn Haverbeke 已提交
804
        commasep_exprs(s, inconsistent, exprs);
805 806
        pclose(s);
      }
M
Marijn Haverbeke 已提交
807 808 809 810 811 812 813 814 815 816 817
      ast::expr_call(func, args) {
        print_expr_parens_if_unary(s, func);
        popen(s);
        commasep_exprs(s, inconsistent, args);
        pclose(s);
      }
      ast::expr_self_method(ident) {
        word(s.s, "self.");
        print_ident(s, ident);
      }
      ast::expr_bind(func, args) {
818
        fn print_opt(s: &ps, expr: &option::t<@ast::expr>) {
M
Marijn Haverbeke 已提交
819 820 821 822
            alt expr {
              some(expr) { print_expr(s, expr); }
              _ { word(s.s, "_"); }
            }
823
        }
M
Marijn Haverbeke 已提交
824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845
        word_nbsp(s, "bind");
        print_expr(s, func);
        popen(s);
        commasep(s, inconsistent, args, print_opt);
        pclose(s);
      }
      ast::expr_binary(op, lhs, rhs) {
        let prec = operator_prec(op);
        print_maybe_parens(s, lhs, prec);
        space(s.s);
        word_space(s, ast::binop_to_str(op));
        print_maybe_parens(s, rhs, prec + 1);
      }
      ast::expr_unary(op, expr) {
        word(s.s, ast::unop_to_str(op));
        print_maybe_parens(s, expr, parse::parser::unop_prec);
      }
      ast::expr_lit(lit) { print_literal(s, lit); }
      ast::expr_cast(expr, ty) {
        print_maybe_parens(s, expr, parse::parser::as_prec);
        space(s.s);
        word_space(s, "as");
846
        print_type(s, ty);
M
Marijn Haverbeke 已提交
847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
      }
      ast::expr_if(test, blk, elseopt) {
        print_if(s, test, blk, elseopt, false);
      }
      ast::expr_if_check(test, blk, elseopt) {
        print_if(s, test, blk, elseopt, true);
      }
      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);
      }
      ast::expr_while(test, blk) {
        head(s, "while");
865
        print_maybe_parens_discrim(s, test);
M
Marijn Haverbeke 已提交
866 867 868 869 870
        space(s.s);
        print_block(s, blk);
      }
      ast::expr_for(decl, expr, blk) {
        head(s, "for");
871
        print_for_decl(s, decl, expr);
M
Marijn Haverbeke 已提交
872 873 874 875 876
        space(s.s);
        print_block(s, blk);
      }
      ast::expr_for_each(decl, expr, blk) {
        head(s, "for each");
877
        print_for_decl(s, decl, expr);
M
Marijn Haverbeke 已提交
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892
        space(s.s);
        print_block(s, blk);
      }
      ast::expr_do_while(blk, expr) {
        head(s, "do");
        space(s.s);
        print_block(s, blk);
        space(s.s);
        word_space(s, "while");
        print_expr(s, expr);
      }
      ast::expr_alt(expr, arms) {
        cbox(s, alt_indent_unit);
        ibox(s, 4u);
        word_nbsp(s, "alt");
893
        print_maybe_parens_discrim(s, expr);
M
Marijn Haverbeke 已提交
894 895
        space(s.s);
        bopen(s);
896
        for arm: ast::arm in arms {
897
            space(s.s);
898
            cbox(s, alt_indent_unit);
M
Marijn Haverbeke 已提交
899 900
            ibox(s, 0u);
            let first = true;
901
            for p: @ast::pat in arm.pats {
M
Marijn Haverbeke 已提交
902 903 904 905
                if first {
                    first = false;
                } else { space(s.s); word_space(s, "|"); }
                print_pat(s, p);
906
            }
907
            space(s.s);
M
Michael Sullivan 已提交
908
            print_possibly_embedded_block(s, arm.body, block_normal,
M
Marijn Haverbeke 已提交
909
                                          alt_indent_unit);
910
        }
M
Marijn Haverbeke 已提交
911 912 913
        bclose_(s, expr.span, alt_indent_unit);
      }
      ast::expr_fn(f) {
B
Brian Anderson 已提交
914

M
Michael Sullivan 已提交
915 916 917 918 919 920 921 922 923
        // If the return type is the magic ty_infer, then we need to
        // pretty print as a lambda-block
        if f.decl.output.node == ast::ty_infer {
            // containing cbox, will be closed by print-block at }
            cbox(s, indent_unit);
            // head-box, will be closed by print-block at start
            ibox(s, 0u);
            word(s.s, "{");
            print_fn_block_args(s, f.decl);
B
Brian Anderson 已提交
924 925
            print_possibly_embedded_block(s, f.body, block_block_fn,
                                          indent_unit);
M
Michael Sullivan 已提交
926 927
        } else {
            head(s, proto_to_str(f.proto));
B
Brian Anderson 已提交
928
            print_fn_args_and_ret(s, f.decl, []);
M
Michael Sullivan 已提交
929 930 931
            space(s.s);
            print_block(s, f.body);
        }
M
Marijn Haverbeke 已提交
932 933 934 935 936 937 938 939
      }
      ast::expr_block(blk) {
        // containing cbox, will be closed by print-block at }
        cbox(s, indent_unit);
        // head-box, will be closed by print-block after {
        ibox(s, 0u);
        print_block(s, blk);
      }
B
Brian Anderson 已提交
940
      ast::expr_copy(e) { word_space(s, "copy"); print_expr(s, e); }
M
Marijn Haverbeke 已提交
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
      ast::expr_move(lhs, rhs) {
        print_expr(s, lhs);
        space(s.s);
        word_space(s, "<-");
        print_expr(s, rhs);
      }
      ast::expr_assign(lhs, rhs) {
        print_expr(s, lhs);
        space(s.s);
        word_space(s, "=");
        print_expr(s, rhs);
      }
      ast::expr_swap(lhs, rhs) {
        print_expr(s, lhs);
        space(s.s);
        word_space(s, "<->");
        print_expr(s, rhs);
      }
      ast::expr_assign_op(op, lhs, rhs) {
        print_expr(s, lhs);
        space(s.s);
        word(s.s, ast::binop_to_str(op));
        word_space(s, "=");
        print_expr(s, rhs);
      }
      ast::expr_field(expr, id) {
        print_expr_parens_if_unary(s, expr);
        word(s.s, ".");
        word(s.s, id);
      }
      ast::expr_index(expr, index) {
        print_expr_parens_if_unary(s, expr);
B
Brian Anderson 已提交
973
        word(s.s, "[");
M
Marijn Haverbeke 已提交
974
        print_expr(s, index);
B
Brian Anderson 已提交
975
        word(s.s, "]");
M
Marijn Haverbeke 已提交
976
      }
977
      ast::expr_path(path) { print_path(s, path, true); }
M
Marijn Haverbeke 已提交
978 979 980 981 982
      ast::expr_fail(maybe_fail_val) {
        word(s.s, "fail");
        alt maybe_fail_val {
          some(expr) { word(s.s, " "); print_expr(s, expr); }
          _ { }
983
        }
M
Marijn Haverbeke 已提交
984 985 986 987 988 989 990 991
      }
      ast::expr_break. { word(s.s, "break"); }
      ast::expr_cont. { word(s.s, "cont"); }
      ast::expr_ret(result) {
        word(s.s, "ret");
        alt result {
          some(expr) { word(s.s, " "); print_expr(s, expr); }
          _ { }
992
        }
M
Marijn Haverbeke 已提交
993 994 995 996 997 998
      }
      ast::expr_put(result) {
        word(s.s, "put");
        alt result {
          some(expr) { word(s.s, " "); print_expr(s, expr); }
          _ { }
999
        }
M
Marijn Haverbeke 已提交
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
      }
      ast::expr_be(result) { word_nbsp(s, "be"); print_expr(s, result); }
      ast::expr_log(lvl, expr) {
        alt lvl { 1 { word_nbsp(s, "log"); } 0 { word_nbsp(s, "log_err"); } }
        print_expr(s, expr);
      }
      ast::expr_check(m, expr) {
        alt m {
          ast::unchecked. { word_nbsp(s, "claim"); }
          ast::checked. { word_nbsp(s, "check"); }
        }
        popen(s);
        print_expr(s, expr);
        pclose(s);
      }
      ast::expr_assert(expr) {
        word_nbsp(s, "assert");
        popen(s);
        print_expr(s, expr);
        pclose(s);
      }
      ast::expr_mac(m) { print_mac(s, m); }
      ast::expr_anon_obj(anon_obj) {
        head(s, "obj");

        // Fields
        popen(s);
        fn print_field(s: &ps, field: &ast::anon_obj_field) {
            ibox(s, indent_unit);
            print_mutability(s, field.mut);
            word_space(s, field.ident + ":");
1031
            print_type(s, field.ty);
1032
            space(s.s);
G
Graydon Hoare 已提交
1033
            word_space(s, "=");
M
Marijn Haverbeke 已提交
1034 1035
            print_expr(s, field.expr);
            end(s);
1036
        }
M
Marijn Haverbeke 已提交
1037 1038
        fn get_span(f: &ast::anon_obj_field) -> codemap::span {
            ret f.ty.span;
1039
        }
M
Marijn Haverbeke 已提交
1040 1041 1042 1043 1044
        alt anon_obj.fields {
          none. { }
          some(fields) {
            commasep_cmnt(s, consistent, fields, print_field, get_span);
          }
M
Marijn Haverbeke 已提交
1045
        }
M
Marijn Haverbeke 已提交
1046 1047 1048
        pclose(s);
        space(s.s);
        bopen(s);
1049

M
Marijn Haverbeke 已提交
1050
        // Methods
1051
        for meth: @ast::method in anon_obj.methods {
B
Brian Anderson 已提交
1052
            let typarams: [ast::ty_param] = [];
M
Marijn Haverbeke 已提交
1053 1054 1055
            hardbreak_if_not_bol(s);
            maybe_print_comment(s, meth.span.lo);
            print_fn(s, meth.node.meth.decl, meth.node.meth.proto,
B
Brian Anderson 已提交
1056
                     meth.node.ident, typarams, []);
M
Marijn Haverbeke 已提交
1057 1058 1059
            word(s.s, " ");
            print_block(s, meth.node.meth.body);
        }
1060

M
Marijn Haverbeke 已提交
1061
        // With object
1062
        alt anon_obj.inner_obj {
M
Marijn Haverbeke 已提交
1063
          none. { }
B
Brian Anderson 已提交
1064
          some(e) { space(s.s); word_space(s, "with"); print_expr(s, e); }
1065
        }
M
Marijn Haverbeke 已提交
1066 1067
        bclose(s, expr.span);
      }
B
Brian Anderson 已提交
1068
      ast::expr_uniq(expr) { word(s.s, "~"); print_expr(s, expr); }
1069
    }
1070
    s.ann.post(ann_node);
1071
    end(s);
M
Marijn Haverbeke 已提交
1072 1073
}

M
Marijn Haverbeke 已提交
1074 1075
fn print_expr_parens_if_unary(s: &ps, ex: &@ast::expr) {
    let parens = alt ex.node { ast::expr_unary(_, _) { true } _ { false } };
1076 1077 1078 1079 1080
    if parens { popen(s); }
    print_expr(s, ex);
    if parens { pclose(s); }
}

1081 1082 1083 1084
fn print_local_decl(s: &ps, loc: &@ast::local) {
    print_pat(s, loc.node.pat);
    alt loc.node.ty.node {
      ast::ty_infer. { }
1085
      _ { word_space(s, ":"); print_type(s, loc.node.ty); }
1086 1087 1088
    }
}

M
Marijn Haverbeke 已提交
1089
fn print_decl(s: &ps, decl: &@ast::decl) {
1090
    maybe_print_comment(s, decl.span.lo);
M
Marijn Haverbeke 已提交
1091 1092 1093 1094 1095 1096
    alt decl.node {
      ast::decl_local(locs) {
        space_if_not_bol(s);
        ibox(s, indent_unit);
        word_nbsp(s, "let");
        fn print_local(s: &ps, loc: &@ast::local) {
1097
            ibox(s, indent_unit);
1098
            print_local_decl(s, loc);
1099
            end(s);
M
Marijn Haverbeke 已提交
1100 1101 1102 1103 1104 1105
            alt loc.node.init {
              some(init) {
                nbsp(s);
                alt init.op {
                  ast::init_assign. { word_space(s, "="); }
                  ast::init_move. { word_space(s, "<-"); }
1106
                }
M
Marijn Haverbeke 已提交
1107 1108 1109
                print_expr(s, init.expr);
              }
              _ { }
1110
            }
M
Marijn Haverbeke 已提交
1111
        }
1112
        commasep(s, consistent, locs, print_local);
M
Marijn Haverbeke 已提交
1113 1114 1115
        end(s);
      }
      ast::decl_item(item) { print_item(s, item); }
M
Marijn Haverbeke 已提交
1116
    }
1117 1118
}

M
Marijn Haverbeke 已提交
1119
fn print_ident(s: &ps, ident: &ast::ident) { word(s.s, ident); }
1120

1121
fn print_for_decl(s: &ps, loc: &@ast::local, coll: &@ast::expr) {
1122
    print_local_decl(s, loc);
1123
    space(s.s);
1124 1125
    word_space(s, "in");
    print_expr(s, coll);
M
Marijn Haverbeke 已提交
1126 1127
}

1128
fn print_path(s: &ps, path: &ast::path, colons_before_params: bool) {
1129
    maybe_print_comment(s, path.span.lo);
1130
    if path.node.global { word(s.s, "::"); }
M
Marijn Haverbeke 已提交
1131
    let first = true;
1132
    for id: str in path.node.idents {
M
Marijn Haverbeke 已提交
1133
        if first { first = false; } else { word(s.s, "::"); }
G
Graydon Hoare 已提交
1134
        word(s.s, id);
1135
    }
B
Brian Anderson 已提交
1136
    if vec::len(path.node.types) > 0u {
1137
        if colons_before_params { word(s.s, "::"); }
1138
        word(s.s, "<");
1139
        commasep(s, inconsistent, path.node.types, print_type);
1140
        word(s.s, ">");
1141
    }
M
Marijn Haverbeke 已提交
1142 1143
}

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

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

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

M
Michael Sullivan 已提交
1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231
fn print_fn_block_args(s: &ps, decl: &ast::fn_decl) {
    word(s.s, "|");
    fn print_arg(s: &ps, x: &ast::arg) {
        ibox(s, indent_unit);
        print_alias(s, x.mode);
        word(s.s, x.ident);
        end(s);
    }
    commasep(s, inconsistent, decl.inputs, print_arg);
    word(s.s, "|");
    maybe_print_comment(s, decl.output.span.lo);
}

M
Marijn Haverbeke 已提交
1232 1233 1234 1235
fn print_alias(s: &ps, m: ast::mode) {
    alt m {
      ast::alias(true) { word_space(s, "&mutable"); }
      ast::alias(false) { word(s.s, "&"); }
1236
      ast::move. { word(s.s, "-"); }
M
Marijn Haverbeke 已提交
1237
      ast::val. { }
1238 1239 1240
    }
}

1241 1242 1243 1244
fn print_kind(s: &ps, kind: ast::kind) {
    alt kind {
      ast::kind_unique. { word(s.s, "~"); }
      ast::kind_shared. { word(s.s, "@"); }
B
Brian Anderson 已提交
1245
      _ {/* fallthrough */ }
1246 1247 1248
    }
}

1249
fn print_type_params(s: &ps, params: &[ast::ty_param]) {
B
Brian Anderson 已提交
1250
    if vec::len(params) > 0u {
1251
        word(s.s, "<");
1252
        fn printParam(s: &ps, param: &ast::ty_param) {
1253
            print_kind(s, param.kind);
1254 1255
            word(s.s, param.ident);
        }
1256
        commasep(s, inconsistent, params, printParam);
1257
        word(s.s, ">");
1258
    }
M
Marijn Haverbeke 已提交
1259 1260
}

M
Marijn Haverbeke 已提交
1261
fn print_meta_item(s: &ps, item: &@ast::meta_item) {
1262
    ibox(s, indent_unit);
M
Marijn Haverbeke 已提交
1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275
    alt item.node {
      ast::meta_word(name) { word(s.s, name); }
      ast::meta_name_value(name, value) {
        word_space(s, name);
        word_space(s, "=");
        print_literal(s, @value);
      }
      ast::meta_list(name, items) {
        word(s.s, name);
        popen(s);
        commasep(s, consistent, items, print_meta_item);
        pclose(s);
      }
1276
    }
1277 1278 1279
    end(s);
}

M
Marijn Haverbeke 已提交
1280
fn print_view_item(s: &ps, item: &@ast::view_item) {
1281
    hardbreak_if_not_bol(s);
1282
    maybe_print_comment(s, item.span.lo);
M
Marijn Haverbeke 已提交
1283 1284 1285 1286
    alt item.node {
      ast::view_item_use(id, mta, _) {
        head(s, "use");
        word(s.s, id);
B
Brian Anderson 已提交
1287
        if vec::len(mta) > 0u {
M
Marijn Haverbeke 已提交
1288 1289 1290
            popen(s);
            commasep(s, consistent, mta, print_meta_item);
            pclose(s);
1291
        }
M
Marijn Haverbeke 已提交
1292 1293 1294
      }
      ast::view_item_import(id, ids, _) {
        head(s, "import");
B
Brian Anderson 已提交
1295
        if !str::eq(id, ids[vec::len(ids) - 1u]) {
M
Marijn Haverbeke 已提交
1296 1297
            word_space(s, id);
            word_space(s, "=");
G
Graydon Hoare 已提交
1298
        }
M
Marijn Haverbeke 已提交
1299
        let first = true;
1300
        for elt: str in ids {
M
Marijn Haverbeke 已提交
1301 1302
            if first { first = false; } else { word(s.s, "::"); }
            word(s.s, elt);
1303
        }
M
Marijn Haverbeke 已提交
1304
      }
1305 1306
      ast::view_item_import_from(mod_path, idents, _) {
        head(s, "import");
B
Brian Anderson 已提交
1307
        for elt: str in mod_path { word(s.s, elt); word(s.s, "::"); }
1308 1309
        word(s.s, "{");
        commasep(s, inconsistent, idents,
B
Brian Anderson 已提交
1310
                 fn (s: &ps, w: &ast::import_ident) {
1311 1312 1313 1314
                     word(s.s, w.node.name)
                 });
        word(s.s, "}");
      }
M
Marijn Haverbeke 已提交
1315 1316 1317
      ast::view_item_import_glob(ids, _) {
        head(s, "import");
        let first = true;
1318
        for elt: str in ids {
M
Marijn Haverbeke 已提交
1319 1320 1321 1322 1323
            if first { first = false; } else { word(s.s, "::"); }
            word(s.s, elt);
        }
        word(s.s, "::*");
      }
1324 1325
      ast::view_item_export(ids, _) {
        head(s, "export");
B
Brian Anderson 已提交
1326
        commasep(s, inconsistent, ids, fn (s: &ps, w: &str) { word(s.s, w) });
1327
      }
M
Marijn Haverbeke 已提交
1328
    }
G
Graydon Hoare 已提交
1329
    word(s.s, ";");
1330
    end(s); // end inner head-block
1331

1332
    end(s); // end outer head-block
1333

M
Marijn Haverbeke 已提交
1334 1335
}

1336

M
Marijn Haverbeke 已提交
1337 1338
// FIXME: The fact that this builds up the table anew for every call is
// not good. Eventually, table should be a const.
M
Marijn Haverbeke 已提交
1339
fn operator_prec(op: ast::binop) -> int {
1340
    for spec: parse::parser::op_spec in *parse::parser::prec_table() {
M
Marijn Haverbeke 已提交
1341
        if spec.op == op { ret spec.prec; }
1342 1343
    }
    fail;
M
Marijn Haverbeke 已提交
1344 1345
}

1346
fn need_parens(expr: &@ast::expr, outer_prec: int) -> bool {
M
Marijn Haverbeke 已提交
1347
    alt expr.node {
B
Brian Anderson 已提交
1348
      ast::expr_binary(op, _, _) { operator_prec(op) < outer_prec }
1349
      ast::expr_cast(_, _) { parse::parser::as_prec < outer_prec }
B
Brian Anderson 已提交
1350 1351
      ast::expr_ternary(_, _, _) { parse::parser::ternary_prec < outer_prec }

1352 1353

      // This may be too conservative in some cases
B
Brian Anderson 已提交
1354 1355 1356
      ast::expr_assign(_, _) {
        true
      }
1357 1358 1359 1360 1361 1362 1363 1364 1365 1366
      ast::expr_move(_, _) { true }
      ast::expr_swap(_, _) { true }
      ast::expr_assign_op(_, _, _) { true }
      ast::expr_ret(_) { true }
      ast::expr_put(_) { true }
      ast::expr_be(_) { true }
      ast::expr_assert(_) { true }
      ast::expr_check(_, _) { true }
      ast::expr_log(_, _) { true }
      _ { false }
M
Marijn Haverbeke 已提交
1367
    }
1368 1369 1370 1371
}

fn print_maybe_parens(s: &ps, expr: &@ast::expr, outer_prec: int) {
    let add_them = need_parens(expr, outer_prec);
M
Marijn Haverbeke 已提交
1372
    if add_them { popen(s); }
1373
    print_expr(s, expr);
M
Marijn Haverbeke 已提交
1374
    if add_them { pclose(s); }
M
Marijn Haverbeke 已提交
1375 1376
}

M
Marijn Haverbeke 已提交
1377 1378 1379 1380 1381
fn print_mutability(s: &ps, mut: &ast::mutability) {
    alt mut {
      ast::mut. { word_nbsp(s, "mutable"); }
      ast::maybe_mut. { word_nbsp(s, "mutable?"); }
      ast::imm. {/* nothing */ }
1382
    }
G
Graydon Hoare 已提交
1383 1384
}

M
Marijn Haverbeke 已提交
1385
fn print_mt(s: &ps, mt: &ast::mt) {
G
Graydon Hoare 已提交
1386
    print_mutability(s, mt.mut);
1387
    print_type(s, mt.ty);
M
Marijn Haverbeke 已提交
1388 1389
}

1390
fn print_ty_fn(s: &ps, proto: &ast::proto, id: &option::t<str>,
1391 1392
               inputs: &[ast::ty_arg], output: &@ast::ty,
               cf: &ast::controlflow, constrs: &[@ast::constr]) {
1393
    ibox(s, indent_unit);
1394
    word(s.s, proto_to_str(proto));
M
Marijn Haverbeke 已提交
1395
    alt id { some(id) { word(s.s, " "); word(s.s, id); } _ { } }
G
Graydon Hoare 已提交
1396
    zerobreak(s.s);
G
Graydon Hoare 已提交
1397
    popen(s);
M
Marijn Haverbeke 已提交
1398
    fn print_arg(s: &ps, input: &ast::ty_arg) {
1399
        print_alias(s, input.node.mode);
1400
        print_type(s, input.node.ty);
1401
    }
1402
    commasep(s, inconsistent, inputs, print_arg);
1403 1404
    pclose(s);
    maybe_print_comment(s, output.span.lo);
M
Marijn Haverbeke 已提交
1405
    if output.node != ast::ty_nil {
1406
        space_if_not_bol(s);
1407
        ibox(s, indent_unit);
G
Graydon Hoare 已提交
1408
        word_space(s, "->");
M
Marijn Haverbeke 已提交
1409
        alt cf {
1410
          ast::return. { print_type(s, output); }
M
Marijn Haverbeke 已提交
1411
          ast::noreturn. { word_nbsp(s, "!"); }
1412
        }
1413
        end(s);
1414
    }
1415
    word(s.s, ast_ty_fn_constrs_str(constrs));
1416
    end(s);
1417 1418
}

M
Marijn Haverbeke 已提交
1419
fn maybe_print_trailing_comment(s: &ps, span: codemap::span,
1420
                                next_pos: option::t<uint>) {
M
Marijn Haverbeke 已提交
1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433
    let cm;
    alt s.cm { some(ccm) { cm = ccm; } _ { ret; } }
    alt next_comment(s) {
      some(cmnt) {
        if cmnt.style != lexer::trailing { ret; }
        let span_line = codemap::lookup_char_pos(cm, span.hi);
        let comment_line = codemap::lookup_char_pos(cm, cmnt.pos);
        let next = cmnt.pos + 1u;
        alt next_pos { none. { } some(p) { next = p; } }
        if span.hi < cmnt.pos && cmnt.pos < next &&
               span_line.line == comment_line.line {
            print_comment(s, cmnt);
            s.cur_cmnt += 1u;
1434
        }
M
Marijn Haverbeke 已提交
1435 1436
      }
      _ { }
1437 1438 1439
    }
}

M
Marijn Haverbeke 已提交
1440
fn print_remaining_comments(s: &ps) {
1441 1442 1443
    // If there aren't any remaining comments, then we need to manually
    // make sure there is a line break at the end.
    if option::is_none(next_comment(s)) { hardbreak(s.s); }
M
Marijn Haverbeke 已提交
1444 1445 1446 1447
    while true {
        alt next_comment(s) {
          some(cmnt) { print_comment(s, cmnt); s.cur_cmnt += 1u; }
          _ { break; }
1448 1449 1450 1451
        }
    }
}

M
Marijn Haverbeke 已提交
1452
fn in_cbox(s: &ps) -> bool {
B
Brian Anderson 已提交
1453
    let len = vec::len(s.boxes);
M
Marijn Haverbeke 已提交
1454
    if len == 0u { ret false; }
B
Brian Anderson 已提交
1455
    ret s.boxes[len - 1u] == pp::consistent;
1456
}
1457

M
Marijn Haverbeke 已提交
1458
fn print_literal(s: &ps, lit: &@ast::lit) {
1459
    maybe_print_comment(s, lit.span.lo);
M
Marijn Haverbeke 已提交
1460 1461 1462 1463 1464
    alt next_lit(s) {
      some(lt) {
        if lt.pos == lit.span.lo { word(s.s, lt.lit); s.cur_lit += 1u; ret; }
      }
      _ { }
1465
    }
M
Marijn Haverbeke 已提交
1466 1467 1468 1469 1470 1471
    alt lit.node {
      ast::lit_str(st, kind) {
        if kind == ast::sk_unique { word(s.s, "~"); }
        print_string(s, st);
      }
      ast::lit_char(ch) {
B
Brian Anderson 已提交
1472 1473 1474
        word(s.s,
             "'" + escape_str(str::unsafe_from_bytes([ch as u8]), '\'') +
                 "'");
M
Marijn Haverbeke 已提交
1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491
      }
      ast::lit_int(val) { word(s.s, int::str(val)); }
      ast::lit_uint(val) { word(s.s, uint::str(val) + "u"); }
      ast::lit_float(fstr) { word(s.s, fstr); }
      ast::lit_mach_int(mach, val) {
        word(s.s, int::str(val as int));
        word(s.s, ast::ty_mach_to_str(mach));
      }
      ast::lit_mach_float(mach, val) {
        // val is already a str
        word(s.s, val);
        word(s.s, ast::ty_mach_to_str(mach));
      }
      ast::lit_nil. { word(s.s, "()"); }
      ast::lit_bool(val) {
        if val { word(s.s, "true"); } else { word(s.s, "false"); }
      }
1492 1493 1494
    }
}

M
Marijn Haverbeke 已提交
1495
fn lit_to_str(l: &@ast::lit) -> str { be to_str(l, print_literal); }
1496

1497
fn next_lit(s: &ps) -> option::t<lexer::lit> {
M
Marijn Haverbeke 已提交
1498 1499
    alt s.literals {
      some(lits) {
B
Brian Anderson 已提交
1500
        if s.cur_lit < vec::len(lits) {
B
Brian Anderson 已提交
1501
            ret some(lits[s.cur_lit]);
1502
        } else { ret none::<lexer::lit>; }
M
Marijn Haverbeke 已提交
1503
      }
1504
      _ { ret none::<lexer::lit>; }
1505 1506 1507
    }
}

M
Marijn Haverbeke 已提交
1508 1509 1510 1511 1512 1513 1514 1515 1516 1517
fn maybe_print_comment(s: &ps, pos: uint) {
    while true {
        alt next_comment(s) {
          some(cmnt) {
            if cmnt.pos < pos {
                print_comment(s, cmnt);
                s.cur_cmnt += 1u;
            } else { break; }
          }
          _ { break; }
1518 1519 1520 1521
        }
    }
}

M
Marijn Haverbeke 已提交
1522 1523 1524
fn print_comment(s: &ps, cmnt: lexer::cmnt) {
    alt cmnt.style {
      lexer::mixed. {
B
Brian Anderson 已提交
1525
        assert (vec::len(cmnt.lines) == 1u);
M
Marijn Haverbeke 已提交
1526
        zerobreak(s.s);
B
Brian Anderson 已提交
1527
        word(s.s, cmnt.lines[0]);
M
Marijn Haverbeke 已提交
1528 1529 1530 1531
        zerobreak(s.s);
      }
      lexer::isolated. {
        pprust::hardbreak_if_not_bol(s);
1532 1533 1534 1535 1536 1537
        for line: str in cmnt.lines {
            // Don't print empty lines because they will end up as trailing
            // whitespace
            if str::is_not_empty(line) { word(s.s, line); }
            hardbreak(s.s);
        }
M
Marijn Haverbeke 已提交
1538 1539 1540
      }
      lexer::trailing. {
        word(s.s, " ");
B
Brian Anderson 已提交
1541
        if vec::len(cmnt.lines) == 1u {
B
Brian Anderson 已提交
1542
            word(s.s, cmnt.lines[0]);
1543
            hardbreak(s.s);
M
Marijn Haverbeke 已提交
1544 1545
        } else {
            ibox(s, 0u);
1546 1547 1548 1549
            for line: str in cmnt.lines {
                if str::is_not_empty(line) { word(s.s, line); }
                hardbreak(s.s);
            }
M
Marijn Haverbeke 已提交
1550
            end(s);
1551
        }
M
Marijn Haverbeke 已提交
1552 1553 1554
      }
      lexer::blank_line. {
        // We need to do at least one, possibly two hardbreaks.
B
Brian Anderson 已提交
1555 1556 1557 1558 1559
        let is_semi =
            alt s.s.last_token() {
              pp::STRING(s, _) { s == ";" }
              _ { false }
            };
1560
        if is_semi || is_begin(s) || is_end(s) { hardbreak(s.s) }
M
Marijn Haverbeke 已提交
1561 1562
        hardbreak(s.s);
      }
1563 1564 1565
    }
}

M
Marijn Haverbeke 已提交
1566
fn print_string(s: &ps, st: &str) {
1567 1568 1569 1570 1571
    word(s.s, "\"");
    word(s.s, escape_str(st, '"'));
    word(s.s, "\"");
}

M
Marijn Haverbeke 已提交
1572 1573 1574 1575 1576
fn escape_str(st: str, to_escape: char) -> str {
    let out: str = "";
    let len = str::byte_len(st);
    let i = 0u;
    while i < len {
B
Brian Anderson 已提交
1577
        alt st[i] as char {
M
Marijn Haverbeke 已提交
1578 1579 1580 1581 1582 1583 1584 1585 1586 1587
          '\n' { out += "\\n"; }
          '\t' { out += "\\t"; }
          '\r' { out += "\\r"; }
          '\\' { out += "\\\\"; }
          cur {
            if cur == to_escape { out += "\\"; }
            // FIXME some (or all?) non-ascii things should be escaped

            str::push_char(out, cur);
          }
1588 1589 1590 1591 1592 1593
        }
        i += 1u;
    }
    ret out;
}

B
Brian Anderson 已提交
1594
fn to_str<T>(t: &T, f: fn(&ps, &T)) -> str {
B
Brian Anderson 已提交
1595
    let writer = io::string_writer();
M
Marijn Haverbeke 已提交
1596
    let s = rust_printer(writer.get_writer());
1597 1598 1599 1600 1601
    f(s, t);
    eof(s.s);
    ret writer.get_str();
}

1602
fn next_comment(s: &ps) -> option::t<lexer::cmnt> {
M
Marijn Haverbeke 已提交
1603 1604
    alt s.comments {
      some(cmnts) {
B
Brian Anderson 已提交
1605
        if s.cur_cmnt < vec::len(cmnts) {
B
Brian Anderson 已提交
1606
            ret some(cmnts[s.cur_cmnt]);
1607
        } else { ret none::<lexer::cmnt>; }
M
Marijn Haverbeke 已提交
1608
      }
1609
      _ { ret none::<lexer::cmnt>; }
1610 1611 1612
    }
}

1613 1614
// 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
B
Brian Anderson 已提交
1615 1616
fn constr_args_to_str<T>(f: &fn(&T) -> str, args: &[@ast::sp_constr_arg<T>])
   -> str {
M
Marijn Haverbeke 已提交
1617 1618
    let comma = false;
    let s = "(";
1619
    for a: @ast::sp_constr_arg<T> in args {
M
Marijn Haverbeke 已提交
1620
        if comma { s += ", "; } else { comma = true; }
1621
        s += constr_arg_to_str::<T>(f, a.node);
1622 1623 1624 1625 1626
    }
    s += ")";
    ret s;
}

B
Brian Anderson 已提交
1627 1628
fn constr_arg_to_str<T>(f: &fn(&T) -> str, c: &ast::constr_arg_general_<T>) ->
   str {
M
Marijn Haverbeke 已提交
1629 1630 1631 1632
    alt c {
      ast::carg_base. { ret "*"; }
      ast::carg_ident(i) { ret f(i); }
      ast::carg_lit(l) { ret lit_to_str(l); }
1633 1634 1635 1636 1637 1638
    }
}

// needed b/c constr_args_to_str needs
// something that takes an alias
// (argh)
M
Marijn Haverbeke 已提交
1639
fn uint_to_str(i: &uint) -> str { ret uint::str(i); }
1640

1641
fn ast_ty_fn_constr_to_str(c: &@ast::constr) -> str {
1642
    ret path_to_str(c.node.path) +
M
Marijn Haverbeke 已提交
1643
            constr_args_to_str(uint_to_str, c.node.args);
1644 1645
}

1646
// FIXME: fix repeated code
1647
fn ast_ty_fn_constrs_str(constrs: &[@ast::constr]) -> str {
M
Marijn Haverbeke 已提交
1648 1649
    let s = "";
    let colon = true;
1650
    for c: @ast::constr in constrs {
M
Marijn Haverbeke 已提交
1651
        if colon { s += " : "; colon = false; } else { s += ", "; }
1652 1653 1654 1655 1656 1657
        s += ast_ty_fn_constr_to_str(c);
    }
    ret s;
}

fn fn_arg_idx_to_str(decl: &ast::fn_decl, idx: &uint) -> str {
B
Brian Anderson 已提交
1658
    decl.inputs[idx].ident
1659 1660 1661 1662 1663 1664 1665 1666 1667
}

fn ast_fn_constr_to_str(decl: &ast::fn_decl, c: &@ast::constr) -> str {
    let arg_to_str = bind fn_arg_idx_to_str(decl, _);
    ret path_to_str(c.node.path) +
            constr_args_to_str(arg_to_str, c.node.args);
}

// FIXME: fix repeated code
B
Brian Anderson 已提交
1668
fn ast_fn_constrs_str(decl: &ast::fn_decl, constrs: &[@ast::constr]) -> str {
1669 1670
    let s = "";
    let colon = true;
1671
    for c: @ast::constr in constrs {
1672 1673
        if colon { s += " : "; colon = false; } else { s += ", "; }
        s += ast_fn_constr_to_str(decl, c);
1674 1675 1676 1677
    }
    ret s;
}

M
Marijn Haverbeke 已提交
1678 1679 1680 1681 1682 1683 1684
fn proto_to_str(p: &ast::proto) -> str {
    ret alt p {
          ast::proto_fn. { "fn" }
          ast::proto_iter. { "iter" }
          ast::proto_block. { "block" }
          ast::proto_closure. { "lambda" }
        };
1685 1686
}

M
Marijn Haverbeke 已提交
1687
fn ty_constr_to_str(c: &@ast::ty_constr) -> str {
B
Brian Anderson 已提交
1688
    fn ty_constr_path_to_str(p: &ast::path) -> str { "*." + path_to_str(p) }
1689

1690
    ret path_to_str(c.node.path) +
1691 1692
            constr_args_to_str::<ast::path>(ty_constr_path_to_str,
                                            c.node.args);
1693 1694 1695
}


1696
fn ast_ty_constrs_str(constrs: &[@ast::ty_constr]) -> str {
M
Marijn Haverbeke 已提交
1697 1698
    let s = "";
    let colon = true;
1699
    for c: @ast::ty_constr in constrs {
M
Marijn Haverbeke 已提交
1700
        if colon { s += " : "; colon = false; } else { s += ", "; }
1701 1702 1703 1704 1705
        s += ty_constr_to_str(c);
    }
    ret s;
}

1706 1707 1708 1709 1710 1711 1712 1713 1714 1715
//
// 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:
//