about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-10-20 23:04:16 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-10-30 19:02:11 -0700
commit8e6e846d8a26e5a9d3aafd0bdcc18ed3ddf0cbca (patch)
treeff3fe4dcde12737779340473a75f5e121d28b485 /src/libsyntax
parentfd53657484d78d0b7c00ce3264d99c051cf07d26 (diff)
downloadrust-8e6e846d8a26e5a9d3aafd0bdcc18ed3ddf0cbca.tar.gz
rust-8e6e846d8a26e5a9d3aafd0bdcc18ed3ddf0cbca.zip
rustc: Implement -l and include! tweaks
This is an implementation of the rustc bits of [RFC 403][rfc]. This adds a new
flag to the compiler, `-l`, as well as tweaking the `include!` macro (and
related source-centric macros).

The compiler's new `-l` flag is used to link libraries in from the command line.
This flag stacks with `#[link]` directives already found in the program. The
purpose of this flag, also stated in the RFC, is to ease linking against native
libraries which have wildly different requirements across platforms and even
within distributions of one platform. This flag accepts a string of the form
`NAME[:KIND]` where `KIND` is optional or one of dylib, static, or framework.
This is roughly equivalent to if the equivalent `#[link]` directive were just
written in the program.

The `include!` macro has been modified to recursively expand macros to allow
usage of `concat!` as an argument, for example. The use case spelled out in RFC
403 was for `env!` to be used as well to include compile-time generated files.
The macro also received a bit of tweaking to allow it to expand to either an
expression or a series of items, depending on what context it's used in.

[rfc]: https://github.com/rust-lang/rfcs/pull/403
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/base.rs23
-rw-r--r--src/libsyntax/ext/source_util.rs35
2 files changed, 37 insertions, 21 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index a8326e79ef3..d474cc8cf0a 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -675,26 +675,19 @@ pub fn check_zero_tts(cx: &ExtCtxt,
 
 /// Extract the string literal from the first token of `tts`. If this
 /// is not a string literal, emit an error and return None.
-pub fn get_single_str_from_tts(cx: &ExtCtxt,
+pub fn get_single_str_from_tts(cx: &mut ExtCtxt,
                                sp: Span,
                                tts: &[ast::TokenTree],
                                name: &str)
                                -> Option<String> {
-    if tts.len() != 1 {
-        cx.span_err(sp, format!("{} takes 1 argument.", name).as_slice());
-    } else {
-        match tts[0] {
-            ast::TtToken(_, token::LitStr(ident)) => return Some(parse::str_lit(ident.as_str())),
-            ast::TtToken(_, token::LitStrRaw(ident, _)) => {
-                return Some(parse::raw_str_lit(ident.as_str()))
-            }
-            _ => {
-                cx.span_err(sp,
-                            format!("{} requires a string.", name).as_slice())
-            }
-        }
+    let mut p = cx.new_parser_from_tts(tts);
+    let ret = cx.expander().fold_expr(p.parse_expr());
+    if p.token != token::Eof {
+        cx.span_err(sp, format!("{} takes 1 argument", name).as_slice());
     }
-    None
+    expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| {
+        s.get().to_string()
+    })
 }
 
 /// Extract comma-separated expressions from `tts`. If there is a
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index 41967b0680c..f1923084409 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -9,14 +9,16 @@
 // except according to those terms.
 
 use ast;
-use codemap;
 use codemap::{Pos, Span};
+use codemap;
 use ext::base::*;
 use ext::base;
 use ext::build::AstBuilder;
-use parse;
 use parse::token;
+use parse;
 use print::pprust;
+use ptr::P;
+use util::small_vector::SmallVector;
 
 use std::io::File;
 use std::rc::Rc;
@@ -82,14 +84,14 @@ pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
 /// include! : parse the given file as an expr
 /// This is generally a bad idea because it's going to behave
 /// unhygienically.
-pub fn expand_include(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-                      -> Box<base::MacResult+'static> {
+pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
+                           -> Box<base::MacResult+'cx> {
     let file = match get_single_str_from_tts(cx, sp, tts, "include!") {
         Some(f) => f,
         None => return DummyResult::expr(sp),
     };
     // The file will be added to the code map by the parser
-    let mut p =
+    let p =
         parse::new_sub_parser_from_file(cx.parse_sess(),
                                         cx.cfg(),
                                         &res_rel_file(cx,
@@ -98,7 +100,28 @@ pub fn expand_include(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                                         true,
                                         None,
                                         sp);
-    base::MacExpr::new(p.parse_expr())
+
+    struct ExpandResult<'a> {
+        p: parse::parser::Parser<'a>,
+    }
+    impl<'a> base::MacResult for ExpandResult<'a> {
+        fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> {
+            Some(self.p.parse_expr())
+        }
+        fn make_items(mut self: Box<ExpandResult<'a>>)
+                      -> Option<SmallVector<P<ast::Item>>> {
+            let mut ret = SmallVector::zero();
+            loop {
+                match self.p.parse_item_with_outer_attributes() {
+                    Some(item) => ret.push(item),
+                    None => break
+                }
+            }
+            Some(ret)
+        }
+    }
+
+    box ExpandResult { p: p }
 }
 
 // include_str! : read the given file, insert it as a literal string expr