Niko Matsakis 1ba4ca4c4a allow fn exprs to omit arg types
also, avoid using type variables for fn args with omitted types
unless necessary.  This will be important for bound regions in
fn types.

fixes #2093
2012-05-03 14:32:32 -07:00

1847 lines
51 KiB
Rust

import parse::classify::*;
import parse::comments;
import parse::lexer;
import codemap::codemap;
import pp::{break_offset, word, printer,
space, zerobreak, hardbreak, breaks, consistent,
inconsistent, eof};
import diagnostic;
import ast_util::operator_prec;
// The ps is stored here to prevent recursive type.
enum ann_node {
node_block(ps, ast::blk),
node_item(ps, @ast::item),
node_expr(ps, @ast::expr),
node_pat(ps, @ast::pat),
}
type pp_ann = {pre: fn@(ann_node), post: fn@(ann_node)};
fn no_ann() -> pp_ann {
fn ignore(_node: ann_node) { }
ret {pre: ignore, post: ignore};
}
type ps =
@{s: pp::printer,
cm: option<codemap>,
comments: option<[comments::cmnt]>,
literals: option<[comments::lit]>,
mut cur_cmnt: uint,
mut cur_lit: uint,
mut boxes: [pp::breaks],
ann: pp_ann};
fn ibox(s: ps, u: uint) { s.boxes += [pp::inconsistent]; pp::ibox(s.s, u); }
fn end(s: ps) { vec::pop(s.boxes); pp::end(s.s); }
fn rust_printer(writer: io::writer) -> ps {
let boxes: [pp::breaks] = [];
ret @{s: pp::mk_printer(writer, default_columns),
cm: none::<codemap>,
comments: none::<[comments::cmnt]>,
literals: none::<[comments::lit]>,
mut cur_cmnt: 0u,
mut cur_lit: 0u,
mut boxes: boxes,
ann: no_ann()};
}
const indent_unit: uint = 4u;
const alt_indent_unit: uint = 2u;
const default_columns: uint = 78u;
// Requires you to pass an input filename and reader so that
// it can scan the input text for comments and literals to
// copy forward.
fn print_crate(cm: codemap, span_diagnostic: diagnostic::span_handler,
crate: @ast::crate, filename: str, in: io::reader,
out: io::writer, ann: pp_ann) {
let boxes: [pp::breaks] = [];
let r = comments::gather_comments_and_literals(span_diagnostic,
filename, in);
let s =
@{s: pp::mk_printer(out, default_columns),
cm: some(cm),
comments: some(r.cmnts),
literals: some(r.lits),
mut cur_cmnt: 0u,
mut cur_lit: 0u,
mut boxes: boxes,
ann: ann};
print_crate_(s, crate);
}
fn print_crate_(s: ps, &&crate: @ast::crate) {
print_mod(s, crate.node.module, crate.node.attrs);
print_remaining_comments(s);
eof(s.s);
}
fn ty_to_str(ty: @ast::ty) -> str { be to_str(ty, print_type); }
fn pat_to_str(pat: @ast::pat) -> str { be to_str(pat, print_pat); }
fn expr_to_str(e: @ast::expr) -> str { be to_str(e, print_expr); }
fn stmt_to_str(s: ast::stmt) -> str { be to_str(s, print_stmt); }
fn item_to_str(i: @ast::item) -> str { be to_str(i, print_item); }
fn attr_to_str(i: ast::attribute) -> str { be to_str(i, print_attribute); }
fn typarams_to_str(tps: [ast::ty_param]) -> str {
be to_str(tps, print_type_params)
}
fn path_to_str(&&p: @ast::path) -> str {
be to_str(p, bind print_path(_, _, false));
}
fn fun_to_str(decl: ast::fn_decl, name: ast::ident,
params: [ast::ty_param]) -> str {
let buffer = io::mem_buffer();
let s = rust_printer(io::mem_buffer_writer(buffer));
print_fn(s, decl, name, params);
end(s); // Close the head box
end(s); // Close the outer box
eof(s.s);
io::mem_buffer_str(buffer)
}
#[test]
fn test_fun_to_str() {
let decl: ast::fn_decl = {
inputs: [],
output: @{id: 0,
node: ast::ty_nil,
span: ast_util::dummy_sp()},
purity: ast::impure_fn,
cf: ast::return_val,
constraints: []
};
assert fun_to_str(decl, "a", []) == "fn a()";
}
fn res_to_str(decl: ast::fn_decl, name: ast::ident,
params: [ast::ty_param], rp: ast::region_param) -> str {
let buffer = io::mem_buffer();
let s = rust_printer(io::mem_buffer_writer(buffer));
print_res(s, decl, name, params, rp);
end(s); // Close the head box
end(s); // Close the outer box
eof(s.s);
io::mem_buffer_str(buffer)
}
#[test]
fn test_res_to_str() {
let decl: ast::fn_decl = {
inputs: [{
mode: ast::expl(ast::by_val),
ty: @{id: 0,
node: ast::ty_nil,
span: ast_util::dummy_sp()},
ident: "b",
id: 0
}],
output: @{id: 0,
node: ast::ty_nil,
span: ast_util::dummy_sp()},
purity: ast::impure_fn,
cf: ast::return_val,
constraints: []
};
assert res_to_str(decl, "a", []) == "resource a(b: ())";
}
fn block_to_str(blk: ast::blk) -> str {
let buffer = io::mem_buffer();
let s = rust_printer(io::mem_buffer_writer(buffer));
// containing cbox, will be closed by print-block at }
cbox(s, indent_unit);
// head-ibox, will be closed by print-block after {
ibox(s, 0u);
print_block(s, blk);
eof(s.s);
io::mem_buffer_str(buffer)
}
fn meta_item_to_str(mi: ast::meta_item) -> str {
ret to_str(@mi, print_meta_item);
}
fn attribute_to_str(attr: ast::attribute) -> str {
be to_str(attr, print_attribute);
}
fn variant_to_str(var: ast::variant) -> str {
be to_str(var, print_variant);
}
#[test]
fn test_variant_to_str() {
let var = ast_util::respan(ast_util::dummy_sp(), {
name: "principle_skinner",
attrs: [],
args: [],
id: 0,
disr_expr: none
});
let varstr = variant_to_str(var);
assert varstr == "principle_skinner";
}
fn cbox(s: ps, u: uint) { s.boxes += [pp::consistent]; pp::cbox(s.s, u); }
fn box(s: ps, u: uint, b: pp::breaks) { s.boxes += [b]; pp::box(s.s, u, b); }
fn nbsp(s: ps) { word(s.s, " "); }
fn word_nbsp(s: ps, w: str) { word(s.s, w); nbsp(s); }
fn word_space(s: ps, w: str) { word(s.s, w); space(s.s); }
fn popen(s: ps) { word(s.s, "("); }
fn pclose(s: ps) { word(s.s, ")"); }
fn head(s: ps, w: str) {
// outer-box is consistent
cbox(s, indent_unit);
// head-box is inconsistent
ibox(s, str::len(w) + 1u);
// keyword that starts the head
word_nbsp(s, w);
}
fn bopen(s: ps) {
word(s.s, "{");
end(s); // close the head-box
}
fn bclose_(s: ps, span: codemap::span, indented: uint) {
maybe_print_comment(s, span.hi);
break_offset_if_not_bol(s, 1u, -(indented as int));
word(s.s, "}");
end(s); // close the outer-box
}
fn bclose(s: ps, span: codemap::span) { bclose_(s, span, indent_unit); }
fn is_begin(s: ps) -> bool {
alt s.s.last_token() { pp::BEGIN(_) { true } _ { false } }
}
fn is_end(s: ps) -> bool {
alt s.s.last_token() { pp::END { true } _ { false } }
}
fn is_bol(s: ps) -> bool {
ret s.s.last_token() == pp::EOF ||
s.s.last_token() == pp::hardbreak_tok();
}
fn in_cbox(s: ps) -> bool {
let len = vec::len(s.boxes);
if len == 0u { ret false; }
ret s.boxes[len - 1u] == pp::consistent;
}
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) {
break_offset(s.s, n, off);
} else {
if off != 0 && s.s.last_token() == pp::hardbreak_tok() {
// We do something pretty sketchy here: tuck the nonzero
// offset-adjustment we were going to deposit along with the
// break into the previous hardbreak.
s.s.replace_last_token(pp::hardbreak_tok_offset(off));
}
}
}
// Synthesizes a comment that was not textually present in the original source
// file.
fn synth_comment(s: ps, text: str) {
word(s.s, "/*");
space(s.s);
word(s.s, text);
space(s.s);
word(s.s, "*/");
}
fn commasep<IN>(s: ps, b: breaks, elts: [IN], op: fn(ps, IN)) {
box(s, 0u, b);
let mut first = true;
for elts.each {|elt|
if first { first = false; } else { word_space(s, ","); }
op(s, elt);
}
end(s);
}
fn commasep_cmnt<IN>(s: ps, b: breaks, elts: [IN], op: fn(ps, IN),
get_span: fn(IN) -> codemap::span) {
box(s, 0u, b);
let len = vec::len::<IN>(elts);
let mut i = 0u;
for elts.each {|elt|
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_bol(s);
}
}
end(s);
}
fn commasep_exprs(s: ps, b: breaks, exprs: [@ast::expr]) {
fn expr_span(&&expr: @ast::expr) -> codemap::span { ret expr.span; }
commasep_cmnt(s, b, exprs, print_expr, expr_span);
}
fn print_mod(s: ps, _mod: ast::_mod, attrs: [ast::attribute]) {
print_inner_attributes(s, attrs);
for _mod.view_items.each {|vitem|
print_view_item(s, vitem);
}
for _mod.items.each {|item| print_item(s, item); }
}
fn print_native_mod(s: ps, nmod: ast::native_mod, attrs: [ast::attribute]) {
print_inner_attributes(s, attrs);
for nmod.view_items.each {|vitem|
print_view_item(s, vitem);
}
for nmod.items.each {|item| print_native_item(s, item); }
}
fn print_region(s: ps, region: @ast::region) {
alt region.node {
ast::re_anon { word_space(s, "&"); }
ast::re_named(name) {
word(s.s, "&");
word_space(s, name);
}
}
}
fn print_type(s: ps, &&ty: @ast::ty) {
maybe_print_comment(s, ty.span.lo);
ibox(s, 0u);
alt ty.node {
ast::ty_nil { word(s.s, "()"); }
ast::ty_bot { word(s.s, "!"); }
ast::ty_box(mt) { word(s.s, "@"); print_mt(s, mt); }
ast::ty_uniq(mt) { word(s.s, "~"); print_mt(s, mt); }
ast::ty_vec(mt) {
word(s.s, "[");
alt mt.mutbl {
ast::m_mutbl { word_space(s, "mut"); }
ast::m_const { word_space(s, "const"); }
ast::m_imm { }
}
print_type(s, mt.ty);
word(s.s, "]");
}
ast::ty_ptr(mt) { word(s.s, "*"); print_mt(s, mt); }
ast::ty_rptr(region, mt) {
alt region.node {
ast::re_anon { word(s.s, "&"); }
_ { print_region(s, region); word(s.s, "."); }
}
print_mt(s, mt);
}
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.mutbl);
word(s.s, f.node.ident);
word_space(s, ":");
print_type(s, f.node.mt.ty);
end(s);
}
fn get_span(f: ast::ty_field) -> codemap::span { ret f.span; }
commasep_cmnt(s, consistent, fields, print_field, get_span);
word(s.s, ",}");
}
ast::ty_tup(elts) {
popen(s);
commasep(s, inconsistent, elts, print_type);
pclose(s);
}
ast::ty_fn(proto, d) {
print_ty_fn(s, some(proto), d, none, none);
}
ast::ty_path(path, _) { print_path(s, path, false); }
ast::ty_constr(t, cs) {
print_type(s, t);
space(s.s);
word(s.s, constrs_str(cs, ty_constr_to_str));
}
ast::ty_vstore(t, v) {
print_type(s, t);
print_vstore(s, v);
}
ast::ty_mac(_) {
fail "print_type doesn't know how to print a ty_mac";
}
ast::ty_infer {
fail "print_type shouldn't see a ty_infer";
}
}
end(s);
}
fn print_native_item(s: ps, item: @ast::native_item) {
hardbreak_if_not_bol(s);
maybe_print_comment(s, item.span.lo);
print_outer_attributes(s, item.attrs);
alt item.node {
ast::native_item_fn(decl, typarams) {
print_fn(s, decl, item.ident, typarams);
end(s); // end head-ibox
word(s.s, ";");
end(s); // end the outer fn box
}
}
}
fn print_item(s: ps, &&item: @ast::item) {
hardbreak_if_not_bol(s);
maybe_print_comment(s, item.span.lo);
print_outer_attributes(s, item.attrs);
let ann_node = node_item(s, item);
s.ann.pre(ann_node);
alt item.node {
ast::item_const(ty, expr) {
head(s, "const");
word_space(s, item.ident + ":");
print_type(s, ty);
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
}
ast::item_fn(decl, typarams, body) {
print_fn(s, decl, item.ident, typarams);
word(s.s, " ");
print_block_with_attrs(s, body, item.attrs);
}
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");
word_nbsp(s, "mod");
word_nbsp(s, item.ident);
bopen(s);
print_native_mod(s, nmod, item.attrs);
bclose(s, item.span);
}
ast::item_ty(ty, params, rp) {
ibox(s, indent_unit);
ibox(s, 0u);
word_nbsp(s, "type");
word(s.s, item.ident);
print_region_param(s, rp);
print_type_params(s, params);
end(s); // end the inner ibox
space(s.s);
word_space(s, "=");
print_type(s, ty);
word(s.s, ";");
end(s); // end the outer ibox
}
ast::item_enum(variants, params, rp) {
let newtype =
vec::len(variants) == 1u &&
str::eq(item.ident, variants[0].node.name) &&
vec::len(variants[0].node.args) == 1u;
if newtype {
ibox(s, indent_unit);
word_space(s, "enum");
} else { head(s, "enum"); }
word(s.s, item.ident);
print_region_param(s, rp);
print_type_params(s, params);
space(s.s);
if newtype {
word_space(s, "=");
print_type(s, variants[0].node.args[0].ty);
word(s.s, ";");
end(s);
} else {
bopen(s);
for variants.each {|v|
space_if_not_bol(s);
maybe_print_comment(s, v.span.lo);
print_outer_attributes(s, v.node.attrs);
ibox(s, indent_unit);
print_variant(s, v);
word(s.s, ",");
end(s);
maybe_print_trailing_comment(s, v.span, none::<uint>);
}
bclose(s, item.span);
}
}
ast::item_class(tps,ifaces,items,ctor, rp) {
head(s, "class");
word_nbsp(s, item.ident);
print_region_param(s, rp);
print_type_params(s, tps);
word_space(s, "implements");
commasep(s, inconsistent, ifaces, {|s, p|
print_path(s, p.path, false)});
bopen(s);
hardbreak_if_not_bol(s);
maybe_print_comment(s, ctor.span.lo);
head(s, "new");
print_fn_args_and_ret(s, ctor.node.dec);
space(s.s);
print_block(s, ctor.node.body);
for items.each {|ci|
/*
FIXME: collect all private items and print them
in a single "priv" section
tjc: I'm not going to fix this yet b/c we might
change how exports work, including for class items
(see #1893)
*/
hardbreak_if_not_bol(s);
maybe_print_comment(s, ci.span.lo);
let pr = ast_util::class_member_privacy(ci);
alt pr {
ast::priv {
head(s, "priv");
bopen(s);
hardbreak_if_not_bol(s);
}
_ {}
}
alt ci.node {
ast::instance_var(nm, t, mt, _,_) {
word_nbsp(s, "let");
alt mt {
ast::class_mutable { word_nbsp(s, "mut"); }
_ {}
}
word(s.s, nm);
word_nbsp(s, ":");
print_type(s, t);
word(s.s, ";");
}
ast::class_method(m) {
print_method(s, m);
}
}
alt pr {
ast::priv { bclose(s, ci.span); }
_ {}
}
}
bclose(s, item.span);
}
ast::item_impl(tps, rp, ifce, ty, methods) {
head(s, "impl");
word(s.s, item.ident);
print_region_param(s, rp);
print_type_params(s, tps);
space(s.s);
option::iter(ifce, {|p|
word_nbsp(s, "of");
print_path(s, p.path, false);
space(s.s);
});
word_nbsp(s, "for");
print_type(s, ty);
space(s.s);
bopen(s);
for methods.each {|meth|
print_method(s, meth);
}
bclose(s, item.span);
}
ast::item_iface(tps, rp, methods) {
head(s, "iface");
word(s.s, item.ident);
print_region_param(s, rp);
print_type_params(s, tps);
word(s.s, " ");
bopen(s);
for methods.each {|meth| print_ty_method(s, meth); }
bclose(s, item.span);
}
ast::item_res(decl, tps, body, dt_id, ct_id, rp) {
print_res(s, decl, item.ident, tps, rp);
print_block(s, body);
}
}
s.ann.post(ann_node);
}
fn print_res(s: ps, decl: ast::fn_decl, name: ast::ident,
typarams: [ast::ty_param], rp: ast::region_param) {
head(s, "resource");
word(s.s, name);
print_region_param(s, rp);
print_type_params(s, typarams);
popen(s);
word_space(s, decl.inputs[0].ident + ":");
print_type(s, decl.inputs[0].ty);
pclose(s);
space(s.s);
}
fn print_variant(s: ps, v: ast::variant) {
word(s.s, v.node.name);
if vec::len(v.node.args) > 0u {
popen(s);
fn print_variant_arg(s: ps, arg: ast::variant_arg) {
print_type(s, arg.ty);
}
commasep(s, consistent, v.node.args, print_variant_arg);
pclose(s);
}
alt v.node.disr_expr {
some(d) {
space(s.s);
word_space(s, "=");
print_expr(s, d);
}
_ {}
}
}
fn print_ty_method(s: ps, m: ast::ty_method) {
hardbreak_if_not_bol(s);
maybe_print_comment(s, m.span.lo);
print_outer_attributes(s, m.attrs);
print_ty_fn(s, none, m.decl, some(m.ident), some(m.tps));
word(s.s, ";");
}
fn print_method(s: ps, meth: @ast::method) {
hardbreak_if_not_bol(s);
maybe_print_comment(s, meth.span.lo);
print_outer_attributes(s, meth.attrs);
print_fn(s, meth.decl, meth.ident, meth.tps);
word(s.s, " ");
print_block_with_attrs(s, meth.body, meth.attrs);
}
fn print_outer_attributes(s: ps, attrs: [ast::attribute]) {
let mut count = 0;
for attrs.each {|attr|
alt attr.node.style {
ast::attr_outer { print_attribute(s, attr); count += 1; }
_ {/* fallthrough */ }
}
}
if count > 0 { hardbreak_if_not_bol(s); }
}
fn print_inner_attributes(s: ps, attrs: [ast::attribute]) {
let mut count = 0;
for attrs.each {|attr|
alt attr.node.style {
ast::attr_inner {
print_attribute(s, attr);
word(s.s, ";");
count += 1;
}
_ {/* fallthrough */ }
}
}
if count > 0 { hardbreak_if_not_bol(s); }
}
fn print_attribute(s: ps, attr: ast::attribute) {
hardbreak_if_not_bol(s);
maybe_print_comment(s, attr.span.lo);
word(s.s, "#[");
print_meta_item(s, @attr.node.value);
word(s.s, "]");
}
fn print_stmt(s: ps, st: ast::stmt) {
maybe_print_comment(s, st.span.lo);
alt st.node {
ast::stmt_decl(decl, _) {
print_decl(s, decl);
}
ast::stmt_expr(expr, _) {
space_if_not_bol(s);
print_expr(s, expr);
}
ast::stmt_semi(expr, _) {
space_if_not_bol(s);
print_expr(s, expr);
word(s.s, ";");
}
}
if parse::classify::stmt_ends_with_semi(st) { word(s.s, ";"); }
maybe_print_trailing_comment(s, st.span, none::<uint>);
}
fn print_block(s: ps, blk: ast::blk) {
print_possibly_embedded_block(s, blk, block_normal, indent_unit);
}
fn print_block_with_attrs(s: ps, blk: ast::blk, attrs: [ast::attribute]) {
print_possibly_embedded_block_(s, blk, block_normal, indent_unit, attrs);
}
enum embed_type { block_macro, block_block_fn, block_normal, }
fn print_possibly_embedded_block(s: ps, blk: ast::blk, embedded: embed_type,
indented: uint) {
print_possibly_embedded_block_(
s, blk, embedded, indented, []);
}
fn print_possibly_embedded_block_(s: ps, blk: ast::blk, embedded: embed_type,
indented: uint, attrs: [ast::attribute]) {
alt blk.node.rules {
ast::unchecked_blk { word(s.s, "unchecked"); }
ast::unsafe_blk { word(s.s, "unsafe"); }
ast::default_blk { }
}
maybe_print_comment(s, blk.span.lo);
let ann_node = node_block(s, blk);
s.ann.pre(ann_node);
alt embedded {
block_macro { word(s.s, "#{"); end(s); }
block_block_fn { end(s); }
block_normal { bopen(s); }
}
print_inner_attributes(s, attrs);
for blk.node.view_items.each {|vi| print_view_item(s, vi); }
for blk.node.stmts.each {|st|
print_stmt(s, *st);
}
alt blk.node.expr {
some(expr) {
space_if_not_bol(s);
print_expr(s, expr);
maybe_print_trailing_comment(s, expr.span, some(blk.span.hi));
}
_ { }
}
bclose_(s, blk.span, indented);
s.ann.post(ann_node);
}
// 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) {
let disambig = alt e.node {
ast::expr_ret(none) | ast::expr_fail(none) { true }
_ { false }
};
if disambig { popen(s); }
print_expr(s, e);
if disambig { pclose(s); }
}
fn print_if(s: ps, test: @ast::expr, blk: ast::blk,
elseopt: option<@ast::expr>, chk: bool) {
head(s, "if");
if chk { word_nbsp(s, "check"); }
print_maybe_parens_discrim(s, test);
space(s.s);
print_block(s, blk);
fn do_else(s: ps, els: option<@ast::expr>) {
alt els {
some(_else) {
alt _else.node {
// "another else-if"
ast::expr_if(i, t, e) {
cbox(s, indent_unit - 1u);
ibox(s, 0u);
word(s.s, " else if ");
print_maybe_parens_discrim(s, i);
space(s.s);
print_block(s, t);
do_else(s, e);
}
// "final else"
ast::expr_block(b) {
cbox(s, indent_unit - 1u);
ibox(s, 0u);
word(s.s, " else ");
print_block(s, b);
}
// BLEAH, constraints would be great here
_ {
fail "print_if saw if with weird alternative";
}
}
}
_ {/* fall through */ }
}
}
do_else(s, elseopt);
}
fn print_mac(s: ps, m: ast::mac) {
alt m.node {
ast::mac_invoc(path, arg, body) {
word(s.s, "#");
print_path(s, path, false);
alt arg {
some(@{node: ast::expr_vec(_, _), _}) { }
_ { word(s.s, " "); }
}
option::iter(arg, bind print_expr(s, _));
// FIXME: extension 'body' (#2339)
}
ast::mac_embed_type(ty) {
word(s.s, "#<");
print_type(s, ty);
word(s.s, ">");
}
ast::mac_embed_block(blk) {
print_possibly_embedded_block(s, blk, block_normal, indent_unit);
}
ast::mac_ellipsis { word(s.s, "..."); }
ast::mac_var(v) { word(s.s, #fmt("$%u", v)); }
_ { /* fixme */ }
}
}
fn print_vstore(s: ps, t: ast::vstore) {
alt t {
ast::vstore_fixed(some(i)) { word_space(s, #fmt("/%u", i)); }
ast::vstore_fixed(none) { word_space(s, "/_"); }
ast::vstore_uniq { word_space(s, "/~"); }
ast::vstore_box { word_space(s, "/@"); }
ast::vstore_slice(r) { word(s.s, "/"); print_region(s, r); }
}
}
fn print_expr(s: ps, &&expr: @ast::expr) {
maybe_print_comment(s, expr.span.lo);
ibox(s, indent_unit);
let ann_node = node_expr(s, expr);
s.ann.pre(ann_node);
alt expr.node {
ast::expr_vstore(e, v) {
print_expr(s, e);
print_vstore(s, v);
}
ast::expr_vec(exprs, mutbl) {
ibox(s, indent_unit);
word(s.s, "[");
if mutbl == ast::m_mutbl {
word(s.s, "mut");
if vec::len(exprs) > 0u { nbsp(s); }
}
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.mutbl == ast::m_mutbl { word_nbsp(s, "mut"); }
word(s.s, field.node.ident);
word_space(s, ":");
print_expr(s, field.node.expr);
end(s);
}
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) {
if vec::len(fields) > 0u { space(s.s); }
ibox(s, indent_unit);
word_space(s, "with");
print_expr(s, expr);
end(s);
}
_ { word(s.s, ","); }
}
word(s.s, "}");
}
ast::expr_tup(exprs) {
popen(s);
commasep_exprs(s, inconsistent, exprs);
pclose(s);
}
ast::expr_call(func, args, has_block) {
let mut base_args = args;
let blk = if has_block {
let blk_arg = vec::pop(base_args);
alt blk_arg.node {
ast::expr_loop_body(_) { word_nbsp(s, "for"); }
_ {}
}
some(blk_arg)
} else { none };
print_expr_parens_if_not_bot(s, func);
if !has_block || vec::len(base_args) > 0u {
popen(s);
commasep_exprs(s, inconsistent, base_args);
pclose(s);
}
if has_block {
nbsp(s);
print_expr(s, option::get(blk));
}
}
ast::expr_bind(func, args) {
fn print_opt(s: ps, expr: option<@ast::expr>) {
alt expr {
some(expr) { print_expr(s, expr); }
_ { word(s.s, "_"); }
}
}
// "bind" keyword is only needed if there are no "_" arguments.
if !vec::any(args) {|arg| option::is_none(arg) } {
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_op_maybe_parens(s, lhs, prec);
space(s.s);
word_space(s, ast_util::binop_to_str(op));
print_op_maybe_parens(s, rhs, prec + 1u);
}
ast::expr_unary(op, expr) {
word(s.s, ast_util::unop_to_str(op));
print_op_maybe_parens(s, expr, parse::prec::unop_prec);
}
ast::expr_addr_of(m, expr) {
word(s.s, "&");
print_mutability(s, m);
print_expr(s, expr);
}
ast::expr_lit(lit) { print_literal(s, lit); }
ast::expr_cast(expr, ty) {
print_op_maybe_parens(s, expr, parse::prec::as_prec);
space(s.s);
word_space(s, "as");
print_type(s, ty);
}
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_while(test, blk) {
head(s, "while");
print_maybe_parens_discrim(s, test);
space(s.s);
print_block(s, blk);
}
ast::expr_loop(blk) {
head(s, "loop");
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, mode) {
cbox(s, alt_indent_unit);
ibox(s, 4u);
word_nbsp(s, "alt");
if mode == ast::alt_check { word_nbsp(s, "check"); }
print_maybe_parens_discrim(s, expr);
space(s.s);
bopen(s);
for arms.each {|arm|
space(s.s);
cbox(s, alt_indent_unit);
ibox(s, 0u);
let mut first = true;
for arm.pats.each {|p|
if first {
first = false;
} else { space(s.s); word_space(s, "|"); }
print_pat(s, p);
}
space(s.s);
alt arm.guard {
some(e) { word_space(s, "if"); print_expr(s, e); space(s.s); }
none { }
}
print_possibly_embedded_block(s, arm.body, block_normal,
alt_indent_unit);
}
bclose_(s, expr.span, alt_indent_unit);
}
ast::expr_fn(proto, decl, body, cap_clause) {
// 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, proto_to_str(proto));
print_cap_clause(s, *cap_clause);
print_fn_args_and_ret(s, decl);
space(s.s);
print_block(s, body);
}
ast::expr_fn_block(decl, body) {
// 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, decl);
print_possibly_embedded_block(s, body, block_block_fn, indent_unit);
}
ast::expr_loop_body(body) {
print_expr(s, body);
}
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);
}
ast::expr_copy(e) { word_space(s, "copy"); print_expr(s, e); }
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_util::binop_to_str(op));
word_space(s, "=");
print_expr(s, rhs);
}
ast::expr_field(expr, id, tys) {
// Deal with '10.x'
if ends_in_lit_int(expr) {
popen(s); print_expr(s, expr); pclose(s);
} else {
print_expr_parens_if_not_bot(s, expr);
}
word(s.s, ".");
word(s.s, id);
if vec::len(tys) > 0u {
word(s.s, "::<");
commasep(s, inconsistent, tys, print_type);
word(s.s, ">");
}
}
ast::expr_index(expr, index) {
print_expr_parens_if_not_bot(s, expr);
word(s.s, "[");
print_expr(s, index);
word(s.s, "]");
}
ast::expr_path(path) { print_path(s, path, true); }
ast::expr_fail(maybe_fail_val) {
word(s.s, "fail");
alt maybe_fail_val {
some(expr) { word(s.s, " "); print_expr(s, expr); }
_ { }
}
}
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); }
_ { }
}
}
ast::expr_be(result) { word_nbsp(s, "be"); print_expr(s, result); }
ast::expr_log(lvl, lexp, expr) {
alt check lvl {
1 { word_nbsp(s, "log"); print_expr(s, expr); }
0 { word_nbsp(s, "log_err"); print_expr(s, expr); }
2 {
word_nbsp(s, "log");
popen(s);
print_expr(s, lexp);
word(s.s, ",");
space_if_not_bol(s);
print_expr(s, expr);
pclose(s);
}
}
}
ast::expr_check(m, expr) {
alt m {
ast::claimed_expr { word_nbsp(s, "claim"); }
ast::checked_expr { word_nbsp(s, "check"); }
}
popen(s);
print_expr(s, expr);
pclose(s);
}
ast::expr_assert(expr) {
word_nbsp(s, "assert");
print_expr(s, expr);
}
ast::expr_new(p, _, v) {
word_nbsp(s, "new");
popen(s);
print_expr(s, p);
pclose(s);
print_expr(s, v);
}
ast::expr_mac(m) { print_mac(s, m); }
}
s.ann.post(ann_node);
end(s);
}
fn print_expr_parens_if_not_bot(s: ps, ex: @ast::expr) {
let parens = alt ex.node {
ast::expr_fail(_) | ast::expr_ret(_) |
ast::expr_binary(_, _, _) | ast::expr_unary(_, _) |
ast::expr_move(_, _) | ast::expr_copy(_) |
ast::expr_assign(_, _) | ast::expr_be(_) |
ast::expr_assign_op(_, _, _) | ast::expr_swap(_, _) |
ast::expr_log(_, _, _) | ast::expr_assert(_) |
ast::expr_call(_, _, true) |
ast::expr_check(_, _) { true }
_ { false }
};
if parens { popen(s); }
print_expr(s, ex);
if parens { pclose(s); }
}
fn print_local_decl(s: ps, loc: @ast::local) {
print_pat(s, loc.node.pat);
alt loc.node.ty.node {
ast::ty_infer { }
_ { word_space(s, ":"); print_type(s, loc.node.ty); }
}
}
fn print_decl(s: ps, decl: @ast::decl) {
maybe_print_comment(s, decl.span.lo);
alt decl.node {
ast::decl_local(locs) {
space_if_not_bol(s);
ibox(s, indent_unit);
word_nbsp(s, "let");
// if any are mut, all are mut
if vec::any(locs) {|l| l.node.is_mutbl } {
assert vec::all(locs) {|l| l.node.is_mutbl };
word_nbsp(s, "mut");
}
fn print_local(s: ps, &&loc: @ast::local) {
ibox(s, indent_unit);
print_local_decl(s, loc);
end(s);
alt loc.node.init {
some(init) {
nbsp(s);
alt init.op {
ast::init_assign { word_space(s, "="); }
ast::init_move { word_space(s, "<-"); }
}
print_expr(s, init.expr);
}
_ { }
}
}
commasep(s, consistent, locs, print_local);
end(s);
}
ast::decl_item(item) { print_item(s, item); }
}
}
fn print_ident(s: ps, ident: ast::ident) { word(s.s, ident); }
fn print_for_decl(s: ps, loc: @ast::local, coll: @ast::expr) {
print_local_decl(s, loc);
space(s.s);
word_space(s, "in");
print_expr(s, coll);
}
fn print_path(s: ps, &&path: @ast::path, colons_before_params: bool) {
maybe_print_comment(s, path.span.lo);
if path.global { word(s.s, "::"); }
let mut first = true;
for path.idents.each {|id|
if first { first = false; } else { word(s.s, "::"); }
word(s.s, id);
}
if path.rp.is_some() || !path.types.is_empty() {
if colons_before_params { word(s.s, "::"); }
alt path.rp {
none { /* ok */ }
some(r) {
word(s.s, "/");
print_region(s, r);
}
}
if !path.types.is_empty() {
word(s.s, "<");
commasep(s, inconsistent, path.types, print_type);
word(s.s, ">");
}
}
}
fn print_pat(s: ps, &&pat: @ast::pat) {
maybe_print_comment(s, pat.span.lo);
let ann_node = node_pat(s, pat);
s.ann.pre(ann_node);
/* Pat isn't normalized, but the beauty of it
is that it doesn't matter */
alt pat.node {
ast::pat_wild { word(s.s, "_"); }
ast::pat_ident(path, sub) {
print_path(s, path, true);
alt sub {
some(p) { word(s.s, "@"); print_pat(s, p); }
none {}
}
}
ast::pat_enum(path, args_) {
print_path(s, path, true);
alt args_ {
none { word(s.s, "(*)"); }
some(args) {
if vec::len(args) > 0u {
popen(s);
commasep(s, inconsistent, args, print_pat);
pclose(s);
} else { }
}
}
}
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);
}
fn get_span(f: ast::field_pat) -> codemap::span { ret f.pat.span; }
commasep_cmnt(s, consistent, fields, print_field, get_span);
if etc {
if vec::len(fields) != 0u { word_space(s, ","); }
word(s.s, "_");
}
word(s.s, "}");
}
ast::pat_tup(elts) {
popen(s);
commasep(s, inconsistent, elts, print_pat);
pclose(s);
}
ast::pat_box(inner) { word(s.s, "@"); print_pat(s, inner); }
ast::pat_uniq(inner) { word(s.s, "~"); print_pat(s, inner); }
ast::pat_lit(e) { print_expr(s, e); }
ast::pat_range(begin, end) {
print_expr(s, begin);
space(s.s);
word_space(s, "to");
print_expr(s, end);
}
}
s.ann.post(ann_node);
}
fn print_fn(s: ps, decl: ast::fn_decl, name: ast::ident,
typarams: [ast::ty_param]) {
alt decl.purity {
ast::impure_fn { head(s, "fn"); }
ast::unsafe_fn { head(s, "unsafe fn"); }
ast::pure_fn { head(s, "pure fn"); }
ast::crust_fn { head(s, "crust fn"); }
}
word(s.s, name);
print_type_params(s, typarams);
print_fn_args_and_ret(s, decl);
}
fn print_cap_clause(s: ps, cap_clause: ast::capture_clause) {
fn print_cap_item(s: ps, &&cap_item: @ast::capture_item) {
word(s.s, cap_item.name);
}
let has_copies = vec::is_not_empty(cap_clause.copies);
let has_moves = vec::is_not_empty(cap_clause.moves);
if !has_copies && !has_moves { ret; }
word(s.s, "[");
if has_copies {
word_nbsp(s, "copy");
commasep(s, inconsistent, cap_clause.copies, print_cap_item);
if has_moves {
word_space(s, ";");
}
}
if has_moves {
word_nbsp(s, "move");
commasep(s, inconsistent, cap_clause.moves, print_cap_item);
}
word(s.s, "]");
}
fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl) {
popen(s);
commasep(s, inconsistent, decl.inputs, print_arg);
pclose(s);
word(s.s, constrs_str(decl.constraints, {|c|
ast_fn_constr_to_str(decl, c)
}));
maybe_print_comment(s, decl.output.span.lo);
if decl.output.node != ast::ty_nil {
space_if_not_bol(s);
word_space(s, "->");
print_type(s, decl.output);
}
}
fn print_fn_block_args(s: ps, decl: ast::fn_decl) {
word(s.s, "|");
commasep(s, inconsistent, decl.inputs, print_arg);
word(s.s, "|");
if decl.output.node != ast::ty_infer {
space_if_not_bol(s);
word_space(s, "->");
print_type(s, decl.output);
}
maybe_print_comment(s, decl.output.span.lo);
}
fn mode_to_str(m: ast::mode) -> str {
alt m {
ast::expl(ast::by_mutbl_ref) { "&" }
ast::expl(ast::by_move) { "-" }
ast::expl(ast::by_ref) { "&&" }
ast::expl(ast::by_val) { "++" }
ast::expl(ast::by_copy) { "+" }
ast::infer(_) { "" }
}
}
fn print_arg_mode(s: ps, m: ast::mode) {
let ms = mode_to_str(m);
if ms != "" { word(s.s, ms); }
}
fn print_bounds(s: ps, bounds: @[ast::ty_param_bound]) {
if vec::len(*bounds) > 0u {
word(s.s, ":");
for vec::each(*bounds) {|bound|
nbsp(s);
alt bound {
ast::bound_copy { word(s.s, "copy"); }
ast::bound_send { word(s.s, "send"); }
ast::bound_iface(t) { print_type(s, t); }
}
}
}
}
fn print_region_param(s: ps, rp: ast::region_param) {
alt rp {
ast::rp_self { word(s.s, "/&") }
ast::rp_none { }
}
}
fn print_type_params(s: ps, &&params: [ast::ty_param]) {
if vec::len(params) > 0u {
word(s.s, "<");
fn printParam(s: ps, param: ast::ty_param) {
word(s.s, param.ident);
print_bounds(s, param.bounds);
}
commasep(s, inconsistent, params, printParam);
word(s.s, ">");
}
}
fn print_meta_item(s: ps, &&item: @ast::meta_item) {
ibox(s, indent_unit);
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);
}
}
end(s);
}
fn print_view_path(s: ps, &&vp: @ast::view_path) {
alt vp.node {
ast::view_path_simple(ident, path, _) {
if path.idents[vec::len(path.idents)-1u] != ident {
word_space(s, ident);
word_space(s, "=");
}
print_path(s, path, false);
}
ast::view_path_glob(path, _) {
print_path(s, path, false);
word(s.s, "::*");
}
ast::view_path_list(path, idents, _) {
print_path(s, path, false);
word(s.s, "::{");
commasep(s, inconsistent, idents) {|s, w|
word(s.s, w.node.name)
}
word(s.s, "}");
}
}
}
fn print_view_paths(s: ps, vps: [@ast::view_path]) {
commasep(s, inconsistent, vps, print_view_path);
}
fn print_view_item(s: ps, item: @ast::view_item) {
hardbreak_if_not_bol(s);
maybe_print_comment(s, item.span.lo);
alt item.node {
ast::view_item_use(id, mta, _) {
head(s, "use");
word(s.s, id);
if vec::len(mta) > 0u {
popen(s);
commasep(s, consistent, mta, print_meta_item);
pclose(s);
}
}
ast::view_item_import(vps) {
head(s, "import");
print_view_paths(s, vps);
}
ast::view_item_export(vps) {
head(s, "export");
print_view_paths(s, vps);
}
}
word(s.s, ";");
end(s); // end inner head-block
end(s); // end outer head-block
}
fn print_op_maybe_parens(s: ps, expr: @ast::expr, outer_prec: uint) {
let add_them = need_parens(expr, outer_prec);
if add_them { popen(s); }
print_expr(s, expr);
if add_them { pclose(s); }
}
fn print_mutability(s: ps, mutbl: ast::mutability) {
alt mutbl {
ast::m_mutbl { word_nbsp(s, "mut"); }
ast::m_const { word_nbsp(s, "const"); }
ast::m_imm {/* nothing */ }
}
}
fn print_mt(s: ps, mt: ast::mt) {
print_mutability(s, mt.mutbl);
print_type(s, mt.ty);
}
fn print_arg(s: ps, input: ast::arg) {
ibox(s, indent_unit);
print_arg_mode(s, input.mode);
alt input.ty.node {
ast::ty_infer {
word(s.s, input.ident);
}
_ {
if str::len(input.ident) > 0u {
word_space(s, input.ident + ":");
}
print_type(s, input.ty);
}
}
end(s);
}
fn print_ty_fn(s: ps, opt_proto: option<ast::proto>,
decl: ast::fn_decl, id: option<ast::ident>,
tps: option<[ast::ty_param]>) {
ibox(s, indent_unit);
word(s.s, opt_proto_to_str(opt_proto));
alt id { some(id) { word(s.s, " "); word(s.s, id); } _ { } }
alt tps { some(tps) { print_type_params(s, tps); } _ { } }
zerobreak(s.s);
popen(s);
commasep(s, inconsistent, decl.inputs, print_arg);
pclose(s);
maybe_print_comment(s, decl.output.span.lo);
if decl.output.node != ast::ty_nil {
space_if_not_bol(s);
ibox(s, indent_unit);
word_space(s, "->");
if decl.cf == ast::noreturn { word_nbsp(s, "!"); }
else { print_type(s, decl.output); }
end(s);
}
word(s.s, constrs_str(decl.constraints, ast_ty_fn_constr_to_str));
end(s);
}
fn maybe_print_trailing_comment(s: ps, span: codemap::span,
next_pos: option<uint>) {
let mut cm;
alt s.cm { some(ccm) { cm = ccm; } _ { ret; } }
alt next_comment(s) {
some(cmnt) {
if cmnt.style != comments::trailing { ret; }
let span_line = codemap::lookup_char_pos(cm, span.hi);
let comment_line = codemap::lookup_char_pos(cm, cmnt.pos);
let mut 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;
}
}
_ { }
}
}
fn print_remaining_comments(s: ps) {
// 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); }
loop {
alt next_comment(s) {
some(cmnt) { print_comment(s, cmnt); s.cur_cmnt += 1u; }
_ { break; }
}
}
}
fn print_literal(s: ps, &&lit: @ast::lit) {
maybe_print_comment(s, lit.span.lo);
alt next_lit(s, lit.span.lo) {
some(lt) {
word(s.s, lt.lit);
ret;
}
_ {}
}
alt lit.node {
ast::lit_str(st) { print_string(s, st); }
ast::lit_int(ch, ast::ty_char) {
word(s.s, "'" + escape_str(str::from_char(ch as char), '\'') + "'");
}
ast::lit_int(i, t) {
if i < 0_i64 {
word(s.s,
"-" + u64::to_str(-i as u64, 10u)
+ ast_util::int_ty_to_str(t));
} else {
word(s.s,
u64::to_str(i as u64, 10u)
+ ast_util::int_ty_to_str(t));
}
}
ast::lit_uint(u, t) {
word(s.s,
u64::to_str(u, 10u)
+ ast_util::uint_ty_to_str(t));
}
ast::lit_float(f, t) {
word(s.s, f + ast_util::float_ty_to_str(t));
}
ast::lit_nil { word(s.s, "()"); }
ast::lit_bool(val) {
if val { word(s.s, "true"); } else { word(s.s, "false"); }
}
}
}
fn lit_to_str(l: @ast::lit) -> str { be to_str(l, print_literal); }
fn next_lit(s: ps, pos: uint) -> option<comments::lit> {
alt s.literals {
some(lits) {
while s.cur_lit < vec::len(lits) {
let lt = lits[s.cur_lit];
if lt.pos > pos { ret none; }
s.cur_lit += 1u;
if lt.pos == pos { ret some(lt); }
}
ret none;
}
_ { ret none; }
}
}
fn maybe_print_comment(s: ps, pos: uint) {
loop {
alt next_comment(s) {
some(cmnt) {
if cmnt.pos < pos {
print_comment(s, cmnt);
s.cur_cmnt += 1u;
} else { break; }
}
_ { break; }
}
}
}
fn print_comment(s: ps, cmnt: comments::cmnt) {
alt cmnt.style {
comments::mixed {
assert (vec::len(cmnt.lines) == 1u);
zerobreak(s.s);
word(s.s, cmnt.lines[0]);
zerobreak(s.s);
}
comments::isolated {
pprust::hardbreak_if_not_bol(s);
for cmnt.lines.each {|line|
// 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);
}
}
comments::trailing {
word(s.s, " ");
if vec::len(cmnt.lines) == 1u {
word(s.s, cmnt.lines[0]);
hardbreak(s.s);
} else {
ibox(s, 0u);
for cmnt.lines.each {|line|
if str::is_not_empty(line) { word(s.s, line); }
hardbreak(s.s);
}
end(s);
}
}
comments::blank_line {
// We need to do at least one, possibly two hardbreaks.
let is_semi =
alt s.s.last_token() {
pp::STRING(s, _) { s == ";" }
_ { false }
};
if is_semi || is_begin(s) || is_end(s) { hardbreak(s.s); }
hardbreak(s.s);
}
}
}
fn print_string(s: ps, st: str) {
word(s.s, "\"");
word(s.s, escape_str(st, '"'));
word(s.s, "\"");
}
fn escape_str(st: str, to_escape: char) -> str {
let mut out: str = "";
let len = str::len(st);
let mut i = 0u;
while i < len {
alt st[i] as char {
'\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
// (See #2306)
str::push_char(out, cur);
}
}
i += 1u;
}
ret out;
}
fn to_str<T>(t: T, f: fn@(ps, T)) -> str {
let buffer = io::mem_buffer();
let s = rust_printer(io::mem_buffer_writer(buffer));
f(s, t);
eof(s.s);
io::mem_buffer_str(buffer)
}
fn next_comment(s: ps) -> option<comments::cmnt> {
alt s.comments {
some(cmnts) {
if s.cur_cmnt < vec::len(cmnts) {
ret some(cmnts[s.cur_cmnt]);
} else { ret none::<comments::cmnt>; }
}
_ { ret none::<comments::cmnt>; }
}
}
fn constr_args_to_str<T>(f: fn@(T) -> str, args: [@ast::sp_constr_arg<T>]) ->
str {
let mut comma = false;
let mut s = "(";
for args.each {|a|
if comma { s += ", "; } else { comma = true; }
s += constr_arg_to_str::<T>(f, a.node);
}
s += ")";
ret s;
}
fn constr_arg_to_str<T>(f: fn@(T) -> str, c: ast::constr_arg_general_<T>) ->
str {
alt c {
ast::carg_base { ret "*"; }
ast::carg_ident(i) { ret f(i); }
ast::carg_lit(l) { ret lit_to_str(l); }
}
}
// needed b/c constr_args_to_str needs
// something that takes an alias
// (argh)
fn uint_to_str(&&i: uint) -> str { ret uint::str(i); }
fn ast_ty_fn_constr_to_str(&&c: @ast::constr) -> str {
ret path_to_str(c.node.path) +
constr_args_to_str(uint_to_str, c.node.args);
}
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);
}
fn ty_constr_to_str(&&c: @ast::ty_constr) -> str {
fn ty_constr_path_to_str(&&p: @ast::path) -> str { "*." + path_to_str(p) }
ret path_to_str(c.node.path) +
constr_args_to_str::<@ast::path>(ty_constr_path_to_str,
c.node.args);
}
fn constrs_str<T>(constrs: [T], elt: fn(T) -> str) -> str {
let mut s = "", colon = true;
for constrs.each {|c|
if colon { s += " : "; colon = false; } else { s += ", "; }
s += elt(c);
}
ret s;
}
fn fn_arg_idx_to_str(decl: ast::fn_decl, &&idx: uint) -> str {
decl.inputs[idx].ident
}
fn opt_proto_to_str(opt_p: option<ast::proto>) -> str {
alt opt_p {
none { "fn" }
some(p) { proto_to_str(p) }
}
}
fn proto_to_str(p: ast::proto) -> str {
ret alt p {
ast::proto_bare { "native fn" }
ast::proto_any { "fn" }
ast::proto_block { "fn&" }
ast::proto_uniq { "fn~" }
ast::proto_box { "fn@" }
};
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//