rust/src/rustc/util/ppaux.rs

367 lines
12 KiB
Rust
Raw Normal View History

import std::map::hashmap;
import middle::ty;
import middle::ty::{arg, canon_mode};
import middle::ty::{bound_region, br_anon, br_named, br_self, br_cap_avoid};
import middle::ty::{ck_block, ck_box, ck_uniq, ctxt, field, method};
import middle::ty::{mt, t};
import middle::ty::{re_bound, re_free, re_scope, re_var, re_static, region};
import middle::ty::{ty_bool, ty_bot, ty_box, ty_class, ty_enum};
import middle::ty::{ty_estr, ty_evec, ty_float, ty_fn, ty_trait, ty_int};
import middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param};
2012-07-14 14:19:36 -05:00
import middle::ty::{ty_ptr, ty_rec, ty_rptr, ty_self, ty_tup};
import middle::ty::{ty_type, ty_uniq, ty_uint, ty_var, ty_var_integral};
2012-07-14 14:19:36 -05:00
import middle::ty::{ty_unboxed_vec, vid};
import metadata::encoder;
import syntax::codemap;
import syntax::codemap::span;
2011-11-10 10:41:42 -06:00
import syntax::print::pprust;
import syntax::print::pprust::{path_to_str, proto_to_str,
2012-05-25 01:44:58 -05:00
mode_to_str, purity_to_str};
import syntax::{ast, ast_util};
import syntax::ast_map;
import driver::session::session;
/// Returns a string like "reference valid for the block at 27:31 in foo.rs"
/// that attempts to explain a lifetime in a way it might plausibly be
/// understood.
fn explain_region(cx: ctxt, region: ty::region) -> ~str {
2012-08-06 14:34:08 -05:00
return match region {
re_scope(node_id) => {
match cx.items.find(node_id) {
some(ast_map::node_block(blk)) => {
explain_span(cx, ~"block", blk.span)
}
some(ast_map::node_expr(expr)) => {
2012-08-06 14:34:08 -05:00
match expr.node {
ast::expr_call(*) => { explain_span(cx, ~"call", expr.span) }
2012-08-07 15:35:51 -05:00
ast::expr_match(*) => { explain_span(cx, ~"alt", expr.span) }
_ => { explain_span(cx, ~"expression", expr.span) }
}
}
some(_) | none => {
// this really should not happen
fmt!{"unknown scope: %d. Please report a bug.", node_id}
}
}
}
re_free(id, br) => {
2012-08-06 14:34:08 -05:00
match cx.items.find(id) {
some(ast_map::node_block(blk)) => {
fmt!{"the lifetime %s as defined on %s",
bound_region_to_str(cx, br),
explain_span(cx, ~"block", blk.span)}
}
some(_) | none => {
// this really should not happen
fmt!{"the lifetime %s as defined on node %d",
bound_region_to_str(cx, br), id}
}
}
}
re_static => { ~"the static lifetime" }
// I believe these cases should not occur (except when debugging,
// perhaps)
re_var(_) | re_bound(_) => {
fmt!{"lifetime %?", region}
}
};
fn explain_span(cx: ctxt, heading: ~str, span: span) -> ~str {
let lo = codemap::lookup_char_pos_adj(cx.sess.codemap, span.lo);
fmt!{"the %s at %u:%u", heading, lo.line, lo.col}
}
}
fn bound_region_to_str(cx: ctxt, br: bound_region) -> ~str {
2012-08-06 14:34:08 -05:00
match br {
br_anon => { ~"&" }
br_named(str) => { fmt!{"&%s", *str} }
br_self if cx.sess.ppregions() => { ~"&<self>" }
br_self => { ~"&self" }
// FIXME(#3011) -- even if this arm is removed, exhaustiveness checking
// does not fail
br_cap_avoid(id, br) => {
if cx.sess.ppregions() {
fmt!{"br_cap_avoid(%?, %s)", id, bound_region_to_str(cx, *br)}
} else {
bound_region_to_str(cx, *br)
}
}
}
}
fn re_scope_id_to_str(cx: ctxt, node_id: ast::node_id) -> ~str {
2012-08-06 14:34:08 -05:00
match cx.items.find(node_id) {
2012-08-03 21:59:04 -05:00
some(ast_map::node_block(blk)) => {
fmt!{"<block at %s>",
codemap::span_to_str(blk.span, cx.sess.codemap)}
}
2012-08-03 21:59:04 -05:00
some(ast_map::node_expr(expr)) => {
2012-08-06 14:34:08 -05:00
match expr.node {
2012-08-03 21:59:04 -05:00
ast::expr_call(*) => {
fmt!{"<call at %s>",
codemap::span_to_str(expr.span, cx.sess.codemap)}
}
2012-08-07 15:35:51 -05:00
ast::expr_match(*) => {
fmt!{"<alt at %s>",
codemap::span_to_str(expr.span, cx.sess.codemap)}
}
2012-07-06 11:14:57 -05:00
ast::expr_assign_op(*) |
ast::expr_field(*) |
ast::expr_unary(*) |
ast::expr_binary(*) |
2012-08-03 21:59:04 -05:00
ast::expr_index(*) => {
fmt!{"<method at %s>",
codemap::span_to_str(expr.span, cx.sess.codemap)}
}
2012-08-03 21:59:04 -05:00
_ => {
fmt!{"<expression at %s>",
codemap::span_to_str(expr.span, cx.sess.codemap)}
}
}
}
2012-08-03 21:59:04 -05:00
none => {
fmt!{"<unknown-%d>", node_id}
}
2012-08-03 21:59:04 -05:00
_ => { cx.sess.bug(
fmt!{"re_scope refers to %s",
ast_map::node_id_to_str(cx.items, node_id)}) }
}
}
fn region_to_str(cx: ctxt, region: region) -> ~str {
2012-08-06 14:34:08 -05:00
match region {
2012-08-03 21:59:04 -05:00
re_scope(node_id) => {
if cx.sess.ppregions() {
fmt!{"&%s", re_scope_id_to_str(cx, node_id)}
} else {
~"&"
}
}
2012-08-03 21:59:04 -05:00
re_bound(br) => {
bound_region_to_str(cx, br)
}
2012-08-03 21:59:04 -05:00
re_free(id, br) => {
if cx.sess.ppregions() {
2012-04-17 12:05:28 -05:00
// For debugging, this version is sometimes helpful:
fmt!{"{%d} %s", id, bound_region_to_str(cx, br)}
2012-04-17 12:05:28 -05:00
} else {
// But this version is what the user expects to see:
bound_region_to_str(cx, br)
}
}
// These two should not be seen by end-users (very often, anyhow):
2012-08-03 21:59:04 -05:00
re_var(id) => fmt!{"&%s", id.to_str()},
re_static => ~"&static"
}
}
fn mt_to_str(cx: ctxt, m: mt) -> ~str {
2012-08-06 14:34:08 -05:00
let mstr = match m.mutbl {
2012-08-03 21:59:04 -05:00
ast::m_mutbl => ~"mut ",
ast::m_imm => ~"",
ast::m_const => ~"const "
2012-03-22 22:06:01 -05:00
};
2012-08-01 19:30:05 -05:00
return mstr + ty_to_str(cx, m.ty);
2012-03-22 22:06:01 -05:00
}
fn vstore_to_str(cx: ctxt, vs: ty::vstore) -> ~str {
2012-08-06 14:34:08 -05:00
match vs {
2012-08-03 21:59:04 -05:00
ty::vstore_fixed(n) => fmt!{"%u", n},
ty::vstore_uniq => ~"~",
ty::vstore_box => ~"@",
ty::vstore_slice(r) => region_to_str(cx, r)
}
}
fn vstore_ty_to_str(cx: ctxt, ty: ~str, vs: ty::vstore) -> ~str {
2012-08-06 14:34:08 -05:00
match vs {
2012-08-03 21:59:04 -05:00
ty::vstore_fixed(_) => {
fmt!{"%s/%s", ty, vstore_to_str(cx, vs)}
}
2012-08-03 21:59:04 -05:00
_ => fmt!{"%s%s", vstore_to_str(cx, vs), ty}
}
}
fn proto_ty_to_str(cx: ctxt, proto: ty::fn_proto) -> ~str {
match proto {
ty::proto_bare => ~"",
ty::proto_vstore(vstore) => vstore_to_str(cx, vstore)
}
}
fn tys_to_str(cx: ctxt, ts: ~[t]) -> ~str {
let mut rs = ~"";
2012-06-30 18:19:07 -05:00
for ts.each |t| { rs += ty_to_str(cx, t); }
rs
}
fn ty_to_str(cx: ctxt, typ: t) -> ~str {
fn fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) ->
~str {
let {mode, ty} = input;
2012-08-06 14:34:08 -05:00
let modestr = match canon_mode(cx, mode) {
2012-08-03 21:59:04 -05:00
ast::infer(_) => ~"",
ast::expl(m) => {
if !ty::type_needs_infer(ty) &&
m == ty::default_arg_mode_for_ty(ty) {
~""
} else {
mode_to_str(ast::expl(m))
}
}
};
modestr + ty_to_str(cx, ty)
}
fn fn_to_str(cx: ctxt, purity: ast::purity, proto: ty::fn_proto,
2012-05-25 01:44:58 -05:00
ident: option<ast::ident>,
inputs: ~[arg], output: t, cf: ast::ret_style) -> ~str {
2012-05-25 01:44:58 -05:00
let mut s;
2012-08-06 14:34:08 -05:00
s = match purity {
2012-08-03 21:59:04 -05:00
ast::impure_fn => ~"",
_ => purity_to_str(purity) + ~" "
2012-05-25 01:44:58 -05:00
};
s += ~"fn";
s += proto_ty_to_str(cx, proto);
2012-08-06 14:34:08 -05:00
match ident {
2012-08-03 21:59:04 -05:00
some(i) => { s += ~" "; s += *i; }
_ => { }
}
s += ~"(";
let mut strs = ~[];
2012-06-30 18:19:07 -05:00
for inputs.each |a| { vec::push(strs, fn_input_to_str(cx, a)); }
s += str::connect(strs, ~", ");
s += ~")";
if ty::get(output).struct != ty_nil {
s += ~" -> ";
2012-08-06 14:34:08 -05:00
match cf {
2012-08-03 21:59:04 -05:00
ast::noreturn => { s += ~"!"; }
ast::return_val => { s += ty_to_str(cx, output); }
}
}
2012-08-01 19:30:05 -05:00
return s;
}
fn method_to_str(cx: ctxt, m: method) -> ~str {
2012-08-01 19:30:05 -05:00
return fn_to_str(
2012-05-25 01:44:58 -05:00
cx, m.fty.purity, m.fty.proto, some(m.ident), m.fty.inputs,
m.fty.output, m.fty.ret_style) + ~";";
}
fn field_to_str(cx: ctxt, f: field) -> ~str {
2012-08-01 19:30:05 -05:00
return *f.ident + ~": " + mt_to_str(cx, f.mt);
}
// if there is an id, print that instead of the structural type:
2012-06-30 18:19:07 -05:00
for ty::type_def_id(typ).each |def_id| {
2012-05-04 14:33:04 -05:00
// note that this typedef cannot have type parameters
2012-08-01 19:30:05 -05:00
return ast_map::path_to_str(ty::item_path(cx, def_id));
}
// pretty print the structural type representation:
2012-08-06 14:34:08 -05:00
return match ty::get(typ).struct {
2012-08-03 21:59:04 -05:00
ty_nil => ~"()",
ty_bot => ~"_|_",
ty_bool => ~"bool",
ty_int(ast::ty_i) => ~"int",
ty_int(ast::ty_char) => ~"char",
ty_int(t) => ast_util::int_ty_to_str(t),
ty_uint(ast::ty_u) => ~"uint",
ty_uint(t) => ast_util::uint_ty_to_str(t),
ty_float(ast::ty_f) => ~"float",
ty_float(t) => ast_util::float_ty_to_str(t),
ty_box(tm) => ~"@" + mt_to_str(cx, tm),
ty_uniq(tm) => ~"~" + mt_to_str(cx, tm),
ty_ptr(tm) => ~"*" + mt_to_str(cx, tm),
ty_rptr(r, tm) => {
let rs = region_to_str(cx, r);
if rs == ~"&" {
rs + mt_to_str(cx, tm)
} else {
rs + ~"/" + mt_to_str(cx, tm)
}
}
2012-08-03 21:59:04 -05:00
ty_unboxed_vec(tm) => { ~"unboxed_vec<" + mt_to_str(cx, tm) + ~">" }
ty_type => ~"type",
ty_rec(elems) => {
let mut strs: ~[~str] = ~[];
2012-06-30 18:19:07 -05:00
for elems.each |fld| { vec::push(strs, field_to_str(cx, fld)); }
~"{" + str::connect(strs, ~",") + ~"}"
}
2012-08-03 21:59:04 -05:00
ty_tup(elems) => {
let mut strs = ~[];
2012-06-30 18:19:07 -05:00
for elems.each |elem| { vec::push(strs, ty_to_str(cx, elem)); }
~"(" + str::connect(strs, ~",") + ~")"
}
2012-08-03 21:59:04 -05:00
ty_fn(f) => {
2012-05-25 01:44:58 -05:00
fn_to_str(cx, f.purity, f.proto, none, f.inputs,
f.output, f.ret_style)
}
2012-08-03 21:59:04 -05:00
ty_var(v) => v.to_str(),
ty_var_integral(v) => v.to_str(),
ty_param({idx: id, _}) => {
~"'" + str::from_bytes(~[('a' as u8) + (id as u8)])
}
2012-08-03 21:59:04 -05:00
ty_self => ~"self",
ty_enum(did, substs) | ty_class(did, substs) => {
let path = ty::item_path(cx, did);
let base = ast_map::path_to_str(path);
parameterized(cx, base, substs.self_r, substs.tps)
}
ty_trait(did, substs, vs) => {
let path = ty::item_path(cx, did);
let base = ast_map::path_to_str(path);
let result = parameterized(cx, base, substs.self_r, substs.tps);
vstore_ty_to_str(cx, result, vs)
}
2012-08-03 21:59:04 -05:00
ty_evec(mt, vs) => {
vstore_ty_to_str(cx, fmt!{"[%s]", mt_to_str(cx, mt)}, vs)
}
2012-08-03 21:59:04 -05:00
ty_estr(vs) => vstore_ty_to_str(cx, ~"str", vs),
ty_opaque_box => ~"@?",
ty_opaque_closure_ptr(ck_block) => ~"closure&",
ty_opaque_closure_ptr(ck_box) => ~"closure@",
ty_opaque_closure_ptr(ck_uniq) => ~"closure~"
}
}
fn parameterized(cx: ctxt,
base: ~str,
self_r: option<ty::region>,
tps: ~[ty::t]) -> ~str {
2012-08-06 14:34:08 -05:00
let r_str = match self_r {
2012-08-03 21:59:04 -05:00
none => ~"",
some(r) => {
fmt!{"/%s", region_to_str(cx, r)}
}
};
if vec::len(tps) > 0u {
2012-06-30 18:19:07 -05:00
let strs = vec::map(tps, |t| ty_to_str(cx, t) );
fmt!{"%s%s<%s>", base, r_str, str::connect(strs, ~",")}
} else {
fmt!{"%s%s", base, r_str}
}
}
fn ty_to_short_str(cx: ctxt, typ: t) -> ~str {
let mut s = encoder::encoded_ty(cx, typ);
2012-02-23 03:44:04 -06:00
if str::len(s) >= 32u { s = str::slice(s, 0u, 32u); }
2012-08-01 19:30:05 -05:00
return s;
}
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End: