diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 301a49d8aec..9e11e8f9b37 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -176,6 +176,9 @@ pub fn phase_2_configure_and_expand(sess: Session, time(time_passes, "gated feature checking", (), |_| front::feature_gate::check_crate(sess, &crate)); + crate = time(time_passes, "crate injection", crate, |crate| + front::std_inject::maybe_inject_crates_ref(sess, crate)); + // strip before expansion to allow macros to depend on // configuration variables e.g/ in // @@ -183,10 +186,6 @@ pub fn phase_2_configure_and_expand(sess: Session, // mod bar { macro_rules! baz!(() => {{}}) } // // baz! should not use this definition unless foo is enabled. - crate = time(time_passes, "std macros injection", crate, |crate| - syntax::ext::expand::inject_std_macros(sess.parse_sess, - cfg.clone(), - crate)); crate = time(time_passes, "configuration 1", crate, |crate| front::config::strip_unconfigured_items(crate)); @@ -207,8 +206,8 @@ pub fn phase_2_configure_and_expand(sess: Session, crate = time(time_passes, "maybe building test harness", crate, |crate| front::test::modify_for_testing(sess, crate)); - crate = time(time_passes, "std injection", crate, |crate| - front::std_inject::maybe_inject_libstd_ref(sess, crate)); + crate = time(time_passes, "prelude injection", crate, |crate| + front::std_inject::maybe_inject_prelude(sess, crate)); time(time_passes, "assinging node ids and indexing ast", crate, |crate| front::assign_node_ids_and_map::assign_node_ids_and_map(sess, crate)) diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs index 6fa54061e34..71a82536aee 100644 --- a/src/librustc/front/std_inject.rs +++ b/src/librustc/front/std_inject.rs @@ -23,10 +23,18 @@ use syntax::util::small_vector::SmallVector; pub static VERSION: &'static str = "0.10-pre"; -pub fn maybe_inject_libstd_ref(sess: Session, crate: ast::Crate) +pub fn maybe_inject_crates_ref(sess: Session, crate: ast::Crate) -> ast::Crate { if use_std(&crate) { - inject_libstd_ref(sess, crate) + inject_crates_ref(sess, crate) + } else { + crate + } +} + +pub fn maybe_inject_prelude(sess: Session, crate: ast::Crate) -> ast::Crate { + if use_std(&crate) { + inject_prelude(sess, crate) } else { crate } @@ -44,13 +52,6 @@ fn no_prelude(attrs: &[ast::Attribute]) -> bool { attr::contains_name(attrs, "no_implicit_prelude") } -fn spanned(x: T) -> codemap::Spanned { - codemap::Spanned { - node: x, - span: DUMMY_SP, - } -} - struct StandardLibraryInjector { sess: Session, } @@ -71,7 +72,11 @@ impl fold::Folder for StandardLibraryInjector { node: ast::ViewItemExternMod(self.sess.ident_of("std"), with_version("std"), ast::DUMMY_NODE_ID), - attrs: ~[], + attrs: ~[ + attr::mk_attr(attr::mk_list_item(@"phase", + ~[attr::mk_word_item(@"syntax"), + attr::mk_word_item(@"link")])) + ], vis: ast::Inherited, span: DUMMY_SP }]; @@ -96,22 +101,43 @@ impl fold::Folder for StandardLibraryInjector { } vis.push_all(crate.module.view_items); - let mut new_module = ast::Mod { + let new_module = ast::Mod { view_items: vis, ..crate.module.clone() }; - if !no_prelude(crate.attrs) { - // only add `use std::prelude::*;` if there wasn't a - // `#[no_implicit_prelude];` at the crate level. - new_module = self.fold_mod(&new_module); - } - ast::Crate { module: new_module, ..crate } } +} + +fn inject_crates_ref(sess: Session, crate: ast::Crate) -> ast::Crate { + let mut fold = StandardLibraryInjector { + sess: sess, + }; + fold.fold_crate(crate) +} + +struct PreludeInjector { + sess: Session, +} + + +impl fold::Folder for PreludeInjector { + fn fold_crate(&mut self, crate: ast::Crate) -> ast::Crate { + if !no_prelude(crate.attrs) { + // only add `use std::prelude::*;` if there wasn't a + // `#[no_implicit_prelude];` at the crate level. + ast::Crate { + module: self.fold_mod(&crate.module), + ..crate + } + } else { + crate + } + } fn fold_item(&mut self, item: @ast::Item) -> SmallVector<@ast::Item> { if !no_prelude(item.attrs) { @@ -142,7 +168,7 @@ impl fold::Folder for StandardLibraryInjector { ], }; - let vp = @spanned(ast::ViewPathGlob(prelude_path, ast::DUMMY_NODE_ID)); + let vp = @codemap::dummy_spanned(ast::ViewPathGlob(prelude_path, ast::DUMMY_NODE_ID)); let vi2 = ast::ViewItem { node: ast::ViewItemUse(~[vp]), attrs: ~[], @@ -161,8 +187,8 @@ impl fold::Folder for StandardLibraryInjector { } } -fn inject_libstd_ref(sess: Session, crate: ast::Crate) -> ast::Crate { - let mut fold = StandardLibraryInjector { +fn inject_prelude(sess: Session, crate: ast::Crate) -> ast::Crate { + let mut fold = PreludeInjector { sess: sess, }; fold.fold_crate(crate) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 7e53a0071bd..4f13a517878 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -76,6 +76,8 @@ #[cfg(test)] pub use ops = realstd::ops; #[cfg(test)] pub use cmp = realstd::cmp; +mod macros; + mod rtdeps; /* The Prelude. */ diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs new file mode 100644 index 00000000000..effc9a77c1d --- /dev/null +++ b/src/libstd/macros.rs @@ -0,0 +1,192 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#[macro_escape]; + +#[macro_export] +macro_rules! ignore (($($x:tt)*) => (())) + +#[macro_export] +macro_rules! log( + ($lvl:expr, $($arg:tt)+) => ({ + let lvl = $lvl; + if lvl <= __log_level() { + format_args!(|args| { + ::std::logging::log(lvl, args) + }, $($arg)+) + } + }) +) +#[macro_export] +macro_rules! error( ($($arg:tt)*) => (log!(1u32, $($arg)*)) ) +#[macro_export] +macro_rules! warn ( ($($arg:tt)*) => (log!(2u32, $($arg)*)) ) +#[macro_export] +macro_rules! info ( ($($arg:tt)*) => (log!(3u32, $($arg)*)) ) +#[macro_export] +macro_rules! debug( ($($arg:tt)*) => ( + if cfg!(not(ndebug)) { log!(4u32, $($arg)*) } +)) + +#[macro_export] +macro_rules! log_enabled( + ($lvl:expr) => ( { + let lvl = $lvl; + lvl <= __log_level() && (lvl != 4 || cfg!(not(ndebug))) + } ) +) + +#[macro_export] +macro_rules! fail( + () => ( + fail!("explicit failure") + ); + ($msg:expr) => ( + ::std::rt::begin_unwind($msg, file!(), line!()) + ); + ($fmt:expr, $($arg:tt)*) => ( + ::std::rt::begin_unwind(format!($fmt, $($arg)*), file!(), line!()) + ) +) + +#[macro_export] +macro_rules! assert( + ($cond:expr) => { + if !$cond { + fail!("assertion failed: {:s}", stringify!($cond)) + } + }; + ($cond:expr, $msg:expr) => { + if !$cond { + fail!($msg) + } + }; + ($cond:expr, $( $arg:expr ),+) => { + if !$cond { + fail!( $($arg),+ ) + } + } +) + +#[macro_export] +macro_rules! assert_eq ( + ($given:expr , $expected:expr) => ( + { + let given_val = &($given); + let expected_val = &($expected); + // check both directions of equality.... + if !((*given_val == *expected_val) && + (*expected_val == *given_val)) { + fail!("assertion failed: `(left == right) && (right == left)` \ + (left: `{:?}`, right: `{:?}`)", *given_val, *expected_val) + } + } + ) +) + +/// A utility macro for indicating unreachable code. It will fail if +/// executed. This is occasionally useful to put after loops that never +/// terminate normally, but instead directly return from a function. +/// +/// # Example +/// +/// ```rust +/// fn choose_weighted_item(v: &[Item]) -> Item { +/// assert!(!v.is_empty()); +/// let mut so_far = 0u; +/// for item in v.iter() { +/// so_far += item.weight; +/// if so_far > 100 { +/// return item; +/// } +/// } +/// // The above loop always returns, so we must hint to the +/// // type checker that it isn't possible to get down here +/// unreachable!(); +/// } +/// ``` +#[macro_export] +macro_rules! unreachable (() => ( + fail!("internal error: entered unreachable code"); +)) + +#[macro_export] +macro_rules! condition ( + + { pub $c:ident: $input:ty -> $out:ty; } => { + + pub mod $c { + #[allow(unused_imports)]; + #[allow(non_uppercase_statics)]; + #[allow(missing_doc)]; + + use super::*; + + local_data_key!(key: @::std::condition::Handler<$input, $out>) + + pub static cond : + ::std::condition::Condition<$input,$out> = + ::std::condition::Condition { + name: stringify!($c), + key: key + }; + } + }; + + { $c:ident: $input:ty -> $out:ty; } => { + + mod $c { + #[allow(unused_imports)]; + #[allow(non_uppercase_statics)]; + #[allow(dead_code)]; + + use super::*; + + local_data_key!(key: @::std::condition::Handler<$input, $out>) + + pub static cond : + ::std::condition::Condition<$input,$out> = + ::std::condition::Condition { + name: stringify!($c), + key: key + }; + } + } +) + +#[macro_export] +macro_rules! format(($($arg:tt)*) => ( + format_args!(::std::fmt::format, $($arg)*) +)) +#[macro_export] +macro_rules! write(($dst:expr, $($arg:tt)*) => ( + format_args!(|args| { ::std::fmt::write($dst, args) }, $($arg)*) +)) +#[macro_export] +macro_rules! writeln(($dst:expr, $($arg:tt)*) => ( + format_args!(|args| { ::std::fmt::writeln($dst, args) }, $($arg)*) +)) +#[macro_export] +macro_rules! print ( + ($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*)) +) +#[macro_export] +macro_rules! println ( + ($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*)) +) + +#[macro_export] +macro_rules! local_data_key ( + ($name:ident: $ty:ty) => ( + static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key; + ); + (pub $name:ident: $ty:ty) => ( + pub static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key; + ) +) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 0534aa39848..43a5b01698b 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -22,7 +22,6 @@ use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use ext::base::*; use fold::*; use parse; -use parse::{parse_item_from_source_str}; use parse::token; use parse::token::{fresh_mark, fresh_name, ident_to_str, intern}; use visit; @@ -754,218 +753,6 @@ pub fn new_span(cx: &ExtCtxt, sp: Span) -> Span { } } -// FIXME (#2247): this is a moderately bad kludge to inject some macros into -// the default compilation environment in that it injects strings, rather than -// syntax elements. - -pub fn std_macros() -> @str { -@r#"mod __std_macros { - #[macro_escape]; - #[doc(hidden)]; - #[allow(dead_code)]; - - macro_rules! ignore (($($x:tt)*) => (())) - - macro_rules! log( - ($lvl:expr, $($arg:tt)+) => ({ - let lvl = $lvl; - if lvl <= __log_level() { - format_args!(|args| { - ::std::logging::log(lvl, args) - }, $($arg)+) - } - }) - ) - macro_rules! error( ($($arg:tt)*) => (log!(1u32, $($arg)*)) ) - macro_rules! warn ( ($($arg:tt)*) => (log!(2u32, $($arg)*)) ) - macro_rules! info ( ($($arg:tt)*) => (log!(3u32, $($arg)*)) ) - macro_rules! debug( ($($arg:tt)*) => ( - if cfg!(not(ndebug)) { log!(4u32, $($arg)*) } - )) - - macro_rules! log_enabled( - ($lvl:expr) => ( { - let lvl = $lvl; - lvl <= __log_level() && (lvl != 4 || cfg!(not(ndebug))) - } ) - ) - - macro_rules! fail( - () => ( - fail!("explicit failure") - ); - ($msg:expr) => ( - ::std::rt::begin_unwind($msg, file!(), line!()) - ); - ($fmt:expr, $($arg:tt)*) => ( - ::std::rt::begin_unwind(format!($fmt, $($arg)*), file!(), line!()) - ) - ) - - macro_rules! assert( - ($cond:expr) => { - if !$cond { - fail!("assertion failed: {:s}", stringify!($cond)) - } - }; - ($cond:expr, $msg:expr) => { - if !$cond { - fail!($msg) - } - }; - ($cond:expr, $( $arg:expr ),+) => { - if !$cond { - fail!( $($arg),+ ) - } - } - ) - - macro_rules! assert_eq ( - ($given:expr , $expected:expr) => ( - { - let given_val = &($given); - let expected_val = &($expected); - // check both directions of equality.... - if !((*given_val == *expected_val) && - (*expected_val == *given_val)) { - fail!("assertion failed: `(left == right) && (right == left)` \ - (left: `{:?}`, right: `{:?}`)", *given_val, *expected_val) - } - } - ) - ) - - /// A utility macro for indicating unreachable code. It will fail if - /// executed. This is occasionally useful to put after loops that never - /// terminate normally, but instead directly return from a function. - /// - /// # Example - /// - /// ```rust - /// fn choose_weighted_item(v: &[Item]) -> Item { - /// assert!(!v.is_empty()); - /// let mut so_far = 0u; - /// for item in v.iter() { - /// so_far += item.weight; - /// if so_far > 100 { - /// return item; - /// } - /// } - /// // The above loop always returns, so we must hint to the - /// // type checker that it isn't possible to get down here - /// unreachable!(); - /// } - /// ``` - macro_rules! unreachable (() => ( - fail!("internal error: entered unreachable code"); - )) - - macro_rules! condition ( - - { pub $c:ident: $input:ty -> $out:ty; } => { - - pub mod $c { - #[allow(unused_imports)]; - #[allow(non_uppercase_statics)]; - #[allow(missing_doc)]; - - use super::*; - - local_data_key!(key: @::std::condition::Handler<$input, $out>) - - pub static cond : - ::std::condition::Condition<$input,$out> = - ::std::condition::Condition { - name: stringify!($c), - key: key - }; - } - }; - - { $c:ident: $input:ty -> $out:ty; } => { - - mod $c { - #[allow(unused_imports)]; - #[allow(non_uppercase_statics)]; - #[allow(dead_code)]; - - use super::*; - - local_data_key!(key: @::std::condition::Handler<$input, $out>) - - pub static cond : - ::std::condition::Condition<$input,$out> = - ::std::condition::Condition { - name: stringify!($c), - key: key - }; - } - } - ) - - macro_rules! format(($($arg:tt)*) => ( - format_args!(::std::fmt::format, $($arg)*) - )) - macro_rules! write(($dst:expr, $($arg:tt)*) => ( - format_args!(|args| { ::std::fmt::write($dst, args) }, $($arg)*) - )) - macro_rules! writeln(($dst:expr, $($arg:tt)*) => ( - format_args!(|args| { ::std::fmt::writeln($dst, args) }, $($arg)*) - )) - macro_rules! print ( - ($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*)) - ) - macro_rules! println ( - ($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*)) - ) - - macro_rules! local_data_key ( - ($name:ident: $ty:ty) => ( - static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key; - ); - (pub $name:ident: $ty:ty) => ( - pub static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key; - ) - ) -}"# -} - -struct Injector { - sm: @ast::Item, -} - -impl Folder for Injector { - fn fold_mod(&mut self, module: &ast::Mod) -> ast::Mod { - // Just inject the standard macros at the start of the first module - // in the crate: that is, at the start of the crate file itself. - let items = vec::append(~[ self.sm ], module.items); - ast::Mod { - items: items, - ..(*module).clone() // FIXME #2543: Bad copy. - } - } -} - -// add a bunch of macros as though they were placed at the head of the -// program (ick). This should run before cfg stripping. -pub fn inject_std_macros(parse_sess: @parse::ParseSess, - cfg: ast::CrateConfig, - c: Crate) - -> Crate { - let sm = match parse_item_from_source_str(@"", - std_macros(), - cfg.clone(), - parse_sess) { - Some(item) => item, - None => fail!("expected core macros to parse correctly") - }; - - let mut injector = Injector { - sm: sm, - }; - injector.fold_crate(c) -} - pub struct MacroExpander<'a> { extsbox: SyntaxEnv, cx: &'a mut ExtCtxt<'a>, @@ -1231,20 +1018,6 @@ mod test { } } - // make sure that fail! is present - #[test] fn fail_exists_test () { - let src = @"fn main() { fail!(\"something appropriately gloomy\");}"; - let sess = parse::new_parse_sess(None); - let crate_ast = parse::parse_crate_from_source_str( - @"", - src, - ~[],sess); - let crate_ast = inject_std_macros(sess, ~[], crate_ast); - // don't bother with striping, doesn't affect fail!. - let mut loader = ErrLoader; - expand_crate(sess,&mut loader,~[],crate_ast); - } - // these following tests are quite fragile, in that they don't test what // *kind* of failure occurs. @@ -1292,20 +1065,6 @@ mod test { expand_crate(sess,&mut loader,~[],crate_ast); } - #[test] fn std_macros_must_parse () { - let src = super::std_macros(); - let sess = parse::new_parse_sess(None); - let cfg = ~[]; - let item_ast = parse::parse_item_from_source_str( - @"", - src, - cfg,sess); - match item_ast { - Some(_) => (), // success - None => fail!("expected this to parse") - } - } - #[test] fn test_contains_flatten (){ let attr1 = make_dummy_attr (@"foo"); let attr2 = make_dummy_attr (@"bar"); diff --git a/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs b/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs index ebd3320d901..0fc3b3912b1 100644 --- a/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs +++ b/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs @@ -11,9 +11,7 @@ // error-pattern:mismatched types: expected `char` but found // Issue #876 -#[no_std]; - -extern mod std; +#[no_implicit_prelude]; fn last(v: ~[&T]) -> std::option::Option { fail!();