Expand string literals and exprs inside of macros
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.
This commit is contained in:
parent
25431774a9
commit
a0e54c7761
7 changed files with 41 additions and 23 deletions
|
@ -405,11 +405,13 @@ impl<'a> ExtCtxt<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract a string literal from `expr`, emitting `err_msg` if `expr`
|
/// Extract a string literal from the macro expanded version of `expr`,
|
||||||
/// is not a string literal. This does not stop compilation on error,
|
/// emitting `err_msg` if `expr` is not a string literal. This does not stop
|
||||||
/// merely emits a non-fatal error and returns None.
|
/// 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)
|
pub fn expr_to_str(cx: &mut ExtCtxt, expr: @ast::Expr, err_msg: &str)
|
||||||
-> Option<(InternedString, ast::StrStyle)> {
|
-> 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 {
|
match expr.node {
|
||||||
ast::ExprLit(l) => match l.node {
|
ast::ExprLit(l) => match l.node {
|
||||||
ast::LitStr(ref s, style) => return Some(((*s).clone(), style)),
|
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
|
/// Extract comma-separated expressions from `tts`. If there is a
|
||||||
/// parsing error, emit a non-fatal error and return None.
|
/// 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,
|
sp: Span,
|
||||||
tts: &[ast::TokenTree]) -> Option<Vec<@ast::Expr> > {
|
tts: &[ast::TokenTree]) -> Option<Vec<@ast::Expr> > {
|
||||||
let mut p = parse::new_parser_from_tts(cx.parse_sess(),
|
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: `,`");
|
cx.span_err(sp, "expected token: `,`");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
es.push(p.parse_expr());
|
es.push(cx.expand_expr(p.parse_expr()));
|
||||||
}
|
}
|
||||||
Some(es)
|
Some(es)
|
||||||
}
|
}
|
||||||
|
@ -482,9 +484,6 @@ pub fn get_exprs_from_tts(cx: &ExtCtxt,
|
||||||
|
|
||||||
// This environment maps Names to SyntaxExtensions.
|
// 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
|
//impl question: how to implement it? Initially, the
|
||||||
// env will contain only macros, so it might be painful
|
// env will contain only macros, so it might be painful
|
||||||
// to add an empty frame for every context. Let's just
|
// to add an empty frame for every context. Let's just
|
||||||
|
@ -500,14 +499,6 @@ struct MapChainFrame {
|
||||||
map: HashMap<Name, SyntaxExtension>,
|
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
|
// Only generic to make it easy to test
|
||||||
pub struct SyntaxEnv {
|
pub struct SyntaxEnv {
|
||||||
priv chain: Vec<MapChainFrame> ,
|
priv chain: Vec<MapChainFrame> ,
|
||||||
|
|
|
@ -25,7 +25,6 @@ pub fn expand_syntax_ext(cx: &mut base::ExtCtxt,
|
||||||
};
|
};
|
||||||
let mut accumulator = ~"";
|
let mut accumulator = ~"";
|
||||||
for e in es.move_iter() {
|
for e in es.move_iter() {
|
||||||
let e = cx.expand_expr(e);
|
|
||||||
match e.node {
|
match e.node {
|
||||||
ast::ExprLit(lit) => {
|
ast::ExprLit(lit) => {
|
||||||
match lit.node {
|
match lit.node {
|
||||||
|
|
|
@ -843,11 +843,8 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
|
||||||
fmtsp: sp,
|
fmtsp: sp,
|
||||||
};
|
};
|
||||||
cx.fmtsp = efmt.span;
|
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,
|
let fmt = match expr_to_str(cx.ecx,
|
||||||
expr,
|
efmt,
|
||||||
"format argument must be a string literal.") {
|
"format argument must be a string literal.") {
|
||||||
Some((fmt, _)) => fmt,
|
Some((fmt, _)) => fmt,
|
||||||
None => return MacResult::raw_dummy_expr(sp)
|
None => return MacResult::raw_dummy_expr(sp)
|
||||||
|
|
16
src/test/run-pass/asm-concat-src.rs
Normal file
16
src/test/run-pass/asm-concat-src.rs
Normal file
|
@ -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!("", "")) };
|
||||||
|
}
|
|
@ -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
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
//
|
//
|
||||||
|
|
15
src/test/run-pass/ext-expand-inner-exprs.rs
Normal file
15
src/test/run-pass/ext-expand-inner-exprs.rs
Normal file
|
@ -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());
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue