]> git.lizzy.rs Git - rust.git/commitdiff
Expand string literals and exprs inside of macros
authorSteven Fackler <sfackler@gmail.com>
Sun, 2 Mar 2014 21:38:44 +0000 (13:38 -0800)
committerSteven Fackler <sfackler@gmail.com>
Sun, 2 Mar 2014 22:12:02 +0000 (14:12 -0800)
A couple of syntax extensions manually expanded expressions, but it
wasn't done universally, most noticably inside of asm!().

There's also a bit of random cleanup.

src/libsyntax/ext/base.rs
src/libsyntax/ext/concat.rs
src/libsyntax/ext/format.rs
src/test/run-pass-fulldeps/phase-syntax-link-does-resolve.rs [new file with mode: 0644]
src/test/run-pass/asm-concat-src.rs [new file with mode: 0644]
src/test/run-pass/asm-out-assign.rs
src/test/run-pass/ext-expand-inner-exprs.rs [new file with mode: 0644]
src/test/run-pass/phase-syntax-link-does-resolve.rs [deleted file]

index e9fe21eded60c87ab17f43a55c42eea7cd1b9d31..5cb09ec823221ab86026069e65a9897eb585229b 100644 (file)
@@ -405,11 +405,13 @@ pub fn ident_of(&self, st: &str) -> ast::Ident {
     }
 }
 
