2011-06-27 17:30:17 -05:00
|
|
|
// Type decoding
|
2011-06-27 18:03:01 -05:00
|
|
|
|
2011-06-27 17:30:17 -05:00
|
|
|
import std::str;
|
|
|
|
import std::vec;
|
|
|
|
import std::uint;
|
|
|
|
import std::option;
|
|
|
|
import std::option::none;
|
|
|
|
import std::option::some;
|
2011-07-05 04:48:19 -05:00
|
|
|
import syntax::ast;
|
|
|
|
import ast::respan;
|
2011-06-27 17:30:17 -05:00
|
|
|
import middle::ty;
|
|
|
|
|
|
|
|
export parse_def_id;
|
|
|
|
export parse_ty_data;
|
|
|
|
|
2011-07-04 21:07:56 -05:00
|
|
|
// Compact string representation for ty::t values. API ty_str &
|
|
|
|
// parse_from_str. Extra parameters are for converting to/from def_ids in the
|
|
|
|
// data buffer. Whatever format you choose should not contain pipe characters.
|
2011-06-27 17:30:17 -05:00
|
|
|
|
|
|
|
// Callback to translate defs to strs or back:
|
|
|
|
type str_def = fn(str) -> ast::def_id ;
|
|
|
|
|
|
|
|
type pstate =
|
|
|
|
rec(vec[u8] data, int crate, mutable uint pos, uint len, ty::ctxt tcx);
|
|
|
|
|
2011-07-05 04:48:19 -05:00
|
|
|
tag ty_or_bang { a_ty(ty::t); a_bang; }
|
2011-06-27 17:30:17 -05:00
|
|
|
|
|
|
|
fn peek(@pstate st) -> u8 { ret st.data.(st.pos); }
|
|
|
|
|
|
|
|
fn next(@pstate st) -> u8 {
|
|
|
|
auto ch = st.data.(st.pos);
|
|
|
|
st.pos = st.pos + 1u;
|
|
|
|
ret ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_ident(@pstate st, str_def sd, char last) -> ast::ident {
|
|
|
|
fn is_last(char b, char c) -> bool {
|
|
|
|
ret c == b;
|
|
|
|
}
|
|
|
|
ret parse_ident_(st, sd, bind is_last(last, _));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_ident_(@pstate st, str_def sd, fn(char) -> bool is_last)
|
|
|
|
-> ast::ident {
|
|
|
|
auto rslt = "";
|
|
|
|
while (! is_last(peek(st) as char)) {
|
|
|
|
rslt += str::unsafe_from_byte(next(st));
|
|
|
|
}
|
|
|
|
ret rslt;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn parse_ty_data(vec[u8] data, int crate_num, uint pos, uint len, str_def sd,
|
|
|
|
ty::ctxt tcx) -> ty::t {
|
|
|
|
auto st =
|
|
|
|
@rec(data=data, crate=crate_num, mutable pos=pos, len=len, tcx=tcx);
|
|
|
|
auto result = parse_ty(st, sd);
|
|
|
|
ret result;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_ty_or_bang(@pstate st, str_def sd) -> ty_or_bang {
|
|
|
|
alt (peek(st) as char) {
|
2011-07-05 04:48:19 -05:00
|
|
|
case ('!') { next(st); ret a_bang; }
|
|
|
|
case (_) { ret a_ty(parse_ty(st, sd)); }
|
2011-06-27 17:30:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-01 17:50:32 -05:00
|
|
|
fn parse_constrs(@pstate st, str_def sd) -> (@ty::constr_def)[] {
|
|
|
|
let (@ty::constr_def)[] rslt = ~[];
|
2011-06-27 17:30:17 -05:00
|
|
|
alt (peek(st) as char) {
|
|
|
|
case (':') {
|
|
|
|
do {
|
2011-06-30 11:00:44 -05:00
|
|
|
next(st);
|
2011-07-01 17:50:32 -05:00
|
|
|
rslt += ~[parse_constr(st, sd)];
|
2011-06-27 17:30:17 -05:00
|
|
|
} while (peek(st) as char == ';')
|
|
|
|
}
|
|
|
|
case (_) { }
|
|
|
|
}
|
|
|
|
ret rslt;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_path(@pstate st, str_def sd) -> ast::path {
|
2011-07-06 13:26:26 -05:00
|
|
|
let vec[ast::ident] idents = [];
|
2011-06-27 17:30:17 -05:00
|
|
|
fn is_last(char c) -> bool {
|
|
|
|
ret (c == '(' || c == ':');
|
|
|
|
}
|
2011-07-06 13:26:26 -05:00
|
|
|
idents += [parse_ident_(st, sd, is_last)];
|
2011-06-27 17:30:17 -05:00
|
|
|
while (true) {
|
|
|
|
alt (peek(st) as char) {
|
2011-06-30 11:00:44 -05:00
|
|
|
case (':') { next(st); next(st); }
|
2011-06-27 17:30:17 -05:00
|
|
|
case (?c) {
|
|
|
|
if (c == '(') {
|
|
|
|
ret respan(rec(lo=0u, hi=0u),
|
2011-07-06 13:26:26 -05:00
|
|
|
rec(idents=idents, types=[]));
|
2011-06-27 17:30:17 -05:00
|
|
|
}
|
|
|
|
else {
|
2011-07-06 13:26:26 -05:00
|
|
|
idents += [parse_ident_(st, sd, is_last)];
|
2011-06-27 17:30:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fail "parse_path: ill-formed path";
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_constr(@pstate st, str_def sd) -> @ty::constr_def {
|
2011-07-06 13:26:26 -05:00
|
|
|
let vec[@ast::constr_arg] args = [];
|
2011-06-27 17:30:17 -05:00
|
|
|
auto sp = rec(lo=0u,hi=0u); // FIXME: use a real span
|
|
|
|
let ast::path pth = parse_path(st, sd);
|
|
|
|
let char ignore = next(st) as char;
|
|
|
|
assert(ignore as char == '(');
|
|
|
|
auto def = parse_def(st, sd);
|
|
|
|
do {
|
|
|
|
alt (peek(st) as char) {
|
|
|
|
case ('*') {
|
|
|
|
st.pos += 1u;
|
2011-07-06 13:26:26 -05:00
|
|
|
args += [@respan(sp, ast::carg_base)];
|
2011-06-27 17:30:17 -05:00
|
|
|
}
|
|
|
|
case (?c) {
|
|
|
|
/* how will we disambiguate between
|
|
|
|
an arg index and a lit argument? */
|
|
|
|
if (c >= '0' && c <= '9') {
|
|
|
|
// FIXME
|
2011-07-06 13:26:26 -05:00
|
|
|
args += [@respan(sp, ast::carg_ident((c as uint) - 48u))];
|
2011-06-27 17:30:17 -05:00
|
|
|
ignore = next(st) as char;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
log_err("Lit args are unimplemented");
|
|
|
|
fail; // FIXME
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
else {
|
|
|
|
auto lit = parse_lit(st, sd, ',');
|
|
|
|
args += [respan(st.span, ast::carg_lit(lit))];
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ignore = next(st) as char;
|
|
|
|
} while (ignore == ';');
|
|
|
|
assert(ignore == ')');
|
|
|
|
ret @respan(sp, rec(path=pth, args=args, id=def));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_ty(@pstate st, str_def sd) -> ty::t {
|
|
|
|
alt (next(st) as char) {
|
|
|
|
case ('n') { ret ty::mk_nil(st.tcx); }
|
|
|
|
case ('z') { ret ty::mk_bot(st.tcx); }
|
|
|
|
case ('b') { ret ty::mk_bool(st.tcx); }
|
|
|
|
case ('i') { ret ty::mk_int(st.tcx); }
|
|
|
|
case ('u') { ret ty::mk_uint(st.tcx); }
|
|
|
|
case ('l') { ret ty::mk_float(st.tcx); }
|
|
|
|
case ('M') {
|
|
|
|
alt (next(st) as char) {
|
2011-07-05 04:48:19 -05:00
|
|
|
case ('b') { ret ty::mk_mach(st.tcx, ast::ty_u8); }
|
|
|
|
case ('w') { ret ty::mk_mach(st.tcx, ast::ty_u16); }
|
|
|
|
case ('l') { ret ty::mk_mach(st.tcx, ast::ty_u32); }
|
|
|
|
case ('d') { ret ty::mk_mach(st.tcx, ast::ty_u64); }
|
|
|
|
case ('B') { ret ty::mk_mach(st.tcx, ast::ty_i8); }
|
|
|
|
case ('W') { ret ty::mk_mach(st.tcx, ast::ty_i16); }
|
|
|
|
case ('L') { ret ty::mk_mach(st.tcx, ast::ty_i32); }
|
|
|
|
case ('D') { ret ty::mk_mach(st.tcx, ast::ty_i64); }
|
|
|
|
case ('f') { ret ty::mk_mach(st.tcx, ast::ty_f32); }
|
|
|
|
case ('F') { ret ty::mk_mach(st.tcx, ast::ty_f64); }
|
2011-06-27 17:30:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
case ('c') { ret ty::mk_char(st.tcx); }
|
|
|
|
case ('s') { ret ty::mk_str(st.tcx); }
|
|
|
|
case ('S') { ret ty::mk_istr(st.tcx); }
|
|
|
|
case ('t') {
|
|
|
|
assert (next(st) as char == '[');
|
|
|
|
auto def = parse_def(st, sd);
|
2011-07-01 14:46:14 -05:00
|
|
|
let ty::t[] params = ~[];
|
|
|
|
while (peek(st) as char != ']') { params += ~[parse_ty(st, sd)]; }
|
2011-06-27 17:30:17 -05:00
|
|
|
st.pos = st.pos + 1u;
|
|
|
|
ret ty::mk_tag(st.tcx, def, params);
|
|
|
|
}
|
|
|
|
case ('p') { ret ty::mk_param(st.tcx, parse_int(st) as uint); }
|
|
|
|
case ('@') { ret ty::mk_box(st.tcx, parse_mt(st, sd)); }
|
|
|
|
case ('*') { ret ty::mk_ptr(st.tcx, parse_mt(st, sd)); }
|
|
|
|
case ('V') { ret ty::mk_vec(st.tcx, parse_mt(st, sd)); }
|
|
|
|
case ('I') { ret ty::mk_ivec(st.tcx, parse_mt(st, sd)); }
|
|
|
|
case ('a') { ret ty::mk_task(st.tcx); }
|
|
|
|
case ('P') { ret ty::mk_port(st.tcx, parse_ty(st, sd)); }
|
|
|
|
case ('C') { ret ty::mk_chan(st.tcx, parse_ty(st, sd)); }
|
|
|
|
case ('T') {
|
|
|
|
assert (next(st) as char == '[');
|
2011-06-29 16:54:18 -05:00
|
|
|
let ty::mt[] params = ~[];
|
|
|
|
while (peek(st) as char != ']') { params += ~[parse_mt(st, sd)]; }
|
2011-06-27 17:30:17 -05:00
|
|
|
st.pos = st.pos + 1u;
|
|
|
|
ret ty::mk_tup(st.tcx, params);
|
|
|
|
}
|
|
|
|
case ('R') {
|
|
|
|
assert (next(st) as char == '[');
|
2011-06-30 14:02:26 -05:00
|
|
|
let ty::field[] fields = ~[];
|
2011-06-27 17:30:17 -05:00
|
|
|
while (peek(st) as char != ']') {
|
|
|
|
auto name = "";
|
|
|
|
while (peek(st) as char != '=') {
|
|
|
|
name += str::unsafe_from_byte(next(st));
|
|
|
|
}
|
|
|
|
st.pos = st.pos + 1u;
|
2011-06-30 14:02:26 -05:00
|
|
|
fields += ~[rec(ident=name, mt=parse_mt(st, sd))];
|
2011-06-27 17:30:17 -05:00
|
|
|
}
|
|
|
|
st.pos = st.pos + 1u;
|
|
|
|
ret ty::mk_rec(st.tcx, fields);
|
|
|
|
}
|
|
|
|
case ('F') {
|
|
|
|
auto func = parse_ty_fn(st, sd);
|
|
|
|
ret ty::mk_fn(st.tcx, ast::proto_fn, func._0, func._1, func._2,
|
|
|
|
func._3);
|
|
|
|
}
|
|
|
|
case ('W') {
|
|
|
|
auto func = parse_ty_fn(st, sd);
|
|
|
|
ret ty::mk_fn(st.tcx, ast::proto_iter, func._0, func._1, func._2,
|
|
|
|
func._3);
|
|
|
|
}
|
|
|
|
case ('N') {
|
|
|
|
auto abi;
|
|
|
|
alt (next(st) as char) {
|
|
|
|
case ('r') { abi = ast::native_abi_rust; }
|
|
|
|
case ('i') { abi = ast::native_abi_rust_intrinsic; }
|
|
|
|
case ('c') { abi = ast::native_abi_cdecl; }
|
|
|
|
case ('l') { abi = ast::native_abi_llvm; }
|
|
|
|
}
|
|
|
|
auto func = parse_ty_fn(st, sd);
|
|
|
|
ret ty::mk_native_fn(st.tcx, abi, func._0, func._1);
|
|
|
|
}
|
|
|
|
case ('O') {
|
|
|
|
assert (next(st) as char == '[');
|
2011-07-06 13:26:26 -05:00
|
|
|
let vec[ty::method] methods = [];
|
2011-06-27 17:30:17 -05:00
|
|
|
while (peek(st) as char != ']') {
|
|
|
|
auto proto;
|
|
|
|
alt (next(st) as char) {
|
|
|
|
case ('W') { proto = ast::proto_iter; }
|
|
|
|
case ('F') { proto = ast::proto_fn; }
|
|
|
|
}
|
|
|
|
auto name = "";
|
|
|
|
while (peek(st) as char != '[') {
|
|
|
|
name += str::unsafe_from_byte(next(st));
|
|
|
|
}
|
|
|
|
auto func = parse_ty_fn(st, sd);
|
|
|
|
methods +=
|
2011-07-06 13:26:26 -05:00
|
|
|
[rec(proto=proto,
|
|
|
|
ident=name,
|
|
|
|
inputs=func._0,
|
|
|
|
output=func._1,
|
|
|
|
cf=func._2,
|
|
|
|
constrs=func._3)];
|
2011-06-27 17:30:17 -05:00
|
|
|
}
|
|
|
|
st.pos += 1u;
|
|
|
|
ret ty::mk_obj(st.tcx, methods);
|
|
|
|
}
|
|
|
|
case ('r') {
|
2011-06-30 07:46:17 -05:00
|
|
|
assert (next(st) as char == '[');
|
2011-06-27 17:30:17 -05:00
|
|
|
auto def = parse_def(st, sd);
|
|
|
|
auto inner = parse_ty(st, sd);
|
2011-07-01 15:01:00 -05:00
|
|
|
let ty::t[] params = ~[];
|
|
|
|
while (peek(st) as char != ']') { params += ~[parse_ty(st, sd)]; }
|
2011-06-30 07:46:17 -05:00
|
|
|
st.pos = st.pos + 1u;
|
|
|
|
ret ty::mk_res(st.tcx, def, inner, params);
|
2011-06-27 17:30:17 -05:00
|
|
|
}
|
|
|
|
case ('X') { ret ty::mk_var(st.tcx, parse_int(st)); }
|
2011-07-01 11:39:24 -05:00
|
|
|
case ('E') {
|
|
|
|
auto def = parse_def(st, sd);
|
|
|
|
ret ty::mk_native(st.tcx, def);
|
|
|
|
}
|
2011-06-27 17:30:17 -05:00
|
|
|
case ('Y') { ret ty::mk_type(st.tcx); }
|
|
|
|
case ('#') {
|
|
|
|
auto pos = parse_hex(st);
|
|
|
|
assert (next(st) as char == ':');
|
|
|
|
auto len = parse_hex(st);
|
|
|
|
assert (next(st) as char == '#');
|
|
|
|
alt (st.tcx.rcache.find(tup(st.crate, pos, len))) {
|
|
|
|
case (some(?tt)) { ret tt; }
|
|
|
|
case (none) {
|
|
|
|
auto ps = @rec(pos=pos, len=len with *st);
|
|
|
|
auto tt = parse_ty(ps, sd);
|
|
|
|
st.tcx.rcache.insert(tup(st.crate, pos, len), tt);
|
|
|
|
ret tt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case (?c) {
|
|
|
|
log_err "unexpected char in type string: ";
|
|
|
|
log_err c;
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_mt(@pstate st, str_def sd) -> ty::mt {
|
|
|
|
auto mut;
|
|
|
|
alt (peek(st) as char) {
|
|
|
|
case ('m') { next(st); mut = ast::mut; }
|
|
|
|
case ('?') { next(st); mut = ast::maybe_mut; }
|
|
|
|
case (_) { mut = ast::imm; }
|
|
|
|
}
|
|
|
|
ret rec(ty=parse_ty(st, sd), mut=mut);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_def(@pstate st, str_def sd) -> ast::def_id {
|
|
|
|
auto def = "";
|
|
|
|
while (peek(st) as char != '|') {
|
|
|
|
def += str::unsafe_from_byte(next(st));
|
|
|
|
}
|
|
|
|
st.pos = st.pos + 1u;
|
|
|
|
ret sd(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_int(@pstate st) -> int {
|
|
|
|
auto n = 0;
|
|
|
|
while (true) {
|
|
|
|
auto cur = peek(st) as char;
|
|
|
|
if (cur < '0' || cur > '9') { break; }
|
|
|
|
st.pos = st.pos + 1u;
|
|
|
|
n *= 10;
|
|
|
|
n += (cur as int) - ('0' as int);
|
|
|
|
}
|
|
|
|
ret n;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_hex(@pstate st) -> uint {
|
|
|
|
auto n = 0u;
|
|
|
|
while (true) {
|
|
|
|
auto cur = peek(st) as char;
|
|
|
|
if ((cur < '0' || cur > '9') && (cur < 'a' || cur > 'f')) { break; }
|
|
|
|
st.pos = st.pos + 1u;
|
|
|
|
n *= 16u;
|
|
|
|
if ('0' <= cur && cur <= '9') {
|
|
|
|
n += (cur as uint) - ('0' as uint);
|
|
|
|
} else { n += 10u + (cur as uint) - ('a' as uint); }
|
|
|
|
}
|
|
|
|
ret n;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_ty_fn(@pstate st, str_def sd) ->
|
2011-07-01 17:50:32 -05:00
|
|
|
tup(ty::arg[], ty::t, ast::controlflow, (@ty::constr_def)[]) {
|
2011-06-27 17:30:17 -05:00
|
|
|
assert (next(st) as char == '[');
|
2011-06-30 18:10:33 -05:00
|
|
|
let ty::arg[] inputs = ~[];
|
2011-06-27 17:30:17 -05:00
|
|
|
while (peek(st) as char != ']') {
|
|
|
|
auto mode = ty::mo_val;
|
|
|
|
if (peek(st) as char == '&') {
|
|
|
|
mode = ty::mo_alias(false);
|
|
|
|
st.pos += 1u;
|
|
|
|
if (peek(st) as char == 'm') {
|
|
|
|
mode = ty::mo_alias(true);
|
|
|
|
st.pos += 1u;
|
|
|
|
}
|
|
|
|
}
|
2011-06-30 18:10:33 -05:00
|
|
|
inputs += ~[rec(mode=mode, ty=parse_ty(st, sd))];
|
2011-06-27 17:30:17 -05:00
|
|
|
}
|
|
|
|
st.pos += 1u; // eat the ']'
|
|
|
|
auto cs = parse_constrs(st, sd);
|
|
|
|
alt (parse_ty_or_bang(st, sd)) {
|
|
|
|
case (a_bang) {
|
|
|
|
ret tup(inputs, ty::mk_bot(st.tcx), ast::noreturn, cs);
|
|
|
|
}
|
|
|
|
case (a_ty(?t)) { ret tup(inputs, t, ast::return, cs); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Rust metadata parsing
|
|
|
|
fn parse_def_id(vec[u8] buf) -> ast::def_id {
|
|
|
|
auto colon_idx = 0u;
|
|
|
|
auto len = vec::len[u8](buf);
|
|
|
|
while (colon_idx < len && buf.(colon_idx) != ':' as u8) {
|
|
|
|
colon_idx += 1u;
|
|
|
|
}
|
|
|
|
if (colon_idx == len) {
|
|
|
|
log_err "didn't find ':' when parsing def id";
|
|
|
|
fail;
|
|
|
|
}
|
|
|
|
auto crate_part = vec::slice[u8](buf, 0u, colon_idx);
|
|
|
|
auto def_part = vec::slice[u8](buf, colon_idx + 1u, len);
|
|
|
|
auto crate_num = uint::parse_buf(crate_part, 10u) as int;
|
|
|
|
auto def_id = uint::parse_buf(def_part, 10u) as int;
|
|
|
|
ret tup(crate_num, def_id);
|
|
|
|
}
|