diff --git a/src/cargo/cargo.rs b/src/cargo/cargo.rs index 6f356a6e943a4..b5c9fc174162f 100644 --- a/src/cargo/cargo.rs +++ b/src/cargo/cargo.rs @@ -11,13 +11,14 @@ use syntax::diagnostic; use result::{Ok, Err}; use io::WriterUtil; +use send_map::linear::LinearMap; use std::{map, json, tempfile, term, sort, getopts}; use map::HashMap; use to_str::to_str; use getopts::{optflag, optopt, opt_present}; use dvec::DVec; -type package = { +struct Package { name: ~str, uuid: ~str, url: ~str, @@ -26,10 +27,10 @@ type package = { reference: Option<~str>, tags: ~[~str], versions: ~[(~str, ~str)] -}; +} -impl package : cmp::Ord { - pure fn lt(other: &package) -> bool { +impl Package : cmp::Ord { + pure fn lt(other: &Package) -> bool { if self.name.lt(&(*other).name) { return true; } if (*other).name.lt(&self.name) { return false; } if self.uuid.lt(&(*other).uuid) { return true; } @@ -45,28 +46,21 @@ impl package : cmp::Ord { if self.versions.lt(&(*other).versions) { return true; } return false; } - pure fn le(other: &package) -> bool { !(*other).lt(&self) } - pure fn ge(other: &package) -> bool { !self.lt(other) } - pure fn gt(other: &package) -> bool { (*other).lt(&self) } + pure fn le(other: &Package) -> bool { !(*other).lt(&self) } + pure fn ge(other: &Package) -> bool { !self.lt(other) } + pure fn gt(other: &Package) -> bool { (*other).lt(&self) } } -type local_package = { - name: ~str, - metaname: ~str, - version: ~str, - files: ~[~str] -}; - -type source = @{ +struct Source { name: ~str, mut url: ~str, mut method: ~str, mut key: Option<~str>, mut keyfp: Option<~str>, - packages: DVec -}; + packages: DVec +} -type cargo = { +struct Cargo { pgp: bool, root: Path, installdir: Path, @@ -74,13 +68,13 @@ type cargo = { libdir: Path, workdir: Path, sourcedir: Path, - sources: map::HashMap<~str, source>, + sources: map::HashMap<~str, @Source>, mut current_install: ~str, dep_cache: map::HashMap<~str, bool>, - opts: options -}; + opts: Options +} -type crate = { +struct Crate { name: ~str, vers: ~str, uuid: ~str, @@ -88,22 +82,22 @@ type crate = { sigs: Option<~str>, crate_type: Option<~str>, deps: ~[~str] -}; +} -type options = { +struct Options { test: bool, - mode: mode, + mode: Mode, free: ~[~str], help: bool, -}; +} -enum mode { system_mode, user_mode, local_mode } +enum Mode { SystemMode, UserMode, LocalMode } -impl mode : cmp::Eq { - pure fn eq(other: &mode) -> bool { +impl Mode : cmp::Eq { + pure fn eq(other: &Mode) -> bool { (self as uint) == ((*other) as uint) } - pure fn ne(other: &mode) -> bool { !self.eq(other) } + pure fn ne(other: &Mode) -> bool { !self.eq(other) } } fn opts() -> ~[getopts::Opt] { @@ -270,7 +264,7 @@ fn load_link(mis: ~[@ast::meta_item]) -> (Option<~str>, (name, vers, uuid) } -fn load_crate(filename: &Path) -> Option { +fn load_crate(filename: &Path) -> Option { let sess = parse::new_parse_sess(None); let c = parse::parse_crate_from_crate_file(filename, ~[], sess); @@ -375,7 +369,7 @@ fn load_crate(filename: &Path) -> Option { match (name, vers, uuid) { (Some(name0), Some(vers0), Some(uuid0)) => { - Some({ + Some(Crate { name: name0, vers: vers0, uuid: uuid0, @@ -407,7 +401,7 @@ fn need_dir(s: &Path) { } } -fn valid_pkg_name(s: ~str) -> bool { +fn valid_pkg_name(s: &str) -> bool { fn is_valid_digit(c: char) -> bool { ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || @@ -419,33 +413,33 @@ fn valid_pkg_name(s: ~str) -> bool { s.all(is_valid_digit) } -fn parse_source(name: ~str, j: json::Json) -> source { +fn parse_source(name: ~str, j: &json::Json) -> @Source { if !valid_pkg_name(name) { fail fmt!("'%s' is an invalid source name", name); } - match j { - json::Dict(j) => { - let mut url = match j.find(~"url") { - Some(json::String(u)) => *u, + match *j { + json::Object(j) => { + let mut url = match j.find(&~"url") { + Some(json::String(u)) => u, _ => fail ~"needed 'url' field in source" }; - let method = match j.find(~"method") { - Some(json::String(u)) => *u, + let method = match j.find(&~"method") { + Some(json::String(u)) => u, _ => assume_source_method(url) }; - let key = match j.find(~"key") { - Some(json::String(u)) => Some(*u), + let key = match j.find(&~"key") { + Some(json::String(u)) => Some(u), _ => None }; - let keyfp = match j.find(~"keyfp") { - Some(json::String(u)) => Some(*u), + let keyfp = match j.find(&~"keyfp") { + Some(json::String(u)) => Some(u), _ => None }; if method == ~"file" { url = os::make_absolute(&Path(url)).to_str(); } - return @{ + return @Source { name: name, mut url: url, mut method: method, @@ -457,14 +451,14 @@ fn parse_source(name: ~str, j: json::Json) -> source { }; } -fn try_parse_sources(filename: &Path, sources: map::HashMap<~str, source>) { +fn try_parse_sources(filename: &Path, sources: map::HashMap<~str, @Source>) { if !os::path_exists(filename) { return; } let c = io::read_whole_file_str(filename); match json::from_str(c.get()) { - Ok(json::Dict(j)) => { - for j.each |k, v| { - sources.insert(k, parse_source(k, v)); - debug!("source: %s", k); + Ok(json::Object(j)) => { + for j.each |k, v| { + sources.insert(copy *k, parse_source(*k, v)); + debug!("source: %s", *k); } } Ok(_) => fail ~"malformed sources.json", @@ -472,17 +466,17 @@ fn try_parse_sources(filename: &Path, sources: map::HashMap<~str, source>) { } } -fn load_one_source_package(src: source, p: map::HashMap<~str, json::Json>) { - let name = match p.find(~"name") { +fn load_one_source_package(src: @Source, p: &json::Object) { + let name = match p.find(&~"name") { Some(json::String(n)) => { - if !valid_pkg_name(*n) { + if !valid_pkg_name(n) { warn(~"malformed source json: " - + src.name + ~", '" + *n + ~"'"+ + + src.name + ~", '" + n + ~"'"+ ~" is an invalid name (alphanumeric, underscores and" + ~" dashes only)"); return; } - *n + n } _ => { warn(~"malformed source json: " + src.name + ~" (missing name)"); @@ -490,15 +484,15 @@ fn load_one_source_package(src: source, p: map::HashMap<~str, json::Json>) { } }; - let uuid = match p.find(~"uuid") { + let uuid = match p.find(&~"uuid") { Some(json::String(n)) => { - if !is_uuid(*n) { + if !is_uuid(n) { warn(~"malformed source json: " - + src.name + ~", '" + *n + ~"'"+ + + src.name + ~", '" + n + ~"'"+ ~" is an invalid uuid"); return; } - *n + n } _ => { warn(~"malformed source json: " + src.name + ~" (missing uuid)"); @@ -506,16 +500,16 @@ fn load_one_source_package(src: source, p: map::HashMap<~str, json::Json>) { } }; - let url = match p.find(~"url") { - Some(json::String(n)) => *n, + let url = match p.find(&~"url") { + Some(json::String(n)) => n, _ => { warn(~"malformed source json: " + src.name + ~" (missing url)"); return; } }; - let method = match p.find(~"method") { - Some(json::String(n)) => *n, + let method = match p.find(&~"method") { + Some(json::String(n)) => n, _ => { warn(~"malformed source json: " + src.name + ~" (missing method)"); @@ -523,17 +517,17 @@ fn load_one_source_package(src: source, p: map::HashMap<~str, json::Json>) { } }; - let reference = match p.find(~"ref") { - Some(json::String(n)) => Some(*n), + let reference = match p.find(&~"ref") { + Some(json::String(n)) => Some(n), _ => None }; let mut tags = ~[]; - match p.find(~"tags") { + match p.find(&~"tags") { Some(json::List(js)) => { - for (*js).each |j| { + for js.each |j| { match *j { - json::String(j) => vec::grow(tags, 1u, *j), + json::String(j) => vec::grow(tags, 1u, j), _ => () } } @@ -541,8 +535,8 @@ fn load_one_source_package(src: source, p: map::HashMap<~str, json::Json>) { _ => () } - let description = match p.find(~"description") { - Some(json::String(n)) => *n, + let description = match p.find(&~"description") { + Some(json::String(n)) => n, _ => { warn(~"malformed source json: " + src.name + ~" (missing description)"); @@ -550,7 +544,7 @@ fn load_one_source_package(src: source, p: map::HashMap<~str, json::Json>) { } }; - let newpkg = { + let newpkg = Package { name: name, uuid: uuid, url: url, @@ -574,14 +568,14 @@ fn load_one_source_package(src: source, p: map::HashMap<~str, json::Json>) { log(debug, ~" loaded package: " + src.name + ~"/" + name); } -fn load_source_info(c: &cargo, src: source) { +fn load_source_info(c: &Cargo, src: @Source) { let dir = c.sourcedir.push(src.name); let srcfile = dir.push("source.json"); if !os::path_exists(&srcfile) { return; } let srcstr = io::read_whole_file_str(&srcfile); match json::from_str(srcstr.get()) { - Ok(json::Dict(s)) => { - let o = parse_source(src.name, json::Dict(s)); + Ok(ref json @ json::Object(_)) => { + let o = parse_source(src.name, json); src.key = o.key; src.keyfp = o.keyfp; @@ -595,7 +589,7 @@ fn load_source_info(c: &cargo, src: source) { } }; } -fn load_source_packages(c: &cargo, src: source) { +fn load_source_packages(c: &Cargo, src: @Source) { log(debug, ~"loading source: " + src.name); let dir = c.sourcedir.push(src.name); let pkgfile = dir.push("packages.json"); @@ -603,9 +597,9 @@ fn load_source_packages(c: &cargo, src: source) { let pkgstr = io::read_whole_file_str(&pkgfile); match json::from_str(pkgstr.get()) { Ok(json::List(js)) => { - for (*js).each |j| { + for js.each |j| { match *j { - json::Dict(p) => { + json::Object(p) => { load_one_source_package(src, p); } _ => { @@ -625,7 +619,7 @@ fn load_source_packages(c: &cargo, src: source) { }; } -fn build_cargo_options(argv: ~[~str]) -> options { +fn build_cargo_options(argv: ~[~str]) -> Options { let matches = match getopts::getopts(argv, opts()) { result::Ok(m) => m, result::Err(f) => { @@ -649,34 +643,34 @@ fn build_cargo_options(argv: ~[~str]) -> options { } let mode = - if (!is_install && !is_uninstall) || g { user_mode } - else if G { system_mode } - else { local_mode }; + if (!is_install && !is_uninstall) || g { UserMode } + else if G { SystemMode } + else { LocalMode }; - {test: test, mode: mode, free: matches.free, help: help} + Options {test: test, mode: mode, free: matches.free, help: help} } -fn configure(opts: options) -> cargo { +fn configure(opts: Options) -> Cargo { let home = match get_cargo_root() { Ok(home) => home, Err(_err) => get_cargo_sysroot().get() }; let get_cargo_dir = match opts.mode { - system_mode => get_cargo_sysroot, - user_mode => get_cargo_root, - local_mode => get_cargo_root_nearest + SystemMode => get_cargo_sysroot, + UserMode => get_cargo_root, + LocalMode => get_cargo_root_nearest }; let p = get_cargo_dir().get(); - let sources = map::HashMap(); + let sources = HashMap(); try_parse_sources(&home.push("sources.json"), sources); try_parse_sources(&home.push("local-sources.json"), sources); - let dep_cache = map::HashMap(); + let dep_cache = HashMap(); - let mut c = { + let mut c = Cargo { pgp: pgp::supported(), root: home, installdir: p, @@ -714,10 +708,10 @@ fn configure(opts: options) -> cargo { c } -fn for_each_package(c: &cargo, b: fn(source, package)) { +fn for_each_package(c: &Cargo, b: fn(s: @Source, p: &Package)) { for c.sources.each_value |v| { for v.packages.each |p| { - b(v, *p); + b(v, p); } } } @@ -748,7 +742,7 @@ fn run_in_buildpath(what: &str, path: &Path, subdir: &Path, cf: &Path, Some(buildpath) } -fn test_one_crate(_c: &cargo, path: &Path, cf: &Path) { +fn test_one_crate(_c: &Cargo, path: &Path, cf: &Path) { let buildpath = match run_in_buildpath(~"testing", path, &Path("test"), cf, @@ -759,7 +753,7 @@ fn test_one_crate(_c: &cargo, path: &Path, cf: &Path) { run_programs(&buildpath); } -fn install_one_crate(c: &cargo, path: &Path, cf: &Path) { +fn install_one_crate(c: &Cargo, path: &Path, cf: &Path) { let buildpath = match run_in_buildpath(~"installing", path, &Path("build"), cf, ~[]) { @@ -776,7 +770,7 @@ fn install_one_crate(c: &cargo, path: &Path, cf: &Path) { ~"lib")) { debug!(" bin: %s", ct.to_str()); install_to_dir(*ct, &c.bindir); - if c.opts.mode == system_mode { + if c.opts.mode == SystemMode { // FIXME (#2662): Put this file in PATH / symlink it so it can // be used as a generic executable // `cargo install -G rustray` and `rustray file.obj` @@ -800,7 +794,7 @@ fn rustc_sysroot() -> ~str { } } -fn install_source(c: &cargo, path: &Path) { +fn install_source(c: &Cargo, path: &Path) { debug!("source: %s", path.to_str()); os::change_dir(path); @@ -839,7 +833,7 @@ fn install_source(c: &cargo, path: &Path) { } } -fn install_git(c: &cargo, wd: &Path, url: ~str, reference: Option<~str>) { +fn install_git(c: &Cargo, wd: &Path, url: ~str, reference: Option<~str>) { run::program_output(~"git", ~[~"clone", url, wd.to_str()]); if reference.is_some() { let r = reference.get(); @@ -850,7 +844,7 @@ fn install_git(c: &cargo, wd: &Path, url: ~str, reference: Option<~str>) { install_source(c, wd); } -fn install_curl(c: &cargo, wd: &Path, url: ~str) { +fn install_curl(c: &Cargo, wd: &Path, url: ~str) { let tarpath = wd.push("pkg.tar"); let p = run::program_output(~"curl", ~[~"-f", ~"-s", ~"-o", tarpath.to_str(), url]); @@ -863,14 +857,14 @@ fn install_curl(c: &cargo, wd: &Path, url: ~str) { install_source(c, wd); } -fn install_file(c: &cargo, wd: &Path, path: &Path) { +fn install_file(c: &Cargo, wd: &Path, path: &Path) { run::program_output(~"tar", ~[~"-x", ~"--strip-components=1", ~"-C", wd.to_str(), ~"-f", path.to_str()]); install_source(c, wd); } -fn install_package(c: &cargo, src: ~str, wd: &Path, pkg: package) { +fn install_package(c: &Cargo, src: ~str, wd: &Path, pkg: Package) { let url = copy pkg.url; let method = match pkg.method { ~"git" => ~"git", @@ -883,12 +877,12 @@ fn install_package(c: &cargo, src: ~str, wd: &Path, pkg: package) { match method { ~"git" => install_git(c, wd, url, copy pkg.reference), ~"file" => install_file(c, wd, &Path(url)), - ~"curl" => install_curl(c, wd, copy url), + ~"curl" => install_curl(c, wd, url), _ => () } } -fn cargo_suggestion(c: &cargo, fallback: fn()) +fn cargo_suggestion(c: &Cargo, fallback: fn()) { if c.sources.size() == 0u { error(~"no sources defined - you may wish to run " + @@ -898,11 +892,11 @@ fn cargo_suggestion(c: &cargo, fallback: fn()) fallback(); } -fn install_uuid(c: &cargo, wd: &Path, uuid: ~str) { +fn install_uuid(c: &Cargo, wd: &Path, uuid: ~str) { let mut ps = ~[]; for_each_package(c, |s, p| { if p.uuid == uuid { - vec::grow(ps, 1u, (s.name, copy p)); + vec::push(ps, (s.name, copy *p)); } }); if vec::len(ps) == 1u { @@ -922,11 +916,11 @@ fn install_uuid(c: &cargo, wd: &Path, uuid: ~str) { } } -fn install_named(c: &cargo, wd: &Path, name: ~str) { +fn install_named(c: &Cargo, wd: &Path, name: ~str) { let mut ps = ~[]; for_each_package(c, |s, p| { if p.name == name { - vec::grow(ps, 1u, (s.name, copy p)); + vec::push(ps, (s.name, copy *p)); } }); if vec::len(ps) == 1u { @@ -946,7 +940,7 @@ fn install_named(c: &cargo, wd: &Path, name: ~str) { } } -fn install_uuid_specific(c: &cargo, wd: &Path, src: ~str, uuid: ~str) { +fn install_uuid_specific(c: &Cargo, wd: &Path, src: ~str, uuid: ~str) { match c.sources.find(src) { Some(s) => { for s.packages.each |p| { @@ -961,7 +955,7 @@ fn install_uuid_specific(c: &cargo, wd: &Path, src: ~str, uuid: ~str) { error(~"can't find package: " + src + ~"/" + uuid); } -fn install_named_specific(c: &cargo, wd: &Path, src: ~str, name: ~str) { +fn install_named_specific(c: &Cargo, wd: &Path, src: ~str, name: ~str) { match c.sources.find(src) { Some(s) => { for s.packages.each |p| { @@ -976,7 +970,7 @@ fn install_named_specific(c: &cargo, wd: &Path, src: ~str, name: ~str) { error(~"can't find package: " + src + ~"/" + name); } -fn cmd_uninstall(c: &cargo) { +fn cmd_uninstall(c: &Cargo) { if vec::len(c.opts.free) < 3u { cmd_usage(); return; @@ -1028,7 +1022,7 @@ fn cmd_uninstall(c: &cargo) { } } -fn install_query(c: &cargo, wd: &Path, target: ~str) { +fn install_query(c: &Cargo, wd: &Path, target: ~str) { match c.dep_cache.find(target) { Some(inst) => { if inst { @@ -1088,7 +1082,7 @@ fn install_query(c: &cargo, wd: &Path, target: ~str) { } } -fn get_temp_workdir(c: &cargo) -> Path { +fn get_temp_workdir(c: &Cargo) -> Path { match tempfile::mkdtemp(&c.workdir, "cargo") { Some(wd) => wd, None => fail fmt!("needed temp dir: %s", @@ -1096,7 +1090,7 @@ fn get_temp_workdir(c: &cargo) -> Path { } } -fn cmd_install(c: &cargo) unsafe { +fn cmd_install(c: &Cargo) unsafe { let wd = get_temp_workdir(c); if vec::len(c.opts.free) == 2u { @@ -1120,7 +1114,7 @@ fn cmd_install(c: &cargo) unsafe { install_query(c, &wd, query); } -fn sync(c: &cargo) { +fn sync(c: &Cargo) { for c.sources.each_key |k| { let mut s = c.sources.get(k); sync_one(c, s); @@ -1128,7 +1122,7 @@ fn sync(c: &cargo) { } } -fn sync_one_file(c: &cargo, dir: &Path, src: source) -> bool { +fn sync_one_file(c: &Cargo, dir: &Path, src: @Source) -> bool { let name = src.name; let srcfile = dir.push("source.json.new"); let destsrcfile = dir.push("source.json"); @@ -1206,7 +1200,7 @@ fn sync_one_file(c: &cargo, dir: &Path, src: source) -> bool { return true; } -fn sync_one_git(c: &cargo, dir: &Path, src: source) -> bool { +fn sync_one_git(c: &Cargo, dir: &Path, src: @Source) -> bool { let name = src.name; let srcfile = dir.push("source.json"); let pkgfile = dir.push("packages.json"); @@ -1309,7 +1303,7 @@ fn sync_one_git(c: &cargo, dir: &Path, src: source) -> bool { return true; } -fn sync_one_curl(c: &cargo, dir: &Path, src: source) -> bool { +fn sync_one_curl(c: &Cargo, dir: &Path, src: @Source) -> bool { let name = src.name; let srcfile = dir.push("source.json.new"); let destsrcfile = dir.push("source.json"); @@ -1425,7 +1419,7 @@ fn sync_one_curl(c: &cargo, dir: &Path, src: source) -> bool { return true; } -fn sync_one(c: &cargo, src: source) { +fn sync_one(c: &Cargo, src: @Source) { let name = src.name; let dir = c.sourcedir.push(name); @@ -1445,7 +1439,7 @@ fn sync_one(c: &cargo, src: source) { } } -fn cmd_init(c: &cargo) { +fn cmd_init(c: &Cargo) { let srcurl = ~"http://www.rust-lang.org/cargo/sources.json"; let sigurl = ~"http://www.rust-lang.org/cargo/sources.json.sig"; @@ -1484,7 +1478,7 @@ fn cmd_init(c: &cargo) { info(fmt!("initialized .cargo in %s", c.root.to_str())); } -fn print_pkg(s: source, p: package) { +fn print_pkg(s: @Source, p: &Package) { let mut m = s.name + ~"/" + p.name + ~" (" + p.uuid + ~")"; if vec::len(p.tags) > 0u { m = m + ~" [" + str::connect(p.tags, ~", ") + ~"]"; @@ -1495,7 +1489,7 @@ fn print_pkg(s: source, p: package) { } } -fn print_source(s: source) { +fn print_source(s: @Source) { info(s.name + ~" (" + s.url + ~")"); let pks = sort::merge_sort(sys::shape_lt, s.packages.get()); @@ -1516,7 +1510,7 @@ fn print_source(s: source) { })); } -fn cmd_list(c: &cargo) { +fn cmd_list(c: &Cargo) { sync(c); if vec::len(c.opts.free) >= 3u { @@ -1542,7 +1536,7 @@ fn cmd_list(c: &cargo) { } } -fn cmd_search(c: &cargo) { +fn cmd_search(c: &Cargo) { if vec::len(c.opts.free) < 3u { cmd_usage(); return; @@ -1575,17 +1569,17 @@ fn install_to_dir(srcfile: &Path, destdir: &Path) { } } -fn dump_cache(c: &cargo) { +fn dump_cache(c: &Cargo) { need_dir(&c.root); let out = c.root.push("cache.json"); - let _root = json::Dict(map::HashMap()); + let _root = json::Object(~LinearMap()); if os::path_exists(&out) { copy_warn(&out, &c.root.push("cache.json.old")); } } -fn dump_sources(c: &cargo) { +fn dump_sources(c: &Cargo) { if c.sources.size() < 1u { return; } @@ -1600,33 +1594,31 @@ fn dump_sources(c: &cargo) { match io::buffered_file_writer(&out) { result::Ok(writer) => { - let hash = map::HashMap(); - let root = json::Dict(hash); + let mut hash = ~LinearMap(); - for c.sources.each |k, v| { - let chash = map::HashMap(); - let child = json::Dict(chash); + for c.sources.each |k, v| { + let mut chash = ~LinearMap(); - chash.insert(~"url", json::String(@v.url)); - chash.insert(~"method", json::String(@v.method)); + chash.insert(~"url", json::String(v.url)); + chash.insert(~"method", json::String(v.method)); match copy v.key { Some(key) => { - chash.insert(~"key", json::String(@key)); + chash.insert(~"key", json::String(copy key)); } _ => () } match copy v.keyfp { Some(keyfp) => { - chash.insert(~"keyfp", json::String(@keyfp)); + chash.insert(~"keyfp", json::String(copy keyfp)); } _ => () } - hash.insert(k, child); + hash.insert(copy k, json::Object(chash)); } - writer.write_str(json::to_str(root)); + json::to_writer(writer, &json::Object(hash)) } result::Err(e) => { error(fmt!("could not dump sources: %s", e)); @@ -1641,7 +1633,7 @@ fn copy_warn(srcfile: &Path, destfile: &Path) { } } -fn cmd_sources(c: &cargo) { +fn cmd_sources(c: &Cargo) { if vec::len(c.opts.free) < 3u { for c.sources.each_value |v| { info(fmt!("%s (%s) via %s", @@ -1677,7 +1669,7 @@ fn cmd_sources(c: &cargo) { if c.sources.contains_key(name) { error(fmt!("source already exists: %s", name)); } else { - c.sources.insert(name, @{ + c.sources.insert(name, @Source { name: name, mut url: url, mut method: assume_source_method(url), diff --git a/src/fuzzer/fuzzer.rs b/src/fuzzer/fuzzer.rs index 65adbb9e09e6a..9f1cc419d1538 100644 --- a/src/fuzzer/fuzzer.rs +++ b/src/fuzzer/fuzzer.rs @@ -243,7 +243,7 @@ fn check_variants_T( filename: &Path, thing_label: ~str, things: ~[T], - stringifier: fn@(@T, syntax::parse::token::ident_interner) -> ~str, + stringifier: fn@(@T, @syntax::parse::token::ident_interner) -> ~str, replacer: fn@(ast::crate, uint, T, test_mode) -> ast::crate, cx: context ) { diff --git a/src/libstd/ebml2.rs b/src/libstd/ebml2.rs new file mode 100644 index 0000000000000..8b37dea62108e --- /dev/null +++ b/src/libstd/ebml2.rs @@ -0,0 +1,623 @@ +use serialization2; + +// Simple Extensible Binary Markup Language (ebml) reader and writer on a +// cursor model. See the specification here: +// http://www.matroska.org/technical/specs/rfc/index.html +export Doc; +export doc_at; +export maybe_get_doc; +export get_doc; +export docs; +export tagged_docs; +export doc_data; +export doc_as_str; +export doc_as_u8; +export doc_as_u16; +export doc_as_u32; +export doc_as_u64; +export doc_as_i8; +export doc_as_i16; +export doc_as_i32; +export doc_as_i64; +export Serializer; +export Deserializer; +export with_doc_data; +export get_doc; +export extensions; + +struct EbmlTag { + id: uint, + size: uint, +} + +struct EbmlState { + ebml_tag: EbmlTag, + tag_pos: uint, + data_pos: uint, +} + +// FIXME (#2739): When we have module renaming, make "reader" and "writer" +// separate modules within this file. + +// ebml reading +struct Doc { + data: @~[u8], + start: uint, + end: uint, +} + +struct TaggedDoc { + tag: uint, + doc: Doc, +} + +impl Doc: ops::Index { + pure fn index(+tag: uint) -> Doc { + unsafe { + get_doc(self, tag) + } + } +} + +fn vuint_at(data: &[u8], start: uint) -> {val: uint, next: uint} { + let a = data[start]; + if a & 0x80u8 != 0u8 { + return {val: (a & 0x7fu8) as uint, next: start + 1u}; + } + if a & 0x40u8 != 0u8 { + return {val: ((a & 0x3fu8) as uint) << 8u | + (data[start + 1u] as uint), + next: start + 2u}; + } else if a & 0x20u8 != 0u8 { + return {val: ((a & 0x1fu8) as uint) << 16u | + (data[start + 1u] as uint) << 8u | + (data[start + 2u] as uint), + next: start + 3u}; + } else if a & 0x10u8 != 0u8 { + return {val: ((a & 0x0fu8) as uint) << 24u | + (data[start + 1u] as uint) << 16u | + (data[start + 2u] as uint) << 8u | + (data[start + 3u] as uint), + next: start + 4u}; + } else { error!("vint too big"); fail; } +} + +fn Doc(data: @~[u8]) -> Doc { + Doc { data: data, start: 0u, end: vec::len::(*data) } +} + +fn doc_at(data: @~[u8], start: uint) -> TaggedDoc { + let elt_tag = vuint_at(*data, start); + let elt_size = vuint_at(*data, elt_tag.next); + let end = elt_size.next + elt_size.val; + TaggedDoc { + tag: elt_tag.val, + doc: Doc { data: data, start: elt_size.next, end: end } + } +} + +fn maybe_get_doc(d: Doc, tg: uint) -> Option { + let mut pos = d.start; + while pos < d.end { + let elt_tag = vuint_at(*d.data, pos); + let elt_size = vuint_at(*d.data, elt_tag.next); + pos = elt_size.next + elt_size.val; + if elt_tag.val == tg { + return Some(Doc { data: d.data, start: elt_size.next, end: pos }); + } + } + None +} + +fn get_doc(d: Doc, tg: uint) -> Doc { + match maybe_get_doc(d, tg) { + Some(d) => d, + None => { + error!("failed to find block with tag %u", tg); + fail; + } + } +} + +fn docs(d: Doc, it: fn(uint, Doc) -> bool) { + let mut pos = d.start; + while pos < d.end { + let elt_tag = vuint_at(*d.data, pos); + let elt_size = vuint_at(*d.data, elt_tag.next); + pos = elt_size.next + elt_size.val; + let doc = Doc { data: d.data, start: elt_size.next, end: pos }; + if !it(elt_tag.val, doc) { + break; + } + } +} + +fn tagged_docs(d: Doc, tg: uint, it: fn(Doc) -> bool) { + let mut pos = d.start; + while pos < d.end { + let elt_tag = vuint_at(*d.data, pos); + let elt_size = vuint_at(*d.data, elt_tag.next); + pos = elt_size.next + elt_size.val; + if elt_tag.val == tg { + let doc = Doc { data: d.data, start: elt_size.next, end: pos }; + if !it(doc) { + break; + } + } + } +} + +fn doc_data(d: Doc) -> ~[u8] { vec::slice::(*d.data, d.start, d.end) } + +fn with_doc_data(d: Doc, f: fn(x: &[u8]) -> T) -> T { + f(vec::view(*d.data, d.start, d.end)) +} + +fn doc_as_str(d: Doc) -> ~str { str::from_bytes(doc_data(d)) } + +fn doc_as_u8(d: Doc) -> u8 { + assert d.end == d.start + 1u; + (*d.data)[d.start] +} + +fn doc_as_u16(d: Doc) -> u16 { + assert d.end == d.start + 2u; + io::u64_from_be_bytes(*d.data, d.start, 2u) as u16 +} + +fn doc_as_u32(d: Doc) -> u32 { + assert d.end == d.start + 4u; + io::u64_from_be_bytes(*d.data, d.start, 4u) as u32 +} + +fn doc_as_u64(d: Doc) -> u64 { + assert d.end == d.start + 8u; + io::u64_from_be_bytes(*d.data, d.start, 8u) +} + +fn doc_as_i8(d: Doc) -> i8 { doc_as_u8(d) as i8 } +fn doc_as_i16(d: Doc) -> i16 { doc_as_u16(d) as i16 } +fn doc_as_i32(d: Doc) -> i32 { doc_as_u32(d) as i32 } +fn doc_as_i64(d: Doc) -> i64 { doc_as_u64(d) as i64 } + +// ebml writing +struct Serializer { + writer: io::Writer, + priv mut size_positions: ~[uint], +} + +fn write_sized_vuint(w: io::Writer, n: uint, size: uint) { + match size { + 1u => w.write(&[0x80u8 | (n as u8)]), + 2u => w.write(&[0x40u8 | ((n >> 8_u) as u8), n as u8]), + 3u => w.write(&[0x20u8 | ((n >> 16_u) as u8), (n >> 8_u) as u8, + n as u8]), + 4u => w.write(&[0x10u8 | ((n >> 24_u) as u8), (n >> 16_u) as u8, + (n >> 8_u) as u8, n as u8]), + _ => fail fmt!("vint to write too big: %?", n) + }; +} + +fn write_vuint(w: io::Writer, n: uint) { + if n < 0x7f_u { write_sized_vuint(w, n, 1u); return; } + if n < 0x4000_u { write_sized_vuint(w, n, 2u); return; } + if n < 0x200000_u { write_sized_vuint(w, n, 3u); return; } + if n < 0x10000000_u { write_sized_vuint(w, n, 4u); return; } + fail fmt!("vint to write too big: %?", n); +} + +fn Serializer(w: io::Writer) -> Serializer { + let size_positions: ~[uint] = ~[]; + Serializer { writer: w, mut size_positions: size_positions } +} + +// FIXME (#2741): Provide a function to write the standard ebml header. +impl Serializer { + fn start_tag(tag_id: uint) { + debug!("Start tag %u", tag_id); + + // Write the enum ID: + write_vuint(self.writer, tag_id); + + // Write a placeholder four-byte size. + vec::push(self.size_positions, self.writer.tell()); + let zeroes: &[u8] = &[0u8, 0u8, 0u8, 0u8]; + self.writer.write(zeroes); + } + + fn end_tag() { + let last_size_pos = vec::pop::(self.size_positions); + let cur_pos = self.writer.tell(); + self.writer.seek(last_size_pos as int, io::SeekSet); + let size = (cur_pos - last_size_pos - 4u); + write_sized_vuint(self.writer, size, 4u); + self.writer.seek(cur_pos as int, io::SeekSet); + + debug!("End tag (size = %u)", size); + } + + fn wr_tag(tag_id: uint, blk: fn()) { + self.start_tag(tag_id); + blk(); + self.end_tag(); + } + + fn wr_tagged_bytes(tag_id: uint, b: &[u8]) { + write_vuint(self.writer, tag_id); + write_vuint(self.writer, vec::len(b)); + self.writer.write(b); + } + + fn wr_tagged_u64(tag_id: uint, v: u64) { + do io::u64_to_be_bytes(v, 8u) |v| { + self.wr_tagged_bytes(tag_id, v); + } + } + + fn wr_tagged_u32(tag_id: uint, v: u32) { + do io::u64_to_be_bytes(v as u64, 4u) |v| { + self.wr_tagged_bytes(tag_id, v); + } + } + + fn wr_tagged_u16(tag_id: uint, v: u16) { + do io::u64_to_be_bytes(v as u64, 2u) |v| { + self.wr_tagged_bytes(tag_id, v); + } + } + + fn wr_tagged_u8(tag_id: uint, v: u8) { + self.wr_tagged_bytes(tag_id, &[v]); + } + + fn wr_tagged_i64(tag_id: uint, v: i64) { + do io::u64_to_be_bytes(v as u64, 8u) |v| { + self.wr_tagged_bytes(tag_id, v); + } + } + + fn wr_tagged_i32(tag_id: uint, v: i32) { + do io::u64_to_be_bytes(v as u64, 4u) |v| { + self.wr_tagged_bytes(tag_id, v); + } + } + + fn wr_tagged_i16(tag_id: uint, v: i16) { + do io::u64_to_be_bytes(v as u64, 2u) |v| { + self.wr_tagged_bytes(tag_id, v); + } + } + + fn wr_tagged_i8(tag_id: uint, v: i8) { + self.wr_tagged_bytes(tag_id, &[v as u8]); + } + + fn wr_tagged_str(tag_id: uint, v: &str) { + str::byte_slice(v, |b| self.wr_tagged_bytes(tag_id, b)); + } + + fn wr_bytes(b: &[u8]) { + debug!("Write %u bytes", vec::len(b)); + self.writer.write(b); + } + + fn wr_str(s: ~str) { + debug!("Write str: %?", s); + self.writer.write(str::to_bytes(s)); + } +} + +// FIXME (#2743): optionally perform "relaxations" on end_tag to more +// efficiently encode sizes; this is a fixed point iteration + +// Set to true to generate more debugging in EBML serialization. +// Totally lame approach. +const debug: bool = false; + +enum EbmlSerializerTag { + EsUint, EsU64, EsU32, EsU16, EsU8, + EsInt, EsI64, EsI32, EsI16, EsI8, + EsBool, + EsStr, + EsF64, EsF32, EsFloat, + EsEnum, EsEnumVid, EsEnumBody, + EsVec, EsVecLen, EsVecElt, + + EsOpaque, + + EsLabel // Used only when debugging +} + +priv impl Serializer { + // used internally to emit things like the vector length and so on + fn _emit_tagged_uint(t: EbmlSerializerTag, v: uint) { + assert v <= 0xFFFF_FFFF_u; + self.wr_tagged_u32(t as uint, v as u32); + } + + fn _emit_label(label: &str) { + // There are various strings that we have access to, such as + // the name of a record field, which do not actually appear in + // the serialized EBML (normally). This is just for + // efficiency. When debugging, though, we can emit such + // labels and then they will be checked by deserializer to + // try and check failures more quickly. + if debug { self.wr_tagged_str(EsLabel as uint, label) } + } +} + +impl Serializer { + fn emit_opaque(&self, f: fn()) { + do self.wr_tag(EsOpaque as uint) { + f() + } + } +} + +impl Serializer: serialization2::Serializer { + fn emit_nil(&self) {} + + fn emit_uint(&self, v: uint) { + self.wr_tagged_u64(EsUint as uint, v as u64); + } + fn emit_u64(&self, v: u64) { self.wr_tagged_u64(EsU64 as uint, v); } + fn emit_u32(&self, v: u32) { self.wr_tagged_u32(EsU32 as uint, v); } + fn emit_u16(&self, v: u16) { self.wr_tagged_u16(EsU16 as uint, v); } + fn emit_u8(&self, v: u8) { self.wr_tagged_u8 (EsU8 as uint, v); } + + fn emit_int(&self, v: int) { + self.wr_tagged_i64(EsInt as uint, v as i64); + } + fn emit_i64(&self, v: i64) { self.wr_tagged_i64(EsI64 as uint, v); } + fn emit_i32(&self, v: i32) { self.wr_tagged_i32(EsI32 as uint, v); } + fn emit_i16(&self, v: i16) { self.wr_tagged_i16(EsI16 as uint, v); } + fn emit_i8(&self, v: i8) { self.wr_tagged_i8 (EsI8 as uint, v); } + + fn emit_bool(&self, v: bool) { + self.wr_tagged_u8(EsBool as uint, v as u8) + } + + // FIXME (#2742): implement these + fn emit_f64(&self, _v: f64) { fail ~"Unimplemented: serializing an f64"; } + fn emit_f32(&self, _v: f32) { fail ~"Unimplemented: serializing an f32"; } + fn emit_float(&self, _v: float) { + fail ~"Unimplemented: serializing a float"; + } + + fn emit_str(&self, v: &str) { self.wr_tagged_str(EsStr as uint, v) } + + fn emit_enum(&self, name: &str, f: fn()) { + self._emit_label(name); + self.wr_tag(EsEnum as uint, f) + } + fn emit_enum_variant(&self, _v_name: &str, v_id: uint, _cnt: uint, + f: fn()) { + self._emit_tagged_uint(EsEnumVid, v_id); + self.wr_tag(EsEnumBody as uint, f) + } + fn emit_enum_variant_arg(&self, _idx: uint, f: fn()) { f() } + + fn emit_vec(&self, len: uint, f: fn()) { + do self.wr_tag(EsVec as uint) { + self._emit_tagged_uint(EsVecLen, len); + f() + } + } + + fn emit_vec_elt(&self, _idx: uint, f: fn()) { + self.wr_tag(EsVecElt as uint, f) + } + + fn emit_box(&self, f: fn()) { f() } + fn emit_uniq(&self, f: fn()) { f() } + fn emit_rec(&self, f: fn()) { f() } + fn emit_rec_field(&self, f_name: &str, _f_idx: uint, f: fn()) { + self._emit_label(f_name); + f() + } + fn emit_tup(&self, _sz: uint, f: fn()) { f() } + fn emit_tup_elt(&self, _idx: uint, f: fn()) { f() } +} + +struct Deserializer { + priv mut parent: Doc, + priv mut pos: uint, +} + +fn Deserializer(d: Doc) -> Deserializer { + Deserializer { mut parent: d, mut pos: d.start } +} + +priv impl Deserializer { + fn _check_label(lbl: ~str) { + if self.pos < self.parent.end { + let TaggedDoc { tag: r_tag, doc: r_doc } = + doc_at(self.parent.data, self.pos); + + if r_tag == (EsLabel as uint) { + self.pos = r_doc.end; + let str = doc_as_str(r_doc); + if lbl != str { + fail fmt!("Expected label %s but found %s", lbl, str); + } + } + } + } + + fn next_doc(exp_tag: EbmlSerializerTag) -> Doc { + debug!(". next_doc(exp_tag=%?)", exp_tag); + if self.pos >= self.parent.end { + fail ~"no more documents in current node!"; + } + let TaggedDoc { tag: r_tag, doc: r_doc } = + doc_at(self.parent.data, self.pos); + debug!("self.parent=%?-%? self.pos=%? r_tag=%? r_doc=%?-%?", + copy self.parent.start, copy self.parent.end, + copy self.pos, r_tag, r_doc.start, r_doc.end); + if r_tag != (exp_tag as uint) { + fail fmt!("expected EMBL doc with tag %? but found tag %?", + exp_tag, r_tag); + } + if r_doc.end > self.parent.end { + fail fmt!("invalid EBML, child extends to 0x%x, parent to 0x%x", + r_doc.end, self.parent.end); + } + self.pos = r_doc.end; + r_doc + } + + fn push_doc(d: Doc, f: fn() -> T) -> T{ + let old_parent = self.parent; + let old_pos = self.pos; + self.parent = d; + self.pos = d.start; + let r = f(); + self.parent = old_parent; + self.pos = old_pos; + move r + } + + fn _next_uint(exp_tag: EbmlSerializerTag) -> uint { + let r = doc_as_u32(self.next_doc(exp_tag)); + debug!("_next_uint exp_tag=%? result=%?", exp_tag, r); + r as uint + } +} + +impl Deserializer { + fn read_opaque(&self, op: fn(Doc) -> R) -> R { + do self.push_doc(self.next_doc(EsOpaque)) { + op(copy self.parent) + } + } +} + +impl Deserializer: serialization2::Deserializer { + fn read_nil(&self) -> () { () } + + fn read_u64(&self) -> u64 { doc_as_u64(self.next_doc(EsU64)) } + fn read_u32(&self) -> u32 { doc_as_u32(self.next_doc(EsU32)) } + fn read_u16(&self) -> u16 { doc_as_u16(self.next_doc(EsU16)) } + fn read_u8 (&self) -> u8 { doc_as_u8 (self.next_doc(EsU8 )) } + fn read_uint(&self) -> uint { + let v = doc_as_u64(self.next_doc(EsUint)); + if v > (core::uint::max_value as u64) { + fail fmt!("uint %? too large for this architecture", v); + } + v as uint + } + + fn read_i64(&self) -> i64 { doc_as_u64(self.next_doc(EsI64)) as i64 } + fn read_i32(&self) -> i32 { doc_as_u32(self.next_doc(EsI32)) as i32 } + fn read_i16(&self) -> i16 { doc_as_u16(self.next_doc(EsI16)) as i16 } + fn read_i8 (&self) -> i8 { doc_as_u8 (self.next_doc(EsI8 )) as i8 } + fn read_int(&self) -> int { + let v = doc_as_u64(self.next_doc(EsInt)) as i64; + if v > (int::max_value as i64) || v < (int::min_value as i64) { + fail fmt!("int %? out of range for this architecture", v); + } + v as int + } + + fn read_bool(&self) -> bool { doc_as_u8(self.next_doc(EsBool)) as bool } + + fn read_f64(&self) -> f64 { fail ~"read_f64()"; } + fn read_f32(&self) -> f32 { fail ~"read_f32()"; } + fn read_float(&self) -> float { fail ~"read_float()"; } + + fn read_str(&self) -> ~str { doc_as_str(self.next_doc(EsStr)) } + + // Compound types: + fn read_enum(&self, name: ~str, f: fn() -> T) -> T { + debug!("read_enum(%s)", name); + self._check_label(name); + self.push_doc(self.next_doc(EsEnum), f) + } + + fn read_enum_variant(&self, f: fn(uint) -> T) -> T { + debug!("read_enum_variant()"); + let idx = self._next_uint(EsEnumVid); + debug!(" idx=%u", idx); + do self.push_doc(self.next_doc(EsEnumBody)) { + f(idx) + } + } + + fn read_enum_variant_arg(&self, idx: uint, f: fn() -> T) -> T { + debug!("read_enum_variant_arg(idx=%u)", idx); + f() + } + + fn read_vec(&self, f: fn(uint) -> T) -> T { + debug!("read_vec()"); + do self.push_doc(self.next_doc(EsVec)) { + let len = self._next_uint(EsVecLen); + debug!(" len=%u", len); + f(len) + } + } + + fn read_vec_elt(&self, idx: uint, f: fn() -> T) -> T { + debug!("read_vec_elt(idx=%u)", idx); + self.push_doc(self.next_doc(EsVecElt), f) + } + + fn read_box(&self, f: fn() -> T) -> T { + debug!("read_box()"); + f() + } + + fn read_uniq(&self, f: fn() -> T) -> T { + debug!("read_uniq()"); + f() + } + + fn read_rec(&self, f: fn() -> T) -> T { + debug!("read_rec()"); + f() + } + + fn read_rec_field(&self, f_name: ~str, f_idx: uint, + f: fn() -> T) -> T { + debug!("read_rec_field(%s, idx=%u)", f_name, f_idx); + self._check_label(f_name); + f() + } + + fn read_tup(&self, sz: uint, f: fn() -> T) -> T { + debug!("read_tup(sz=%u)", sz); + f() + } + + fn read_tup_elt(&self, idx: uint, f: fn() -> T) -> T { + debug!("read_tup_elt(idx=%u)", idx); + f() + } +} + + +// ___________________________________________________________________________ +// Testing + +#[cfg(test)] +mod tests { + #[test] + fn test_option_int() { + fn test_v(v: Option) { + debug!("v == %?", v); + let bytes = do io::with_bytes_writer |wr| { + let ebml_w = Serializer(wr); + v.serialize(&ebml_w) + }; + let ebml_doc = Doc(@bytes); + let deser = Deserializer(ebml_doc); + let v1 = serialization2::deserialize(&deser); + debug!("v1 == %?", v1); + assert v == v1; + } + + test_v(Some(22)); + test_v(None); + test_v(Some(3)); + } +} diff --git a/src/libstd/json.rs b/src/libstd/json.rs index db22b9ff30b75..8709e83d719cd 100644 --- a/src/libstd/json.rs +++ b/src/libstd/json.rs @@ -7,218 +7,328 @@ //! json serialization use core::cmp::{Eq, Ord}; -use result::{Result, Ok, Err}; use io::WriterUtil; -use map::HashMap; -use map::Map; +use send_map::linear; use sort::Sort; -export Json; -export Error; -export to_writer; -export to_writer_pretty; -export to_str; -export to_str_pretty; -export from_reader; -export from_str; -export eq; -export ToJson; - -export Num; -export String; -export Boolean; -export List; -export Dict; -export Null; - /// Represents a json value -enum Json { - Num(float), - String(@~str), +pub enum Json { + Number(float), + String(~str), Boolean(bool), - List(@~[Json]), - Dict(map::HashMap<~str, Json>), + List(List), + Object(~Object), Null, } -type Error = { +pub type List = ~[Json]; +pub type Object = linear::LinearMap<~str, Json>; + +pub struct Error { line: uint, col: uint, msg: @~str, -}; +} -/// Serializes a json value into a io::writer -fn to_writer(wr: io::Writer, j: Json) { - match j { - Num(n) => wr.write_str(float::to_str(n, 6u)), - String(s) => wr.write_str(escape_str(*s)), - Boolean(b) => wr.write_str(if b { ~"true" } else { ~"false" }), - List(v) => { - wr.write_char('['); - let mut first = true; - for (*v).each |item| { - if !first { - wr.write_str(~", "); - } - first = false; - to_writer(wr, *item); - }; - wr.write_char(']'); - } - Dict(d) => { - if d.size() == 0u { - wr.write_str(~"{}"); - return; +fn escape_str(s: &str) -> ~str { + let mut escaped = ~"\""; + for str::chars_each(s) |c| { + match c { + '"' => escaped += ~"\\\"", + '\\' => escaped += ~"\\\\", + '\x08' => escaped += ~"\\b", + '\x0c' => escaped += ~"\\f", + '\n' => escaped += ~"\\n", + '\r' => escaped += ~"\\r", + '\t' => escaped += ~"\\t", + _ => escaped += str::from_char(c) } + }; - wr.write_str(~"{ "); - let mut first = true; - for d.each |key, value| { - if !first { - wr.write_str(~", "); - } - first = false; - wr.write_str(escape_str(key)); - wr.write_str(~": "); - to_writer(wr, value); - }; - wr.write_str(~" }"); - } - Null => wr.write_str(~"null") - } + escaped += ~"\""; + + escaped } -/// Serializes a json value into a io::writer -fn to_writer_pretty(wr: io::Writer, j: Json, indent: uint) { - fn spaces(n: uint) -> ~str { - let mut ss = ~""; - for n.times { str::push_str(&mut ss, " "); } - return ss; - } - - match j { - Num(n) => wr.write_str(float::to_str(n, 6u)), - String(s) => wr.write_str(escape_str(*s)), - Boolean(b) => wr.write_str(if b { ~"true" } else { ~"false" }), - List(vv) => { - if vv.len() == 0u { - wr.write_str(~"[]"); - return; +fn spaces(n: uint) -> ~str { + let mut ss = ~""; + for n.times { str::push_str(&ss, " "); } + return ss; +} + +pub struct Serializer { + priv wr: io::Writer, +} + +pub fn Serializer(wr: io::Writer) -> Serializer { + Serializer { wr: wr } +} + +pub impl Serializer: serialization2::Serializer { + fn emit_nil(&self) { self.wr.write_str("null") } + + fn emit_uint(&self, v: uint) { self.emit_float(v as float); } + fn emit_u64(&self, v: u64) { self.emit_float(v as float); } + fn emit_u32(&self, v: u32) { self.emit_float(v as float); } + fn emit_u16(&self, v: u16) { self.emit_float(v as float); } + fn emit_u8(&self, v: u8) { self.emit_float(v as float); } + + fn emit_int(&self, v: int) { self.emit_float(v as float); } + fn emit_i64(&self, v: i64) { self.emit_float(v as float); } + fn emit_i32(&self, v: i32) { self.emit_float(v as float); } + fn emit_i16(&self, v: i16) { self.emit_float(v as float); } + fn emit_i8(&self, v: i8) { self.emit_float(v as float); } + + fn emit_bool(&self, v: bool) { + if v { + self.wr.write_str("true"); + } else { + self.wr.write_str("false"); } + } - let inner_indent = indent + 2; + fn emit_f64(&self, v: f64) { self.emit_float(v as float); } + fn emit_f32(&self, v: f32) { self.emit_float(v as float); } + fn emit_float(&self, v: float) { + self.wr.write_str(float::to_str(v, 6u)); + } - // [ - wr.write_str("[\n"); - wr.write_str(spaces(inner_indent)); + fn emit_str(&self, v: &str) { + let s = escape_str(v); + self.wr.write_str(s); + } - // [ elem, - // elem, - // elem ] - let mut first = true; - for (*vv).each |item| { - if !first { - wr.write_str(~",\n"); - wr.write_str(spaces(inner_indent)); - } - first = false; - to_writer_pretty(wr, *item, inner_indent); - }; + fn emit_enum(&self, name: &str, f: fn()) { + if name != "option" { fail ~"only supports option enum" } + f() + } + fn emit_enum_variant(&self, _name: &str, id: uint, _cnt: uint, f: fn()) { + if id == 0 { + self.emit_nil(); + } else { + f() + } + } + fn emit_enum_variant_arg(&self, _idx: uint, f: fn()) { + f() + } + + fn emit_vec(&self, _len: uint, f: fn()) { + self.wr.write_char('['); + f(); + self.wr.write_char(']'); + } + + fn emit_vec_elt(&self, idx: uint, f: fn()) { + if idx != 0 { self.wr.write_char(','); } + f() + } + + fn emit_box(&self, f: fn()) { f() } + fn emit_uniq(&self, f: fn()) { f() } + fn emit_rec(&self, f: fn()) { + self.wr.write_char('{'); + f(); + self.wr.write_char('}'); + } + fn emit_rec_field(&self, name: &str, idx: uint, f: fn()) { + if idx != 0 { self.wr.write_char(','); } + self.wr.write_str(escape_str(name)); + self.wr.write_char(':'); + f(); + } + fn emit_tup(&self, sz: uint, f: fn()) { + self.emit_vec(sz, f); + } + fn emit_tup_elt(&self, idx: uint, f: fn()) { + self.emit_vec_elt(idx, f) + } +} + +pub struct PrettySerializer { + priv wr: io::Writer, + priv mut indent: uint, +} + +pub fn PrettySerializer(wr: io::Writer) -> PrettySerializer { + PrettySerializer { wr: wr, indent: 0 } +} - // ] - wr.write_str("\n"); - wr.write_str(spaces(indent)); - wr.write_str(~"]"); - } - Dict(dd) => { - if dd.size() == 0u { - wr.write_str(~"{}"); - return; +pub impl PrettySerializer: serialization2::Serializer { + fn emit_nil(&self) { self.wr.write_str("null") } + + fn emit_uint(&self, v: uint) { self.emit_float(v as float); } + fn emit_u64(&self, v: u64) { self.emit_float(v as float); } + fn emit_u32(&self, v: u32) { self.emit_float(v as float); } + fn emit_u16(&self, v: u16) { self.emit_float(v as float); } + fn emit_u8(&self, v: u8) { self.emit_float(v as float); } + + fn emit_int(&self, v: int) { self.emit_float(v as float); } + fn emit_i64(&self, v: i64) { self.emit_float(v as float); } + fn emit_i32(&self, v: i32) { self.emit_float(v as float); } + fn emit_i16(&self, v: i16) { self.emit_float(v as float); } + fn emit_i8(&self, v: i8) { self.emit_float(v as float); } + + fn emit_bool(&self, v: bool) { + if v { + self.wr.write_str("true"); + } else { + self.wr.write_str("false"); } + } + + fn emit_f64(&self, v: f64) { self.emit_float(v as float); } + fn emit_f32(&self, v: f32) { self.emit_float(v as float); } + fn emit_float(&self, v: float) { + self.wr.write_str(float::to_str(v, 6u)); + } - let inner_indent = indent + 2; + fn emit_str(&self, v: &str) { self.wr.write_str(escape_str(v)); } - // convert from a dictionary - let mut pairs = ~[]; - for dd.each |key, value| { - vec::push(pairs, (key, value)); + fn emit_enum(&self, name: &str, f: fn()) { + if name != "option" { fail ~"only supports option enum" } + f() + } + fn emit_enum_variant(&self, _name: &str, id: uint, _cnt: uint, f: fn()) { + if id == 0 { + self.emit_nil(); + } else { + f() } + } + fn emit_enum_variant_arg(&self, _idx: uint, f: fn()) { + f() + } - // sort by key strings - let sorted_pairs = sort::merge_sort(|a,b| *a <= *b, pairs); - - // { - wr.write_str(~"{\n"); - wr.write_str(spaces(inner_indent)); - - // { k: v, - // k: v, - // k: v } - let mut first = true; - for sorted_pairs.each |kv| { - let (key, value) = *kv; - if !first { - wr.write_str(~",\n"); - wr.write_str(spaces(inner_indent)); - } - first = false; - let key = str::append(escape_str(key), ~": "); - let key_indent = inner_indent + str::len(key); - wr.write_str(key); - to_writer_pretty(wr, value, key_indent); - }; + fn emit_vec(&self, _len: uint, f: fn()) { + self.wr.write_char('['); + self.indent += 2; + f(); + self.indent -= 2; + self.wr.write_char(']'); + } + + fn emit_vec_elt(&self, idx: uint, f: fn()) { + if idx == 0 { + self.wr.write_char('\n'); + } else { + self.wr.write_str(",\n"); + } + self.wr.write_str(spaces(self.indent)); + f() + } - // } - wr.write_str(~"\n"); - wr.write_str(spaces(indent)); - wr.write_str(~"}"); - } - Null => wr.write_str(~"null") + fn emit_box(&self, f: fn()) { f() } + fn emit_uniq(&self, f: fn()) { f() } + fn emit_rec(&self, f: fn()) { + self.wr.write_char('{'); + self.indent += 2; + f(); + self.indent -= 2; + self.wr.write_char('}'); + } + fn emit_rec_field(&self, name: &str, idx: uint, f: fn()) { + if idx == 0 { + self.wr.write_char('\n'); + } else { + self.wr.write_str(",\n"); + } + self.wr.write_str(spaces(self.indent)); + self.wr.write_str(escape_str(name)); + self.wr.write_str(": "); + f(); + } + fn emit_tup(&self, sz: uint, f: fn()) { + self.emit_vec(sz, f); + } + fn emit_tup_elt(&self, idx: uint, f: fn()) { + self.emit_vec_elt(idx, f) } } -fn escape_str(s: &str) -> ~str { - let mut escaped = ~"\""; - for str::chars_each(s) |c| { - match c { - '"' => escaped += ~"\\\"", - '\\' => escaped += ~"\\\\", - '\x08' => escaped += ~"\\b", - '\x0c' => escaped += ~"\\f", - '\n' => escaped += ~"\\n", - '\r' => escaped += ~"\\r", - '\t' => escaped += ~"\\t", - _ => escaped += str::from_char(c) +pub fn to_serializer(ser: &S, json: &Json) { + match *json { + Number(f) => ser.emit_float(f), + String(s) => ser.emit_str(s), + Boolean(b) => ser.emit_bool(b), + List(v) => { + do ser.emit_vec(v.len()) || { + for v.eachi |i, elt| { + ser.emit_vec_elt(i, || to_serializer(ser, elt)) + } + } } - }; + Object(o) => { + do ser.emit_rec || { + let mut idx = 0; + for o.each |key, value| { + do ser.emit_rec_field(*key, idx) { + to_serializer(ser, value); + } + idx += 1; + } + } + } + Null => ser.emit_nil(), + } +} - escaped += ~"\""; +/// Serializes a json value into a io::writer +pub fn to_writer(wr: io::Writer, json: &Json) { + to_serializer(&Serializer(wr), json) +} - escaped +/// Serializes a json value into a string +pub fn to_str(json: &Json) -> ~str { + io::with_str_writer(|wr| to_writer(wr, json)) +} + +/// Serializes a json value into a io::writer +pub fn to_pretty_writer(wr: io::Writer, json: &Json) { + to_serializer(&PrettySerializer(wr), json) } /// Serializes a json value into a string -fn to_str(j: Json) -> ~str { - io::with_str_writer(|wr| to_writer(wr, j)) +pub fn to_pretty_str(json: &Json) -> ~str { + io::with_str_writer(|wr| to_pretty_writer(wr, json)) } -/// Serializes a json value into a string, with whitespace and sorting -fn to_str_pretty(j: Json) -> ~str { - io::with_str_writer(|wr| to_writer_pretty(wr, j, 0)) +pub struct Parser { + priv rdr: io::Reader, + priv mut ch: char, + priv mut line: uint, + priv mut col: uint, } -type Parser_ = { - rdr: io::Reader, - mut ch: char, - mut line: uint, - mut col: uint, -}; +/// Deserializes a json value from an io::reader +pub fn Parser(rdr: io::Reader) -> Parser { + Parser { + rdr: rdr, + ch: rdr.read_char(), + line: 1u, + col: 1u, + } +} -enum Parser { - Parser_(Parser_) +pub impl Parser { + fn parse() -> Result { + match move self.parse_value() { + Ok(move value) => { + // Skip trailing whitespaces. + self.parse_whitespace(); + // Make sure there is no trailing characters. + if self.eof() { + Ok(value) + } else { + self.error(~"trailing characters") + } + } + Err(move e) => Err(e) + } + } } -impl Parser { +priv impl Parser { fn eof() -> bool { self.ch == -1 as char } fn bump() { @@ -238,23 +348,7 @@ impl Parser { } fn error(+msg: ~str) -> Result { - Err({ line: self.line, col: self.col, msg: @msg }) - } - - fn parse() -> Result { - match self.parse_value() { - Ok(value) => { - // Skip trailing whitespaces. - self.parse_whitespace(); - // Make sure there is no trailing characters. - if self.eof() { - Ok(value) - } else { - self.error(~"trailing characters") - } - } - e => e - } + Err(Error { line: self.line, col: self.col, msg: @msg }) } fn parse_value() -> Result { @@ -267,10 +361,11 @@ impl Parser { 't' => self.parse_ident(~"rue", Boolean(true)), 'f' => self.parse_ident(~"alse", Boolean(false)), '0' .. '9' | '-' => self.parse_number(), - '"' => match self.parse_str() { - Ok(s) => Ok(String(s)), - Err(e) => Err(e) - }, + '"' => + match move self.parse_str() { + Ok(move s) => Ok(String(s)), + Err(move e) => Err(e), + }, '[' => self.parse_list(), '{' => self.parse_object(), _ => self.error(~"invalid syntax") @@ -281,10 +376,10 @@ impl Parser { while char::is_whitespace(self.ch) { self.bump(); } } - fn parse_ident(ident: ~str, value: Json) -> Result { + fn parse_ident(ident: ~str, +value: Json) -> Result { if str::all(ident, |c| c == self.next_char()) { self.bump(); - Ok(value) + Ok(move value) } else { self.error(~"invalid syntax") } @@ -317,7 +412,7 @@ impl Parser { } } - Ok(Num(neg * res)) + Ok(Number(neg * res)) } fn parse_integer() -> Result { @@ -419,7 +514,7 @@ impl Parser { Ok(res) } - fn parse_str() -> Result<@~str, Error> { + fn parse_str() -> Result<~str, Error> { let mut escape = false; let mut res = ~""; @@ -428,14 +523,14 @@ impl Parser { if (escape) { match self.ch { - '"' => str::push_char(&mut res, '"'), - '\\' => str::push_char(&mut res, '\\'), - '/' => str::push_char(&mut res, '/'), - 'b' => str::push_char(&mut res, '\x08'), - 'f' => str::push_char(&mut res, '\x0c'), - 'n' => str::push_char(&mut res, '\n'), - 'r' => str::push_char(&mut res, '\r'), - 't' => str::push_char(&mut res, '\t'), + '"' => str::push_char(&res, '"'), + '\\' => str::push_char(&res, '\\'), + '/' => str::push_char(&res, '/'), + 'b' => str::push_char(&res, '\x08'), + 'f' => str::push_char(&res, '\x0c'), + 'n' => str::push_char(&res, '\n'), + 'r' => str::push_char(&res, '\r'), + 't' => str::push_char(&res, '\t'), 'u' => { // Parse \u1234. let mut i = 0u; @@ -464,7 +559,7 @@ impl Parser { ~"invalid \\u escape (not four digits)"); } - str::push_char(&mut res, n as char); + str::push_char(&res, n as char); } _ => return self.error(~"invalid escape") } @@ -474,9 +569,9 @@ impl Parser { } else { if self.ch == '"' { self.bump(); - return Ok(@res); + return Ok(res); } - str::push_char(&mut res, self.ch); + str::push_char(&res, self.ch); } } @@ -491,13 +586,13 @@ impl Parser { if self.ch == ']' { self.bump(); - return Ok(List(@values)); + return Ok(List(values)); } loop { - match self.parse_value() { - Ok(v) => vec::push(values, v), - e => return e + match move self.parse_value() { + Ok(move v) => vec::push(values, v), + Err(move e) => return Err(e) } self.parse_whitespace(); @@ -507,7 +602,7 @@ impl Parser { match self.ch { ',' => self.bump(), - ']' => { self.bump(); return Ok(List(@values)); } + ']' => { self.bump(); return Ok(List(values)); } _ => return self.error(~"expected `,` or `]`") } }; @@ -517,11 +612,11 @@ impl Parser { self.bump(); self.parse_whitespace(); - let values = map::HashMap(); + let mut values = ~linear::LinearMap(); if self.ch == '}' { self.bump(); - return Ok(Dict(values)); + return Ok(Object(values)); } while !self.eof() { @@ -531,9 +626,9 @@ impl Parser { return self.error(~"key must be a string"); } - let key = match self.parse_str() { - Ok(key) => key, - Err(e) => return Err(e) + let key = match move self.parse_str() { + Ok(move key) => key, + Err(move e) => return Err(e) }; self.parse_whitespace(); @@ -544,15 +639,15 @@ impl Parser { } self.bump(); - match self.parse_value() { - Ok(value) => { values.insert(copy *key, value); } - e => return e + match move self.parse_value() { + Ok(move value) => { values.insert(key, value); } + Err(move e) => return Err(e) } self.parse_whitespace(); match self.ch { ',' => self.bump(), - '}' => { self.bump(); return Ok(Dict(values)); } + '}' => { self.bump(); return Ok(Object(values)); } _ => { if self.eof() { break; } return self.error(~"expected `,` or `}`"); @@ -565,198 +660,382 @@ impl Parser { } /// Deserializes a json value from an io::reader -fn from_reader(rdr: io::Reader) -> Result { - let parser = Parser_({ - rdr: rdr, - mut ch: rdr.read_char(), - mut line: 1u, - mut col: 1u, - }); - - parser.parse() +pub fn from_reader(rdr: io::Reader) -> Result { + Parser(rdr).parse() } /// Deserializes a json value from a string -fn from_str(s: &str) -> Result { - io::with_str_reader(s, from_reader) +pub fn from_str(s: &str) -> Result { + do io::with_str_reader(s) |rdr| { + from_reader(rdr) + } } -/// Test if two json values are equal -pure fn eq(value0: Json, value1: Json) -> bool { - match (value0, value1) { - (Num(f0), Num(f1)) => f0 == f1, - (String(s0), String(s1)) => s0 == s1, - (Boolean(b0), Boolean(b1)) => b0 == b1, - (List(l0), List(l1)) => vec::all2(*l0, *l1, eq), - (Dict(d0), Dict(d1)) => { - if d0.size() == d1.size() { - let mut equal = true; - for d0.each |k, v0| { - match d1.find(k) { - Some(v1) => if !eq(v0, v1) { equal = false }, - None => equal = false - } - }; - equal - } else { - false - } - } - (Null, Null) => true, - _ => false +pub struct Deserializer { + priv json: Json, + priv mut stack: ~[&Json], +} + +pub fn Deserializer(rdr: io::Reader) -> Result { + match move from_reader(rdr) { + Ok(move json) => { + let des = Deserializer { json: json, stack: ~[] }; + Ok(move des) + } + Err(move e) => Err(e) } } -/// Test if two json values are less than one another -pure fn lt(value0: Json, value1: Json) -> bool { - match value0 { - Num(f0) => { - match value1 { - Num(f1) => f0 < f1, - String(_) | Boolean(_) | List(_) | Dict(_) | Null => true - } +priv impl Deserializer { + fn peek() -> &self/Json { + if self.stack.len() == 0 { vec::push(self.stack, &self.json); } + vec::last(self.stack) + } + + fn pop() -> &self/Json { + if self.stack.len() == 0 { vec::push(self.stack, &self.json); } + vec::pop(self.stack) + } +} + +pub impl Deserializer: serialization2::Deserializer { + fn read_nil(&self) -> () { + debug!("read_nil"); + match *self.pop() { + Null => (), + _ => fail ~"not a null" } + } - String(s0) => { - match value1 { - Num(_) => false, - String(s1) => s0 < s1, - Boolean(_) | List(_) | Dict(_) | Null => true - } + fn read_u64(&self) -> u64 { self.read_float() as u64 } + fn read_u32(&self) -> u32 { self.read_float() as u32 } + fn read_u16(&self) -> u16 { self.read_float() as u16 } + fn read_u8 (&self) -> u8 { self.read_float() as u8 } + fn read_uint(&self) -> uint { self.read_float() as uint } + + fn read_i64(&self) -> i64 { self.read_float() as i64 } + fn read_i32(&self) -> i32 { self.read_float() as i32 } + fn read_i16(&self) -> i16 { self.read_float() as i16 } + fn read_i8 (&self) -> i8 { self.read_float() as i8 } + fn read_int(&self) -> int { self.read_float() as int } + + fn read_bool(&self) -> bool { + debug!("read_bool"); + match *self.pop() { + Boolean(b) => b, + _ => fail ~"not a boolean" } + } - Boolean(b0) => { - match value1 { - Num(_) | String(_) => false, - Boolean(b1) => b0 < b1, - List(_) | Dict(_) | Null => true - } + fn read_f64(&self) -> f64 { self.read_float() as f64 } + fn read_f32(&self) -> f32 { self.read_float() as f32 } + fn read_float(&self) -> float { + debug!("read_float"); + match *self.pop() { + Number(f) => f, + _ => fail ~"not a number" + } + } + + fn read_str(&self) -> ~str { + debug!("read_str"); + match *self.pop() { + String(ref s) => copy *s, + _ => fail ~"not a string" } + } + + fn read_enum(&self, name: ~str, f: fn() -> T) -> T { + debug!("read_enum(%s)", name); + if name != ~"option" { fail ~"only supports the option enum" } + f() + } + + fn read_enum_variant(&self, f: fn(uint) -> T) -> T { + debug!("read_enum_variant()"); + let idx = match *self.peek() { + Null => 0, + _ => 1, + }; + f(idx) + } + + fn read_enum_variant_arg(&self, idx: uint, f: fn() -> T) -> T { + debug!("read_enum_variant_arg(idx=%u)", idx); + if idx != 0 { fail ~"unknown index" } + f() + } - List(l0) => { - match value1 { - Num(_) | String(_) | Boolean(_) => false, - List(l1) => l0 < l1, - Dict(_) | Null => true + fn read_vec(&self, f: fn(uint) -> T) -> T { + debug!("read_vec()"); + let len = match *self.peek() { + List(list) => list.len(), + _ => fail ~"not a list", + }; + let res = f(len); + self.pop(); + res + } + + fn read_vec_elt(&self, idx: uint, f: fn() -> T) -> T { + debug!("read_vec_elt(idx=%u)", idx); + match *self.peek() { + List(ref list) => { + vec::push(self.stack, &list[idx]); + f() } + _ => fail ~"not a list", } + } - Dict(d0) => { - match value1 { - Num(_) | String(_) | Boolean(_) | List(_) => false, - Dict(d1) => { - unsafe { - let (d0_flat, d1_flat) = { - let d0_flat = dvec::DVec(); - for d0.each |k, v| { d0_flat.push((k, v)); } - let mut d0_flat = dvec::unwrap(move d0_flat); - d0_flat.qsort(); + fn read_box(&self, f: fn() -> T) -> T { + debug!("read_box()"); + f() + } - let mut d1_flat = dvec::DVec(); - for d1.each |k, v| { d1_flat.push((k, v)); } - let mut d1_flat = dvec::unwrap(move d1_flat); - d1_flat.qsort(); + fn read_uniq(&self, f: fn() -> T) -> T { + debug!("read_uniq()"); + f() + } - (move d0_flat, move d1_flat) - }; + fn read_rec(&self, f: fn() -> T) -> T { + debug!("read_rec()"); + let value = f(); + self.pop(); + value + } - d0_flat < d1_flat + fn read_rec_field(&self, f_name: ~str, f_idx: uint, + f: fn() -> T) -> T { + debug!("read_rec_field(%s, idx=%u)", f_name, f_idx); + let top = self.peek(); + match *top { + Object(ref obj) => { + // FIXME(#3148) This hint should not be necessary. + let obj: &self/~Object = obj; + + match obj.find_ref(&f_name) { + None => fail fmt!("no such field: %s", f_name), + Some(json) => { + vec::push(self.stack, json); + f() } } - Null => true } - } + Number(_) => fail ~"num", + String(_) => fail ~"str", + Boolean(_) => fail ~"bool", + List(_) => fail fmt!("list: %?", top), + Null => fail ~"null", - Null => { - match value1 { - Num(_) | String(_) | Boolean(_) | List(_) | Dict(_) => false, - Null => true - } + //_ => fail fmt!("not an object: %?", *top) } } -} -impl Error : Eq { - pure fn eq(other: &Error) -> bool { - self.line == (*other).line && - self.col == (*other).col && - self.msg == (*other).msg + fn read_tup(&self, sz: uint, f: fn() -> T) -> T { + debug!("read_tup(sz=%u)", sz); + let value = f(); + self.pop(); + value + } + + fn read_tup_elt(&self, idx: uint, f: fn() -> T) -> T { + debug!("read_tup_elt(idx=%u)", idx); + match *self.peek() { + List(list) => { + vec::push(self.stack, &list[idx]); + f() + } + _ => fail ~"not a list" + } } - pure fn ne(other: &Error) -> bool { !self.eq(other) } } impl Json : Eq { - pure fn eq(other: &Json) -> bool { eq(self, (*other)) } + pure fn eq(other: &Json) -> bool { + // XXX: This is ugly because matching on references is broken, and + // we can't match on dereferenced tuples without a copy. + match self { + Number(f0) => + match *other { Number(f1) => f0 == f1, _ => false }, + String(s0) => + match *other { String(s1) => s0 == s1, _ => false }, + Boolean(b0) => + match *other { Boolean(b1) => b0 == b1, _ => false }, + Null => + match *other { Null => true, _ => false }, + List(v0) => + match *other { List(v1) => v0 == v1, _ => false }, + Object(ref d0) => { + match *other { + Object(ref d1) => { + if d0.len() == d1.len() { + let mut equal = true; + for d0.each |k, v0| { + match d1.find_ref(k) { + Some(v1) if v0 == v1 => { }, + _ => { equal = false; break } + } + }; + equal + } else { + false + } + } + _ => false + } + } + } + } pure fn ne(other: &Json) -> bool { !self.eq(other) } } +/// Test if two json values are less than one another impl Json : Ord { - pure fn lt(other: &Json) -> bool { lt(self, (*other)) } + pure fn lt(other: &Json) -> bool { + match self { + Number(f0) => { + match *other { + Number(f1) => f0 < f1, + String(_) | Boolean(_) | List(_) | Object(_) | + Null => true + } + } + + String(s0) => { + match *other { + Number(_) => false, + String(s1) => s0 < s1, + Boolean(_) | List(_) | Object(_) | Null => true + } + } + + Boolean(b0) => { + match *other { + Number(_) | String(_) => false, + Boolean(b1) => b0 < b1, + List(_) | Object(_) | Null => true + } + } + + List(l0) => { + match *other { + Number(_) | String(_) | Boolean(_) => false, + List(l1) => l0 < l1, + Object(_) | Null => true + } + } + + Object(d0) => { + match *other { + Number(_) | String(_) | Boolean(_) | List(_) => false, + Object(d1) => { + unsafe { + let mut d0_flat = ~[]; + let mut d1_flat = ~[]; + + // XXX: this is horribly inefficient... + for d0.each |k, v| { + vec::push(d0_flat, (@copy *k, @copy *v)); + } + d0_flat.qsort(); + + for d1.each |k, v| { + vec::push(d1_flat, (@copy *k, @copy *v)); + } + d1_flat.qsort(); + + d0_flat < d1_flat + } + } + Null => true + } + } + + Null => { + match *other { + Number(_) | String(_) | Boolean(_) | List(_) | + Object(_) => + false, + Null => true + } + } + } + } pure fn le(other: &Json) -> bool { !(*other).lt(&self) } - pure fn ge(other: &Json) -> bool { !self.lt(other) } + pure fn ge(other: &Json) -> bool { !self.lt(other) } pure fn gt(other: &Json) -> bool { (*other).lt(&self) } } +impl Error : Eq { + pure fn eq(other: &Error) -> bool { + self.line == other.line && + self.col == other.col && + self.msg == other.msg + } + pure fn ne(other: &Error) -> bool { !self.eq(other) } +} + trait ToJson { fn to_json() -> Json; } impl Json: ToJson { - fn to_json() -> Json { self } + fn to_json() -> Json { copy self } } impl @Json: ToJson { - fn to_json() -> Json { *self } + fn to_json() -> Json { (*self).to_json() } } impl int: ToJson { - fn to_json() -> Json { Num(self as float) } + fn to_json() -> Json { Number(self as float) } } impl i8: ToJson { - fn to_json() -> Json { Num(self as float) } + fn to_json() -> Json { Number(self as float) } } impl i16: ToJson { - fn to_json() -> Json { Num(self as float) } + fn to_json() -> Json { Number(self as float) } } impl i32: ToJson { - fn to_json() -> Json { Num(self as float) } + fn to_json() -> Json { Number(self as float) } } impl i64: ToJson { - fn to_json() -> Json { Num(self as float) } + fn to_json() -> Json { Number(self as float) } } impl uint: ToJson { - fn to_json() -> Json { Num(self as float) } + fn to_json() -> Json { Number(self as float) } } impl u8: ToJson { - fn to_json() -> Json { Num(self as float) } + fn to_json() -> Json { Number(self as float) } } impl u16: ToJson { - fn to_json() -> Json { Num(self as float) } + fn to_json() -> Json { Number(self as float) } } impl u32: ToJson { - fn to_json() -> Json { Num(self as float) } + fn to_json() -> Json { Number(self as float) } } impl u64: ToJson { - fn to_json() -> Json { Num(self as float) } + fn to_json() -> Json { Number(self as float) } } impl float: ToJson { - fn to_json() -> Json { Num(self) } + fn to_json() -> Json { Number(self) } } impl f32: ToJson { - fn to_json() -> Json { Num(self as float) } + fn to_json() -> Json { Number(self as float) } } impl f64: ToJson { - fn to_json() -> Json { Num(self as float) } + fn to_json() -> Json { Number(self as float) } } impl (): ToJson { @@ -768,47 +1047,58 @@ impl bool: ToJson { } impl ~str: ToJson { - fn to_json() -> Json { String(@copy self) } + fn to_json() -> Json { String(copy self) } } impl @~str: ToJson { - fn to_json() -> Json { String(self) } + fn to_json() -> Json { String(copy *self) } } impl (A, B): ToJson { fn to_json() -> Json { match self { (a, b) => { - List(@~[a.to_json(), b.to_json()]) + List(~[a.to_json(), b.to_json()]) } } } } impl (A, B, C): ToJson { - fn to_json() -> Json { match self { (a, b, c) => { - List(@~[a.to_json(), b.to_json(), c.to_json()]) + List(~[a.to_json(), b.to_json(), c.to_json()]) } } } } impl ~[A]: ToJson { - fn to_json() -> Json { List(@self.map(|elt| elt.to_json())) } + fn to_json() -> Json { List(self.map(|elt| elt.to_json())) } } -impl HashMap<~str, A>: ToJson { +impl linear::LinearMap<~str, A>: ToJson { fn to_json() -> Json { - let d = map::HashMap(); + let mut d = linear::LinearMap(); for self.each() |key, value| { - d.insert(copy key, value.to_json()); + d.insert(copy *key, value.to_json()); + } + Object(~d) + } +} + +/* +impl @std::map::HashMap<~str, A>: ToJson { + fn to_json() -> Json { + let mut d = linear::LinearMap(); + for self.each_ref |key, value| { + d.insert(copy *key, value.to_json()); } - Dict(d) + Object(~d) } } +*/ impl Option: ToJson { fn to_json() -> Json { @@ -820,7 +1110,7 @@ impl Option: ToJson { } impl Json: to_str::ToStr { - fn to_str() -> ~str { to_str(self) } + fn to_str() -> ~str { to_str(&self) } } impl Error: to_str::ToStr { @@ -831,105 +1121,104 @@ impl Error: to_str::ToStr { #[cfg(test)] mod tests { - #[legacy_exports]; - fn mk_dict(items: &[(~str, Json)]) -> Json { - let d = map::HashMap(); + fn mk_object(items: &[(~str, Json)]) -> Json { + let mut d = ~linear::LinearMap(); - for vec::each(items) |item| { - let (key, value) = copy *item; - d.insert(key, value); + for items.each |item| { + match *item { + (key, value) => { d.insert(copy key, copy value); }, + } }; - Dict(d) + Object(d) } #[test] fn test_write_null() { - assert to_str(Null) == ~"null"; + assert to_str(&Null) == ~"null"; } #[test] - fn test_write_num() { - assert to_str(Num(3f)) == ~"3"; - assert to_str(Num(3.1f)) == ~"3.1"; - assert to_str(Num(-1.5f)) == ~"-1.5"; - assert to_str(Num(0.5f)) == ~"0.5"; + fn test_write_number() { + assert to_str(&Number(3f)) == ~"3"; + assert to_str(&Number(3.1f)) == ~"3.1"; + assert to_str(&Number(-1.5f)) == ~"-1.5"; + assert to_str(&Number(0.5f)) == ~"0.5"; } #[test] fn test_write_str() { - assert to_str(String(@~"")) == ~"\"\""; - assert to_str(String(@~"foo")) == ~"\"foo\""; + assert to_str(&String(~"")) == ~"\"\""; + assert to_str(&String(~"foo")) == ~"\"foo\""; } #[test] fn test_write_bool() { - assert to_str(Boolean(true)) == ~"true"; - assert to_str(Boolean(false)) == ~"false"; + assert to_str(&Boolean(true)) == ~"true"; + assert to_str(&Boolean(false)) == ~"false"; } #[test] fn test_write_list() { - assert to_str(List(@~[])) == ~"[]"; - assert to_str(List(@~[Boolean(true)])) == ~"[true]"; - assert to_str(List(@~[ + assert to_str(&List(~[])) == ~"[]"; + assert to_str(&List(~[Boolean(true)])) == ~"[true]"; + assert to_str(&List(~[ Boolean(false), Null, - List(@~[String(@~"foo\nbar"), Num(3.5f)]) - ])) == ~"[false, null, [\"foo\\nbar\", 3.5]]"; + List(~[String(~"foo\nbar"), Number(3.5f)]) + ])) == ~"[false,null,[\"foo\\nbar\",3.5]]"; } #[test] - fn test_write_dict() { - assert to_str(mk_dict(~[])) == ~"{}"; - assert to_str(mk_dict(~[(~"a", Boolean(true))])) - == ~"{ \"a\": true }"; - let a = mk_dict(~[ + fn test_write_object() { + assert to_str(&mk_object(~[])) == ~"{}"; + assert to_str(&mk_object(~[(~"a", Boolean(true))])) + == ~"{\"a\":true}"; + let a = mk_object(~[ (~"a", Boolean(true)), - (~"b", List(@~[ - mk_dict(~[(~"c", String(@~"\x0c\r"))]), - mk_dict(~[(~"d", String(@~""))]) + (~"b", List(~[ + mk_object(~[(~"c", String(~"\x0c\r"))]), + mk_object(~[(~"d", String(~""))]) ])) ]); - let astr = to_str(a); - let b = result::get(&from_str(astr)); - let bstr = to_str(b); - assert astr == bstr; + // We can't compare the strings directly because the object fields be + // printed in a different order. + let b = result::unwrap(from_str(to_str(&a))); assert a == b; } #[test] fn test_trailing_characters() { assert from_str(~"nulla") == - Err({line: 1u, col: 5u, msg: @~"trailing characters"}); + Err(Error {line: 1u, col: 5u, msg: @~"trailing characters"}); assert from_str(~"truea") == - Err({line: 1u, col: 5u, msg: @~"trailing characters"}); + Err(Error {line: 1u, col: 5u, msg: @~"trailing characters"}); assert from_str(~"falsea") == - Err({line: 1u, col: 6u, msg: @~"trailing characters"}); + Err(Error {line: 1u, col: 6u, msg: @~"trailing characters"}); assert from_str(~"1a") == - Err({line: 1u, col: 2u, msg: @~"trailing characters"}); + Err(Error {line: 1u, col: 2u, msg: @~"trailing characters"}); assert from_str(~"[]a") == - Err({line: 1u, col: 3u, msg: @~"trailing characters"}); + Err(Error {line: 1u, col: 3u, msg: @~"trailing characters"}); assert from_str(~"{}a") == - Err({line: 1u, col: 3u, msg: @~"trailing characters"}); + Err(Error {line: 1u, col: 3u, msg: @~"trailing characters"}); } #[test] fn test_read_identifiers() { assert from_str(~"n") == - Err({line: 1u, col: 2u, msg: @~"invalid syntax"}); + Err(Error {line: 1u, col: 2u, msg: @~"invalid syntax"}); assert from_str(~"nul") == - Err({line: 1u, col: 4u, msg: @~"invalid syntax"}); + Err(Error {line: 1u, col: 4u, msg: @~"invalid syntax"}); assert from_str(~"t") == - Err({line: 1u, col: 2u, msg: @~"invalid syntax"}); + Err(Error {line: 1u, col: 2u, msg: @~"invalid syntax"}); assert from_str(~"truz") == - Err({line: 1u, col: 4u, msg: @~"invalid syntax"}); + Err(Error {line: 1u, col: 4u, msg: @~"invalid syntax"}); assert from_str(~"f") == - Err({line: 1u, col: 2u, msg: @~"invalid syntax"}); + Err(Error {line: 1u, col: 2u, msg: @~"invalid syntax"}); assert from_str(~"faz") == - Err({line: 1u, col: 3u, msg: @~"invalid syntax"}); + Err(Error {line: 1u, col: 3u, msg: @~"invalid syntax"}); assert from_str(~"null") == Ok(Null); assert from_str(~"true") == Ok(Boolean(true)); @@ -940,125 +1229,125 @@ mod tests { } #[test] - fn test_read_num() { + fn test_read_number() { assert from_str(~"+") == - Err({line: 1u, col: 1u, msg: @~"invalid syntax"}); + Err(Error {line: 1u, col: 1u, msg: @~"invalid syntax"}); assert from_str(~".") == - Err({line: 1u, col: 1u, msg: @~"invalid syntax"}); + Err(Error {line: 1u, col: 1u, msg: @~"invalid syntax"}); assert from_str(~"-") == - Err({line: 1u, col: 2u, msg: @~"invalid number"}); + Err(Error {line: 1u, col: 2u, msg: @~"invalid number"}); assert from_str(~"00") == - Err({line: 1u, col: 2u, msg: @~"invalid number"}); + Err(Error {line: 1u, col: 2u, msg: @~"invalid number"}); assert from_str(~"1.") == - Err({line: 1u, col: 3u, msg: @~"invalid number"}); + Err(Error {line: 1u, col: 3u, msg: @~"invalid number"}); assert from_str(~"1e") == - Err({line: 1u, col: 3u, msg: @~"invalid number"}); + Err(Error {line: 1u, col: 3u, msg: @~"invalid number"}); assert from_str(~"1e+") == - Err({line: 1u, col: 4u, msg: @~"invalid number"}); - - assert from_str(~"3") == Ok(Num(3f)); - assert from_str(~"3.1") == Ok(Num(3.1f)); - assert from_str(~"-1.2") == Ok(Num(-1.2f)); - assert from_str(~"0.4") == Ok(Num(0.4f)); - assert from_str(~"0.4e5") == Ok(Num(0.4e5f)); - assert from_str(~"0.4e+15") == Ok(Num(0.4e15f)); - assert from_str(~"0.4e-01") == Ok(Num(0.4e-01f)); - assert from_str(~" 3 ") == Ok(Num(3f)); + Err(Error {line: 1u, col: 4u, msg: @~"invalid number"}); + + assert from_str(~"3") == Ok(Number(3f)); + assert from_str(~"3.1") == Ok(Number(3.1f)); + assert from_str(~"-1.2") == Ok(Number(-1.2f)); + assert from_str(~"0.4") == Ok(Number(0.4f)); + assert from_str(~"0.4e5") == Ok(Number(0.4e5f)); + assert from_str(~"0.4e+15") == Ok(Number(0.4e15f)); + assert from_str(~"0.4e-01") == Ok(Number(0.4e-01f)); + assert from_str(~" 3 ") == Ok(Number(3f)); } #[test] fn test_read_str() { assert from_str(~"\"") == - Err({line: 1u, col: 2u, msg: @~"EOF while parsing string"}); + Err(Error {line: 1u, col: 2u, msg: @~"EOF while parsing string"}); assert from_str(~"\"lol") == - Err({line: 1u, col: 5u, msg: @~"EOF while parsing string"}); - - assert from_str(~"\"\"") == Ok(String(@~"")); - assert from_str(~"\"foo\"") == Ok(String(@~"foo")); - assert from_str(~"\"\\\"\"") == Ok(String(@~"\"")); - assert from_str(~"\"\\b\"") == Ok(String(@~"\x08")); - assert from_str(~"\"\\n\"") == Ok(String(@~"\n")); - assert from_str(~"\"\\r\"") == Ok(String(@~"\r")); - assert from_str(~"\"\\t\"") == Ok(String(@~"\t")); - assert from_str(~" \"foo\" ") == Ok(String(@~"foo")); + Err(Error {line: 1u, col: 5u, msg: @~"EOF while parsing string"}); + + assert from_str(~"\"\"") == Ok(String(~"")); + assert from_str(~"\"foo\"") == Ok(String(~"foo")); + assert from_str(~"\"\\\"\"") == Ok(String(~"\"")); + assert from_str(~"\"\\b\"") == Ok(String(~"\x08")); + assert from_str(~"\"\\n\"") == Ok(String(~"\n")); + assert from_str(~"\"\\r\"") == Ok(String(~"\r")); + assert from_str(~"\"\\t\"") == Ok(String(~"\t")); + assert from_str(~" \"foo\" ") == Ok(String(~"foo")); } #[test] fn test_unicode_hex_escapes_in_str() { - assert from_str(~"\"\\u12ab\"") == Ok(String(@~"\u12ab")); - assert from_str(~"\"\\uAB12\"") == Ok(String(@~"\uAB12")); + assert from_str(~"\"\\u12ab\"") == Ok(String(~"\u12ab")); + assert from_str(~"\"\\uAB12\"") == Ok(String(~"\uAB12")); } #[test] fn test_read_list() { assert from_str(~"[") == - Err({line: 1u, col: 2u, msg: @~"EOF while parsing value"}); + Err(Error {line: 1u, col: 2u, msg: @~"EOF while parsing value"}); assert from_str(~"[1") == - Err({line: 1u, col: 3u, msg: @~"EOF while parsing list"}); + Err(Error {line: 1u, col: 3u, msg: @~"EOF while parsing list"}); assert from_str(~"[1,") == - Err({line: 1u, col: 4u, msg: @~"EOF while parsing value"}); + Err(Error {line: 1u, col: 4u, msg: @~"EOF while parsing value"}); assert from_str(~"[1,]") == - Err({line: 1u, col: 4u, msg: @~"invalid syntax"}); + Err(Error {line: 1u, col: 4u, msg: @~"invalid syntax"}); assert from_str(~"[6 7]") == - Err({line: 1u, col: 4u, msg: @~"expected `,` or `]`"}); - - assert from_str(~"[]") == Ok(List(@~[])); - assert from_str(~"[ ]") == Ok(List(@~[])); - assert from_str(~"[true]") == Ok(List(@~[Boolean(true)])); - assert from_str(~"[ false ]") == Ok(List(@~[Boolean(false)])); - assert from_str(~"[null]") == Ok(List(@~[Null])); - assert from_str(~"[3, 1]") == Ok(List(@~[Num(3f), Num(1f)])); - assert from_str(~"\n[3, 2]\n") == Ok(List(@~[Num(3f), Num(2f)])); + Err(Error {line: 1u, col: 4u, msg: @~"expected `,` or `]`"}); + + assert from_str(~"[]") == Ok(List(~[])); + assert from_str(~"[ ]") == Ok(List(~[])); + assert from_str(~"[true]") == Ok(List(~[Boolean(true)])); + assert from_str(~"[ false ]") == Ok(List(~[Boolean(false)])); + assert from_str(~"[null]") == Ok(List(~[Null])); + assert from_str(~"[3, 1]") == Ok(List(~[Number(3f), Number(1f)])); + assert from_str(~"\n[3, 2]\n") == Ok(List(~[Number(3f), Number(2f)])); assert from_str(~"[2, [4, 1]]") == - Ok(List(@~[Num(2f), List(@~[Num(4f), Num(1f)])])); + Ok(List(~[Number(2f), List(~[Number(4f), Number(1f)])])); } #[test] - fn test_read_dict() { + fn test_read_object() { assert from_str(~"{") == - Err({line: 1u, col: 2u, msg: @~"EOF while parsing object"}); + Err(Error {line: 1u, col: 2u, msg: @~"EOF while parsing object"}); assert from_str(~"{ ") == - Err({line: 1u, col: 3u, msg: @~"EOF while parsing object"}); + Err(Error {line: 1u, col: 3u, msg: @~"EOF while parsing object"}); assert from_str(~"{1") == - Err({line: 1u, col: 2u, msg: @~"key must be a string"}); + Err(Error {line: 1u, col: 2u, msg: @~"key must be a string"}); assert from_str(~"{ \"a\"") == - Err({line: 1u, col: 6u, msg: @~"EOF while parsing object"}); + Err(Error {line: 1u, col: 6u, msg: @~"EOF while parsing object"}); assert from_str(~"{\"a\"") == - Err({line: 1u, col: 5u, msg: @~"EOF while parsing object"}); + Err(Error {line: 1u, col: 5u, msg: @~"EOF while parsing object"}); assert from_str(~"{\"a\" ") == - Err({line: 1u, col: 6u, msg: @~"EOF while parsing object"}); + Err(Error {line: 1u, col: 6u, msg: @~"EOF while parsing object"}); assert from_str(~"{\"a\" 1") == - Err({line: 1u, col: 6u, msg: @~"expected `:`"}); + Err(Error {line: 1u, col: 6u, msg: @~"expected `:`"}); assert from_str(~"{\"a\":") == - Err({line: 1u, col: 6u, msg: @~"EOF while parsing value"}); + Err(Error {line: 1u, col: 6u, msg: @~"EOF while parsing value"}); assert from_str(~"{\"a\":1") == - Err({line: 1u, col: 7u, msg: @~"EOF while parsing object"}); + Err(Error {line: 1u, col: 7u, msg: @~"EOF while parsing object"}); assert from_str(~"{\"a\":1 1") == - Err({line: 1u, col: 8u, msg: @~"expected `,` or `}`"}); + Err(Error {line: 1u, col: 8u, msg: @~"expected `,` or `}`"}); assert from_str(~"{\"a\":1,") == - Err({line: 1u, col: 8u, msg: @~"EOF while parsing object"}); + Err(Error {line: 1u, col: 8u, msg: @~"EOF while parsing object"}); - assert eq(result::get(&from_str(~"{}")), mk_dict(~[])); - assert eq(result::get(&from_str(~"{\"a\": 3}")), - mk_dict(~[(~"a", Num(3.0f))])); + assert result::unwrap(from_str(~"{}")) == mk_object(~[]); + assert result::unwrap(from_str(~"{\"a\": 3}")) == + mk_object(~[(~"a", Number(3.0f))]); - assert eq(result::get(&from_str(~"{ \"a\": null, \"b\" : true }")), - mk_dict(~[ + assert result::unwrap(from_str(~"{ \"a\": null, \"b\" : true }")) == + mk_object(~[ (~"a", Null), - (~"b", Boolean(true))])); - assert eq(result::get(&from_str( - ~"\n{ \"a\": null, \"b\" : true }\n")), - mk_dict(~[ + (~"b", Boolean(true))]); + assert result::unwrap( + from_str(~"\n{ \"a\": null, \"b\" : true }\n")) == + mk_object(~[ (~"a", Null), - (~"b", Boolean(true))])); - assert eq(result::get(&from_str(~"{\"a\" : 1.0 ,\"b\": [ true ]}")), - mk_dict(~[ - (~"a", Num(1.0)), - (~"b", List(@~[Boolean(true)])) - ])); - assert eq(result::get(&from_str( + (~"b", Boolean(true))]); + assert result::unwrap(from_str(~"{\"a\" : 1.0 ,\"b\": [ true ]}")) == + mk_object(~[ + (~"a", Number(1.0)), + (~"b", List(~[Boolean(true)])) + ]); + assert result::unwrap(from_str( ~"{" + ~"\"a\": 1.0, " + ~"\"b\": [" + @@ -1066,22 +1355,22 @@ mod tests { ~"\"foo\\nbar\", " + ~"{ \"c\": {\"d\": null} } " + ~"]" + - ~"}")), - mk_dict(~[ - (~"a", Num(1.0f)), - (~"b", List(@~[ + ~"}")) == + mk_object(~[ + (~"a", Number(1.0f)), + (~"b", List(~[ Boolean(true), - String(@~"foo\nbar"), - mk_dict(~[ - (~"c", mk_dict(~[(~"d", Null)])) + String(~"foo\nbar"), + mk_object(~[ + (~"c", mk_object(~[(~"d", Null)])) ]) ])) - ])); + ]); } #[test] fn test_multiline_errors() { assert from_str(~"{\n \"foo\":\n \"bar\"") == - Err({line: 3u, col: 8u, msg: @~"EOF while parsing object"}); + Err(Error {line: 3u, col: 8u, msg: @~"EOF while parsing object"}); } } diff --git a/src/libstd/prettyprint2.rs b/src/libstd/prettyprint2.rs new file mode 100644 index 0000000000000..c0e76662bcb01 --- /dev/null +++ b/src/libstd/prettyprint2.rs @@ -0,0 +1,142 @@ +#[forbid(deprecated_mode)]; +#[forbid(deprecated_pattern)]; + +use io::Writer; +use io::WriterUtil; +use serialization2; + +struct Serializer { + wr: io::Writer, +} + +fn Serializer(wr: io::Writer) -> Serializer { + Serializer { wr: wr } +} + +impl Serializer: serialization2::Serializer { + fn emit_nil(&self) { + self.wr.write_str(~"()") + } + + fn emit_uint(&self, v: uint) { + self.wr.write_str(fmt!("%?u", v)); + } + + fn emit_u64(&self, v: u64) { + self.wr.write_str(fmt!("%?_u64", v)); + } + + fn emit_u32(&self, v: u32) { + self.wr.write_str(fmt!("%?_u32", v)); + } + + fn emit_u16(&self, v: u16) { + self.wr.write_str(fmt!("%?_u16", v)); + } + + fn emit_u8(&self, v: u8) { + self.wr.write_str(fmt!("%?_u8", v)); + } + + fn emit_int(&self, v: int) { + self.wr.write_str(fmt!("%?", v)); + } + + fn emit_i64(&self, v: i64) { + self.wr.write_str(fmt!("%?_i64", v)); + } + + fn emit_i32(&self, v: i32) { + self.wr.write_str(fmt!("%?_i32", v)); + } + + fn emit_i16(&self, v: i16) { + self.wr.write_str(fmt!("%?_i16", v)); + } + + fn emit_i8(&self, v: i8) { + self.wr.write_str(fmt!("%?_i8", v)); + } + + fn emit_bool(&self, v: bool) { + self.wr.write_str(fmt!("%b", v)); + } + + fn emit_float(&self, v: float) { + self.wr.write_str(fmt!("%?_f", v)); + } + + fn emit_f64(&self, v: f64) { + self.wr.write_str(fmt!("%?_f64", v)); + } + + fn emit_f32(&self, v: f32) { + self.wr.write_str(fmt!("%?_f32", v)); + } + + fn emit_str(&self, v: &str) { + self.wr.write_str(fmt!("%?", v)); + } + + fn emit_enum(&self, _name: &str, f: fn()) { + f(); + } + + fn emit_enum_variant(&self, v_name: &str, _v_id: uint, sz: uint, + f: fn()) { + self.wr.write_str(v_name); + if sz > 0u { self.wr.write_str(~"("); } + f(); + if sz > 0u { self.wr.write_str(~")"); } + } + + fn emit_enum_variant_arg(&self, idx: uint, f: fn()) { + if idx > 0u { self.wr.write_str(~", "); } + f(); + } + + fn emit_vec(&self, _len: uint, f: fn()) { + self.wr.write_str(~"["); + f(); + self.wr.write_str(~"]"); + } + + fn emit_vec_elt(&self, idx: uint, f: fn()) { + if idx > 0u { self.wr.write_str(~", "); } + f(); + } + + fn emit_box(&self, f: fn()) { + self.wr.write_str(~"@"); + f(); + } + + fn emit_uniq(&self, f: fn()) { + self.wr.write_str(~"~"); + f(); + } + + fn emit_rec(&self, f: fn()) { + self.wr.write_str(~"{"); + f(); + self.wr.write_str(~"}"); + } + + fn emit_rec_field(&self, f_name: &str, f_idx: uint, f: fn()) { + if f_idx > 0u { self.wr.write_str(~", "); } + self.wr.write_str(f_name); + self.wr.write_str(~": "); + f(); + } + + fn emit_tup(&self, _sz: uint, f: fn()) { + self.wr.write_str(~"("); + f(); + self.wr.write_str(~")"); + } + + fn emit_tup_elt(&self, idx: uint, f: fn()) { + if idx > 0u { self.wr.write_str(~", "); } + f(); + } +} diff --git a/src/libstd/serialization2.rs b/src/libstd/serialization2.rs new file mode 100644 index 0000000000000..81941627ef64b --- /dev/null +++ b/src/libstd/serialization2.rs @@ -0,0 +1,410 @@ +//! Support code for serialization. + +/* +Core serialization interfaces. +*/ + +#[forbid(deprecated_mode)]; +#[forbid(deprecated_pattern)]; +#[forbid(non_camel_case_types)]; + +pub trait Serializer { + // Primitive types: + fn emit_nil(&self); + fn emit_uint(&self, v: uint); + fn emit_u64(&self, v: u64); + fn emit_u32(&self, v: u32); + fn emit_u16(&self, v: u16); + fn emit_u8(&self, v: u8); + fn emit_int(&self, v: int); + fn emit_i64(&self, v: i64); + fn emit_i32(&self, v: i32); + fn emit_i16(&self, v: i16); + fn emit_i8(&self, v: i8); + fn emit_bool(&self, v: bool); + fn emit_float(&self, v: float); + fn emit_f64(&self, v: f64); + fn emit_f32(&self, v: f32); + fn emit_str(&self, v: &str); + + // Compound types: + fn emit_enum(&self, name: &str, f: fn()); + fn emit_enum_variant(&self, v_name: &str, v_id: uint, sz: uint, f: fn()); + fn emit_enum_variant_arg(&self, idx: uint, f: fn()); + fn emit_vec(&self, len: uint, f: fn()); + fn emit_vec_elt(&self, idx: uint, f: fn()); + fn emit_box(&self, f: fn()); + fn emit_uniq(&self, f: fn()); + fn emit_rec(&self, f: fn()); + fn emit_rec_field(&self, f_name: &str, f_idx: uint, f: fn()); + fn emit_tup(&self, sz: uint, f: fn()); + fn emit_tup_elt(&self, idx: uint, f: fn()); +} + +pub trait Deserializer { + // Primitive types: + fn read_nil(&self) -> (); + fn read_uint(&self) -> uint; + fn read_u64(&self) -> u64; + fn read_u32(&self) -> u32; + fn read_u16(&self) -> u16; + fn read_u8(&self) -> u8; + fn read_int(&self) -> int; + fn read_i64(&self) -> i64; + fn read_i32(&self) -> i32; + fn read_i16(&self) -> i16; + fn read_i8(&self) -> i8; + fn read_bool(&self) -> bool; + fn read_f64(&self) -> f64; + fn read_f32(&self) -> f32; + fn read_float(&self) -> float; + fn read_str(&self) -> ~str; + + // Compound types: + fn read_enum(&self, name: ~str, f: fn() -> T) -> T; + fn read_enum_variant(&self, f: fn(uint) -> T) -> T; + fn read_enum_variant_arg(&self, idx: uint, f: fn() -> T) -> T; + fn read_vec(&self, f: fn(uint) -> T) -> T; + fn read_vec_elt(&self, idx: uint, f: fn() -> T) -> T; + fn read_box(&self, f: fn() -> T) -> T; + fn read_uniq(&self, f: fn() -> T) -> T; + fn read_rec(&self, f: fn() -> T) -> T; + fn read_rec_field(&self, f_name: ~str, f_idx: uint, f: fn() -> T) -> T; + fn read_tup(&self, sz: uint, f: fn() -> T) -> T; + fn read_tup_elt(&self, idx: uint, f: fn() -> T) -> T; +} + +pub trait Serializable { + fn serialize(&self, s: &S); + static fn deserialize(&self, d: &D) -> self; +} + +pub impl uint: Serializable { + fn serialize(&self, s: &S) { s.emit_uint(*self) } + static fn deserialize(&self, d: &D) -> uint { + d.read_uint() + } +} + +pub impl u8: Serializable { + fn serialize(&self, s: &S) { s.emit_u8(*self) } + static fn deserialize(&self, d: &D) -> u8 { + d.read_u8() + } +} + +pub impl u16: Serializable { + fn serialize(&self, s: &S) { s.emit_u16(*self) } + static fn deserialize(&self, d: &D) -> u16 { + d.read_u16() + } +} + +pub impl u32: Serializable { + fn serialize(&self, s: &S) { s.emit_u32(*self) } + static fn deserialize(&self, d: &D) -> u32 { + d.read_u32() + } +} + +pub impl u64: Serializable { + fn serialize(&self, s: &S) { s.emit_u64(*self) } + static fn deserialize(&self, d: &D) -> u64 { + d.read_u64() + } +} + +pub impl int: Serializable { + fn serialize(&self, s: &S) { s.emit_int(*self) } + static fn deserialize(&self, d: &D) -> int { + d.read_int() + } +} + +pub impl i8: Serializable { + fn serialize(&self, s: &S) { s.emit_i8(*self) } + static fn deserialize(&self, d: &D) -> i8 { + d.read_i8() + } +} + +pub impl i16: Serializable { + fn serialize(&self, s: &S) { s.emit_i16(*self) } + static fn deserialize(&self, d: &D) -> i16 { + d.read_i16() + } +} + +pub impl i32: Serializable { + fn serialize(&self, s: &S) { s.emit_i32(*self) } + static fn deserialize(&self, d: &D) -> i32 { + d.read_i32() + } +} + +pub impl i64: Serializable { + fn serialize(&self, s: &S) { s.emit_i64(*self) } + static fn deserialize(&self, d: &D) -> i64 { + d.read_i64() + } +} + +pub impl ~str: Serializable { + fn serialize(&self, s: &S) { s.emit_str(*self) } + static fn deserialize(&self, d: &D) -> ~str { + d.read_str() + } +} + +pub impl float: Serializable { + fn serialize(&self, s: &S) { s.emit_float(*self) } + static fn deserialize(&self, d: &D) -> float { + d.read_float() + } +} + +pub impl f32: Serializable { + fn serialize(&self, s: &S) { s.emit_f32(*self) } + static fn deserialize(&self, d: &D) -> f32 { + d.read_f32() } +} + +pub impl f64: Serializable { + fn serialize(&self, s: &S) { s.emit_f64(*self) } + static fn deserialize(&self, d: &D) -> f64 { + d.read_f64() + } +} + +pub impl bool: Serializable { + fn serialize(&self, s: &S) { s.emit_bool(*self) } + static fn deserialize(&self, d: &D) -> bool { + d.read_bool() + } +} + +pub impl (): Serializable { + fn serialize(&self, s: &S) { s.emit_nil() } + static fn deserialize(&self, d: &D) -> () { + d.read_nil() + } +} + +pub impl @T: Serializable { + fn serialize(&self, s: &S) { + s.emit_box(|| (*self).serialize(s)) + } + + static fn deserialize(&self, d: &D) -> @T { + d.read_box(|| @deserialize(d)) + } +} + +pub impl ~T: Serializable { + fn serialize(&self, s: &S) { + s.emit_uniq(|| (*self).serialize(s)) + } + + static fn deserialize(&self, d: &D) -> ~T { + d.read_uniq(|| ~deserialize(d)) + } +} + +pub impl ~[T]: Serializable { + fn serialize(&self, s: &S) { + do s.emit_vec(self.len()) { + for self.eachi |i, e| { + s.emit_vec_elt(i, || e.serialize(s)) + } + } + } + + static fn deserialize(&self, d: &D) -> ~[T] { + do d.read_vec |len| { + do vec::from_fn(len) |i| { + d.read_vec_elt(i, || deserialize(d)) + } + } + } +} + +pub impl Option: Serializable { + fn serialize(&self, s: &S) { + do s.emit_enum(~"option") { + match *self { + None => do s.emit_enum_variant(~"none", 0u, 0u) { + }, + + Some(v) => do s.emit_enum_variant(~"some", 1u, 1u) { + s.emit_enum_variant_arg(0u, || v.serialize(s)) + } + } + } + } + + static fn deserialize(&self, d: &D) -> Option { + do d.read_enum(~"option") { + do d.read_enum_variant |i| { + match i { + 0 => None, + 1 => Some(d.read_enum_variant_arg(0u, || deserialize(d))), + _ => fail(#fmt("Bad variant for option: %u", i)) + } + } + } + } +} + +pub impl< + T0: Serializable, + T1: Serializable +> (T0, T1): Serializable { + fn serialize(&self, s: &S) { + match *self { + (t0, t1) => { + do s.emit_tup(2) { + s.emit_tup_elt(0, || t0.serialize(s)); + s.emit_tup_elt(1, || t1.serialize(s)); + } + } + } + } + + static fn deserialize(&self, d: &D) -> (T0, T1) { + do d.read_tup(2) { + ( + d.read_tup_elt(0, || deserialize(d)), + d.read_tup_elt(1, || deserialize(d)) + ) + } + } +} + +pub impl< + T0: Serializable, + T1: Serializable, + T2: Serializable +> (T0, T1, T2): Serializable { + fn serialize(&self, s: &S) { + match *self { + (t0, t1, t2) => { + do s.emit_tup(3) { + s.emit_tup_elt(0, || t0.serialize(s)); + s.emit_tup_elt(1, || t1.serialize(s)); + s.emit_tup_elt(2, || t2.serialize(s)); + } + } + } + } + + static fn deserialize(&self, d: &D) -> (T0, T1, T2) { + do d.read_tup(3) { + ( + d.read_tup_elt(0, || deserialize(d)), + d.read_tup_elt(1, || deserialize(d)), + d.read_tup_elt(2, || deserialize(d)) + ) + } + } +} + +pub impl< + T0: Serializable, + T1: Serializable, + T2: Serializable, + T3: Serializable +> (T0, T1, T2, T3): Serializable { + fn serialize(&self, s: &S) { + match *self { + (t0, t1, t2, t3) => { + do s.emit_tup(4) { + s.emit_tup_elt(0, || t0.serialize(s)); + s.emit_tup_elt(1, || t1.serialize(s)); + s.emit_tup_elt(2, || t2.serialize(s)); + s.emit_tup_elt(3, || t3.serialize(s)); + } + } + } + } + + static fn deserialize(&self, d: &D) -> (T0, T1, T2, T3) { + do d.read_tup(4) { + ( + d.read_tup_elt(0, || deserialize(d)), + d.read_tup_elt(1, || deserialize(d)), + d.read_tup_elt(2, || deserialize(d)), + d.read_tup_elt(3, || deserialize(d)) + ) + } + } +} + +pub impl< + T0: Serializable, + T1: Serializable, + T2: Serializable, + T3: Serializable, + T4: Serializable +> (T0, T1, T2, T3, T4): Serializable { + fn serialize(&self, s: &S) { + match *self { + (t0, t1, t2, t3, t4) => { + do s.emit_tup(5) { + s.emit_tup_elt(0, || t0.serialize(s)); + s.emit_tup_elt(1, || t1.serialize(s)); + s.emit_tup_elt(2, || t2.serialize(s)); + s.emit_tup_elt(3, || t3.serialize(s)); + s.emit_tup_elt(4, || t4.serialize(s)); + } + } + } + } + + static fn deserialize(&self, d: &D) + -> (T0, T1, T2, T3, T4) { + do d.read_tup(5) { + ( + d.read_tup_elt(0, || deserialize(d)), + d.read_tup_elt(1, || deserialize(d)), + d.read_tup_elt(2, || deserialize(d)), + d.read_tup_elt(3, || deserialize(d)), + d.read_tup_elt(4, || deserialize(d)) + ) + } + } +} + +// ___________________________________________________________________________ +// Helper routines +// +// In some cases, these should eventually be coded as traits. + +pub trait SerializerHelpers { + fn emit_from_vec(&self, v: ~[T], f: fn(v: &T)); +} + +pub impl S: SerializerHelpers { + fn emit_from_vec(&self, v: ~[T], f: fn(v: &T)) { + do self.emit_vec(v.len()) { + for v.eachi |i, e| { + do self.emit_vec_elt(i) { + f(e) + } + } + } + } +} + +pub trait DeserializerHelpers { + fn read_to_vec(&self, f: fn() -> T) -> ~[T]; +} + +pub impl D: DeserializerHelpers { + fn read_to_vec(&self, f: fn() -> T) -> ~[T] { + do self.read_vec |len| { + do vec::from_fn(len) |i| { + self.read_vec_elt(i, || f()) + } + } + } +} diff --git a/src/libstd/std.rc b/src/libstd/std.rc index 422ff81b9fecc..c3b7c1793ec32 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -34,8 +34,10 @@ export sync, arc, comm; export bitv, deque, fun_treemap, list, map; export smallintmap, sort, treemap; export rope, arena, par; -export ebml, dbg, getopts, json, rand, sha1, term, time, prettyprint; -export test, tempfile, serialization; +export ebml, ebml2; +export dbg, getopts, json, rand, sha1, term, time; +export prettyprint, prettyprint2; +export test, tempfile, serialization, serialization2; export cmp; export base64; export cell; @@ -107,6 +109,8 @@ mod treemap; #[legacy_exports] mod ebml; #[legacy_exports] +mod ebml2; +#[legacy_exports] mod dbg; #[legacy_exports] mod getopts; @@ -125,6 +129,8 @@ mod time; #[legacy_exports] mod prettyprint; #[legacy_exports] +mod prettyprint2; +#[legacy_exports] mod arena; #[legacy_exports] mod par; @@ -144,6 +150,7 @@ mod unicode; mod test; #[legacy_exports] mod serialization; +mod serialization2; // Local Variables: // mode: rust; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 75a2081bc14f6..24dc3660fafc3 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -38,6 +38,10 @@ macro_rules! interner_key ( (-3 as uint, 0u))) ) +// FIXME(#3534): Replace with the struct-based newtype when it's been +// implemented. +struct ident { repr: uint } + fn serialize_ident(s: S, i: ident) { let intr = match unsafe{ task::local_data::local_data_get(interner_key!()) @@ -59,7 +63,16 @@ fn deserialize_ident(d: D) -> ident { (*intr).intern(@d.read_str()) } -type ident = token::str_num; +impl ident: cmp::Eq { + pure fn eq(other: &ident) -> bool { self.repr == other.repr } + pure fn ne(other: &ident) -> bool { !self.eq(other) } +} + +impl ident: to_bytes::IterBytes { + pure fn iter_bytes(lsb0: bool, f: to_bytes::Cb) { + self.repr.iter_bytes(lsb0, f) + } +} // Functions may or may not have names. #[auto_serialize] diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index 9a3e94b737fa5..09922ade073c0 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -34,7 +34,7 @@ impl path_elt : cmp::Eq { type path = ~[path_elt]; /* FIXMEs that say "bad" are as per #2543 */ -fn path_to_str_with_sep(p: path, sep: ~str, itr: ident_interner) -> ~str { +fn path_to_str_with_sep(p: path, sep: ~str, itr: @ident_interner) -> ~str { let strs = do vec::map(p) |e| { match *e { path_mod(s) => *itr.get(s), @@ -44,7 +44,7 @@ fn path_to_str_with_sep(p: path, sep: ~str, itr: ident_interner) -> ~str { str::connect(strs, sep) } -fn path_ident_to_str(p: path, i: ident, itr: ident_interner) -> ~str { +fn path_ident_to_str(p: path, i: ident, itr: @ident_interner) -> ~str { if vec::is_empty(p) { //FIXME /* FIXME (#2543) */ copy *i *itr.get(i) @@ -53,7 +53,7 @@ fn path_ident_to_str(p: path, i: ident, itr: ident_interner) -> ~str { } } -fn path_to_str(p: path, itr: ident_interner) -> ~str { +fn path_to_str(p: path, itr: @ident_interner) -> ~str { path_to_str_with_sep(p, ~"::", itr) } @@ -326,7 +326,7 @@ fn map_stmt(stmt: @stmt, cx: ctx, v: vt) { visit::visit_stmt(stmt, cx, v); } -fn node_id_to_str(map: map, id: node_id, itr: ident_interner) -> ~str { +fn node_id_to_str(map: map, id: node_id, itr: @ident_interner) -> ~str { match map.find(id) { None => { fmt!("unknown node (id=%d)", id) diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index b0df0ea1c8d01..98a471bd54c4a 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -23,7 +23,7 @@ pure fn dummy_sp() -> span { return mk_sp(0u, 0u); } -pure fn path_name_i(idents: ~[ident], intr: token::ident_interner) -> ~str { +pure fn path_name_i(idents: ~[ident], intr: @token::ident_interner) -> ~str { // FIXME: Bad copies (#2543 -- same for everything else that says "bad") str::connect(idents.map(|i| *intr.get(*i)), ~"::") } diff --git a/src/libsyntax/ext/auto_serialize2.rs b/src/libsyntax/ext/auto_serialize2.rs new file mode 100644 index 0000000000000..264711584fcad --- /dev/null +++ b/src/libsyntax/ext/auto_serialize2.rs @@ -0,0 +1,813 @@ +/* + +The compiler code necessary to implement the #[auto_serialize2] +extension. The idea here is that type-defining items may be tagged +with #[auto_serialize2], which will cause us to generate a little +companion module with the same name as the item. + +For example, a type like: + + type node_id = uint; + +would generate two functions like: + + impl node_id: Serializable { + fn serialize(s: S) { + s.emit_uint(self) + } + + static fn deserialize(d: D) -> node_id { + d.read_uint() + } + } + +Other interesting scenarios are whe the item has type parameters or +references other non-built-in types. A type definition like: + + type spanned = {node: T, span: span}; + +would yield functions like: + + impl spanned: Serializable { + fn serialize(s: S) { + do s.emit_rec { + s.emit_rec_field("node", 0, self.node.serialize(s)); + s.emit_rec_field("span", 1, self.span.serialize(s)); + } + } + + static fn deserialize(d: D) -> spanned { + do d.read_rec { + { + node: d.read_rec_field(~"node", 0, || deserialize(d)), + span: d.read_rec_field(~"span", 1, || deserialize(d)), + } + } + } + } + +FIXME (#2810)--Hygiene. Search for "__" strings. We also assume "std" is the +standard library. + +Misc notes: +----------- + +I use move mode arguments for ast nodes that will get inserted as is +into the tree. This is intended to prevent us from inserting the same +node twice. + +*/ + +use base::*; +use codemap::span; +use std::map; +use std::map::HashMap; + +export expand; + +// Transitional reexports so qquote can find the paths it is looking for +mod syntax { + pub use ext; + pub use parse; +} + +fn expand(cx: ext_ctxt, + span: span, + _mitem: ast::meta_item, + in_items: ~[@ast::item]) -> ~[@ast::item] { + fn not_auto_serialize2(a: ast::attribute) -> bool { + attr::get_attr_name(a) != ~"auto_serialize2" + } + + fn filter_attrs(item: @ast::item) -> @ast::item { + @{attrs: vec::filter(item.attrs, not_auto_serialize2), + .. *item} + } + + do vec::flat_map(in_items) |item| { + match item.node { + ast::item_ty(@{node: ast::ty_rec(fields), _}, tps) => { + ~[ + filter_attrs(item), + mk_rec_impl(cx, item.span, item.ident, fields, tps), + ] + }, + ast::item_class(@{ fields, _}, tps) => { + ~[ + filter_attrs(item), + mk_struct_impl(cx, item.span, item.ident, fields, tps), + ] + }, + ast::item_enum(enum_def, tps) => { + ~[ + filter_attrs(item), + mk_enum_impl(cx, item.span, item.ident, enum_def, tps), + ] + }, + _ => { + cx.span_err(span, ~"#[auto_serialize2] can only be applied \ + to structs, record types, and enum \ + definitions"); + ~[item] + } + } + } +} + +priv impl ext_ctxt { + fn expr_path(span: span, strs: ~[ast::ident]) -> @ast::expr { + self.expr(span, ast::expr_path(self.path(span, strs))) + } + + fn expr_var(span: span, var: ~str) -> @ast::expr { + self.expr_path(span, ~[self.ident_of(var)]) + } + + fn expr_field( + span: span, + expr: @ast::expr, + ident: ast::ident + ) -> @ast::expr { + self.expr(span, ast::expr_field(expr, ident, ~[])) + } + + fn expr_call( + span: span, + expr: @ast::expr, + args: ~[@ast::expr] + ) -> @ast::expr { + self.expr(span, ast::expr_call(expr, args, false)) + } + + fn lambda_expr(expr: @ast::expr) -> @ast::expr { + self.lambda(self.expr_blk(expr)) + } + + fn lambda_stmts(span: span, stmts: ~[@ast::stmt]) -> @ast::expr { + self.lambda(self.blk(span, stmts)) + } +} + +fn mk_impl( + cx: ext_ctxt, + span: span, + ident: ast::ident, + tps: ~[ast::ty_param], + ser_body: @ast::expr, + deser_body: @ast::expr +) -> @ast::item { + // Make a path to the std::serialization2::Serializable trait. + let path = cx.path( + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialization2"), + cx.ident_of(~"Serializable"), + ] + ); + + // All the type parameters need to bound to + // std::serialization::Serializable. + let trait_tps = do tps.map |tp| { + let t_bound = ast::bound_trait(@{ + id: cx.next_id(), + node: ast::ty_path(path, cx.next_id()), + span: span, + }); + + { + ident: tp.ident, + id: cx.next_id(), + bounds: @vec::append(~[t_bound], *tp.bounds) + } + }; + + let opt_trait = Some(@{ + path: path, + ref_id: cx.next_id(), + impl_id: cx.next_id(), + }); + + let ty = cx.ty_path( + span, + ~[ident], + tps.map(|tp| cx.ty_path(span, ~[tp.ident], ~[])) + ); + + let methods = ~[ + mk_ser_method(cx, span, cx.expr_blk(ser_body)), + mk_deser_method(cx, span, ty, cx.expr_blk(deser_body)), + ]; + + @{ + // This is a new-style impl declaration. + // XXX: clownshoes + ident: ast::token::special_idents::clownshoes_extensions, + attrs: ~[], + id: cx.next_id(), + node: ast::item_impl(trait_tps, opt_trait, ty, methods), + vis: ast::public, + span: span, + } +} + +fn mk_ser_method( + cx: ext_ctxt, + span: span, + ser_body: ast::blk +) -> @ast::method { + let ser_bound = cx.ty_path( + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialization2"), + cx.ident_of(~"Serializer"), + ], + ~[] + ); + + let ser_tps = ~[{ + ident: cx.ident_of(~"__S"), + id: cx.next_id(), + bounds: @~[ast::bound_trait(ser_bound)], + }]; + + let ty_s = @{ + id: cx.next_id(), + node: ast::ty_rptr( + @{ + id: cx.next_id(), + node: ast::re_anon, + }, + { + ty: cx.ty_path(span, ~[cx.ident_of(~"__S")], ~[]), + mutbl: ast::m_imm + } + ), + span: span, + }; + + let ser_inputs = ~[{ + mode: ast::infer(cx.next_id()), + ty: ty_s, + ident: cx.ident_of(~"__s"), + id: cx.next_id(), + }]; + + let ser_output = @{ + id: cx.next_id(), + node: ast::ty_nil, + span: span, + }; + + let ser_decl = { + inputs: ser_inputs, + output: ser_output, + cf: ast::return_val, + }; + + @{ + ident: cx.ident_of(~"serialize"), + attrs: ~[], + tps: ser_tps, + self_ty: { node: ast::sty_region(ast::m_imm), span: span }, + purity: ast::impure_fn, + decl: ser_decl, + body: ser_body, + id: cx.next_id(), + span: span, + self_id: cx.next_id(), + vis: ast::public, + } +} + +fn mk_deser_method( + cx: ext_ctxt, + span: span, + ty: @ast::ty, + deser_body: ast::blk +) -> @ast::method { + let deser_bound = cx.ty_path( + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialization2"), + cx.ident_of(~"Deserializer"), + ], + ~[] + ); + + let deser_tps = ~[{ + ident: cx.ident_of(~"__D"), + id: cx.next_id(), + bounds: @~[ast::bound_trait(deser_bound)], + }]; + + let ty_d = @{ + id: cx.next_id(), + node: ast::ty_rptr( + @{ + id: cx.next_id(), + node: ast::re_anon, + }, + { + ty: cx.ty_path(span, ~[cx.ident_of(~"__D")], ~[]), + mutbl: ast::m_imm + } + ), + span: span, + }; + + let deser_inputs = ~[{ + mode: ast::infer(cx.next_id()), + ty: ty_d, + ident: cx.ident_of(~"__d"), + id: cx.next_id(), + }]; + + let deser_decl = { + inputs: deser_inputs, + output: ty, + cf: ast::return_val, + }; + + @{ + ident: cx.ident_of(~"deserialize"), + attrs: ~[], + tps: deser_tps, + self_ty: { node: ast::sty_static, span: span }, + purity: ast::impure_fn, + decl: deser_decl, + body: deser_body, + id: cx.next_id(), + span: span, + self_id: cx.next_id(), + vis: ast::public, + } +} + +fn mk_rec_impl( + cx: ext_ctxt, + span: span, + ident: ast::ident, + fields: ~[ast::ty_field], + tps: ~[ast::ty_param] +) -> @ast::item { + // Records and structs don't have the same fields types, but they share + // enough that if we extract the right subfields out we can share the + // serialization generator code. + let fields = do fields.map |field| { + { + span: field.span, + ident: field.node.ident, + mutbl: field.node.mt.mutbl, + } + }; + + let ser_body = mk_ser_fields(cx, span, fields); + let deser_body = do mk_deser_fields(cx, span, fields) |fields| { + cx.expr(span, ast::expr_rec(fields, None)) + }; + + mk_impl(cx, span, ident, tps, ser_body, deser_body) +} + +fn mk_struct_impl( + cx: ext_ctxt, + span: span, + ident: ast::ident, + fields: ~[@ast::struct_field], + tps: ~[ast::ty_param] +) -> @ast::item { + // Records and structs don't have the same fields types, but they share + // enough that if we extract the right subfields out we can share the + // serialization generator code. + let fields = do fields.map |field| { + let (ident, mutbl) = match field.node.kind { + ast::named_field(ident, mutbl, _) => (ident, mutbl), + _ => fail ~"[auto_serialize2] does not support \ + unnamed fields", + }; + + { + span: field.span, + ident: ident, + mutbl: match mutbl { + ast::class_mutable => ast::m_mutbl, + ast::class_immutable => ast::m_imm, + }, + } + }; + + let ser_body = mk_ser_fields(cx, span, fields); + let deser_body = do mk_deser_fields(cx, span, fields) |fields| { + cx.expr(span, ast::expr_struct(cx.path(span, ~[ident]), fields, None)) + }; + + mk_impl(cx, span, ident, tps, ser_body, deser_body) +} + +fn mk_ser_fields( + cx: ext_ctxt, + span: span, + fields: ~[{ span: span, ident: ast::ident, mutbl: ast::mutability }] +) -> @ast::expr { + let stmts = do fields.mapi |idx, field| { + // ast for `|| self.$(name).serialize(__s)` + let expr_lambda = cx.lambda_expr( + cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"self"), + field.ident + ), + cx.ident_of(~"serialize") + ), + ~[cx.expr_var(span, ~"__s")] + ) + ); + + // ast for `__s.emit_rec_field($(name), $(idx), $(expr_lambda))` + cx.stmt( + cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__s"), + cx.ident_of(~"emit_rec_field") + ), + ~[ + cx.lit_str(span, @cx.str_of(field.ident)), + cx.lit_uint(span, idx), + expr_lambda, + ] + ) + ) + }; + + // ast for `__s.emit_rec(|| $(stmts))` + cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__s"), + cx.ident_of(~"emit_rec") + ), + ~[cx.lambda_stmts(span, stmts)] + ) +} + +fn mk_deser_fields( + cx: ext_ctxt, + span: span, + fields: ~[{ span: span, ident: ast::ident, mutbl: ast::mutability }], + f: fn(~[ast::field]) -> @ast::expr +) -> @ast::expr { + let fields = do fields.mapi |idx, field| { + // ast for `|| std::serialization2::deserialize(__d)` + let expr_lambda = cx.lambda( + cx.expr_blk( + cx.expr_call( + span, + cx.expr_path(span, ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialization2"), + cx.ident_of(~"deserialize"), + ]), + ~[cx.expr_var(span, ~"__d")] + ) + ) + ); + + // ast for `__d.read_rec_field($(name), $(idx), $(expr_lambda))` + let expr: @ast::expr = cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__d"), + cx.ident_of(~"read_rec_field") + ), + ~[ + cx.lit_str(span, @cx.str_of(field.ident)), + cx.lit_uint(span, idx), + expr_lambda, + ] + ); + + { + node: { mutbl: field.mutbl, ident: field.ident, expr: expr }, + span: span, + } + }; + + // ast for `__d.read_rec(|| $(fields_expr))` + cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__d"), + cx.ident_of(~"read_rec") + ), + ~[cx.lambda_expr(f(fields))] + ) +} + +fn mk_enum_impl( + cx: ext_ctxt, + span: span, + ident: ast::ident, + enum_def: ast::enum_def, + tps: ~[ast::ty_param] +) -> @ast::item { + let ser_body = mk_enum_ser_body( + cx, + span, + ident, + enum_def.variants + ); + + let deser_body = mk_enum_deser_body( + cx, + span, + ident, + enum_def.variants + ); + + mk_impl(cx, span, ident, tps, ser_body, deser_body) +} + +fn ser_variant( + cx: ext_ctxt, + span: span, + v_name: ast::ident, + v_idx: uint, + args: ~[ast::variant_arg] +) -> ast::arm { + // Name the variant arguments. + let names = args.mapi(|i, _arg| cx.ident_of(fmt!("__v%u", i))); + + // Bind the names to the variant argument type. + let pats = args.mapi(|i, arg| cx.binder_pat(arg.ty.span, names[i])); + + let pat_node = if pats.is_empty() { + ast::pat_ident( + ast::bind_by_implicit_ref, + cx.path(span, ~[v_name]), + None + ) + } else { + ast::pat_enum( + cx.path(span, ~[v_name]), + Some(pats) + ) + }; + + let pat = @{ + id: cx.next_id(), + node: pat_node, + span: span, + }; + + let stmts = do args.mapi |a_idx, _arg| { + // ast for `__s.emit_enum_variant_arg` + let expr_emit = cx.expr_field( + span, + cx.expr_var(span, ~"__s"), + cx.ident_of(~"emit_enum_variant_arg") + ); + + // ast for `|| $(v).serialize(__s)` + let expr_serialize = cx.lambda_expr( + cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_path(span, ~[names[a_idx]]), + cx.ident_of(~"serialize") + ), + ~[cx.expr_var(span, ~"__s")] + ) + ); + + // ast for `$(expr_emit)($(a_idx), $(expr_serialize))` + cx.stmt( + cx.expr_call( + span, + expr_emit, + ~[cx.lit_uint(span, a_idx), expr_serialize] + ) + ) + }; + + // ast for `__s.emit_enum_variant($(name), $(idx), $(sz), $(lambda))` + let body = cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__s"), + cx.ident_of(~"emit_enum_variant") + ), + ~[ + cx.lit_str(span, @cx.str_of(v_name)), + cx.lit_uint(span, v_idx), + cx.lit_uint(span, stmts.len()), + cx.lambda_stmts(span, stmts), + ] + ); + + { pats: ~[pat], guard: None, body: cx.expr_blk(body) } +} + +fn mk_enum_ser_body( + cx: ext_ctxt, + span: span, + name: ast::ident, + variants: ~[ast::variant] +) -> @ast::expr { + let arms = do variants.mapi |v_idx, variant| { + match variant.node.kind { + ast::tuple_variant_kind(args) => + ser_variant(cx, span, variant.node.name, v_idx, args), + ast::struct_variant_kind(*) => + fail ~"struct variants unimplemented", + ast::enum_variant_kind(*) => + fail ~"enum variants unimplemented", + } + }; + + // ast for `match *self { $(arms) }` + let match_expr = cx.expr( + span, + ast::expr_match( + cx.expr( + span, + ast::expr_unary(ast::deref, cx.expr_var(span, ~"self")) + ), + arms + ) + ); + + // ast for `__s.emit_enum($(name), || $(match_expr))` + cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__s"), + cx.ident_of(~"emit_enum") + ), + ~[ + cx.lit_str(span, @cx.str_of(name)), + cx.lambda_expr(match_expr), + ] + ) +} + +fn mk_enum_deser_variant_nary( + cx: ext_ctxt, + span: span, + name: ast::ident, + args: ~[ast::variant_arg] +) -> @ast::expr { + let args = do args.mapi |idx, _arg| { + // ast for `|| std::serialization2::deserialize(__d)` + let expr_lambda = cx.lambda_expr( + cx.expr_call( + span, + cx.expr_path(span, ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialization2"), + cx.ident_of(~"deserialize"), + ]), + ~[cx.expr_var(span, ~"__d")] + ) + ); + + // ast for `__d.read_enum_variant_arg($(a_idx), $(expr_lambda))` + cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__d"), + cx.ident_of(~"read_enum_variant_arg") + ), + ~[cx.lit_uint(span, idx), expr_lambda] + ) + }; + + // ast for `$(name)($(args))` + cx.expr_call(span, cx.expr_path(span, ~[name]), args) +} + +fn mk_enum_deser_body( + cx: ext_ctxt, + span: span, + name: ast::ident, + variants: ~[ast::variant] +) -> @ast::expr { + let mut arms = do variants.mapi |v_idx, variant| { + let body = match variant.node.kind { + ast::tuple_variant_kind(args) => { + if args.is_empty() { + // for a nullary variant v, do "v" + cx.expr_path(span, ~[variant.node.name]) + } else { + // for an n-ary variant v, do "v(a_1, ..., a_n)" + mk_enum_deser_variant_nary( + cx, + span, + variant.node.name, + args + ) + } + }, + ast::struct_variant_kind(*) => + fail ~"struct variants unimplemented", + ast::enum_variant_kind(*) => + fail ~"enum variants unimplemented", + }; + + let pat = @{ + id: cx.next_id(), + node: ast::pat_lit(cx.lit_uint(span, v_idx)), + span: span, + }; + + { + pats: ~[pat], + guard: None, + body: cx.expr_blk(body), + } + }; + + let impossible_case = { + pats: ~[@{ id: cx.next_id(), node: ast::pat_wild, span: span}], + guard: None, + + // FIXME(#3198): proper error message + body: cx.expr_blk(cx.expr(span, ast::expr_fail(None))), + }; + + vec::push(arms, impossible_case); + + // ast for `|i| { match i { $(arms) } }` + let expr_lambda = cx.expr( + span, + ast::expr_fn_block( + { + inputs: ~[{ + mode: ast::infer(cx.next_id()), + ty: @{ + id: cx.next_id(), + node: ast::ty_infer, + span: span + }, + ident: cx.ident_of(~"i"), + id: cx.next_id(), + }], + output: @{ + id: cx.next_id(), + node: ast::ty_infer, + span: span, + }, + cf: ast::return_val, + }, + cx.expr_blk( + cx.expr( + span, + ast::expr_match(cx.expr_var(span, ~"i"), arms) + ) + ), + @~[] + ) + ); + + // ast for `__d.read_enum_variant($(expr_lambda))` + let expr_lambda = cx.lambda_expr( + cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__d"), + cx.ident_of(~"read_enum_variant") + ), + ~[expr_lambda] + ) + ); + + // ast for `__d.read_enum($(e_name), $(expr_lambda))` + cx.expr_call( + span, + cx.expr_field( + span, + cx.expr_var(span, ~"__d"), + cx.ident_of(~"read_enum") + ), + ~[ + cx.lit_str(span, @cx.str_of(name)), + expr_lambda + ] + ) +} diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index a3ab35d77f0e8..1cbcd0f6ddb9b 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -73,7 +73,7 @@ fn syntax_expander_table() -> HashMap<~str, syntax_extension> { fn builtin_item_tt(f: syntax_expander_tt_item_) -> syntax_extension { item_tt({expander: f, span: None}) } - let syntax_expanders = HashMap::<~str,syntax_extension>(); + let syntax_expanders = HashMap(); syntax_expanders.insert(~"macro", macro_defining(ext::simplext::add_new_extension)); syntax_expanders.insert(~"macro_rules", @@ -82,6 +82,8 @@ fn syntax_expander_table() -> HashMap<~str, syntax_extension> { syntax_expanders.insert(~"fmt", builtin(ext::fmt::expand_syntax_ext)); syntax_expanders.insert(~"auto_serialize", item_decorator(ext::auto_serialize::expand)); + syntax_expanders.insert(~"auto_serialize2", + item_decorator(ext::auto_serialize2::expand)); syntax_expanders.insert(~"env", builtin(ext::env::expand_syntax_ext)); syntax_expanders.insert(~"concat_idents", builtin(ext::concat_idents::expand_syntax_ext)); diff --git a/src/libsyntax/ext/simplext.rs b/src/libsyntax/ext/simplext.rs index 3af9cfe852dc9..4729e7da39cc1 100644 --- a/src/libsyntax/ext/simplext.rs +++ b/src/libsyntax/ext/simplext.rs @@ -237,7 +237,7 @@ fn follow_for_trans(cx: ext_ctxt, mmaybe: Option>, /* helper for transcribe_exprs: what vars from `b` occur in `e`? */ fn free_vars(b: bindings, e: @expr, it: fn(ident)) { - let idents: HashMap = HashMap(); + let idents = HashMap(); fn mark_ident(&&i: ident, _fld: ast_fold, b: bindings, idents: HashMap) -> ident { if b.contains_key(i) { idents.insert(i, ()); } diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 74c36dcf1b7f5..a7a459428222b 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -185,7 +185,7 @@ fn nameize(p_s: parse_sess, ms: ~[matcher], res: ~[@named_match]) } } } - let ret_val = HashMap::(); + let ret_val = HashMap(); for ms.each() |m| { n_rec(p_s, *m, res, ret_val) } return ret_val; } diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 7fb910cd4b62d..b208e4f8c6f90 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -25,7 +25,7 @@ type tt_frame = @{ type tt_reader = @{ sp_diag: span_handler, - interner: ident_interner, + interner: @ident_interner, mut cur: tt_frame, /* for MBE-style macro transcription */ interpolations: std::map::HashMap, @@ -39,7 +39,7 @@ type tt_reader = @{ /** This can do Macro-By-Example transcription. On the other hand, if * `src` contains no `tt_seq`s and `tt_nonterminal`s, `interp` can (and * should) be none. */ -fn new_tt_reader(sp_diag: span_handler, itr: ident_interner, +fn new_tt_reader(sp_diag: span_handler, itr: @ident_interner, interp: Option>, src: ~[ast::token_tree]) -> tt_reader { @@ -47,7 +47,7 @@ fn new_tt_reader(sp_diag: span_handler, itr: ident_interner, mut cur: @{readme: src, mut idx: 0u, dotdotdoted: false, sep: None, up: tt_frame_up(option::None)}, interpolations: match interp { /* just a convienience */ - None => std::map::HashMap::(), + None => std::map::HashMap(), Some(x) => x }, mut repeat_idx: ~[], diff --git a/src/libsyntax/parse.rs b/src/libsyntax/parse.rs index 312c78085acfc..751b3ce62b976 100644 --- a/src/libsyntax/parse.rs +++ b/src/libsyntax/parse.rs @@ -25,7 +25,7 @@ type parse_sess = @{ cm: codemap::codemap, mut next_id: node_id, span_diagnostic: span_handler, - interner: ident_interner, + interner: @ident_interner, // these two must be kept up to date mut chpos: uint, mut byte_pos: uint diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index c9b10c7b75471..06fcc1cf9589f 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -13,7 +13,7 @@ trait reader { fn next_token() -> {tok: token::token, sp: span}; fn fatal(~str) -> !; fn span_diag() -> span_handler; - pure fn interner() -> token::ident_interner; + pure fn interner() -> @token::ident_interner; fn peek() -> {tok: token::token, sp: span}; fn dup() -> reader; } @@ -26,7 +26,7 @@ type string_reader = @{ mut curr: char, mut chpos: uint, filemap: codemap::filemap, - interner: token::ident_interner, + interner: @token::ident_interner, /* cached: */ mut peek_tok: token::token, mut peek_span: span @@ -34,7 +34,7 @@ type string_reader = @{ fn new_string_reader(span_diagnostic: span_handler, filemap: codemap::filemap, - itr: token::ident_interner) -> string_reader { + itr: @token::ident_interner) -> string_reader { let r = new_low_level_string_reader(span_diagnostic, filemap, itr); string_advance_token(r); /* fill in peek_* */ return r; @@ -43,7 +43,7 @@ fn new_string_reader(span_diagnostic: span_handler, /* For comments.rs, which hackily pokes into 'pos' and 'curr' */ fn new_low_level_string_reader(span_diagnostic: span_handler, filemap: codemap::filemap, - itr: token::ident_interner) + itr: @token::ident_interner) -> string_reader { let r = @{span_diagnostic: span_diagnostic, src: filemap.src, mut col: 0u, mut pos: 0u, mut curr: -1 as char, @@ -78,7 +78,7 @@ impl string_reader: reader { self.span_diagnostic.span_fatal(copy self.peek_span, m) } fn span_diag() -> span_handler { self.span_diagnostic } - pure fn interner() -> token::ident_interner { self.interner } + pure fn interner() -> @token::ident_interner { self.interner } fn peek() -> {tok: token::token, sp: span} { {tok: self.peek_tok, sp: self.peek_span} } @@ -100,7 +100,7 @@ impl tt_reader: reader { self.sp_diag.span_fatal(copy self.cur_span, m); } fn span_diag() -> span_handler { self.sp_diag } - pure fn interner() -> token::ident_interner { self.interner } + pure fn interner() -> @token::ident_interner { self.interner } fn peek() -> {tok: token::token, sp: span} { { tok: self.cur_tok, sp: self.cur_span } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index bc232f1259e3b..9d970e23f6853 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -237,7 +237,7 @@ struct parser { mut restriction: restriction, mut quote_depth: uint, // not (yet) related to the quasiquoter reader: reader, - interner: interner<@~str>, + interner: @token::ident_interner, keywords: HashMap<~str, ()>, strict_keywords: HashMap<~str, ()>, reserved_keywords: HashMap<~str, ()>, diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 0f9041a2fcdd8..a328ff1bdf645 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -12,9 +12,6 @@ use std::serialization::{Serializer, serialize_bool, deserialize_bool}; -#[auto_serialize] -type str_num = uint; - #[auto_serialize] enum binop { PLUS, @@ -72,17 +69,17 @@ enum token { LIT_INT(i64, ast::int_ty), LIT_UINT(u64, ast::uint_ty), LIT_INT_UNSUFFIXED(i64), - LIT_FLOAT(str_num, ast::float_ty), - LIT_STR(str_num), + LIT_FLOAT(ast::ident, ast::float_ty), + LIT_STR(ast::ident), /* Name components */ - IDENT(str_num, bool), + IDENT(ast::ident, bool), UNDERSCORE, /* For interpolation */ INTERPOLATED(nonterminal), - DOC_COMMENT(str_num), + DOC_COMMENT(ast::ident), EOF, } @@ -95,7 +92,7 @@ enum nonterminal { nt_pat( @ast::pat), nt_expr(@ast::expr), nt_ty( @ast::ty), - nt_ident(str_num, bool), + nt_ident(ast::ident, bool), nt_path(@ast::path), nt_tt( @ast::token_tree), //needs @ed to break a circularity nt_matchers(~[ast::matcher]) @@ -116,7 +113,7 @@ fn binop_to_str(o: binop) -> ~str { } } -fn to_str(in: interner<@~str>, t: token) -> ~str { +fn to_str(in: @ident_interner, t: token) -> ~str { match t { EQ => ~"=", LT => ~"<", @@ -174,7 +171,7 @@ fn to_str(in: interner<@~str>, t: token) -> ~str { } body + ast_util::float_ty_to_str(t) } - LIT_STR(s) => { ~"\"" + str::escape_default( *in.get(s)) + ~"\"" } + LIT_STR(s) => { ~"\"" + str::escape_default(*in.get(s)) + ~"\"" } /* Name components */ IDENT(s, _) => *in.get(s), @@ -281,49 +278,66 @@ pure fn is_bar(t: token) -> bool { mod special_idents { #[legacy_exports]; use ast::ident; - const underscore : ident = 0u; - const anon : ident = 1u; - const dtor : ident = 2u; // 'drop', but that's reserved - const invalid : ident = 3u; // '' - const unary : ident = 4u; - const not_fn : ident = 5u; - const idx_fn : ident = 6u; - const unary_minus_fn : ident = 7u; - const clownshoes_extensions : ident = 8u; - - const self_ : ident = 9u; // 'self' + const underscore : ident = ident { repr: 0u }; + const anon : ident = ident { repr: 1u }; + const dtor : ident = ident { repr: 2u }; // 'drop', but that's reserved + const invalid : ident = ident { repr: 3u }; // '' + const unary : ident = ident { repr: 4u }; + const not_fn : ident = ident { repr: 5u }; + const idx_fn : ident = ident { repr: 6u }; + const unary_minus_fn : ident = ident { repr: 7u }; + const clownshoes_extensions : ident = ident { repr: 8u }; + + const self_ : ident = ident { repr: 9u }; // 'self' /* for matcher NTs */ - const item : ident = 10u; - const block : ident = 11u; - const stmt : ident = 12u; - const pat : ident = 13u; - const expr : ident = 14u; - const ty : ident = 15u; - const ident : ident = 16u; - const path : ident = 17u; - const tt : ident = 18u; - const matchers : ident = 19u; - - const str : ident = 20u; // for the type + const item : ident = ident { repr: 10u }; + const block : ident = ident { repr: 11u }; + const stmt : ident = ident { repr: 12u }; + const pat : ident = ident { repr: 13u }; + const expr : ident = ident { repr: 14u }; + const ty : ident = ident { repr: 15u }; + const ident : ident = ident { repr: 16u }; + const path : ident = ident { repr: 17u }; + const tt : ident = ident { repr: 18u }; + const matchers : ident = ident { repr: 19u }; + + const str : ident = ident { repr: 20u }; // for the type /* outside of libsyntax */ - const ty_visitor : ident = 21u; - const arg : ident = 22u; - const descrim : ident = 23u; - const clownshoe_abi : ident = 24u; - const clownshoe_stack_shim : ident = 25u; - const tydesc : ident = 26u; - const literally_dtor : ident = 27u; - const main : ident = 28u; - const opaque : ident = 29u; - const blk : ident = 30u; - const static : ident = 31u; - const intrinsic : ident = 32u; - const clownshoes_foreign_mod: ident = 33; + const ty_visitor : ident = ident { repr: 21u }; + const arg : ident = ident { repr: 22u }; + const descrim : ident = ident { repr: 23u }; + const clownshoe_abi : ident = ident { repr: 24u }; + const clownshoe_stack_shim : ident = ident { repr: 25u }; + const tydesc : ident = ident { repr: 26u }; + const literally_dtor : ident = ident { repr: 27u }; + const main : ident = ident { repr: 28u }; + const opaque : ident = ident { repr: 29u }; + const blk : ident = ident { repr: 30u }; + const static : ident = ident { repr: 31u }; + const intrinsic : ident = ident { repr: 32u }; + const clownshoes_foreign_mod: ident = ident { repr: 33 }; } -type ident_interner = util::interner::interner<@~str>; +struct ident_interner { + priv interner: util::interner::interner<@~str>, +} + +impl ident_interner { + fn intern(val: @~str) -> ast::ident { + ast::ident { repr: self.interner.intern(val) } + } + fn gensym(val: @~str) -> ast::ident { + ast::ident { repr: self.interner.gensym(val) } + } + pure fn get(idx: ast::ident) -> @~str { + self.interner.get(idx.repr) + } + fn len() -> uint { + self.interner.len() + } +} /** Key for thread-local data for sneaking interner information to the * serializer/deserializer. It sounds like a hack because it is one. @@ -335,7 +349,7 @@ macro_rules! interner_key ( (-3 as uint, 0u))) ) -fn mk_ident_interner() -> ident_interner { +fn mk_ident_interner() -> @ident_interner { /* the indices here must correspond to the numbers in special_idents */ let init_vec = ~[@~"_", @~"anon", @~"drop", @~"", @~"unary", @~"!", @~"[]", @~"unary-", @~"__extensions__", @~"self", @@ -346,7 +360,9 @@ fn mk_ident_interner() -> ident_interner { @~"dtor", @~"main", @~"", @~"blk", @~"static", @~"intrinsic", @~"__foreign_mod__"]; - let rv = interner::mk_prefill::<@~str>(init_vec); + let rv = @ident_interner { + interner: interner::mk_prefill::<@~str>(init_vec) + }; /* having multiple interners will just confuse the serializer */ unsafe { @@ -360,8 +376,8 @@ fn mk_ident_interner() -> ident_interner { /* for when we don't care about the contents; doesn't interact with TLD or serialization */ -fn mk_fake_ident_interner() -> ident_interner { - interner::mk::<@~str>() +fn mk_fake_ident_interner() -> @ident_interner { + @ident_interner { interner: interner::mk::<@~str>() } } /** diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 3630ba8c5c6b2..00652346e102d 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -25,7 +25,7 @@ fn no_ann() -> pp_ann { type ps = @{s: pp::printer, cm: Option, - intr: token::ident_interner, + intr: @token::ident_interner, comments: Option<~[comments::cmnt]>, literals: Option<~[comments::lit]>, mut cur_cmnt: uint, @@ -43,7 +43,7 @@ fn end(s: ps) { pp::end(s.s); } -fn rust_printer(writer: io::Writer, intr: ident_interner) -> ps { +fn rust_printer(writer: io::Writer, intr: @ident_interner) -> ps { return @{s: pp::mk_printer(writer, default_columns), cm: None::, intr: intr, @@ -63,7 +63,7 @@ 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, intr: ident_interner, +fn print_crate(cm: codemap, intr: @ident_interner, span_diagnostic: diagnostic::span_handler, crate: @ast::crate, filename: ~str, in: io::Reader, out: io::Writer, ann: pp_ann, is_expanded: bool) { @@ -91,40 +91,40 @@ fn print_crate_(s: ps, &&crate: @ast::crate) { eof(s.s); } -fn ty_to_str(ty: @ast::ty, intr: ident_interner) -> ~str { +fn ty_to_str(ty: @ast::ty, intr: @ident_interner) -> ~str { to_str(ty, print_type, intr) } -fn pat_to_str(pat: @ast::pat, intr: ident_interner) -> ~str { +fn pat_to_str(pat: @ast::pat, intr: @ident_interner) -> ~str { to_str(pat, print_pat, intr) } -fn expr_to_str(e: @ast::expr, intr: ident_interner) -> ~str { +fn expr_to_str(e: @ast::expr, intr: @ident_interner) -> ~str { to_str(e, print_expr, intr) } -fn tt_to_str(tt: ast::token_tree, intr: ident_interner) -> ~str { +fn tt_to_str(tt: ast::token_tree, intr: @ident_interner) -> ~str { to_str(tt, print_tt, intr) } -fn stmt_to_str(s: ast::stmt, intr: ident_interner) -> ~str { +fn stmt_to_str(s: ast::stmt, intr: @ident_interner) -> ~str { to_str(s, print_stmt, intr) } -fn item_to_str(i: @ast::item, intr: ident_interner) -> ~str { +fn item_to_str(i: @ast::item, intr: @ident_interner) -> ~str { to_str(i, print_item, intr) } -fn typarams_to_str(tps: ~[ast::ty_param], intr: ident_interner) -> ~str { +fn typarams_to_str(tps: ~[ast::ty_param], intr: @ident_interner) -> ~str { to_str(tps, print_type_params, intr) } -fn path_to_str(&&p: @ast::path, intr: ident_interner) -> ~str { +fn path_to_str(&&p: @ast::path, intr: @ident_interner) -> ~str { to_str(p, |a,b| print_path(a, b, false), intr) } fn fun_to_str(decl: ast::fn_decl, name: ast::ident, - params: ~[ast::ty_param], intr: ident_interner) -> ~str { + params: ~[ast::ty_param], intr: @ident_interner) -> ~str { do io::with_str_writer |wr| { let s = rust_printer(wr, intr); print_fn(s, decl, None, name, params, None, ast::inherited); @@ -147,7 +147,7 @@ fn test_fun_to_str() { assert fun_to_str(decl, "a", ~[]) == "fn a()"; } -fn block_to_str(blk: ast::blk, intr: ident_interner) -> ~str { +fn block_to_str(blk: ast::blk, intr: @ident_interner) -> ~str { do io::with_str_writer |wr| { let s = rust_printer(wr, intr); // containing cbox, will be closed by print-block at } @@ -159,15 +159,15 @@ fn block_to_str(blk: ast::blk, intr: ident_interner) -> ~str { } } -fn meta_item_to_str(mi: @ast::meta_item, intr: ident_interner) -> ~str { +fn meta_item_to_str(mi: @ast::meta_item, intr: @ident_interner) -> ~str { to_str(mi, print_meta_item, intr) } -fn attribute_to_str(attr: ast::attribute, intr: ident_interner) -> ~str { +fn attribute_to_str(attr: ast::attribute, intr: @ident_interner) -> ~str { to_str(attr, print_attribute, intr) } -fn variant_to_str(var: ast::variant, intr: ident_interner) -> ~str { +fn variant_to_str(var: ast::variant, intr: @ident_interner) -> ~str { to_str(var, print_variant, intr) } @@ -2059,7 +2059,7 @@ fn print_string(s: ps, st: ~str) { word(s.s, ~"\""); } -fn to_str(t: T, f: fn@(ps, T), intr: ident_interner) -> ~str { +fn to_str(t: T, f: fn@(ps, T), intr: @ident_interner) -> ~str { do io::with_str_writer |wr| { let s = rust_printer(wr, intr); f(s, t); diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc index c62ec28f35952..a8ae9bd63a103 100644 --- a/src/libsyntax/syntax.rc +++ b/src/libsyntax/syntax.rc @@ -129,6 +129,8 @@ mod ext { #[legacy_exports] mod auto_serialize; #[legacy_exports] + mod auto_serialize2; + #[legacy_exports] mod source_util; mod pipes { diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index 15b9e34566fbe..021c25e3dd710 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -59,4 +59,4 @@ impl hash_interner: interner { pure fn get(idx: uint) -> T { self.vect.get_elt(idx) } fn len() -> uint { return self.vect.len(); } -} \ No newline at end of file +} diff --git a/src/rustc/back/link.rs b/src/rustc/back/link.rs index fb3d749673c1a..c8f5871333fc1 100644 --- a/src/rustc/back/link.rs +++ b/src/rustc/back/link.rs @@ -607,7 +607,7 @@ fn mangle_internal_name_by_path(ccx: @crate_ctxt, path: path) -> ~str { } fn mangle_internal_name_by_seq(ccx: @crate_ctxt, flav: ~str) -> ~str { - return fmt!("%s_%u", flav, ccx.names(flav)); + return fmt!("%s_%u", flav, ccx.names(flav).repr); } // If the user wants an exe generated we need to invoke diff --git a/src/rustc/driver/session.rs b/src/rustc/driver/session.rs index 335e100407830..c6c0ff2826a52 100644 --- a/src/rustc/driver/session.rs +++ b/src/rustc/driver/session.rs @@ -243,7 +243,7 @@ impl session { fn ident_of(st: ~str) -> ast::ident { self.parse_sess.interner.intern(@st) } - fn intr() -> syntax::parse::token::ident_interner { + fn intr() -> @syntax::parse::token::ident_interner { self.parse_sess.interner } } diff --git a/src/rustc/metadata/creader.rs b/src/rustc/metadata/creader.rs index f6c2bf7d5a116..0d19fe796e119 100644 --- a/src/rustc/metadata/creader.rs +++ b/src/rustc/metadata/creader.rs @@ -18,7 +18,7 @@ export read_crates; // libraries necessary for later resolving, typechecking, linking, etc. fn read_crates(diag: span_handler, crate: ast::crate, cstore: cstore::cstore, filesearch: filesearch, - os: loader::os, static: bool, intr: ident_interner) { + os: loader::os, static: bool, intr: @ident_interner) { let e = @{diag: diag, filesearch: filesearch, cstore: cstore, @@ -94,7 +94,7 @@ type env = @{diag: span_handler, static: bool, crate_cache: DVec, mut next_crate_num: ast::crate_num, - intr: ident_interner}; + intr: @ident_interner}; fn visit_view_item(e: env, i: @ast::view_item) { match i.node { @@ -248,7 +248,7 @@ fn resolve_crate_deps(e: env, cdata: @~[u8]) -> cstore::cnum_map { debug!("resolving deps of external crate"); // The map from crate numbers in the crate we're resolving to local crate // numbers - let cnum_map = HashMap::(); + let cnum_map = HashMap(); for decoder::get_crate_deps(e.intr, cdata).each |dep| { let extrn_cnum = dep.cnum; let cname = dep.name; diff --git a/src/rustc/metadata/cstore.rs b/src/rustc/metadata/cstore.rs index cb304c419e563..8a982eaf4977e 100644 --- a/src/rustc/metadata/cstore.rs +++ b/src/rustc/metadata/cstore.rs @@ -58,7 +58,7 @@ type cstore_private = mut used_crate_files: ~[Path], mut used_libraries: ~[~str], mut used_link_args: ~[~str], - intr: ident_interner}; + intr: @ident_interner}; // Map from node_id's of local use statements to crate numbers type use_crate_map = map::HashMap; @@ -68,9 +68,9 @@ pure fn p(cstore: cstore) -> cstore_private { match cstore { private(p) => p } } -fn mk_cstore(intr: ident_interner) -> cstore { - let meta_cache = map::HashMap::(); - let crate_map = map::HashMap::(); +fn mk_cstore(intr: @ident_interner) -> cstore { + let meta_cache = map::HashMap(); + let crate_map = map::HashMap(); let mod_path_map = HashMap(); return private(@{metas: meta_cache, use_crate_map: crate_map, diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs index c631e40447227..4a72867eb853e 100644 --- a/src/rustc/metadata/decoder.rs +++ b/src/rustc/metadata/decoder.rs @@ -268,7 +268,7 @@ fn enum_variant_ids(item: ebml::Doc, cdata: cmd) -> ~[ast::def_id] { return ids; } -fn item_path(intr: ident_interner, item_doc: ebml::Doc) -> ast_map::path { +fn item_path(intr: @ident_interner, item_doc: ebml::Doc) -> ast_map::path { let path_doc = ebml::get_doc(item_doc, tag_path); let len_doc = ebml::get_doc(path_doc, tag_path_len); @@ -290,7 +290,7 @@ fn item_path(intr: ident_interner, item_doc: ebml::Doc) -> ast_map::path { return result; } -fn item_name(intr: ident_interner, item: ebml::Doc) -> ast::ident { +fn item_name(intr: @ident_interner, item: ebml::Doc) -> ast::ident { let name = ebml::get_doc(item, tag_paths_data_name); intr.intern(@str::from_bytes(ebml::doc_data(name))) } @@ -365,7 +365,7 @@ fn get_impl_traits(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) -> ~[ty::t] { item_impl_traits(lookup_item(id, cdata.data), tcx, cdata) } -fn get_impl_method(intr: ident_interner, cdata: cmd, id: ast::node_id, +fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, name: ast::ident) -> ast::def_id { let items = ebml::get_doc(ebml::Doc(cdata.data), tag_items); let mut found = None; @@ -378,7 +378,7 @@ fn get_impl_method(intr: ident_interner, cdata: cmd, id: ast::node_id, found.get() } -fn get_class_method(intr: ident_interner, cdata: cmd, id: ast::node_id, +fn get_class_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, name: ast::ident) -> ast::def_id { let items = ebml::get_doc(ebml::Doc(cdata.data), tag_items); let mut found = None; @@ -451,7 +451,7 @@ fn path_entry(path_string: ~str, def_like: def_like) -> path_entry { } /// Iterates over all the paths in the given crate. -fn each_path(intr: ident_interner, cdata: cmd, f: fn(path_entry) -> bool) { +fn each_path(intr: @ident_interner, cdata: cmd, f: fn(path_entry) -> bool) { let root = ebml::Doc(cdata.data); let items = ebml::get_doc(root, tag_items); let items_data = ebml::get_doc(items, tag_items_data); @@ -531,7 +531,7 @@ fn each_path(intr: ident_interner, cdata: cmd, f: fn(path_entry) -> bool) { } } -fn get_item_path(intr: ident_interner, cdata: cmd, id: ast::node_id) +fn get_item_path(intr: @ident_interner, cdata: cmd, id: ast::node_id) -> ast_map::path { item_path(intr, lookup_item(id, cdata.data)) } @@ -542,7 +542,7 @@ type decode_inlined_item = fn( path: ast_map::path, par_doc: ebml::Doc) -> Option; -fn maybe_get_item_ast(intr: ident_interner, cdata: cmd, tcx: ty::ctxt, +fn maybe_get_item_ast(intr: @ident_interner, cdata: cmd, tcx: ty::ctxt, id: ast::node_id, decode_inlined_item: decode_inlined_item ) -> csearch::found_ast { @@ -568,7 +568,7 @@ fn maybe_get_item_ast(intr: ident_interner, cdata: cmd, tcx: ty::ctxt, } } -fn get_enum_variants(intr: ident_interner, cdata: cmd, id: ast::node_id, +fn get_enum_variants(intr: @ident_interner, cdata: cmd, id: ast::node_id, tcx: ty::ctxt) -> ~[ty::variant_info] { let data = cdata.data; let items = ebml::get_doc(ebml::Doc(data), tag_items); @@ -638,7 +638,7 @@ fn get_self_ty(item: ebml::Doc) -> ast::self_ty_ { } } -fn item_impl_methods(intr: ident_interner, cdata: cmd, item: ebml::Doc, +fn item_impl_methods(intr: @ident_interner, cdata: cmd, item: ebml::Doc, base_tps: uint) -> ~[@method_info] { let mut rslt = ~[]; for ebml::tagged_docs(item, tag_item_impl_method) |doc| { @@ -654,7 +654,7 @@ fn item_impl_methods(intr: ident_interner, cdata: cmd, item: ebml::Doc, rslt } -fn get_impls_for_mod(intr: ident_interner, cdata: cmd, +fn get_impls_for_mod(intr: @ident_interner, cdata: cmd, m_id: ast::node_id, name: Option, get_cdata: fn(ast::crate_num) -> cmd) -> @~[@_impl] { @@ -685,7 +685,7 @@ fn get_impls_for_mod(intr: ident_interner, cdata: cmd, } /* Works for both classes and traits */ -fn get_trait_methods(intr: ident_interner, cdata: cmd, id: ast::node_id, +fn get_trait_methods(intr: @ident_interner, cdata: cmd, id: ast::node_id, tcx: ty::ctxt) -> @~[ty::method] { let data = cdata.data; let item = lookup_item(id, data); @@ -712,7 +712,7 @@ fn get_trait_methods(intr: ident_interner, cdata: cmd, id: ast::node_id, // If the item in question is a trait, returns its set of methods and // their self types. Otherwise, returns none. This overlaps in an // annoying way with get_trait_methods. -fn get_method_names_if_trait(intr: ident_interner, cdata: cmd, +fn get_method_names_if_trait(intr: @ident_interner, cdata: cmd, node_id: ast::node_id) -> Option<@DVec<(ast::ident, ast::self_ty_)>> { @@ -742,7 +742,7 @@ fn get_item_attrs(cdata: cmd, } // Helper function that gets either fields or methods -fn get_class_members(intr: ident_interner, cdata: cmd, id: ast::node_id, +fn get_class_members(intr: @ident_interner, cdata: cmd, id: ast::node_id, p: fn(Family) -> bool) -> ~[ty::field_ty] { let data = cdata.data; let item = lookup_item(id, data); @@ -769,7 +769,7 @@ pure fn family_to_visibility(family: Family) -> ast::visibility { } } -fn get_class_fields(intr: ident_interner, cdata: cmd, id: ast::node_id) +fn get_class_fields(intr: @ident_interner, cdata: cmd, id: ast::node_id) -> ~[ty::field_ty] { get_class_members(intr, cdata, id, |f| f == PublicField || f == PrivateField || f == InheritedField) @@ -876,14 +876,14 @@ fn get_attributes(md: ebml::Doc) -> ~[ast::attribute] { return attrs; } -fn list_meta_items(intr: ident_interner, +fn list_meta_items(intr: @ident_interner, meta_items: ebml::Doc, out: io::Writer) { for get_meta_items(meta_items).each |mi| { out.write_str(fmt!("%s\n", pprust::meta_item_to_str(*mi, intr))); } } -fn list_crate_attributes(intr: ident_interner, md: ebml::Doc, hash: ~str, +fn list_crate_attributes(intr: @ident_interner, md: ebml::Doc, hash: ~str, out: io::Writer) { out.write_str(fmt!("=Crate Attributes (%s)=\n", hash)); @@ -901,7 +901,7 @@ fn get_crate_attributes(data: @~[u8]) -> ~[ast::attribute] { type crate_dep = {cnum: ast::crate_num, name: ast::ident, vers: ~str, hash: ~str}; -fn get_crate_deps(intr: ident_interner, data: @~[u8]) -> ~[crate_dep] { +fn get_crate_deps(intr: @ident_interner, data: @~[u8]) -> ~[crate_dep] { let mut deps: ~[crate_dep] = ~[]; let cratedoc = ebml::Doc(data); let depsdoc = ebml::get_doc(cratedoc, tag_crate_deps); @@ -919,7 +919,7 @@ fn get_crate_deps(intr: ident_interner, data: @~[u8]) -> ~[crate_dep] { return deps; } -fn list_crate_deps(intr: ident_interner, data: @~[u8], out: io::Writer) { +fn list_crate_deps(intr: @ident_interner, data: @~[u8], out: io::Writer) { out.write_str(~"=External Dependencies=\n"); for get_crate_deps(intr, data).each |dep| { @@ -946,7 +946,7 @@ fn get_crate_vers(data: @~[u8]) -> ~str { }; } -fn iter_crate_items(intr: ident_interner, +fn iter_crate_items(intr: @ident_interner, cdata: cmd, proc: fn(~str, ast::def_id)) { for each_path(intr, cdata) |path_entry| { match path_entry.def_like { @@ -958,7 +958,7 @@ fn iter_crate_items(intr: ident_interner, } } -fn get_crate_module_paths(intr: ident_interner, cdata: cmd) +fn get_crate_module_paths(intr: @ident_interner, cdata: cmd) -> ~[(ast::def_id, ~str)] { fn mod_of_path(p: ~str) -> ~str { str::connect(vec::init(str::split_str(p, ~"::")), ~"::") @@ -967,7 +967,7 @@ fn get_crate_module_paths(intr: ident_interner, cdata: cmd) // find all module (path, def_ids), which are not // fowarded path due to renamed import or reexport let mut res = ~[]; - let mods = map::HashMap::<~str,bool>(); + let mods = map::HashMap(); do iter_crate_items(intr, cdata) |path, did| { let m = mod_of_path(path); if str::is_not_empty(m) { @@ -985,7 +985,7 @@ fn get_crate_module_paths(intr: ident_interner, cdata: cmd) } } -fn list_crate_metadata(intr: ident_interner, bytes: @~[u8], +fn list_crate_metadata(intr: @ident_interner, bytes: @~[u8], out: io::Writer) { let hash = get_crate_hash(bytes); let md = ebml::Doc(bytes); diff --git a/src/rustc/metadata/loader.rs b/src/rustc/metadata/loader.rs index e11793a36d01e..b2c28fafd4c3c 100644 --- a/src/rustc/metadata/loader.rs +++ b/src/rustc/metadata/loader.rs @@ -35,7 +35,7 @@ type ctxt = { hash: ~str, os: os, static: bool, - intr: ident_interner + intr: @ident_interner }; fn load_library_crate(cx: ctxt) -> {ident: ~str, data: @~[u8]} { @@ -135,7 +135,7 @@ fn crate_name_from_metas(metas: ~[@ast::meta_item]) -> ~str { } } -fn note_linkage_attrs(intr: ident_interner, diag: span_handler, +fn note_linkage_attrs(intr: @ident_interner, diag: span_handler, attrs: ~[ast::attribute]) { for attr::find_linkage_metas(attrs).each |mi| { diag.handler().note(fmt!("meta: %s", @@ -226,7 +226,7 @@ fn meta_section_name(os: os) -> ~str { } // A diagnostic function for dumping crate metadata to an output stream -fn list_file_metadata(intr: ident_interner, +fn list_file_metadata(intr: @ident_interner, os: os, path: &Path, out: io::Writer) { match get_metadata_section(os, path) { option::Some(bytes) => decoder::list_crate_metadata(intr, bytes, out), diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs index afb1cbc36f4bb..7380a217ebe9a 100644 --- a/src/rustc/middle/resolve.rs +++ b/src/rustc/middle/resolve.rs @@ -191,7 +191,7 @@ impl ImportDirectiveNS : cmp::Eq { /// Contains data for specific types of import directives. enum ImportDirectiveSubclass { - SingleImport(Atom /* target */, Atom /* source */, ImportDirectiveNS), + SingleImport(ident /* target */, ident /* source */, ImportDirectiveNS), GlobImport } @@ -303,29 +303,15 @@ enum EnumVariantOrConstResolution { EnumVariantOrConstNotFound } -// FIXME (issue #2550): Should be a class but then it becomes not implicitly -// copyable due to a kind bug. - -type Atom = uint; - -fn Atom(n: uint) -> Atom { - return n; -} - -/// Creates a hash table of atoms. -fn atom_hashmap() -> HashMap { - HashMap::() -} - /// One local scope. struct Rib { - bindings: HashMap, + bindings: HashMap, kind: RibKind, } fn Rib(kind: RibKind) -> Rib { Rib { - bindings: atom_hashmap(), + bindings: HashMap(), kind: kind } } @@ -334,13 +320,13 @@ fn Rib(kind: RibKind) -> Rib { /// One import directive. struct ImportDirective { privacy: Privacy, - module_path: @DVec, + module_path: @DVec, subclass: @ImportDirectiveSubclass, span: span, } fn ImportDirective(privacy: Privacy, - module_path: @DVec, + module_path: @DVec, subclass: @ImportDirectiveSubclass, span: span) -> ImportDirective { ImportDirective { @@ -407,7 +393,7 @@ impl ImportResolution { /// The link from a module up to its nearest parent node. enum ParentLink { NoParentLink, - ModuleParentLink(@Module, Atom), + ModuleParentLink(@Module, ident), BlockParentLink(@Module, node_id) } @@ -416,7 +402,7 @@ struct Module { parent_link: ParentLink, mut def_id: Option, - children: HashMap, + children: HashMap, imports: DVec<@ImportDirective>, // The anonymous children of this node. Anonymous children are pseudo- @@ -439,10 +425,10 @@ struct Module { // XXX: This is about to be reworked so that exports are on individual // items, not names. // - // The atom is the name of the exported item, while the node ID is the + // The ident is the name of the exported item, while the node ID is the // ID of the export path. - exported_names: HashMap, + exported_names: HashMap, // XXX: This is a transition measure to let us switch export-evaluation // logic when compiling modules that have transitioned to listing their @@ -452,7 +438,7 @@ struct Module { legacy_exports: bool, // The status of resolving each import in this module. - import_resolutions: HashMap, + import_resolutions: HashMap, // The number of unresolved globs that this module exports. mut glob_count: uint, @@ -467,12 +453,12 @@ fn Module(parent_link: ParentLink, Module { parent_link: parent_link, def_id: def_id, - children: atom_hashmap(), + children: HashMap(), imports: DVec(), anonymous_children: HashMap(), - exported_names: atom_hashmap(), + exported_names: HashMap(), legacy_exports: legacy_exports, - import_resolutions: atom_hashmap(), + import_resolutions: HashMap(), glob_count: 0u, resolved_import_count: 0u } @@ -648,20 +634,20 @@ fn NameBindings() -> NameBindings { /// Interns the names of the primitive types. struct PrimitiveTypeTable { - primitive_types: HashMap, + primitive_types: HashMap, } impl PrimitiveTypeTable { - fn intern(intr: ident_interner, string: @~str, + fn intern(intr: @ident_interner, string: @~str, primitive_type: prim_ty) { - let atom = intr.intern(string); - self.primitive_types.insert(atom, primitive_type); + let ident = intr.intern(string); + self.primitive_types.insert(ident, primitive_type); } } -fn PrimitiveTypeTable(intr: ident_interner) -> PrimitiveTypeTable { +fn PrimitiveTypeTable(intr: @ident_interner) -> PrimitiveTypeTable { let table = PrimitiveTypeTable { - primitive_types: atom_hashmap() + primitive_types: HashMap() }; table.intern(intr, @~"bool", ty_bool); @@ -743,7 +729,7 @@ fn Resolver(session: session, lang_items: LanguageItems, xray_context: NoXray, current_trait_refs: None, - self_atom: syntax::parse::token::special_idents::self_, + self_ident: syntax::parse::token::special_idents::self_, primitive_type_table: @PrimitiveTypeTable(session. parse_sess.interner), @@ -765,13 +751,13 @@ struct Resolver { lang_items: LanguageItems, crate: @crate, - intr: ident_interner, + intr: @ident_interner, graph_root: @NameBindings, unused_import_lint_level: level, - trait_info: HashMap>, + trait_info: HashMap>, structs: HashMap, // The number of imports that are currently unresolved. @@ -797,10 +783,10 @@ struct Resolver { // The trait that the current context can refer to. mut current_trait_refs: Option<@DVec>, - // The atom for the keyword "self". - self_atom: Atom, + // The ident for the keyword "self". + self_ident: ident, - // The atoms for the primitive types. + // The idents for the primitive types. primitive_type_table: @PrimitiveTypeTable, // The four namespaces. @@ -899,7 +885,7 @@ impl Resolver { * If this node does not have a module definition and we are not inside * a block, fails. */ - fn add_child(name: Atom, + fn add_child(name: ident, reduced_graph_parent: ReducedGraphParent, // Pass in the namespaces for the child item so that we can // check for duplicate items in the same namespace @@ -981,7 +967,8 @@ impl Resolver { return false; } - fn get_parent_link(parent: ReducedGraphParent, name: Atom) -> ParentLink { + fn get_parent_link(parent: ReducedGraphParent, + name: ident) -> ParentLink { match parent { ModuleReducedGraphParent(module_) => { return ModuleParentLink(module_, name); @@ -994,7 +981,7 @@ impl Resolver { parent: ReducedGraphParent, &&visitor: vt) { - let atom = item.ident; + let ident = item.ident; let sp = item.span; let legacy = match parent { ModuleReducedGraphParent(m) => m.legacy_exports @@ -1004,10 +991,10 @@ impl Resolver { match item.node { item_mod(module_) => { let legacy = has_legacy_export_attr(item.attrs); - let (name_bindings, new_parent) = self.add_child(atom, parent, + let (name_bindings, new_parent) = self.add_child(ident, parent, ~[ModuleNS], sp); - let parent_link = self.get_parent_link(new_parent, atom); + let parent_link = self.get_parent_link(new_parent, ident); let def_id = { crate: 0, node: item.id }; (*name_bindings).define_module(privacy, parent_link, Some(def_id), legacy, sp); @@ -1021,10 +1008,10 @@ impl Resolver { let legacy = has_legacy_export_attr(item.attrs); let new_parent = match fm.sort { named => { - let (name_bindings, new_parent) = self.add_child(atom, + let (name_bindings, new_parent) = self.add_child(ident, parent, ~[ModuleNS], sp); - let parent_link = self.get_parent_link(new_parent, atom); + let parent_link = self.get_parent_link(new_parent, ident); let def_id = { crate: 0, node: item.id }; (*name_bindings).define_module(privacy, parent_link, Some(def_id), legacy, sp); @@ -1041,14 +1028,14 @@ impl Resolver { // These items live in the value namespace. item_const(*) => { - let (name_bindings, _) = self.add_child(atom, parent, + let (name_bindings, _) = self.add_child(ident, parent, ~[ValueNS], sp); (*name_bindings).define_value (privacy, def_const(local_def(item.id)), sp); } item_fn(_, purity, _, _) => { - let (name_bindings, new_parent) = self.add_child(atom, parent, + let (name_bindings, new_parent) = self.add_child(ident, parent, ~[ValueNS], sp); let def = def_fn(local_def(item.id), purity); @@ -1058,7 +1045,7 @@ impl Resolver { // These items live in the type namespace. item_ty(*) => { - let (name_bindings, _) = self.add_child(atom, parent, + let (name_bindings, _) = self.add_child(ident, parent, ~[TypeNS], sp); (*name_bindings).define_type @@ -1067,7 +1054,7 @@ impl Resolver { item_enum(enum_definition, _) => { - let (name_bindings, new_parent) = self.add_child(atom, parent, + let (name_bindings, new_parent) = self.add_child(ident, parent, ~[TypeNS], sp); (*name_bindings).define_type @@ -1087,7 +1074,7 @@ impl Resolver { match struct_definition.ctor { None => { let (name_bindings, new_parent) = - self.add_child(atom, parent, ~[TypeNS], sp); + self.add_child(ident, parent, ~[TypeNS], sp); (*name_bindings).define_type (privacy, def_ty(local_def(item.id)), sp); @@ -1095,7 +1082,7 @@ impl Resolver { } Some(ctor) => { let (name_bindings, new_parent) = - self.add_child(atom, parent, ~[ValueNS, TypeNS], + self.add_child(ident, parent, ~[ValueNS, TypeNS], sp); (*name_bindings).define_type @@ -1121,22 +1108,22 @@ impl Resolver { } item_trait(_, _, methods) => { - let (name_bindings, new_parent) = self.add_child(atom, parent, + let (name_bindings, new_parent) = self.add_child(ident, parent, ~[TypeNS], sp); // Add the names of all the methods to the trait info. - let method_names = @atom_hashmap(); + let method_names = @HashMap(); for methods.each |method| { let ty_m = trait_method_to_ty_method(*method); - let atom = ty_m.ident; + let ident = ty_m.ident; // Add it to the trait info if not static, // add it as a name in the enclosing module otherwise. match ty_m.self_ty.node { sty_static => { // which parent to use?? let (method_name_bindings, _) = - self.add_child(atom, new_parent, ~[ValueNS], + self.add_child(ident, new_parent, ~[ValueNS], ty_m.span); let def = def_static_method(local_def(ty_m.id), ty_m.purity); @@ -1144,7 +1131,7 @@ impl Resolver { (Public, def, ty_m.span); } _ => { - (*method_names).insert(atom, ()); + (*method_names).insert(ident, ()); } } } @@ -1176,8 +1163,8 @@ impl Resolver { ModuleReducedGraphParent(m) => m.legacy_exports }; - let atom = variant.node.name; - let (child, _) = self.add_child(atom, parent, ~[ValueNS], + let ident = variant.node.name; + let (child, _) = self.add_child(ident, parent, ~[ValueNS], variant.span); let privacy = self.visibility_to_privacy(variant.node.vis, legacy); @@ -1338,9 +1325,9 @@ impl Resolver { } for path_list_idents.each |path_list_ident| { - let atom = path_list_ident.node.name; + let ident = path_list_ident.node.name; let id = path_list_ident.node.id; - module_.exported_names.insert(atom, id); + module_.exported_names.insert(ident, id); } } } @@ -1433,7 +1420,7 @@ impl Resolver { fn handle_external_def(def: def, modules: HashMap, child_name_bindings: @NameBindings, final_ident: ~str, - atom: Atom, new_parent: ReducedGraphParent) { + ident: ident, new_parent: ReducedGraphParent) { match def { def_mod(def_id) | def_foreign_mod(def_id) => { match copy child_name_bindings.module_def { @@ -1441,7 +1428,7 @@ impl Resolver { debug!("(building reduced graph for \ external crate) building module \ %s", final_ident); - let parent_link = self.get_parent_link(new_parent, atom); + let parent_link = self.get_parent_link(new_parent, ident); match modules.find(def_id) { None => { @@ -1466,9 +1453,9 @@ impl Resolver { BlockParentLink(*) => { fail ~"can't happen"; } - ModuleParentLink(parent_module, atom) => { + ModuleParentLink(parent_module, ident) => { - let name_bindings = parent_module.children.get(atom); + let name_bindings = parent_module.children.get(ident); resolution.module_target = Some(Target(parent_module, name_bindings)); @@ -1478,7 +1465,7 @@ impl Resolver { debug!("(building reduced graph for external crate) \ ... creating import resolution"); - new_parent.import_resolutions.insert(atom, resolution); + new_parent.import_resolutions.insert(ident, resolution); } } } @@ -1510,7 +1497,7 @@ impl Resolver { // Nothing to do. } Some(method_names) => { - let interned_method_names = @atom_hashmap(); + let interned_method_names = @HashMap(); for method_names.each |method_data| { let (method_name, self_ty) = *method_data; debug!("(building reduced graph for \ @@ -1634,7 +1621,7 @@ impl Resolver { /// Creates and adds an import directive to the given module. fn build_import_directive(privacy: Privacy, module_: @Module, - module_path: @DVec, + module_path: @DVec, subclass: @ImportDirectiveSubclass, span: span) { @@ -1764,17 +1751,17 @@ impl Resolver { } } - fn atoms_to_str(atoms: ~[Atom]) -> ~str { + fn idents_to_str(idents: ~[ident]) -> ~str { // XXX: str::connect should do this. let mut result = ~""; let mut first = true; - for atoms.each() |atom| { + for idents.each() |ident| { if first { first = false; } else { result += ~"::"; } - result += self.session.str_of(*atom); + result += self.session.str_of(*ident); } // XXX: Shouldn't copy here. We need string builder functionality. return result; @@ -1795,7 +1782,7 @@ impl Resolver { debug!("(resolving import for module) resolving import `%s::...` in \ `%s`", - self.atoms_to_str((*module_path).get()), + self.idents_to_str((*module_path).get()), self.module_to_str(module_)); // One-level renaming imports of the form `import foo = bar;` are @@ -1882,8 +1869,8 @@ impl Resolver { fn resolve_single_import(module_: @Module, containing_module: @Module, - target: Atom, - source: Atom) + target: ident, + source: ident) -> ResolveResult<()> { debug!("(resolving single import) resolving `%s` = `%s::%s` from \ @@ -2072,8 +2059,8 @@ impl Resolver { fn resolve_single_module_import(module_: @Module, containing_module: @Module, - target: Atom, - source: Atom) + target: ident, + source: ident) -> ResolveResult<()> { debug!("(resolving single module import) resolving `%s` = `%s::%s` \ @@ -2229,11 +2216,11 @@ impl Resolver { // Add all resolved imports from the containing module. for containing_module.import_resolutions.each - |atom, target_import_resolution| { + |ident, target_import_resolution| { - if !self.name_is_exported(containing_module, atom) { + if !self.name_is_exported(containing_module, ident) { debug!("(resolving glob import) name `%s` is unexported", - self.session.str_of(atom)); + self.session.str_of(ident)); loop; } @@ -2243,7 +2230,7 @@ impl Resolver { self.module_to_str(module_)); // Here we merge two import resolutions. - match module_.import_resolutions.find(atom) { + match module_.import_resolutions.find(ident) { None => { // Simple: just copy the old import resolution. let new_import_resolution = @@ -2257,7 +2244,7 @@ impl Resolver { copy target_import_resolution.type_target; module_.import_resolutions.insert - (atom, new_import_resolution); + (ident, new_import_resolution); } Some(dest_import_resolution) => { // Merge the two import resolutions at a finer-grained @@ -2295,21 +2282,21 @@ impl Resolver { } // Add all children from the containing module. - for containing_module.children.each |atom, name_bindings| { - if !self.name_is_exported(containing_module, atom) { + for containing_module.children.each |ident, name_bindings| { + if !self.name_is_exported(containing_module, ident) { debug!("(resolving glob import) name `%s` is unexported", - self.session.str_of(atom)); + self.session.str_of(ident)); loop; } let mut dest_import_resolution; - match module_.import_resolutions.find(atom) { + match module_.import_resolutions.find(ident) { None => { // Create a new import resolution from this child. dest_import_resolution = @ImportResolution(privacy, span); module_.import_resolutions.insert - (atom, dest_import_resolution); + (ident, dest_import_resolution); } Some(existing_import_resolution) => { dest_import_resolution = existing_import_resolution; @@ -2319,7 +2306,7 @@ impl Resolver { debug!("(resolving glob import) writing resolution `%s` in `%s` \ to `%s`", - self.session.str_of(atom), + self.session.str_of(ident), self.module_to_str(containing_module), self.module_to_str(module_)); @@ -2346,7 +2333,7 @@ impl Resolver { } fn resolve_module_path_from_root(module_: @Module, - module_path: @DVec, + module_path: @DVec, index: uint, xray: XrayFlag, span: span) @@ -2403,7 +2390,7 @@ impl Resolver { * the given module. */ fn resolve_module_path_for_import(module_: @Module, - module_path: @DVec, + module_path: @DVec, xray: XrayFlag, span: span) -> ResolveResult<@Module> { @@ -2413,7 +2400,7 @@ impl Resolver { debug!("(resolving module path for import) processing `%s` rooted at \ `%s`", - self.atoms_to_str((*module_path).get()), + self.idents_to_str((*module_path).get()), self.module_to_str(module_)); // The first element of the module path must be in the current scope @@ -2444,7 +2431,7 @@ impl Resolver { } fn resolve_item_in_lexical_scope(module_: @Module, - name: Atom, + name: ident, namespace: Namespace) -> ResolveResult { @@ -2530,7 +2517,7 @@ impl Resolver { } } - fn resolve_module_in_lexical_scope(module_: @Module, name: Atom) + fn resolve_module_in_lexical_scope(module_: @Module, name: ident) -> ResolveResult<@Module> { match self.resolve_item_in_lexical_scope(module_, name, ModuleNS) { @@ -2559,7 +2546,7 @@ impl Resolver { } } - fn name_is_exported(module_: @Module, name: Atom) -> bool { + fn name_is_exported(module_: @Module, name: ident) -> bool { return !module_.legacy_exports || module_.exported_names.size() == 0u || module_.exported_names.contains_key(name); @@ -2571,7 +2558,7 @@ impl Resolver { * the name. */ fn resolve_name_in_module(module_: @Module, - name: Atom, + name: ident, namespace: Namespace, xray: XrayFlag) -> ResolveResult { @@ -2863,7 +2850,7 @@ impl Resolver { self.record_exports_for_module(module_); - for module_.children.each |_atom, child_name_bindings| { + for module_.children.each |_ident, child_name_bindings| { match child_name_bindings.get_module_if_available() { None => { // Nothing to do. @@ -2899,7 +2886,7 @@ impl Resolver { fn add_exports_of_namebindings(exports2: &mut ~[Export2], - atom: Atom, + ident: ident, namebindings: @NameBindings, reexport: bool) { for [ModuleNS, TypeNS, ValueNS].each |ns| { @@ -2908,11 +2895,11 @@ impl Resolver { debug!("(computing exports) YES: %s '%s' \ => %?", if reexport { ~"reexport" } else { ~"export"}, - self.session.str_of(atom), + self.session.str_of(ident), def_id_of_def(d.def)); vec::push(*exports2, Export2 { reexport: reexport, - name: self.session.str_of(atom), + name: self.session.str_of(ident), def_id: def_id_of_def(d.def) }); } @@ -2923,20 +2910,20 @@ impl Resolver { fn add_exports_for_module(exports2: &mut ~[Export2], module_: @Module) { - for module_.children.each_ref |atom, namebindings| { + for module_.children.each_ref |ident, namebindings| { debug!("(computing exports) maybe export '%s'", - self.session.str_of(*atom)); - self.add_exports_of_namebindings(exports2, *atom, + self.session.str_of(*ident)); + self.add_exports_of_namebindings(exports2, *ident, *namebindings, false) } - for module_.import_resolutions.each_ref |atom, importresolution| { + for module_.import_resolutions.each_ref |ident, importresolution| { for [ModuleNS, TypeNS, ValueNS].each |ns| { match importresolution.target_for_namespace(*ns) { Some(target) => { debug!("(computing exports) maybe reexport '%s'", - self.session.str_of(*atom)); - self.add_exports_of_namebindings(exports2, *atom, + self.session.str_of(*ident)); + self.add_exports_of_namebindings(exports2, *ident, target.bindings, true) } @@ -3002,7 +2989,7 @@ impl Resolver { // generate a fake "implementation scope" containing all the // implementations thus found, for compatibility with old resolve pass. - fn with_scope(name: Option, f: fn()) { + fn with_scope(name: Option, f: fn()) { let orig_module = self.current_module; // Move down in the graph. @@ -3142,7 +3129,7 @@ impl Resolver { return Some(dl_def(def)); } - fn search_ribs(ribs: @DVec<@Rib>, name: Atom, span: span, + fn search_ribs(ribs: @DVec<@Rib>, name: ident, span: span, allow_capturing_self: AllowCapturingSelfFlag) -> Option { @@ -3223,7 +3210,7 @@ impl Resolver { // Create a new rib for the self type. let self_type_rib = @Rib(NormalRibKind); (*self.type_ribs).push(self_type_rib); - self_type_rib.bindings.insert(self.self_atom, + self_type_rib.bindings.insert(self.self_ident, dl_def(def_self(item.id))); // Create a new rib for the trait-wide type parameters. @@ -3483,7 +3470,7 @@ impl Resolver { } HasSelfBinding(self_node_id) => { let def_like = dl_def(def_self(self_node_id)); - (*function_value_rib).bindings.insert(self.self_atom, + (*function_value_rib).bindings.insert(self.self_ident, def_like); } } @@ -3818,7 +3805,7 @@ impl Resolver { fn resolve_arm(arm: arm, visitor: ResolveVisitor) { (*self.value_ribs).push(@Rib(NormalRibKind)); - let bindings_list = atom_hashmap(); + let bindings_list = HashMap(); for arm.pats.each |pattern| { self.resolve_pattern(*pattern, RefutableMode, Immutable, Some(bindings_list), visitor); @@ -3937,7 +3924,7 @@ impl Resolver { mutability: Mutability, // Maps idents to the node ID for the (outermost) // pattern that binds them - bindings_list: Option>, + bindings_list: Option>, visitor: ResolveVisitor) { let pat_id = pattern.id; @@ -3954,13 +3941,13 @@ impl Resolver { // matching such a variant is simply disallowed (since // it's rarely what you want). - let atom = path.idents[0]; + let ident = path.idents[0]; - match self.resolve_enum_variant_or_const(atom) { + match self.resolve_enum_variant_or_const(ident) { FoundEnumVariant(def) if mode == RefutableMode => { debug!("(resolving pattern) resolving `%s` to \ enum variant", - self.session.str_of(atom)); + self.session.str_of(ident)); self.record_def(pattern.id, def); } @@ -3970,7 +3957,7 @@ impl Resolver { shadows an enum \ that's in scope", self.session - .str_of(atom))); + .str_of(ident))); } FoundConst => { self.session.span_err(pattern.span, @@ -3980,7 +3967,7 @@ impl Resolver { } EnumVariantOrConstNotFound => { debug!("(resolving pattern) binding `%s`", - self.session.str_of(atom)); + self.session.str_of(ident)); let is_mutable = mutability == Mutable; @@ -4011,14 +3998,14 @@ impl Resolver { match bindings_list { Some(bindings_list) - if !bindings_list.contains_key(atom) => { + if !bindings_list.contains_key(ident) => { let last_rib = (*self.value_ribs).last(); - last_rib.bindings.insert(atom, + last_rib.bindings.insert(ident, dl_def(def)); - bindings_list.insert(atom, pat_id); + bindings_list.insert(ident, pat_id); } Some(b) => { - if b.find(atom) == Some(pat_id) { + if b.find(ident) == Some(pat_id) { // Then this is a duplicate variable // in the same disjunct, which is an // error @@ -4032,7 +4019,7 @@ impl Resolver { } None => { let last_rib = (*self.value_ribs).last(); - last_rib.bindings.insert(atom, + last_rib.bindings.insert(ident, dl_def(def)); } } @@ -4110,7 +4097,7 @@ impl Resolver { } } - fn resolve_enum_variant_or_const(name: Atom) + fn resolve_enum_variant_or_const(name: ident) -> EnumVariantOrConstResolution { match self.resolve_item_in_lexical_scope(self.current_module, @@ -4205,7 +4192,7 @@ impl Resolver { // XXX: Merge me with resolve_name_in_module? fn resolve_definition_of_name_in_module(containing_module: @Module, - name: Atom, + name: ident, namespace: Namespace, xray: XrayFlag) -> NameDefinition { @@ -4266,17 +4253,17 @@ impl Resolver { } } - fn intern_module_part_of_path(path: @path) -> @DVec { - let module_path_atoms = @DVec(); + fn intern_module_part_of_path(path: @path) -> @DVec { + let module_path_idents = @DVec(); for path.idents.eachi |index, ident| { if index == path.idents.len() - 1u { break; } - (*module_path_atoms).push(*ident); + (*module_path_idents).push(*ident); } - return module_path_atoms; + return module_path_idents; } fn resolve_module_relative_path(path: @path, @@ -4284,19 +4271,19 @@ impl Resolver { namespace: Namespace) -> Option { - let module_path_atoms = self.intern_module_part_of_path(path); + let module_path_idents = self.intern_module_part_of_path(path); let mut containing_module; match self.resolve_module_path_for_import(self.current_module, - module_path_atoms, + module_path_idents, xray, path.span) { Failed => { self.session.span_err(path.span, fmt!("use of undeclared module `%s`", - self.atoms_to_str( - (*module_path_atoms).get()))); + self.idents_to_str( + (*module_path_idents).get()))); return None; } @@ -4329,13 +4316,13 @@ impl Resolver { namespace: Namespace) -> Option { - let module_path_atoms = self.intern_module_part_of_path(path); + let module_path_idents = self.intern_module_part_of_path(path); let root_module = (*self.graph_root).get_module(); let mut containing_module; match self.resolve_module_path_from_root(root_module, - module_path_atoms, + module_path_idents, 0u, xray, path.span) { @@ -4343,8 +4330,8 @@ impl Resolver { Failed => { self.session.span_err(path.span, fmt!("use of undeclared module `::%s`", - self.atoms_to_str - ((*module_path_atoms).get()))); + self.idents_to_str + ((*module_path_idents).get()))); return None; } @@ -4676,7 +4663,7 @@ impl Resolver { } } - fn search_for_traits_containing_method(name: Atom) -> @DVec { + fn search_for_traits_containing_method(name: ident) -> @DVec { let found_traits = @DVec(); let mut search_module = self.current_module; loop { @@ -4715,7 +4702,7 @@ impl Resolver { // Look for imports. for search_module.import_resolutions.each - |_atom, import_resolution| { + |_ident, import_resolution| { match import_resolution.target_for_namespace(TypeNS) { None => { @@ -4761,7 +4748,7 @@ impl Resolver { fn add_trait_info_if_containing_method(found_traits: @DVec, trait_def_id: def_id, - name: Atom) { + name: ident) { match self.trait_info.find(trait_def_id) { Some(trait_info) if trait_info.contains_key(name) => { @@ -4827,7 +4814,7 @@ impl Resolver { self.check_for_unused_imports_in_module(module_); - for module_.children.each |_atom, child_name_bindings| { + for module_.children.each |_ident, child_name_bindings| { match (*child_name_bindings).get_module_if_available() { None => { // Nothing to do. @@ -4876,7 +4863,7 @@ impl Resolver { /// A somewhat inefficient routine to print out the name of a module. fn module_to_str(module_: @Module) -> ~str { - let atoms = DVec(); + let idents = DVec(); let mut current_module = module_; loop { match current_module.parent_link { @@ -4884,27 +4871,27 @@ impl Resolver { break; } ModuleParentLink(module_, name) => { - atoms.push(name); + idents.push(name); current_module = module_; } BlockParentLink(module_, _) => { - atoms.push(syntax::parse::token::special_idents::opaque); + idents.push(syntax::parse::token::special_idents::opaque); current_module = module_; } } } - if atoms.len() == 0u { + if idents.len() == 0u { return ~"???"; } let mut string = ~""; - let mut i = atoms.len() - 1u; + let mut i = idents.len() - 1u; loop { - if i < atoms.len() - 1u { + if i < idents.len() - 1u { string += ~"::"; } - string += self.session.str_of(atoms.get_elt(i)); + string += self.session.str_of(idents.get_elt(i)); if i == 0u { break; diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 2e2e2937cf1cd..b29fac0fa2f13 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -1406,9 +1406,9 @@ fn new_fn_ctxt_w_id(ccx: @crate_ctxt, path: path, mut llself: None, mut personality: None, mut loop_ret: None, - llargs: HashMap::(), - lllocals: HashMap::(), - llupvars: HashMap::(), + llargs: HashMap(), + lllocals: HashMap(), + llupvars: HashMap(), id: id, param_substs: param_substs, span: sp, @@ -2315,7 +2315,7 @@ fn declare_intrinsics(llmod: ModuleRef) -> HashMap<~str, ValueRef> { let frameaddress = decl_cdecl_fn(llmod, ~"llvm.frameaddress", T_fn(T_frameaddress_args, T_ptr(T_i8()))); - let intrinsics = HashMap::<~str,ValueRef>(); + let intrinsics = HashMap(); intrinsics.insert(~"llvm.gcroot", gcroot); intrinsics.insert(~"llvm.gcread", gcread); intrinsics.insert(~"llvm.memmove.p0i8.p0i8.i32", memmove32); @@ -2627,17 +2627,17 @@ fn trans_crate(sess: session::session, llmod: llmod, td: td, tn: tn, - externs: HashMap::<~str,ValueRef>(), + externs: HashMap(), intrinsics: intrinsics, - item_vals: HashMap::(), + item_vals: HashMap(), exp_map2: emap2, reachable: reachable, - item_symbols: HashMap::(), + item_symbols: HashMap(), mut main_fn: None::, link_meta: link_meta, enum_sizes: ty::new_ty_hash(), discrims: HashMap(), - discrim_symbols: HashMap::(), + discrim_symbols: HashMap(), tydescs: ty::new_ty_hash(), mut finished_tydescs: false, external: HashMap(), @@ -2646,15 +2646,15 @@ fn trans_crate(sess: session::session, type_use_cache: HashMap(), vtables: map::HashMap(), const_cstr_cache: HashMap(), - const_globals: HashMap::(), - module_data: HashMap::<~str,ValueRef>(), + const_globals: HashMap(), + module_data: HashMap(), lltypes: ty::new_ty_hash(), names: new_namegen(sess.parse_sess.interner), next_addrspace: new_addrspace_gen(), symbol_hasher: symbol_hasher, type_hashcodes: ty::new_ty_hash(), type_short_names: ty::new_ty_hash(), - all_llvm_symbols: HashMap::<~str,()>(), + all_llvm_symbols: HashMap(), tcx: tcx, maps: maps, stats: @@ -2672,7 +2672,7 @@ fn trans_crate(sess: session::session, upcalls: upcall::declare_upcalls(targ_cfg, tn, tydesc_type, llmod), - rtcalls: HashMap::<~str,ast::def_id>(), + rtcalls: HashMap(), tydesc_type: tydesc_type, int_type: int_type, float_type: float_type, @@ -2683,7 +2683,7 @@ fn trans_crate(sess: session::session, crate_map: crate_map, mut uses_gc: false, dbg_cx: dbg_cx, - class_ctors: HashMap::(), + class_ctors: HashMap(), mut do_not_commit_warning_issued: false}; diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs index a1ca4287f0ef2..fc74e5e0e4d0b 100644 --- a/src/rustc/middle/trans/common.rs +++ b/src/rustc/middle/trans/common.rs @@ -25,9 +25,9 @@ use syntax::parse::token::ident_interner; use syntax::ast::ident; type namegen = fn@(~str) -> ident; -fn new_namegen(intr: ident_interner) -> namegen { +fn new_namegen(intr: @ident_interner) -> namegen { return fn@(prefix: ~str) -> ident { - return intr.gensym(@fmt!("%s_%u", prefix, intr.gensym(@prefix))) + return intr.gensym(@fmt!("%s_%u", prefix, intr.gensym(@prefix).repr)) }; } @@ -1024,7 +1024,7 @@ fn C_cstr(cx: @crate_ctxt, s: ~str) -> ValueRef { llvm::LLVMConstString(buf, str::len(s) as c_uint, False) }; let g = - str::as_c_str(fmt!("str%u", cx.names(~"str")), + str::as_c_str(fmt!("str%u", cx.names(~"str").repr), |buf| llvm::LLVMAddGlobal(cx.llmod, val_ty(sc), buf)); llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); @@ -1086,7 +1086,8 @@ fn C_bytes_plus_null(bytes: ~[u8]) -> ValueRef unsafe { fn C_shape(ccx: @crate_ctxt, bytes: ~[u8]) -> ValueRef { let llshape = C_bytes_plus_null(bytes); - let llglobal = str::as_c_str(fmt!("shape%u", ccx.names(~"shape")), |buf| { + let name = fmt!("shape%u", ccx.names(~"shape").repr); + let llglobal = str::as_c_str(name, |buf| { llvm::LLVMAddGlobal(ccx.llmod, val_ty(llshape), buf) }); llvm::LLVMSetInitializer(llglobal, llshape); diff --git a/src/rustc/middle/trans/debuginfo.rs b/src/rustc/middle/trans/debuginfo.rs index 9944daefea404..26a83951c013d 100644 --- a/src/rustc/middle/trans/debuginfo.rs +++ b/src/rustc/middle/trans/debuginfo.rs @@ -90,7 +90,7 @@ type debug_ctxt = { crate_file: ~str }; -fn mk_ctxt(crate: ~str, intr: ident_interner) -> debug_ctxt { +fn mk_ctxt(crate: ~str, intr: @ident_interner) -> debug_ctxt { {llmetadata: map::HashMap(), names: new_namegen(intr), crate_file: crate} diff --git a/src/rustdoc/extract.rs b/src/rustdoc/extract.rs index b8a13b712e586..448e699fc8d08 100644 --- a/src/rustdoc/extract.rs +++ b/src/rustdoc/extract.rs @@ -21,7 +21,7 @@ fn to_str(id: ast::ident) -> ~str { return *(*intr.get()).get(id); } -fn interner() -> syntax::parse::token::ident_interner { +fn interner() -> @syntax::parse::token::ident_interner { return *(unsafe{ local_data_get(interner_key!()) }).get(); } diff --git a/src/test/run-pass/auto_serialize2-box.rs b/src/test/run-pass/auto_serialize2-box.rs new file mode 100644 index 0000000000000..e395b1bfe5de5 --- /dev/null +++ b/src/test/run-pass/auto_serialize2-box.rs @@ -0,0 +1,73 @@ +// xfail-test FIXME Blocked on (#3585) + +extern mod std; + +// These tests used to be separate files, but I wanted to refactor all +// the common code. + +use cmp::Eq; +use std::ebml2; +use io::Writer; +use std::serialization2::{Serializer, Serializable, deserialize}; +use std::prettyprint2; + +fn test_ser_and_deser( + a1: A, + expected: ~str +) { + // check the pretty printer: + let s = do io::with_str_writer |w| { + a1.serialize(&prettyprint2::Serializer(w)) + }; + debug!("s == %?", s); + assert s == expected; + + // check the EBML serializer: + let bytes = do io::with_bytes_writer |wr| { + let ebml_w = &ebml2::Serializer(wr); + a1.serialize(ebml_w) + }; + let d = ebml2::Doc(@bytes); + let a2: A = deserialize(&ebml2::Deserializer(d)); + assert a1 == a2; +} + +#[auto_serialize2] +enum Expr { + Val(uint), + Plus(@Expr, @Expr), + Minus(@Expr, @Expr) +} + +impl Expr : cmp::Eq { + pure fn eq(other: &Expr) -> bool { + match self { + Val(e0a) => { + match *other { + Val(e0b) => e0a == e0b, + _ => false + } + } + Plus(e0a, e1a) => { + match *other { + Plus(e0b, e1b) => e0a == e0b && e1a == e1b, + _ => false + } + } + Minus(e0a, e1a) => { + match *other { + Minus(e0b, e1b) => e0a == e0b && e1a == e1b, + _ => false + } + } + } + } + pure fn ne(other: &Expr) -> bool { !self.eq(other) } +} + +fn main() { + test_ser_and_deser(Plus(@Minus(@Val(3u), @Val(10u)), + @Plus(@Val(22u), @Val(5u))), + ~"Plus(@Minus(@Val(3u), @Val(10u)), \ + @Plus(@Val(22u), @Val(5u)))"); +} diff --git a/src/test/run-pass/auto_serialize2.rs b/src/test/run-pass/auto_serialize2.rs new file mode 100644 index 0000000000000..ac526a8f0b6b0 --- /dev/null +++ b/src/test/run-pass/auto_serialize2.rs @@ -0,0 +1,119 @@ +extern mod std; + +// These tests used to be separate files, but I wanted to refactor all +// the common code. + +use cmp::Eq; +use std::ebml2; +use io::Writer; +use std::serialization2::{Serializer, Serializable, deserialize}; +use std::prettyprint2; + +fn test_ser_and_deser( + a1: A, + expected: ~str +) { + + // check the pretty printer: + let s = do io::with_str_writer |w| { + a1.serialize(&prettyprint2::Serializer(w)) + }; + debug!("s == %?", s); + assert s == expected; + + // check the EBML serializer: + let bytes = do io::with_bytes_writer |wr| { + let ebml_w = &ebml2::Serializer(wr); + a1.serialize(ebml_w) + }; + let d = ebml2::Doc(@bytes); + let a2: A = deserialize(&ebml2::Deserializer(d)); + assert a1 == a2; +} + +impl AnEnum : cmp::Eq { + pure fn eq(other: &AnEnum) -> bool { + self.v == other.v + } + pure fn ne(other: &AnEnum) -> bool { !self.eq(other) } +} + +impl Point : cmp::Eq { + pure fn eq(other: &Point) -> bool { + self.x == other.x && self.y == other.y + } + pure fn ne(other: &Point) -> bool { !self.eq(other) } +} + +impl Quark : cmp::Eq { + pure fn eq(other: &Quark) -> bool { + match self { + Top(ref q) => { + match *other { + Top(ref r) => q == r, + Bottom(_) => false + } + }, + Bottom(ref q) => { + match *other { + Top(_) => false, + Bottom(ref r) => q == r + } + }, + } + } + pure fn ne(other: &Quark) -> bool { !self.eq(other) } +} + +impl CLike : cmp::Eq { + pure fn eq(other: &CLike) -> bool { + self as int == *other as int + } + pure fn ne(other: &CLike) -> bool { !self.eq(other) } +} + +#[auto_serialize2] +type Spanned = {lo: uint, hi: uint, node: T}; + +impl Spanned : cmp::Eq { + pure fn eq(other: &Spanned) -> bool { + self.lo == other.lo && self.hi == other.hi && self.node == other.node + } + pure fn ne(other: &Spanned) -> bool { !self.eq(other) } +} + +#[auto_serialize2] +type SomeRec = {v: ~[uint]}; + +#[auto_serialize2] +enum AnEnum = SomeRec; + +#[auto_serialize2] +type Point = {x: uint, y: uint}; + +#[auto_serialize2] +enum Quark { + Top(T), + Bottom(T) +} + +#[auto_serialize2] +enum CLike { A, B, C } + +fn main() { + test_ser_and_deser({lo: 0u, hi: 5u, node: 22u}, + ~"{lo: 0u, hi: 5u, node: 22u}"); + + test_ser_and_deser(AnEnum({v: ~[1u, 2u, 3u]}), + ~"AnEnum({v: [1u, 2u, 3u]})"); + + test_ser_and_deser({x: 3u, y: 5u}, ~"{x: 3u, y: 5u}"); + + test_ser_and_deser(~[1u, 2u, 3u], ~"[1u, 2u, 3u]"); + + test_ser_and_deser(Top(22u), ~"Top(22u)"); + test_ser_and_deser(Bottom(222u), ~"Bottom(222u)"); + + test_ser_and_deser(A, ~"A"); + test_ser_and_deser(B, ~"B"); +} diff --git a/src/test/run-pass/issue-2804.rs b/src/test/run-pass/issue-2804.rs index 9088f6e3584c4..7ef4ef225604e 100644 --- a/src/test/run-pass/issue-2804.rs +++ b/src/test/run-pass/issue-2804.rs @@ -1,6 +1,7 @@ extern mod std; use io::WriterUtil; use std::map::HashMap; +use std::json; enum object { @@ -8,13 +9,13 @@ enum object int_value(i64), } -fn lookup(table: std::map::HashMap<~str, std::json::Json>, key: ~str, default: ~str) -> ~str +fn lookup(table: ~json::Object, key: ~str, default: ~str) -> ~str { - match table.find(key) + match table.find(&key) { option::Some(std::json::String(s)) => { - *s + s } option::Some(value) => { @@ -32,7 +33,7 @@ fn add_interface(store: int, managed_ip: ~str, data: std::json::Json) -> (~str, { match data { - std::json::Dict(interface) => + std::json::Object(interface) => { let name = lookup(interface, ~"ifDescr", ~""); let label = fmt!("%s-%s", managed_ip, name); @@ -53,7 +54,7 @@ fn add_interfaces(store: int, managed_ip: ~str, device: std::map::HashMap<~str, { std::json::List(interfaces) => { - do vec::map(*interfaces) |interface| { + do vec::map(interfaces) |interface| { add_interface(store, managed_ip, *interface) } }