import std::vec; import std::str; import std::io; import std::option; import driver::session::session; import front::ast; import front::lexer; import middle::ty; import util::common; import pp; import pp::printer; import pp::break_offset; import pp::box; import pp::cbox; import pp::ibox; import pp::word; import pp::word_and_eol; import pp::space; import pp::zerobreak; import pp::hardbreak; import pp::breaks; import pp::consistent; import pp::inconsistent; import pp::end; import pp::eof; const uint indent_unit = 4u; const uint default_columns = 78u; tag mode { mo_untyped; mo_typed(ty::ctxt); } type ps = @rec(pp::printer s, option::t[vec[lexer::cmnt]] comments, mutable uint cur_cmnt, mode mode); fn print_file(session sess, ast::_mod _mod, str filename, io::writer out, mode mode) { auto cmnts = lexer::gather_comments(sess, filename); auto s = @rec(s=pp::mk_printer(out, default_columns), comments=option::some[vec[lexer::cmnt]](cmnts), mutable cur_cmnt=0u, mode=mode); print_mod(s, _mod); eof(s.s); } fn ty_to_str(&@ast::ty ty) -> str { auto writer = io::string_writer(); auto s = @rec(s=pp::mk_printer(writer.get_writer(), default_columns), comments=option::none[vec[lexer::cmnt]], mutable cur_cmnt=0u, mode=mo_untyped); print_type(s, ty); eof(s.s); ret writer.get_str(); } fn block_to_str(&ast::block blk) -> str { auto writer = io::string_writer(); auto s = @rec(s=pp::mk_printer(writer.get_writer(), default_columns), comments=option::none[vec[lexer::cmnt]], mutable cur_cmnt=0u, mode=mo_untyped); cbox(s.s, indent_unit); // containing cbox, will be closed by print-block at } ibox(s.s, 0u); // head-ibox, will be closed by print-block after { print_block(s, blk); eof(s.s); ret writer.get_str(); } fn pat_to_str(&@ast::pat p) -> str { auto writer = io::string_writer(); auto s = @rec(s=pp::mk_printer(writer.get_writer(), default_columns), comments=option::none[vec[lexer::cmnt]], mutable cur_cmnt=0u, mode=mo_untyped); print_pat(s, p); eof(s.s); ret writer.get_str(); } fn word_nbsp(ps s, str w) { word(s.s, w); word(s.s, " "); } fn word_space(ps s, str w) { word(s.s, w); space(s.s); } fn popen(ps s) { word(s.s, "("); } fn pclose(ps s) { word(s.s, ")"); } fn head(ps s, str w) { // outer-box is consistent cbox(s.s, indent_unit); // head-box is inconsistent ibox(s.s, str::char_len(w) + 1u); // keyword that starts the head word_nbsp(s, w); } fn bopen(ps s) { word(s.s, "{"); end(s.s); // close the head-box } fn bclose(ps s, common::span span) { maybe_print_comment(s, span.hi); break_offset(s.s, 1u, -(indent_unit as int)); word(s.s, "}"); end(s.s); // close the outer-box } fn commasep[IN](ps s, breaks b, vec[IN] elts, fn(ps, &IN) op) { box(s.s, 0u, b); auto first = true; for (IN elt in elts) { if (first) {first = false;} else {word_space(s, ",");} op(s, elt); } end(s.s); } fn commasep_cmnt[IN](ps s, breaks b, vec[IN] elts, fn(ps, &IN) op, fn(&IN) -> common::span get_span) { box(s.s, 0u, b); auto len = vec::len[IN](elts); auto i = 0u; for (IN elt in elts) { op(s, elt); i += 1u; if (i < len) { word(s.s, ","); if (!maybe_print_line_comment(s, get_span(elt))) {space(s.s);} } } end(s.s); } fn commasep_exprs(ps s, breaks b, vec[@ast::expr] exprs) { fn expr_span(&@ast::expr expr) -> common::span {ret expr.span;} auto f = print_expr; auto gs = expr_span; commasep_cmnt[@ast::expr](s, b, exprs, f, gs); } fn print_mod(ps s, ast::_mod _mod) { for (@ast::view_item vitem in _mod.view_items) { print_view_item(s, vitem); } for (@ast::item item in _mod.items) { // Mod-level item printing we're a little more space-y about. hardbreak(s.s); print_item(s, item); } print_remaining_comments(s); } fn print_type(ps s, &@ast::ty ty) { maybe_print_comment(s, ty.span.lo); ibox(s.s, 0u); alt (ty.node) { 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");} case (ast::ty_machine(?tm)) {word(s.s, common::ty_mach_to_str(tm));} case (ast::ty_char) {word(s.s, "char");} case (ast::ty_str) {word(s.s, "str");} case (ast::ty_box(?mt)) {word(s.s, "@"); print_mt(s, mt);} case (ast::ty_vec(?mt)) { word(s.s, "vec["); print_mt(s, mt); word(s.s, "]"); } case (ast::ty_port(?t)) { word(s.s, "port["); print_type(s, t); word(s.s, "]"); } case (ast::ty_chan(?t)) { word(s.s, "chan["); print_type(s, t); word(s.s, "]"); } case (ast::ty_type) {word(s.s, "type");} case (ast::ty_tup(?elts)) { word(s.s, "tup"); popen(s); auto f = print_mt; commasep[ast::mt](s, inconsistent, elts, f); pclose(s); } case (ast::ty_rec(?fields)) { word(s.s, "rec"); popen(s); fn print_field(ps s, &ast::ty_field f) { cbox(s.s, indent_unit); print_mt(s, f.mt); space(s.s); word(s.s, f.ident); end(s.s); } fn get_span(&ast::ty_field f) -> common::span { // Try to reconstruct the span for this field auto sp = f.mt.ty.span; auto hi = sp.hi + str::char_len(f.ident) + 1u; ret rec(hi=hi with sp); } auto f = print_field; auto gs = get_span; commasep_cmnt[ast::ty_field](s, consistent, fields, f, gs); pclose(s); } case (ast::ty_obj(?methods)) { head(s, "obj"); bopen(s); for (ast::ty_method m in methods) { cbox(s.s, indent_unit); print_ty_fn(s, m.proto, option::some[str](m.ident), m.inputs, m.output, m.cf); word(s.s, ";"); end(s.s); } bclose(s, ty.span); } case (ast::ty_fn(?proto,?inputs,?output,?cf)) { print_ty_fn(s, proto, option::none[str], inputs, output, cf); } case (ast::ty_path(?path,_)) { print_path(s, path); } } end(s.s); } fn print_item(ps s, @ast::item item) { hardbreak(s.s); maybe_print_comment(s, item.span.lo); alt (item.node) { case (ast::item_const(?id, ?ty, ?expr, _, _)) { head(s, "const"); print_type(s, ty); space(s.s); word_space(s, id); end(s.s); // end the head-ibox word_space(s, "="); print_expr(s, expr); word(s.s, ";"); end(s.s); // end the outer cbox } case (ast::item_fn(?name,?_fn,?typarams,_,_)) { print_fn(s, _fn.decl, name, typarams); word(s.s, " "); print_block(s, _fn.body); } case (ast::item_mod(?id,?_mod,_)) { head(s, "mod"); bopen(s); for (@ast::item itm in _mod.items) {print_item(s, itm);} bclose(s, item.span); } case (ast::item_native_mod(?id,?nmod,_)) { head(s, "native"); alt (nmod.abi) { case (ast::native_abi_rust) {word_nbsp(s, "\"rust\"");} case (ast::native_abi_cdecl) {word_nbsp(s, "\"cdecl\"");} case (ast::native_abi_rust_intrinsic) { word_nbsp(s, "\"rust-intrinsic\""); } } word_nbsp(s, "mod"); word_nbsp(s, id); bopen(s); for (@ast::native_item item in nmod.items) { ibox(s.s, indent_unit); maybe_print_comment(s, item.span.lo); alt (item.node) { case (ast::native_item_ty(?id,_)) { word_nbsp(s, "type"); word(s.s, id); } case (ast::native_item_fn(?id,?lname,?decl, ?typarams,_,_)) { print_fn(s, decl, id, typarams); end(s.s); // end head-ibox alt (lname) { case (option::none[str]) {} case (option::some[str](?ss)) { print_string(s, ss); } } } } word(s.s, ";"); end(s.s); } bclose(s, item.span); } case (ast::item_ty(?id,?ty,?params,_,_)) { ibox(s.s, indent_unit); ibox(s.s, 0u); word_nbsp(s, "type"); word(s.s, id); print_type_params(s, params); end(s.s); // end the inner ibox space(s.s); word_space(s, "="); print_type(s, ty); word(s.s, ";"); end(s.s); // end the outer ibox break_offset(s.s, 0u, 0); } case (ast::item_tag(?id,?variants,?params,_,_)) { head(s, "tag"); word(s.s, id); print_type_params(s, params); space(s.s); bopen(s); for (ast::variant v in variants) { space(s.s); maybe_print_comment(s, v.span.lo); word(s.s, v.node.name); if (vec::len[ast::variant_arg](v.node.args) > 0u) { popen(s); fn print_variant_arg(ps s, &ast::variant_arg arg) { print_type(s, arg.ty); } auto f = print_variant_arg; commasep[ast::variant_arg](s, consistent, v.node.args, f); pclose(s); } word(s.s, ";"); maybe_print_line_comment(s, v.span); } bclose(s, item.span); } case (ast::item_obj(?id,?_obj,?params,_,_)) { head(s, "obj"); word(s.s, id); print_type_params(s, params); popen(s); fn print_field(ps s, &ast::obj_field field) { ibox(s.s, indent_unit); print_type(s, field.ty); space(s.s); word(s.s, field.ident); end(s.s); } fn get_span(&ast::obj_field f) -> common::span {ret f.ty.span;} auto f = print_field; auto gs = get_span; commasep_cmnt[ast::obj_field](s, consistent, _obj.fields, f, gs); pclose(s); space(s.s); bopen(s); for (@ast::method meth in _obj.methods) { let vec[ast::ty_param] typarams = []; hardbreak(s.s); maybe_print_comment(s, meth.span.lo); print_fn(s, meth.node.meth.decl, meth.node.ident, typarams); word(s.s, " "); print_block(s, meth.node.meth.body); } alt (_obj.dtor) { case (option::some[@ast::method](?dtor)) { head(s, "drop"); print_block(s, dtor.node.meth.body); } case (_) {} } bclose(s, item.span); } } } fn print_block(ps s, ast::block blk) { maybe_print_comment(s, blk.span.lo); bopen(s); auto first = true; for (@ast::stmt st in blk.node.stmts) { maybe_print_comment(s, st.span.lo); alt (st.node) { case (ast::stmt_decl(?decl,_)) { print_decl(s, decl); } case (ast::stmt_expr(?expr,_)) { space(s.s); print_expr(s, expr); } } if (front::parser::stmt_ends_with_semi(st)) {word(s.s, ";");} maybe_print_line_comment(s, st.span); } alt (blk.node.expr) { case (option::some[@ast::expr](?expr)) { space(s.s); print_expr(s, expr); maybe_print_line_comment(s, expr.span); } case (_) {} } bclose(s, blk.span); } fn print_literal(ps s, @ast::lit lit) { maybe_print_comment(s, lit.span.lo); alt (lit.node) { case (ast::lit_str(?st)) {print_string(s, st);} case (ast::lit_char(?ch)) { word(s.s, "'" + escape_str(str::from_bytes([ch as u8]), '\'') + "'"); } case (ast::lit_int(?val)) { word(s.s, common::istr(val)); } case (ast::lit_uint(?val)) { // FIXME clipping? uistr? word(s.s, common::istr(val as int) + "u"); } case (ast::lit_float(?fstr)) { word(s.s, fstr); } case (ast::lit_mach_int(?mach,?val)) { word(s.s, common::istr(val as int)); word(s.s, common::ty_mach_to_str(mach)); } case (ast::lit_mach_float(?mach,?val)) { // val is already a str word(s.s, val); word(s.s, common::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 print_expr(ps s, &@ast::expr expr) { maybe_print_comment(s, expr.span.lo); ibox(s.s, indent_unit); alt (s.mode) { case (mo_untyped) { /* no-op */ } case (mo_typed(_)) { popen(s); } } alt (expr.node) { case (ast::expr_vec(?exprs,?mut,_)) { if (mut == ast::mut) { word_nbsp(s, "mutable"); } ibox(s.s, indent_unit); word(s.s, "["); commasep_exprs(s, inconsistent, exprs); word(s.s, "]"); end(s.s); } case (ast::expr_tup(?exprs,_)) { fn printElt(ps s, &ast::elt elt) { ibox(s.s, indent_unit); if (elt.mut == ast::mut) {word_nbsp(s, "mutable");} print_expr(s, elt.expr); end(s.s); } fn get_span(&ast::elt elt) -> common::span {ret elt.expr.span;} word(s.s, "tup"); popen(s); auto f = printElt; auto gs = get_span; commasep_cmnt[ast::elt](s, inconsistent, exprs, f, gs); pclose(s); } case (ast::expr_rec(?fields,?wth,_)) { fn print_field(ps s, &ast::field field) { ibox(s.s, indent_unit); if (field.mut == ast::mut) {word_nbsp(s, "mutable");} word(s.s, field.ident); word(s.s, "="); print_expr(s, field.expr); end(s.s); } fn get_span(&ast::field field) -> common::span { ret field.expr.span; } word(s.s, "rec"); popen(s); auto f = print_field; auto gs = get_span; commasep_cmnt[ast::field](s, consistent, fields, f, gs); alt (wth) { case (option::some[@ast::expr](?expr)) { if (vec::len[ast::field](fields) > 0u) {space(s.s);} ibox(s.s, indent_unit); word_space(s, "with"); print_expr(s, expr); end(s.s); } case (_) {} } pclose(s); } case (ast::expr_call(?func,?args,_)) { print_expr(s, func); popen(s); commasep_exprs(s, inconsistent, args); pclose(s); } case (ast::expr_self_method(?ident,_)) { word(s.s, "self."); print_ident(s, ident); } case (ast::expr_bind(?func,?args,_)) { fn print_opt(ps s, &option::t[@ast::expr] expr) { alt (expr) { case (option::some[@ast::expr](?expr)) { print_expr(s, expr); } case (_) {word(s.s, "_");} } } word_nbsp(s, "bind"); print_expr(s, func); popen(s); auto f = print_opt; commasep[option::t[@ast::expr]](s, inconsistent, args, f); pclose(s); } case (ast::expr_spawn(_,_,?e,?es,_)) { word_nbsp(s, "spawn"); print_expr(s, e); popen(s); commasep_exprs(s, inconsistent, es); pclose(s); } case (ast::expr_binary(?op,?lhs,?rhs,_)) { auto 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); } case (ast::expr_unary(?op,?expr,_)) { word(s.s, ast::unop_to_str(op)); print_expr(s, expr); } case (ast::expr_lit(?lit,_)) { print_literal(s, lit); } case (ast::expr_cast(?expr,?ty,_)) { print_maybe_parens(s, expr, front::parser::as_prec); space(s.s); word_space(s, "as"); print_type(s, ty); } case (ast::expr_if(?test,?block,?elseopt,_)) { head(s, "if"); popen(s); print_expr(s, test); pclose(s); space(s.s); print_block(s, block); alt (elseopt) { case (option::some[@ast::expr](?_else)) { // NB: we can't use 'head' here since // it builds a block that starts in the // wrong column. cbox(s.s, indent_unit-1u); ibox(s.s, 0u); word(s.s, " else "); alt (_else.node) { case (ast::expr_block(?b, _)) { print_block(s, block); } } } case (_) { /* fall through */ } } } case (ast::expr_while(?test,?block,_)) { head(s, "while"); popen(s); print_expr(s, test); pclose(s); space(s.s); print_block(s, block); } case (ast::expr_for(?decl,?expr,?block,_)) { head(s, "for"); popen(s); print_for_decl(s, decl); space(s.s); word_space(s, "in"); print_expr(s, expr); pclose(s); space(s.s); print_block(s, block); } case (ast::expr_for_each(?decl,?expr,?block,_)) { head(s, "for each"); popen(s); print_for_decl(s, decl); space(s.s); word_space(s, "in"); print_expr(s, expr); pclose(s); space(s.s); print_block(s, block); } case (ast::expr_do_while(?block,?expr,_)) { head(s, "do"); space(s.s); print_block(s, block); space(s.s); word_space(s, "while"); popen(s); print_expr(s, expr); pclose(s); } case (ast::expr_alt(?expr,?arms,_)) { head(s, "alt"); popen(s); print_expr(s, expr); pclose(s); space(s.s); bopen(s); for (ast::arm arm in arms) { space(s.s); head(s, "case"); popen(s); print_pat(s, arm.pat); pclose(s); space(s.s); print_block(s, arm.block); } bclose(s, expr.span); } case (ast::expr_block(?block,_)) { cbox(s.s, indent_unit); // containing cbox, will be closed by print-block at } ibox(s.s, 0u); // head-box, will be closed by print-block after { print_block(s, block); } case (ast::expr_assign(?lhs,?rhs,_)) { print_expr(s, lhs); space(s.s); word_space(s, "="); print_expr(s, rhs); } case (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); } case (ast::expr_send(?lhs, ?rhs, _)) { print_expr(s, lhs); space(s.s); word_space(s, "<|"); print_expr(s, rhs); } case (ast::expr_recv(?lhs, ?rhs, _)) { print_expr(s, rhs); space(s.s); word_space(s, "|>"); print_expr(s, lhs); } case (ast::expr_field(?expr,?id,_)) { print_expr(s, expr); word(s.s, "."); word(s.s, id); } case (ast::expr_index(?expr,?index,_)) { print_expr(s, expr); word(s.s, "."); popen(s); print_expr(s, index); pclose(s); } case (ast::expr_path(?path,_)) { print_path(s, path); } case (ast::expr_fail(_)) { word(s.s, "fail"); } case (ast::expr_break(_)) { word(s.s, "break"); } case (ast::expr_cont(_)) { word(s.s, "cont"); } case (ast::expr_ret(?result,_)) { word(s.s, "ret"); alt (result) { case (option::some[@ast::expr](?expr)) { word(s.s, " "); print_expr(s, expr); } case (_) {} } } case (ast::expr_put(?result,_)) { word(s.s, "put"); alt (result) { case (option::some[@ast::expr](?expr)) { word(s.s, " "); print_expr(s, expr); } case (_) {} } } case (ast::expr_be(?result,_)) { word_nbsp(s, "be"); print_expr(s, result); } case (ast::expr_log(?lvl,?expr,_)) { alt (lvl) { case (1) {word_nbsp(s, "log");} case (0) {word_nbsp(s, "log_err");} } print_expr(s, expr); } case (ast::expr_check(?expr,_)) { word_nbsp(s, "check"); popen(s); print_expr(s, expr); pclose(s); } case (ast::expr_assert(?expr,_)) { word_nbsp(s, "assert"); popen(s); print_expr(s, expr); pclose(s); } case (ast::expr_ext(?path, ?args, ?body, _, _)) { word(s.s, "#"); print_path(s, path); if (vec::len[@ast::expr](args) > 0u) { popen(s); commasep_exprs(s, inconsistent, args); pclose(s); } // FIXME: extension 'body' } case (ast::expr_port(_)) { word(s.s, "port"); popen(s); pclose(s); } case (ast::expr_chan(?expr, _)) { word(s.s, "chan"); popen(s); print_expr(s, expr); pclose(s); } case (ast::expr_anon_obj(_,_,_,_)) { word(s.s, "anon obj"); // TODO: nicer pretty-printing of anon objs } } // Print the type if necessary. alt (s.mode) { case (mo_untyped) { /* no-op */ } case (mo_typed(?tcx)) { space(s.s); word(s.s, "as"); space(s.s); word(s.s, ty::ty_to_str(tcx, ty::expr_ty(tcx, expr))); pclose(s); } } end(s.s); } fn print_decl(ps s, @ast::decl decl) { maybe_print_comment(s, decl.span.lo); alt (decl.node) { case (ast::decl_local(?loc)) { space(s.s); ibox(s.s, indent_unit); alt (loc.ty) { case (option::some[@ast::ty](?ty)) { word_nbsp(s, "let"); print_type(s, ty); space(s.s); } case (_) { word_nbsp(s, "auto"); // Print the type if necessary. alt (s.mode) { case (mo_untyped) { /* no-op */ } case (mo_typed(?tcx)) { auto lty = ty::ann_to_type(tcx.node_types, loc.ann); word_space(s, ty::ty_to_str(tcx, lty)); } } } } word(s.s, loc.ident); alt (loc.init) { case (option::some[ast::initializer](?init)) { space(s.s); alt (init.op) { case (ast::init_assign) { word_space(s, "="); } case (ast::init_recv) { word_space(s, "<-"); } } print_expr(s, init.expr); } case (_) {} } end(s.s); } case (ast::decl_item(?item)) { print_item(s, item); } } } fn print_ident(ps s, ast::ident ident) { word(s.s, ident); } fn print_for_decl(ps s, @ast::decl decl) { alt (decl.node) { case (ast::decl_local(?loc)) { print_type(s, option::get[@ast::ty](loc.ty)); space(s.s); word(s.s, loc.ident); } } } fn print_path(ps s, ast::path path) { maybe_print_comment(s, path.span.lo); auto first = true; for (str id in path.node.idents) { if (first) {first = false;} else {word(s.s, "::");} word(s.s, id); } if (vec::len[@ast::ty](path.node.types) > 0u) { word(s.s, "["); auto f = print_type; commasep[@ast::ty](s, inconsistent, path.node.types, f); word(s.s, "]"); } } fn print_pat(ps s, &@ast::pat pat) { maybe_print_comment(s, pat.span.lo); alt (pat.node) { 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,_)) { print_path(s, path); if (vec::len[@ast::pat](args) > 0u) { popen(s); auto f = print_pat; commasep[@ast::pat](s, inconsistent, args, f); pclose(s); } } } } fn print_fn(ps s, ast::fn_decl decl, str name, vec[ast::ty_param] typarams) { alt (decl.purity) { case (ast::impure_fn) { head(s, "fn"); } case (_) { head(s, "pred"); } } word(s.s, name); print_type_params(s, typarams); popen(s); fn print_arg(ps s, &ast::arg x) { ibox(s.s, indent_unit); if (x.mode == ast::alias) {word(s.s, "&");} print_type(s, x.ty); space(s.s); word(s.s, x.ident); end(s.s); } auto f = print_arg; commasep[ast::arg](s, inconsistent, decl.inputs, f); pclose(s); maybe_print_comment(s, decl.output.span.lo); if (decl.output.node != ast::ty_nil) { space(s.s); word_space(s, "->"); print_type(s, decl.output); } } fn print_type_params(ps s, vec[ast::ty_param] params) { if (vec::len[ast::ty_param](params) > 0u) { word(s.s, "["); fn printParam(ps s, &ast::ty_param param) { word(s.s, param); } auto f = printParam; commasep[ast::ty_param](s, inconsistent, params, f); word(s.s, "]"); } } fn print_view_item(ps s, @ast::view_item item) { hardbreak(s.s); maybe_print_comment(s, item.span.lo); alt (item.node) { case (ast::view_item_use(?id,?mta,_,_)) { head(s, "use"); word(s.s, id); if (vec::len[@ast::meta_item](mta) > 0u) { popen(s); fn print_meta(ps s, &@ast::meta_item item) { ibox(s.s, indent_unit); word_space(s, item.node.name); word_space(s, "="); print_string(s, item.node.value); end(s.s); } auto f = print_meta; commasep[@ast::meta_item](s, consistent, mta, f); pclose(s); } } case (ast::view_item_import(?id,?ids,_)) { head(s, "import"); if (!str::eq(id, ids.(vec::len[str](ids)-1u))) { word_space(s, id); word_space(s, "="); } auto first = true; for (str elt in ids) { if (first) {first = false;} else {word(s.s, "::");} word(s.s, elt); } } case (ast::view_item_export(?id)) { head(s, "export"); word(s.s, id); } } word(s.s, ";"); end(s.s); // end inner head-block end(s.s); // end outer head-block } // FIXME: The fact that this builds up the table anew for every call is // not good. Eventually, table should be a const. fn operator_prec(ast::binop op) -> int { for (front::parser::op_spec spec in front::parser::prec_table()) { if (spec.op == op) {ret spec.prec;} } fail; } fn print_maybe_parens(ps s, @ast::expr expr, int outer_prec) { auto add_them; alt (expr.node) { case (ast::expr_binary(?op,_,_,_)) { add_them = operator_prec(op) < outer_prec; } case (ast::expr_cast(_,_,_)) { add_them = front::parser::as_prec < outer_prec; } case (_) { add_them = false; } } if (add_them) {popen(s);} print_expr(s, expr); if (add_them) {pclose(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 print_mt(ps s, &ast::mt mt) { alt (mt.mut) { case (ast::mut) { word_nbsp(s, "mutable"); } case (ast::maybe_mut) { word_nbsp(s, "mutable?"); } case (ast::imm) { /* nothing */ } } print_type(s, mt.ty); } fn print_string(ps s, str st) { word(s.s, "\""); word(s.s, escape_str(st, '"')); word(s.s, "\""); } fn print_ty_fn(ps s, ast::proto proto, option::t[str] id, vec[ast::ty_arg] inputs, @ast::ty output, ast::controlflow cf) { if (proto == ast::proto_fn) {word(s.s, "fn");} else {word(s.s, "iter");} alt (id) { case (option::some[str](?id)) {space(s.s); word(s.s, id);} case (_) {} } popen(s); fn print_arg(ps s, &ast::ty_arg input) { if (input.mode == ast::alias) {word(s.s, "&");} print_type(s, input.ty); } auto f = print_arg; commasep[ast::ty_arg](s, inconsistent, inputs, f); pclose(s); maybe_print_comment(s, output.span.lo); if (output.node != ast::ty_nil) { space(s.s); ibox(s.s, indent_unit); word_space(s, "->"); alt (cf) { case (ast::return) { print_type(s, output); } case (ast::noreturn) { word_nbsp(s, "!"); } } end(s.s); } } fn next_comment(ps s) -> option::t[lexer::cmnt] { alt (s.comments) { case (option::some[vec[lexer::cmnt]](?cmnts)) { if (s.cur_cmnt < vec::len[lexer::cmnt](cmnts)) { ret option::some[lexer::cmnt](cmnts.(s.cur_cmnt)); } else {ret option::none[lexer::cmnt];} } case (_) {ret option::none[lexer::cmnt];} } } fn maybe_print_comment(ps s, uint pos) { auto first = true; while (true) { alt (next_comment(s)) { case (option::some[lexer::cmnt](?cmnt)) { if (cmnt.pos < pos) { if (first) { first = false; break_offset(s.s, 0u, 0); } print_comment(s, cmnt); s.cur_cmnt += 1u; } else { break; } } case (_) {break;} } } } fn maybe_print_line_comment(ps s, common::span span) -> bool { alt (next_comment(s)) { case (option::some[lexer::cmnt](?cmnt)) { if (span.hi + 4u >= cmnt.pos) { word(s.s, " "); print_comment(s, cmnt); s.cur_cmnt += 1u; ret true; } } case (_) {} } ret false; } fn print_remaining_comments(ps s) { while (true) { alt (next_comment(s)) { case (option::some[lexer::cmnt](?cmnt)) { print_comment(s, cmnt); s.cur_cmnt += 1u; } case (_) {break;} } } } fn print_comment(ps s, lexer::cmnt cmnt) { alt (cmnt.style) { case (lexer::isolated) { cbox(s.s, 0u); for (str line in cmnt.lines) { zerobreak(s.s); word_and_eol(s.s, line); } zerobreak(s.s); end(s.s); } case (lexer::trailing) { cbox(s.s, 0u); for (str line in cmnt.lines) { word_and_eol(s.s, line); zerobreak(s.s); } end(s.s); } case (lexer::mixed) { assert vec::len(cmnt.lines) == 1u; zerobreak(s.s); word(s.s, cmnt.lines.(0)); zerobreak(s.s); } } } // // 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: //