-/// Extract a string literal from `expr`, emitting `err_msg` if `expr`
-/// is not a string literal. This does not stop compilation on error,
-/// merely emits a non-fatal error and returns None.
-pub fn expr_to_str(cx: &ExtCtxt, expr: @ast::Expr, err_msg: &str)
+/// Extract a string literal from the macro expanded version of `expr`,
+/// emitting `err_msg` if `expr` is not a string literal. This does not stop
+/// compilation on error, merely emits a non-fatal error and returns None.
+pub fn expr_to_str(cx: &mut ExtCtxt, expr: @ast::Expr, err_msg: &str)
                    -> Option<(InternedString, ast::StrStyle)> {
+    // we want to be able to handle e.g. concat("foo", "bar")
+    let expr = cx.expand_expr(expr);
     match expr.node {
         ast::ExprLit(l) => match l.node {
             ast::LitStr(ref s, style) => return Some(((*s).clone(), style)),
@@ -457,7 +459,7 @@ pub fn get_single_str_from_tts(cx: &ExtCtxt,
 
 /// Extract comma-separated expressions from `tts`. If there is a
 /// parsing error, emit a non-fatal error and return None.
-pub fn get_exprs_from_tts(cx: &ExtCtxt,
+pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
                           sp: Span,
                           tts: &[ast::TokenTree]) -> Option<Vec<@ast::Expr> > {
     let mut p = parse::new_parser_from_tts(cx.parse_sess(),
@@ -471,7 +473,7 @@ pub fn get_exprs_from_tts(cx: &ExtCtxt,
             cx.span_err(sp, "expected token: `,`");
             return None;
         }
-        es.push(p.parse_expr());
+        es.push(cx.expand_expr(p.parse_expr()));
     }
     Some(es)
 }
@@ -482,9 +484,6 @@ pub fn get_exprs_from_tts(cx: &ExtCtxt,
 
 // This environment maps Names to SyntaxExtensions.
 
-// Actually, the following implementation is parameterized
-// by both key and value types.
-
 //impl question: how to implement it? Initially, the
 // env will contain only macros, so it might be painful
 // to add an empty frame for every context. Let's just
@@ -500,14 +499,6 @@ struct MapChainFrame {
     map: HashMap<Name, SyntaxExtension>,
 }
 
-#[unsafe_destructor]
-impl Drop for MapChainFrame {
-    fn drop(&mut self) {
-        // make sure that syntax extension dtors run before we drop the libs
-        self.map.clear();
-    }
-}
-
 // Only generic to make it easy to test
 pub struct SyntaxEnv {
     priv chain: Vec<MapChainFrame> ,
index 5316b8f721248d3a10613360cc477ade984edf97..e638291ecfa3f792aa28b36363f2af9d39481e4a 100644 (file)
@@ -25,7 +25,6 @@ pub fn expand_syntax_ext(cx: &mut base::ExtCtxt,
     };
     let mut accumulator = ~"";
     for e in es.move_iter() {
-        let e = cx.expand_expr(e);
         match e.node {
             ast::ExprLit(lit) => {
                 match lit.node {
index 7752d88596820bd5d66dee1d3da13217d9e0e6d8..b27ea3df21ec0f429622c15445da0ba10139f226 100644 (file)
@@ -843,11 +843,8 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
         fmtsp: sp,
     };
     cx.fmtsp = efmt.span;
-    // Be sure to recursively expand macros just in case the format string uses
-    // a macro to build the format expression.
-    let expr = cx.ecx.expand_expr(efmt);
     let fmt = match expr_to_str(cx.ecx,
-                                expr,
+                                efmt,
                                 "format argument must be a string literal.") {
         Some((fmt, _)) => fmt,
         None => return MacResult::raw_dummy_expr(sp)
diff --git a/src/test/run-pass-fulldeps/phase-syntax-link-does-resolve.rs b/src/test/run-pass-fulldeps/phase-syntax-link-does-resolve.rs
new file mode 100644 (file)
index 0000000..a7b8297
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2013-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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:macro_crate_test.rs
+// ignore-stage1
+// ignore-fast
+// ignore-android
+// force-host
+
+// You'll note that there's lots of directives above. This is a very particular
+// test in which we're both linking to a macro crate and loading macros from it.
+// This implies that both versions are the host architecture, meaning this test
+// must also be compiled with the host arch.
+//
+// Hence, ignore-stage1 because macros are unstable around there, ignore-fast
+// because this doesn't work with that test runner, ignore-android because it
+// can't run host binaries, and force-host to make this test build as the host
+// arch.
+
+#[feature(phase)];
+
+#[phase(syntax, link)]
+extern crate macro_crate_test;
+
+fn main() {
+    assert_eq!(1, make_a_1!());
+    macro_crate_test::foo();
+}
diff --git a/src/test/run-pass/asm-concat-src.rs b/src/test/run-pass/asm-concat-src.rs
new file mode 100644 (file)
index 0000000..96c98a0
--- /dev/null
@@ -0,0 +1,16 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-fast #[feature] doesn't work with check-fast
+#[feature(asm)];
+
+pub fn main() {
+    unsafe { asm!(concat!("", "")) };
+}
index 823da4faaf639a87c7c8b336369494ba43938f03..2f6b87f26a729a70c0151096753d7afee0feb1c1 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2012-2013-2014 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.
 //
diff --git a/src/test/run-pass/ext-expand-inner-exprs.rs b/src/test/run-pass/ext-expand-inner-exprs.rs
new file mode 100644 (file)
index 0000000..1c96cbd
--- /dev/null
@@ -0,0 +1,15 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+static FOO : &'static [u8] = bytes!(concat!(concat!("hel", "lo"), "world"));
+
+pub fn main() {
+    assert_eq!(FOO, "helloworld".as_bytes());
+}
diff --git a/src/test/run-pass/phase-syntax-link-does-resolve.rs b/src/test/run-pass/phase-syntax-link-does-resolve.rs
deleted file mode 100644 (file)
index a7b8297..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2013-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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// aux-build:macro_crate_test.rs
-// ignore-stage1
-// ignore-fast
-// ignore-android
-// force-host
-
-// You'll note that there's lots of directives above. This is a very particular
-// test in which we're both linking to a macro crate and loading macros from it.
-// This implies that both versions are the host architecture, meaning this test
-// must also be compiled with the host arch.
-//
-// Hence, ignore-stage1 because macros are unstable around there, ignore-fast
-// because this doesn't work with that test runner, ignore-android because it
-// can't run host binaries, and force-host to make this test build as the host
-// arch.
-
-#[feature(phase)];
-
-#[phase(syntax, link)]
-extern crate macro_crate_test;
-
-fn main() {
-    assert_eq!(1, make_a_1!());
-    macro_crate_test::foo();
-}