diff options
| -rw-r--r-- | src/libcore/option.rs | 30 | ||||
| -rw-r--r-- | src/librustpkg/rustpkg.rc | 84 | ||||
| -rw-r--r-- | src/librustpkg/util.rs | 437 | ||||
| -rw-r--r-- | src/libstd/semver.rs | 364 |
4 files changed, 394 insertions, 521 deletions
diff --git a/src/libcore/option.rs b/src/libcore/option.rs index a90364c7d8c..13d4ec6e10d 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -41,7 +41,7 @@ let unwrapped_msg = match msg { */ -use cmp::Eq; +use cmp::{Eq,Ord}; use kinds::Copy; use option; use ptr; @@ -56,6 +56,34 @@ pub enum Option<T> { Some(T), } +pub impl<T:Ord> Ord for Option<T> { + pure fn lt(&self, other: &Option<T>) -> bool { + match (self, other) { + (&None, &None) => false, + (&None, &Some(_)) => true, + (&Some(_), &None) => false, + (&Some(ref a), &Some(ref b)) => *a < *b + } + } + + pure fn le(&self, other: &Option<T>) -> bool { + match (self, other) { + (&None, &None) => true, + (&None, &Some(_)) => true, + (&Some(_), &None) => false, + (&Some(ref a), &Some(ref b)) => *a <= *b + } + } + + pure fn ge(&self, other: &Option<T>) -> bool { + ! (self < other) + } + + pure fn gt(&self, other: &Option<T>) -> bool { + ! (self <= other) + } +} + #[inline(always)] pub pure fn get<T: Copy>(opt: Option<T>) -> T { /*! diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rc index 1d537976e5f..5b610bbb1f8 100644 --- a/src/librustpkg/rustpkg.rc +++ b/src/librustpkg/rustpkg.rc @@ -20,6 +20,8 @@ #[allow(vecs_implicitly_copyable, non_implicitly_copyable_typarams)]; +#[legacy_records]; + extern mod core(vers = "0.6"); extern mod std(vers = "0.6"); extern mod rustc(vers = "0.6"); @@ -29,10 +31,11 @@ use core::*; use io::{ReaderUtil, WriterUtil}; use std::{json, semver, getopts}; use std::net::url; -use send_map::linear::LinearMap; +use hashmap::linear::LinearMap; use rustc::metadata::filesearch; use rustc::driver::{driver, session}; use syntax::{ast, attr, codemap, diagnostic, parse, visit}; +use syntax::codemap::spanned; mod usage; mod util; @@ -83,7 +86,7 @@ impl PackageScript { for mis.each |a| { match a.node { - ast::meta_name_value(v, ast::spanned { + ast::meta_name_value(v, spanned { node: ast::lit_str(s), span: _}) => { match v { @@ -106,7 +109,7 @@ impl PackageScript { for mis.each |a| { match a.node { - ast::meta_name_value(v, ast::spanned { + ast::meta_name_value(v, spanned { node: ast::lit_str(s), span: _}) => { match v { @@ -127,7 +130,7 @@ impl PackageScript { for mis.each |a| { match a.node { - ast::meta_name_value(v, ast::spanned { + ast::meta_name_value(v, spanned { node: ast::lit_str(s), span: _}) => { match v { @@ -156,7 +159,7 @@ impl PackageScript { let (u, t) = load_pkg_dep_attr(mis); if u.is_none() { - fail ~"pkg_dep attr without a url value"; + fail!(~"pkg_dep attr without a url value"); } deps.push((u.get(), t)); @@ -165,7 +168,7 @@ impl PackageScript { let f = load_pkg_crate_attr(mis); if f.is_none() { - fail ~"pkg_file attr without a file value"; + fail!(~"pkg_file attr without a file value"); } crates.push(f.get()); @@ -222,7 +225,7 @@ impl PackageScript { // Build the bootstrap and run a command // FIXME (#4432): Use workcache to only compile the script when changed - fn run(cmd: ~str, test: bool) -> int { + fn run(&self, cmd: ~str, test: bool) -> int { let work_dir = self.work_dir(); let input = self.input; let sess = self.sess; @@ -238,12 +241,12 @@ impl PackageScript { run::run_program(exe.to_str(), ~[root.to_str(), cmd, test.to_str()]) } - fn hash() -> ~str { + fn hash(&self) -> ~str { fmt!("%s-%s-%s", self.name, util::hash(self.id + self.vers.to_str()), self.vers.to_str()) } - fn work_dir() -> Path { + fn work_dir(&self) -> Path { util::root().push(~"work").push(self.hash()) } } @@ -255,7 +258,7 @@ struct Ctx { } impl Ctx { - fn run(cmd: ~str, args: ~[~str]) { + fn run(&self, cmd: ~str, args: ~[~str]) { let root = util::root(); util::need_dir(&root); @@ -333,11 +336,11 @@ impl Ctx { self.unprefer(name.get(), vers); } - _ => fail ~"reached an unhandled command" + _ => fail!(~"reached an unhandled command") } } - fn do_cmd(cmd: ~str) -> bool { + fn do_cmd(&self, cmd: ~str) -> bool { match cmd { ~"build" | ~"test" => { util::error(~"that command cannot be manually called"); @@ -367,7 +370,7 @@ impl Ctx { status == 0 } - fn build(dir: &Path, verbose: bool, opt: bool, + fn build(&self, dir: &Path, verbose: bool, opt: bool, test: bool) -> Option<PackageScript> { let cwd = &os::getcwd(); let script = match PackageScript::parse(dir) { @@ -450,12 +453,12 @@ impl Ctx { Some(script) } - fn compile(crate: &Path, dir: &Path, flags: ~[~str], + fn compile(&self, crate: &Path, dir: &Path, flags: ~[~str], cfgs: ~[~str], opt: bool, test: bool) -> bool { util::compile_crate(None, crate, dir, flags, cfgs, opt, test) } - fn clean() -> bool { + fn clean(&self) -> bool { let script = match PackageScript::parse(&os::getcwd()) { result::Ok(script) => script, result::Err(err) => { @@ -480,23 +483,24 @@ impl Ctx { true } - fn info() { + fn info(&self) { if self.json { match PackageScript::parse(&os::getcwd()) { result::Ok(script) => { - let mut map = ~LinearMap(); + let mut map = ~LinearMap::new(); map.insert(~"id", json::String(script.id)); map.insert(~"name", json::String(script.name)); map.insert(~"vers", json::String(script.vers.to_str())); map.insert(~"deps", json::List(do script.deps.map |&dep| { let (url, target) = dep; - let mut inner = ~LinearMap(); + let mut inner = ~LinearMap::new(); inner.insert(~"url", json::String(url)); if !target.is_none() { - inner.insert(~"target", json::String(target.get())); + inner.insert(~"target", + json::String(target.get())); } json::Object(inner) @@ -519,7 +523,12 @@ impl Ctx { util::note(fmt!("id: %s", script.id)); util::note(fmt!("name: %s", script.name)); util::note(fmt!("vers: %s", script.vers.to_str())); - util::note(fmt!("deps: %s", if script.deps.len() > 0 { ~"" } else { ~"none" })); + util::note(fmt!("deps: %s", + if script.deps.len() > 0 { + ~"" + } else { + ~"none" + })); for script.deps.each |&dep| { let (url, target) = dep; @@ -532,7 +541,8 @@ impl Ctx { } } - fn install(url: Option<~str>, target: Option<~str>, cache: bool) -> bool { + fn install(&self, url: Option<~str>, + target: Option<~str>, cache: bool) -> bool { let mut success; let mut dir; @@ -608,7 +618,7 @@ impl Ctx { true } - fn fetch(dir: &Path, url: ~str, target: Option<~str>) -> bool { + fn fetch(&self, dir: &Path, url: ~str, target: Option<~str>) -> bool { let url = if str::find_str(url, "://").is_none() { ~"http://" + url } else { url }; @@ -641,7 +651,7 @@ impl Ctx { } } - fn fetch_curl(dir: &Path, url: ~str) -> bool { + fn fetch_curl(&self, dir: &Path, url: ~str) -> bool { util::note(fmt!("fetching from %s using curl", url)); let tar = dir.dir_path().push(&dir.file_path().to_str() + ~".tar"); @@ -666,7 +676,7 @@ impl Ctx { true } - fn fetch_git(dir: &Path, url: ~str, target: Option<~str>) -> bool { + fn fetch_git(&self, dir: &Path, url: ~str, target: Option<~str>) -> bool { util::note(fmt!("fetching from %s using git", url)); // Git can't clone into a non-empty directory @@ -698,7 +708,7 @@ impl Ctx { true } - fn prefer(id: ~str, vers: Option<~str>) -> bool { + fn prefer(&self, id: ~str, vers: Option<~str>) -> bool { let package = match util::get_pkg(id, vers) { result::Ok(package) => package, result::Err(err) => { @@ -735,7 +745,7 @@ impl Ctx { true } - fn test() -> bool { + fn test(&self) -> bool { let script = match self.build(&os::getcwd(), false, false, true) { Some(script) => script, None => { @@ -773,7 +783,7 @@ impl Ctx { true } - fn uninstall(id: ~str, vers: Option<~str>) -> bool { + fn uninstall(&self, id: ~str, vers: Option<~str>) -> bool { let package = match util::get_pkg(id, vers) { result::Ok(package) => package, result::Err(err) => { @@ -812,7 +822,7 @@ impl Ctx { true } - fn unprefer(id: ~str, vers: Option<~str>) -> bool { + fn unprefer(&self, id: ~str, vers: Option<~str>) -> bool { let package = match util::get_pkg(id, vers) { result::Ok(package) => package, result::Err(err) => { @@ -904,7 +914,7 @@ pub fn main() { Ctx { cfgs: cfgs, json: json, - mut dep_cache: LinearMap() + mut dep_cache: LinearMap::new() }.run(cmd, args); } @@ -942,31 +952,31 @@ pub fn run(listeners: ~[Listener]) { } pub impl Crate { - pub fn flag(flag: ~str) -> Crate { + pub fn flag(&self, flag: ~str) -> Crate { Crate { flags: vec::append(copy self.flags, ~[flag]), - .. copy self + .. copy *self } } - pub fn flags(flags: ~[~str]) -> Crate { + pub fn flags(&self, flags: ~[~str]) -> Crate { Crate { flags: vec::append(copy self.flags, flags), - .. copy self + .. copy *self } } - pub fn cfg(cfg: ~str) -> Crate { + pub fn cfg(&self, cfg: ~str) -> Crate { Crate { cfgs: vec::append(copy self.cfgs, ~[cfg]), - .. copy self + .. copy *self } } - pub fn cfgs(cfgs: ~[~str]) -> Crate { + pub fn cfgs(&self, cfgs: ~[~str]) -> Crate { Crate { cfgs: vec::append(copy self.cfgs, cfgs), - .. copy self + .. copy *self } } } diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index e19eb5e41d8..1ad706742a8 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -9,17 +9,20 @@ // except according to those terms. use core::*; -use send_map::linear::LinearMap; +use hashmap::linear::LinearMap; use rustc::metadata::filesearch; use rustc::driver::{driver, session}; use syntax::ast_util::*; use syntax::{ast, attr, codemap, diagnostic, fold, parse, visit}; -use codemap::span; +use codemap::{span, dummy_sp, spanned}; use std::semver; use std::{json, term, sort, getopts}; use getopts::groups::getopts; use Listener; +use syntax::ext::base::{mk_ctxt, ext_ctxt}; +use syntax::ext::build; + pub struct Package { id: ~str, vers: semver::Version, @@ -30,7 +33,7 @@ pub struct Package { pub fn root() -> Path { match filesearch::get_rustpkg_root() { result::Ok(path) => path, - result::Err(err) => fail err + result::Err(err) => fail!(err) } } @@ -59,23 +62,6 @@ pub fn parse_name(id: ~str) -> result::Result<~str, ~str> { result::Ok(parts.last()) } -fn mk_rustpkg_use(ctx: @ReadyCtx) -> @ast::view_item { - let vers = ast::lit_str(@~"0.6"); - let vers = no_span(vers); - let mi = ast::meta_name_value(~"vers", vers); - let mi = no_span(mi); - let vi = ast::view_item_use(ctx.sess.ident_of(~"rustpkg"), - ~[@mi], - ctx.sess.next_node_id()); - - @ast::view_item { - node: vi, - attrs: ~[], - vis: ast::private, - span: dummy_sp() - } -} - struct ListenerFn { cmds: ~[~str], span: codemap::span, @@ -85,11 +71,12 @@ struct ListenerFn { struct ReadyCtx { sess: session::Session, crate: @ast::crate, + ext_cx: ext_ctxt, mut path: ~[ast::ident], mut fns: ~[ListenerFn] } -fn fold_mod(ctx: @ReadyCtx, m: ast::_mod, +fn fold_mod(_ctx: @ReadyCtx, m: ast::_mod, fold: fold::ast_fold) -> ast::_mod { fn strip_main(item: @ast::item) -> @ast::item { @ast::item { @@ -101,23 +88,13 @@ fn fold_mod(ctx: @ReadyCtx, m: ast::_mod, } fold::noop_fold_mod(ast::_mod { - view_items: vec::append_one(m.view_items, mk_rustpkg_use(ctx)), items: do vec::map(m.items) |item| { strip_main(*item) - } + }, + .. m }, fold) } -fn fold_crate(ctx: @ReadyCtx, crate: ast::crate_, - fold: fold::ast_fold) -> ast::crate_ { - let folded = fold::noop_fold_crate(crate, fold); - - ast::crate_ { - module: add_pkg_module(ctx, /*bad*/copy folded.module), - .. folded - } -} - fn fold_item(ctx: @ReadyCtx, item: @ast::item, fold: fold::ast_fold) -> Option<@ast::item> { @@ -156,315 +133,50 @@ fn fold_item(ctx: @ReadyCtx, item: @ast::item, res } -fn mk_rustpkg_import(ctx: @ReadyCtx) -> @ast::view_item { - let path = @ast::path { - span: dummy_sp(), - global: false, - idents: ~[ctx.sess.ident_of(~"rustpkg")], - rp: None, - types: ~[] - }; - let vp = @no_span(ast::view_path_simple(ctx.sess.ident_of(~"rustpkg"), - path, ast::type_value_ns, - ctx.sess.next_node_id())); - - @ast::view_item { - node: ast::view_item_import(~[vp]), - attrs: ~[], - vis: ast::private, - span: dummy_sp() - } -} - fn add_pkg_module(ctx: @ReadyCtx, m: ast::_mod) -> ast::_mod { - let listeners = mk_listeners(ctx); - let main = mk_main(ctx); - let pkg_mod = @ast::_mod { - view_items: ~[mk_rustpkg_import(ctx)], - items: ~[main, listeners] - }; - let resolve_unexported_attr = - attr::mk_attr(attr::mk_word_item(~"!resolve_unexported")); - let item_ = ast::item_mod(*pkg_mod); - let item = @ast::item { - ident: ctx.sess.ident_of(~"__pkg"), - attrs: ~[resolve_unexported_attr], - id: ctx.sess.next_node_id(), - node: item_, - vis: ast::public, - span: dummy_sp(), - }; - + let listeners = mk_listener_vec(ctx); + let ext_cx = ctx.ext_cx; + let item = quote_item! ( + mod __pkg { + extern mod rustpkg (vers="0.6"); + const listeners : &[rustpkg::Listener] = $listeners; + #[main] + fn main() { + rustpkg::run(listeners); + } + } + ); ast::_mod { - items: vec::append_one(/*bad*/copy m.items, item), + items: vec::append_one(/*bad*/copy m.items, item.get()), .. m } } -fn no_span<T: Copy>(t: T) -> ast::spanned<T> { - ast::spanned { - node: t, - span: dummy_sp() - } -} - -fn path_node(ids: ~[ast::ident]) -> @ast::path { - @ast::path { - span: dummy_sp(), - global: false, - idents: ids, - rp: None, - types: ~[] - } -} - -fn path_node_global(ids: ~[ast::ident]) -> @ast::path { - @ast::path { - span: dummy_sp(), - global: true, - idents: ids, - rp: None, - types: ~[] - } -} - -fn mk_listeners(ctx: @ReadyCtx) -> @ast::item { - let ret_ty = mk_listener_vec_ty(ctx); - let decl = ast::fn_decl { - inputs: ~[], - output: ret_ty, - cf: ast::return_val - }; - let listeners = mk_listener_vec(ctx); - let body_ = default_block(~[], option::Some(listeners), - ctx.sess.next_node_id()); - let body = no_span(body_); - let item_ = ast::item_fn(decl, ast::impure_fn, ~[], body); - - @ast::item { - ident: ctx.sess.ident_of(~"listeners"), - attrs: ~[], - id: ctx.sess.next_node_id(), - node: item_, - vis: ast::public, - span: dummy_sp(), - } -} - -fn mk_path(ctx: @ReadyCtx, path: ~[ast::ident]) -> @ast::path { - path_node(~[ctx.sess.ident_of(~"rustpkg")] + path) -} - -fn mk_listener_vec_ty(ctx: @ReadyCtx) -> @ast::Ty { - let listener_ty_path = mk_path(ctx, ~[ctx.sess.ident_of(~"Listener")]); - let listener_ty = ast::Ty { - id: ctx.sess.next_node_id(), - node: ast::ty_path(listener_ty_path, - ctx.sess.next_node_id()), - span: dummy_sp() - }; - let vec_mt = ast::mt { - ty: @listener_ty, - mutbl: ast::m_imm - }; - let inner_ty = @ast::Ty { - id: ctx.sess.next_node_id(), - node: ast::ty_vec(vec_mt), - span: dummy_sp() - }; - - @ast::Ty { - id: ctx.sess.next_node_id(), - node: ast::ty_uniq(ast::mt { - ty: inner_ty, - mutbl: ast::m_imm - }), - span: dummy_sp() - } -} - fn mk_listener_vec(ctx: @ReadyCtx) -> @ast::expr { let fns = ctx.fns; - let descs = do fns.map |listener| { mk_listener_rec(ctx, *listener) }; - let inner_expr = @ast::expr { - id: ctx.sess.next_node_id(), - callee_id: ctx.sess.next_node_id(), - node: ast::expr_vec(descs, ast::m_imm), - span: dummy_sp() - }; - - @ast::expr { - id: ctx.sess.next_node_id(), - callee_id: ctx.sess.next_node_id(), - node: ast::expr_vstore(inner_expr, ast::expr_vstore_uniq), - span: dummy_sp() - } + build::mk_slice_vec_e(ctx.ext_cx, dummy_sp(), descs) } fn mk_listener_rec(ctx: @ReadyCtx, listener: ListenerFn) -> @ast::expr { + let span = listener.span; - let path = /*bad*/copy listener.path; - let descs = do listener.cmds.map |&cmd| { - let inner = @ast::expr { - id: ctx.sess.next_node_id(), - callee_id: ctx.sess.next_node_id(), - node: ast::expr_lit(@no_span(ast::lit_str(@cmd))), - span: span - }; - - @ast::expr { - id: ctx.sess.next_node_id(), - callee_id: ctx.sess.next_node_id(), - node: ast::expr_vstore(inner, ast::expr_vstore_uniq), - span: dummy_sp() - } - }; - let cmd_expr_inner = @ast::expr { - id: ctx.sess.next_node_id(), - callee_id: ctx.sess.next_node_id(), - node: ast::expr_vec(descs, ast::m_imm), - span: dummy_sp() - }; - let cmd_expr = ast::expr { - id: ctx.sess.next_node_id(), - callee_id: ctx.sess.next_node_id(), - node: ast::expr_vstore(cmd_expr_inner, ast::expr_vstore_uniq), - span: dummy_sp() - }; - let cmd_field = no_span(ast::field_ { - mutbl: ast::m_imm, - ident: ctx.sess.ident_of(~"cmds"), - expr: @cmd_expr, - }); - - let cb_path = path_node_global(path); - let cb_expr = ast::expr { - id: ctx.sess.next_node_id(), - callee_id: ctx.sess.next_node_id(), - node: ast::expr_path(cb_path), - span: span + let cmds = do listener.cmds.map |&cmd| { + build::mk_base_str(ctx.ext_cx, span, cmd) }; - let cb_wrapper_expr = mk_fn_wrapper(ctx, cb_expr, span); - let cb_field = no_span(ast::field_ { - mutbl: ast::m_imm, - ident: ctx.sess.ident_of(~"cb"), - expr: cb_wrapper_expr - }); - - let listener_path = mk_path(ctx, ~[ctx.sess.ident_of(~"Listener")]); - let listener_rec_ = ast::expr_struct(listener_path, - ~[cmd_field, cb_field], - option::None); - @ast::expr { - id: ctx.sess.next_node_id(), - callee_id: ctx.sess.next_node_id(), - node: listener_rec_, - span: span - } -} -fn mk_fn_wrapper(ctx: @ReadyCtx, fn_path_expr: ast::expr, - span: span) -> @ast::expr { - let call_expr = ast::expr { - id: ctx.sess.next_node_id(), - callee_id: ctx.sess.next_node_id(), - node: ast::expr_call(@fn_path_expr, ~[], false), - span: span - }; - let call_stmt = no_span(ast::stmt_semi(@call_expr, - ctx.sess.next_node_id())); - let wrapper_decl = ast::fn_decl { - inputs: ~[], - output: @ast::Ty { - id: ctx.sess.next_node_id(), - node: ast::ty_nil, span: span - }, - cf: ast::return_val - }; - let wrapper_body = no_span(ast::blk_ { - view_items: ~[], - stmts: ~[@call_stmt], - expr: option::None, - id: ctx.sess.next_node_id(), - rules: ast::default_blk - }); - - @ast::expr { - id: ctx.sess.next_node_id(), - callee_id: ctx.sess.next_node_id(), - node: ast::expr_fn(ast::ProtoBare, wrapper_decl, - wrapper_body, @~[]), - span: span - } -} + let cmds_expr = build::mk_slice_vec_e(ctx.ext_cx, span, cmds); + let cb_expr = build::mk_path(ctx.ext_cx, span, copy listener.path); + let ext_cx = ctx.ext_cx; -fn mk_main(ctx: @ReadyCtx) -> @ast::item { - let ret_ty = ast::Ty { - id: ctx.sess.next_node_id(), - node: ast::ty_nil, - span: dummy_sp() - }; - let decl = ast::fn_decl { - inputs: ~[], - output: @ret_ty, - cf: ast::return_val - }; - let run_call_expr = mk_run_call(ctx); - let body_ = default_block(~[], option::Some(run_call_expr), - ctx.sess.next_node_id()); - let body = ast::spanned { - node: body_, - span: dummy_sp() - }; - let item_ = ast::item_fn(decl, ast::impure_fn, ~[], body); - - @ast::item { - ident: ctx.sess.ident_of(~"main"), - attrs: ~[attr::mk_attr(attr::mk_word_item(~"main"))], - id: ctx.sess.next_node_id(), - node: item_, - vis: ast::public, - span: dummy_sp(), - } -} - -fn mk_run_call(ctx: @ReadyCtx) -> @ast::expr { - let listener_path = path_node(~[ctx.sess.ident_of(~"listeners")]); - let listener_path_expr_ = ast::expr_path(listener_path); - let listener_path_expr = ast::expr { - id: ctx.sess.next_node_id(), - callee_id: ctx.sess.next_node_id(), - node: listener_path_expr_, - span: dummy_sp() - }; - let listener_call_expr_ = ast::expr_call(@listener_path_expr, ~[], false); - let listener_call_expr = ast::expr { - id: ctx.sess.next_node_id(), - callee_id: ctx.sess.next_node_id(), - node: listener_call_expr_, - span: dummy_sp() - }; - let rustpkg_run_path = mk_path(ctx, ~[ctx.sess.ident_of(~"run")]); - - let rustpkg_run_path_expr_ = ast::expr_path(rustpkg_run_path); - let rustpkg_run_path_expr = ast::expr { - id: ctx.sess.next_node_id(), - callee_id: ctx.sess.next_node_id(), - node: rustpkg_run_path_expr_, - span: dummy_sp() - }; - let rustpkg_run_call_expr_ = ast::expr_call(@rustpkg_run_path_expr, - ~[@listener_call_expr], - false); - @ast::expr { - id: ctx.sess.next_node_id(), - callee_id: ctx.sess.next_node_id(), - node: rustpkg_run_call_expr_, - span: dummy_sp() - } + quote_expr!( + Listener { + cmds: $cmds_expr, + cb: $cb_expr + } + ) } /// Generate/filter main function, add the list of commands, etc. @@ -473,11 +185,12 @@ pub fn ready_crate(sess: session::Session, let ctx = @ReadyCtx { sess: sess, crate: crate, + ext_cx: mk_ctxt(sess.parse_sess, copy sess.opts.cfg), mut path: ~[], mut fns: ~[] }; let precursor = @fold::AstFoldFns { - fold_crate: fold::wrap(|a, b| fold_crate(ctx, a, b)), + // fold_crate: fold::wrap(|a, b| fold_crate(ctx, a, b)), fold_item: |a, b| fold_item(ctx, a, b), fold_mod: |a, b| fold_mod(ctx, a, b), .. *fold::default_ast_fold() @@ -497,7 +210,7 @@ pub fn parse_vers(vers: ~str) -> result::Result<semver::Version, ~str> { pub fn need_dir(s: &Path) { if !os::path_is_dir(s) && !os::make_dir(s, 493_i32) { - fail fmt!("can't create dir: %s", s.to_str()); + fail!(fmt!("can't create dir: %s", s.to_str())); } } @@ -509,7 +222,9 @@ pub fn note(msg: ~str) { out.write_str(~"note: "); term::reset(out); out.write_line(msg); - } else { out.write_line(~"note: " + msg); } + } else { + out.write_line(~"note: " + msg); + } } pub fn warn(msg: ~str) { @@ -520,7 +235,9 @@ pub fn warn(msg: ~str) { out.write_str(~"warning: "); term::reset(out); out.write_line(msg); - }else { out.write_line(~"warning: " + msg); } + } else { + out.write_line(~"warning: " + msg); + } } pub fn error(msg: ~str) { @@ -531,8 +248,9 @@ pub fn error(msg: ~str) { out.write_str(~"error: "); term::reset(out); out.write_line(msg); + } else { + out.write_line(~"error: " + msg); } - else { out.write_line(~"error: " + msg); } } pub fn hash(data: ~str) -> ~str { @@ -590,13 +308,13 @@ pub fn wait_for_lock(path: &Path) { fn _add_pkg(packages: ~[json::Json], pkg: &Package) -> ~[json::Json] { for packages.each |&package| { - match package { - json::Object(map) => { + match &package { + &json::Object(ref map) => { let mut has_id = false; match map.get(&~"id") { - json::String(str) => { - if pkg.id == str { + &json::String(ref str) => { + if pkg.id == *str { has_id = true; } } @@ -604,9 +322,9 @@ fn _add_pkg(packages: ~[json::Json], pkg: &Package) -> ~[json::Json] { } match map.get(&~"vers") { - json::String(str) => { - if has_id && pkg.vers.to_str() == str { - return packages; + &json::String(ref str) => { + if has_id && pkg.vers.to_str() == *str { + return copy packages; } } _ => {} @@ -616,7 +334,7 @@ fn _add_pkg(packages: ~[json::Json], pkg: &Package) -> ~[json::Json] { } } - let mut map = ~LinearMap(); + let mut map = ~LinearMap::new(); map.insert(~"id", json::String(pkg.id)); map.insert(~"vers", json::String(pkg.vers.to_str())); @@ -631,13 +349,13 @@ fn _add_pkg(packages: ~[json::Json], pkg: &Package) -> ~[json::Json] { } fn _rm_pkg(packages: ~[json::Json], pkg: &Package) -> ~[json::Json] { - do packages.filter_map |&package| { - match package { - json::Object(map) => { + do packages.filter_mapped |&package| { + match &package { + &json::Object(ref map) => { let mut has_id = false; match map.get(&~"id") { - json::String(str) => { + &json::String(str) => { if pkg.id == str { has_id = true; } @@ -646,14 +364,17 @@ fn _rm_pkg(packages: ~[json::Json], pkg: &Package) -> ~[json::Json] { } match map.get(&~"vers") { - json::String(str) => { - if has_id && pkg.vers.to_str() == str { None } - else { Some(package) } + &json::String(ref str) => { + if has_id && pkg.vers.to_str() == *str { + None + } else { + Some(copy package) + } } - _ => { Some(package) } + _ => { Some(copy package) } } } - _ => { Some(package) } + _ => { Some(copy package) } } } } @@ -722,7 +443,7 @@ pub fn get_pkg(id: ~str, match package { json::Object(map) => { let pid = match map.get(&~"id") { - json::String(str) => str, + &json::String(str) => str, _ => loop }; let pname = match parse_name(pid) { @@ -734,12 +455,12 @@ pub fn get_pkg(id: ~str, } }; let pvers = match map.get(&~"vers") { - json::String(str) => str, + &json::String(str) => str, _ => loop }; if pid == id || pname == name { let bins = match map.get(&~"bins") { - json::List(list) => { + &json::List(ref list) => { do list.map |&bin| { match bin { json::String(str) => str, @@ -750,7 +471,7 @@ pub fn get_pkg(id: ~str, _ => ~[] }; let libs = match map.get(&~"libs") { - json::List(list) => { + &json::List(ref list) => { do list.map |&lib| { match lib { json::String(str) => str, @@ -916,7 +637,7 @@ pub fn compile_input(sysroot: Option<Path>, input: driver::input, dir: &Path, for mis.each |a| { match a.node { - ast::meta_name_value(v, ast::spanned {node: ast::lit_str(s), + ast::meta_name_value(v, spanned {node: ast::lit_str(s), span: _}) => { match v { ~"name" => name = Some(*s), @@ -934,7 +655,7 @@ pub fn compile_input(sysroot: Option<Path>, input: driver::input, dir: &Path, for crate.node.attrs.each |a| { match a.node.value.node { - ast::meta_name_value(v, ast::spanned {node: ast::lit_str(s), + ast::meta_name_value(v, spanned {node: ast::lit_str(s), span: _}) => { match v { ~"crate_type" => crate_type = Some(*s), @@ -1051,11 +772,13 @@ pub fn link_exe(_src: &Path, _dest: &Path) -> bool { #[cfg(target_os = "android")] #[cfg(target_os = "freebsd")] #[cfg(target_os = "macos")] -pub fn link_exe(src: &Path, dest: &Path) -> bool unsafe { - do str::as_c_str(src.to_str()) |src_buf| { - do str::as_c_str(dest.to_str()) |dest_buf| { - libc::link(src_buf, dest_buf) == 0 as libc::c_int && - libc::chmod(dest_buf, 755) == 0 as libc::c_int +pub fn link_exe(src: &Path, dest: &Path) -> bool { + unsafe { + do str::as_c_str(src.to_str()) |src_buf| { + do str::as_c_str(dest.to_str()) |dest_buf| { + libc::link(src_buf, dest_buf) == 0 as libc::c_int && + libc::chmod(dest_buf, 755) == 0 as libc::c_int + } } } } diff --git a/src/libstd/semver.rs b/src/libstd/semver.rs index 9de336437d2..97c60330a7e 100644 --- a/src/libstd/semver.rs +++ b/src/libstd/semver.rs @@ -19,169 +19,220 @@ use to_str::ToStr; use char; use core::cmp; +#[deriving_eq] +pub enum Identifier { + Numeric(uint), + AlphaNumeric(~str) +} + +impl cmp::Ord for Identifier { + #[inline(always)] + pure fn lt(&self, other: &Identifier) -> bool { + match (self, other) { + (&Numeric(a), &Numeric(b)) => a < b, + (&Numeric(_), _) => true, + (&AlphaNumeric(ref a), &AlphaNumeric(ref b)) => *a < *b, + (&AlphaNumeric(_), _) => false + } + } + #[inline(always)] + pure fn le(&self, other: &Identifier) -> bool { + ! (other < self) + } + #[inline(always)] + pure fn gt(&self, other: &Identifier) -> bool { + other < self + } + #[inline(always)] + pure fn ge(&self, other: &Identifier) -> bool { + ! (self < other) + } +} + +impl ToStr for Identifier { + #[inline(always)] + pure fn to_str(&self) -> ~str { + match self { + &Numeric(n) => n.to_str(), + &AlphaNumeric(ref s) => s.to_str() + } + } +} + + +#[deriving_eq] pub struct Version { major: uint, minor: uint, patch: uint, - tag: Option<~str>, + pre: ~[Identifier], + build: ~[Identifier], } -impl Version: ToStr { +impl ToStr for Version { #[inline(always)] - pure fn to_str() -> ~str { - let suffix = match copy self.tag { - Some(tag) => ~"-" + tag, - None => ~"" + pure fn to_str(&self) -> ~str { + let s = fmt!("%u.%u.%u", self.major, self.minor, self.patch); + let s = if self.pre.is_empty() { + s + } else { + s + "-" + str::connect(self.pre.map(|i| i.to_str()), ".") }; - - fmt!("%u.%u.%u%s", self.major, self.minor, self.patch, suffix) + if self.build.is_empty() { + s + } else { + s + "+" + str::connect(self.build.map(|i| i.to_str()), ".") + } } } -impl Version: cmp::Ord { +impl cmp::Ord for Version { #[inline(always)] pure fn lt(&self, other: &Version) -> bool { + self.major < other.major || - self.minor < other.minor || - self.patch < other.patch || - (match self.tag { - Some(stag) => match other.tag { - Some(otag) => stag < otag, - None => true - }, - None => false - }) + + (self.major == other.major && + self.minor < other.minor) || + + (self.major == other.major && + self.minor == other.minor && + self.patch < other.patch) || + + (self.major == other.major && + self.minor == other.minor && + self.patch == other.patch && + // NB: semver spec says 0.0.0-pre < 0.0.0 + // but the version of ord defined for vec + // says that [] < [pre], so we alter it + // here. + (match (self.pre.len(), other.pre.len()) { + (0, 0) => false, + (0, _) => false, + (_, 0) => true, + (_, _) => self.pre < other.pre + })) || + + (self.major == other.major && + self.minor == other.minor && + self.patch == other.patch && + self.pre == other.pre && + self.build < other.build) } + #[inline(always)] pure fn le(&self, other: &Version) -> bool { - self.major <= other.major || - self.minor <= other.minor || - self.patch <= other.patch || - (match self.tag { - Some(stag) => match other.tag { - Some(otag) => stag <= otag, - None => true - }, - None => false - }) + ! (other < self) } #[inline(always)] pure fn gt(&self, other: &Version) -> bool { - self.major > other.major || - self.minor > other.minor || - self.patch > other.patch || - (match self.tag { - Some(stag) => match other.tag { - Some(otag) => stag > otag, - None => false - }, - None => true - }) + other < self } #[inline(always)] pure fn ge(&self, other: &Version) -> bool { - self.major >= other.major || - self.minor >= other.minor || - self.patch >= other.patch || - (match self.tag { - Some(stag) => match other.tag { - Some(otag) => stag >= otag, - None => false - }, - None => true - }) + ! (self < other) } } -fn read_whitespace(rdr: io::Reader, ch: char) -> char { - let mut nch = ch; +condition! { + bad_parse: () -> (); +} - while char::is_whitespace(nch) { - nch = rdr.read_char(); +fn take_nonempty_prefix(rdr: io::Reader, + ch: char, + pred: fn(char) -> bool) -> (~str, char) { + let mut buf = ~""; + let mut ch = ch; + while pred(ch) { + str::push_char(&mut buf, ch); + ch = rdr.read_char(); } - - nch + if buf.is_empty() { + bad_parse::cond.raise(()) + } + debug!("extracted nonempty prefix: %s", buf); + (buf, ch) } -fn parse_reader(rdr: io::Reader) -> Option<(Version, char)> { - fn read_digits(rdr: io::Reader, ch: char) -> Option<(uint, char)> { - let mut buf = ~""; - let mut nch = ch; - - while nch != -1 as char { - match nch { - '0' .. '9' => buf += str::from_char(nch), - _ => break - } +fn take_num(rdr: io::Reader, ch: char) -> (uint, char) { + let (s, ch) = take_nonempty_prefix(rdr, ch, char::is_digit); + match uint::from_str(s) { + None => { bad_parse::cond.raise(()); (0, ch) }, + Some(i) => (i, ch) + } +} - nch = rdr.read_char(); +fn take_ident(rdr: io::Reader, ch: char) -> (Identifier, char) { + let (s,ch) = take_nonempty_prefix(rdr, ch, char::is_alphanumeric); + if s.all(char::is_digit) { + match uint::from_str(s) { + None => { bad_parse::cond.raise(()); (Numeric(0), ch) }, + Some(i) => (Numeric(i), ch) } + } else { + (AlphaNumeric(s), ch) + } +} - do uint::from_str(buf).chain_ref |&i| { - Some((i, nch)) - } +fn expect(ch: char, c: char) { + if ch != c { + bad_parse::cond.raise(()) } +} - fn read_tag(rdr: io::Reader) -> Option<(~str, char)> { - let mut ch = rdr.read_char(); - let mut buf = ~""; +fn parse_reader(rdr: io::Reader) -> Version { - while ch != -1 as char { - match ch { - '0' .. '9' | 'A' .. 'Z' | 'a' .. 'z' | '-' => { - buf += str::from_char(ch); - } - _ => break - } + let (major, ch) = take_num(rdr, rdr.read_char()); + expect(ch, '.'); + let (minor, ch) = take_num(rdr, rdr.read_char()); + expect(ch, '.'); + let (patch, ch) = take_num(rdr, rdr.read_char()); - ch = rdr.read_char(); - } + let mut pre = ~[]; + let mut build = ~[]; - if buf == ~"" { return None; } - else { Some((buf, ch)) } + let mut ch = ch; + if ch == '-' { + loop { + let (id, c) = take_ident(rdr, rdr.read_char()); + pre.push(id); + ch = c; + if ch != '.' { break; } + } } - let ch = read_whitespace(rdr, rdr.read_char()); - let (major, ch) = match read_digits(rdr, ch) { - None => return None, - Some(item) => item - }; - - if ch != '.' { return None; } - - let (minor, ch) = match read_digits(rdr, rdr.read_char()) { - None => return None, - Some(item) => item - }; - - if ch != '.' { return None; } - - let (patch, ch) = match read_digits(rdr, rdr.read_char()) { - None => return None, - Some(item) => item - }; - let (tag, ch) = if ch == '-' { - match read_tag(rdr) { - None => return None, - Some((tag, ch)) => (Some(tag), ch) + if ch == '+' { + loop { + let (id, c) = take_ident(rdr, rdr.read_char()); + build.push(id); + ch = c; + if ch != '.' { break; } } - } else { - (None, ch) - }; + } - Some((Version { major: major, minor: minor, patch: patch, tag: tag }, - ch)) + Version { + major: major, + minor: minor, + patch: patch, + pre: pre, + build: build, + } } -pub fn parse(s: &str) -> Option<Version> { - do io::with_str_reader(s) |rdr| { - do parse_reader(rdr).chain_ref |&item| { - let (version, ch) = item; - if read_whitespace(rdr, ch) != -1 as char { +pub fn parse(s: &str) -> Option<Version> { + if ! str::is_ascii(s) { + return None; + } + let s = s.trim(); + let mut bad = false; + do bad_parse::cond.trap(|_| { debug!("bad"); bad = true }).in { + do io::with_str_reader(s) |rdr| { + let v = parse_reader(rdr); + if bad || v.to_str() != s { None } else { - Some(version) + Some(v) } } } @@ -204,26 +255,68 @@ fn test_parse() { major: 1u, minor: 2u, patch: 3u, - tag: None, + pre: ~[], + build: ~[], }); assert parse(" 1.2.3 ") == Some(Version { major: 1u, minor: 2u, patch: 3u, - tag: None, + pre: ~[], + build: ~[], }); assert parse("1.2.3-alpha1") == Some(Version { major: 1u, minor: 2u, patch: 3u, - tag: Some("alpha1") + pre: ~[AlphaNumeric(~"alpha1")], + build: ~[] }); assert parse(" 1.2.3-alpha1 ") == Some(Version { major: 1u, minor: 2u, patch: 3u, - tag: Some("alpha1") + pre: ~[AlphaNumeric(~"alpha1")], + build: ~[] }); + assert parse("1.2.3+build5") == Some(Version { + major: 1u, + minor: 2u, + patch: 3u, + pre: ~[], + build: ~[AlphaNumeric(~"build5")] + }); + assert parse(" 1.2.3+build5 ") == Some(Version { + major: 1u, + minor: 2u, + patch: 3u, + pre: ~[], + build: ~[AlphaNumeric(~"build5")] + }); + assert parse("1.2.3-alpha1+build5") == Some(Version { + major: 1u, + minor: 2u, + patch: 3u, + pre: ~[AlphaNumeric(~"alpha1")], + build: ~[AlphaNumeric(~"build5")] + }); + assert parse(" 1.2.3-alpha1+build5 ") == Some(Version { + major: 1u, + minor: 2u, + patch: 3u, + pre: ~[AlphaNumeric(~"alpha1")], + build: ~[AlphaNumeric(~"build5")] + }); + assert parse("1.2.3-1.alpha1.9+build5.7.3aedf ") == Some(Version { + major: 1u, + minor: 2u, + patch: 3u, + pre: ~[Numeric(1),AlphaNumeric(~"alpha1"),Numeric(9)], + build: ~[AlphaNumeric(~"build5"), + Numeric(7), + AlphaNumeric(~"3aedf")] + }); + } #[test] @@ -245,9 +338,8 @@ fn test_lt() { assert parse("0.0.0") < parse("1.2.3-alpha2"); assert parse("1.0.0") < parse("1.2.3-alpha2"); assert parse("1.2.0") < parse("1.2.3-alpha2"); - assert parse("1.2.3") < parse("1.2.3-alpha2"); + assert parse("1.2.3-alpha1") < parse("1.2.3"); assert parse("1.2.3-alpha1") < parse("1.2.3-alpha2"); - assert !(parse("1.2.3-alpha2") < parse("1.2.3-alpha2")); } @@ -256,7 +348,6 @@ fn test_le() { assert parse("0.0.0") <= parse("1.2.3-alpha2"); assert parse("1.0.0") <= parse("1.2.3-alpha2"); assert parse("1.2.0") <= parse("1.2.3-alpha2"); - assert parse("1.2.3") <= parse("1.2.3-alpha2"); assert parse("1.2.3-alpha1") <= parse("1.2.3-alpha2"); assert parse("1.2.3-alpha2") <= parse("1.2.3-alpha2"); } @@ -266,9 +357,8 @@ fn test_gt() { assert parse("1.2.3-alpha2") > parse("0.0.0"); assert parse("1.2.3-alpha2") > parse("1.0.0"); assert parse("1.2.3-alpha2") > parse("1.2.0"); - assert parse("1.2.3-alpha2") > parse("1.2.3"); assert parse("1.2.3-alpha2") > parse("1.2.3-alpha1"); - + assert parse("1.2.3") > parse("1.2.3-alpha2"); assert !(parse("1.2.3-alpha2") > parse("1.2.3-alpha2")); } @@ -277,7 +367,29 @@ fn test_ge() { assert parse("1.2.3-alpha2") >= parse("0.0.0"); assert parse("1.2.3-alpha2") >= parse("1.0.0"); assert parse("1.2.3-alpha2") >= parse("1.2.0"); - assert parse("1.2.3-alpha2") >= parse("1.2.3"); assert parse("1.2.3-alpha2") >= parse("1.2.3-alpha1"); assert parse("1.2.3-alpha2") >= parse("1.2.3-alpha2"); } + +#[test] +fn test_spec_order() { + + let vs = ["1.0.0-alpha", + "1.0.0-alpha.1", + "1.0.0-beta.2", + "1.0.0-beta.11", + "1.0.0-rc.1", + "1.0.0-rc.1+build.1", + "1.0.0", + "1.0.0+0.3.7", + "1.3.7+build", + "1.3.7+build.2.b8f12d7", + "1.3.7+build.11.e0f985a"]; + let mut i = 1; + while i < vs.len() { + let a = parse(vs[i-1]).get(); + let b = parse(vs[i]).get(); + assert a < b; + i += 1; + } +} \ No newline at end of file |
