// Type decoding import std::ivec; import std::str; import std::uint; import std::option; import std::option::none; import std::option::some; import syntax::ast; import syntax::ast::*; import ast::respan; import middle::ty; export parse_def_id; export parse_ty_data; // 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. // Callback to translate defs to strs or back: type str_def = fn(str) -> ast::def_id ; type pstate = rec(@u8[] data, int crate, mutable uint pos, uint len, ty::ctxt tcx); tag ty_or_bang { a_ty(ty::t); a_bang; } 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(@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) { case ('!') { next(st); ret a_bang; } case (_) { ret a_ty(parse_ty(st, sd)); } } } fn parse_constrs(@pstate st, str_def sd) -> (@ty::constr)[] { let (@ty::constr)[] rslt = ~[]; alt (peek(st) as char) { case (':') { do { next(st); let @ty::constr one = parse_constr[uint](st, sd, parse_constr_arg); rslt += ~[one]; } while (peek(st) as char == ';') } case (_) { } } ret rslt; } // FIXME less copy-and-paste fn parse_ty_constrs(@pstate st, str_def sd) -> (@ty::type_constr)[] { let (@ty::type_constr)[] rslt = ~[]; alt (peek(st) as char) { case (':') { do { next(st); let @ty::type_constr one = parse_constr[path](st, sd, parse_ty_constr_arg); rslt += ~[one]; } while (peek(st) as char == ';') } case (_) { } } ret rslt; } fn parse_path(@pstate st, str_def sd) -> ast::path { let ast::ident[] idents = ~[]; fn is_last(char c) -> bool { ret (c == '(' || c == ':'); } idents += ~[parse_ident_(st, sd, is_last)]; while (true) { alt (peek(st) as char) { case (':') { next(st); next(st); } case (?c) { if (c == '(') { ret respan(rec(lo=0u, hi=0u), rec(global=false, idents=idents, types=~[])); } else { idents += ~[parse_ident_(st, sd, is_last)]; } } } } fail "parse_path: ill-formed path"; } type arg_parser[T] = fn (@pstate st, str_def sd) -> ast::constr_arg_general_[T]; fn parse_constr_arg(@pstate st, str_def sd) -> ast::fn_constr_arg { alt (peek(st) as char) { case ('*') { st.pos += 1u; ret ast::carg_base; } case (?c) { /* how will we disambiguate between an arg index and a lit argument? */ if (c >= '0' && c <= '9') { next(st); // FIXME ret ast::carg_ident((c as uint) - 48u); } else { log_err("Lit args are unimplemented"); fail; // FIXME } /* else { auto lit = parse_lit(st, sd, ','); args += [respan(st.span, ast::carg_lit(lit))]; } */ } } } fn parse_ty_constr_arg(@pstate st, str_def sd) -> ast::constr_arg_general_[path] { alt (peek(st) as char) { case ('*') { st.pos += 1u; ret ast::carg_base; } case (?c) { ret ast::carg_ident(parse_path(st, sd)); } } } fn parse_constr[T](@pstate st, str_def sd, arg_parser[T] pser) -> @ty::constr_general[T] { auto sp = rec(lo=0u,hi=0u); // FIXME: use a real span let (@sp_constr_arg[T])[] args = ~[]; let path pth = parse_path(st, sd); let char ignore = next(st) as char; assert(ignore as char == '('); auto def = parse_def(st, sd); let constr_arg_general_[T] an_arg; do { an_arg = pser(st, sd); // FIXME use a real span args += ~[@respan(sp, an_arg)]; 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) { 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); } } } 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); let ty::t[] params = ~[]; while (peek(st) as char != ']') { params += ~[parse_ty(st, sd)]; } 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 ('R') { assert (next(st) as char == '['); let ty::field[] fields = ~[]; while (peek(st) as char != ']') { auto name = ""; while (peek(st) as char != '=') { name += str::unsafe_from_byte(next(st)); } st.pos = st.pos + 1u; fields += ~[rec(ident=name, mt=parse_mt(st, sd))]; } 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.args, func.ty, func.cf, func.cs); } case ('W') { auto func = parse_ty_fn(st, sd); ret ty::mk_fn(st.tcx, ast::proto_iter, func.args, func.ty, func.cf, func.cs); } 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; } case ('s') { abi = ast::native_abi_x86stdcall; } } auto func = parse_ty_fn(st, sd); ret ty::mk_native_fn(st.tcx, abi, func.args, func.ty); } case ('O') { assert (next(st) as char == '['); let ty::method[] methods = ~[]; 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 += ~[rec(proto=proto, ident=name, inputs=func.args, output=func.ty, cf=func.cf, constrs=func.cs)]; } st.pos += 1u; ret ty::mk_obj(st.tcx, methods); } case ('r') { assert (next(st) as char == '['); auto def = parse_def(st, sd); auto inner = parse_ty(st, sd); let ty::t[] params = ~[]; while (peek(st) as char != ']') { params += ~[parse_ty(st, sd)]; } st.pos = st.pos + 1u; ret ty::mk_res(st.tcx, def, inner, params); } case ('X') { ret ty::mk_var(st.tcx, parse_int(st)); } case ('E') { auto def = parse_def(st, sd); ret ty::mk_native(st.tcx, def); } 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(rec(cnum=st.crate, pos=pos, len=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(rec(cnum=st.crate, pos=pos, len=len), tt); ret tt; } } } case ('A') { assert (next(st) as char == '['); auto tt = parse_ty(st, sd); auto tcs = parse_ty_constrs(st, sd); assert (next(st) as char == ']'); ret ty::mk_constr(st.tcx, tt, tcs); } 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) -> rec(ty::arg[] args, ty::t ty, ast::controlflow cf, (@ty::constr)[] cs) { assert (next(st) as char == '['); let ty::arg[] inputs = ~[]; 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; } } inputs += ~[rec(mode=mode, ty=parse_ty(st, sd))]; } st.pos += 1u; // eat the ']' auto cs = parse_constrs(st, sd); alt (parse_ty_or_bang(st, sd)) { case (a_bang) { ret rec(args=inputs, ty=ty::mk_bot(st.tcx), cf=ast::noreturn, cs=cs); } case (a_ty(?t)) { ret rec(args=inputs, ty=t, cf=ast::return, cs=cs); } } } // Rust metadata parsing fn parse_def_id(&u8[] buf) -> ast::def_id { auto colon_idx = 0u; auto len = ivec::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 = ivec::slice[u8](buf, 0u, colon_idx); auto def_part = ivec::slice[u8](buf, colon_idx + 1u, len); // FIXME: Remove these ivec->vec conversions. auto crate_part_vec = []; auto def_part_vec = []; for (u8 b in crate_part) { crate_part_vec += [b]; } for (u8 b in def_part) { def_part_vec += [b]; } auto crate_num = uint::parse_buf(crate_part_vec, 10u) as int; auto def_num = uint::parse_buf(def_part_vec, 10u) as int; ret rec(crate=crate_num, node=def_num); } // // 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: //