提交 8b80922a 编写于 作者: S Steven Fackler

quote_*! macros take an ExtCtx

They previously required one called "ext_cx" to be in scope.

Fixes part of #7727
上级 0a238288
......@@ -292,6 +292,7 @@ fn mk_std(cx: &TestCtxt) -> ast::view_item {
}
}
#[cfg(stage0)]
fn mk_test_module(cx: &TestCtxt) -> @ast::item {
// Link to extra
......@@ -334,6 +335,48 @@ pub fn main() {
return @item;
}
#[cfg(not(stage0))]
fn mk_test_module(cx: &TestCtxt) -> @ast::item {
// Link to extra
let view_items = ~[mk_std(cx)];
// A constant vector of test descriptors.
let tests = mk_tests(cx);
// The synthesized main function which will call the console test runner
// with our list of tests
let mainfn = (quote_item!(cx.ext_cx,
pub fn main() {
#[main];
extra::test::test_main_static(::std::os::args(), TESTS);
}
)).unwrap();
let testmod = ast::_mod {
view_items: view_items,
items: ~[mainfn, tests],
};
let item_ = ast::item_mod(testmod);
// This attribute tells resolve to let us call unexported functions
let resolve_unexported_attr =
attr::mk_attr(attr::mk_word_item(@"!resolve_unexported"));
let item = ast::item {
ident: cx.sess.ident_of("__test"),
attrs: ~[resolve_unexported_attr],
id: cx.sess.next_node_id(),
node: item_,
vis: ast::public,
span: dummy_sp(),
};
debug!("Synthetic test module:\n%s\n",
pprust::item_to_str(@item.clone(), cx.sess.intr()));
return @item;
}
fn nospan<T>(t: T) -> codemap::spanned<T> {
codemap::spanned { node: t, span: dummy_sp() }
......@@ -355,6 +398,7 @@ fn path_node_global(ids: ~[ast::ident]) -> ast::Path {
types: ~[] }
}
#[cfg(stage0)]
fn mk_tests(cx: &TestCtxt) -> @ast::item {
let ext_cx = cx.ext_cx;
......@@ -368,6 +412,17 @@ fn mk_tests(cx: &TestCtxt) -> @ast::item {
;
)).unwrap()
}
#[cfg(not(stage0))]
fn mk_tests(cx: &TestCtxt) -> @ast::item {
// The vector of test_descs for this crate
let test_descs = mk_test_descs(cx);
(quote_item!(cx.ext_cx,
pub static TESTS : &'static [self::extra::test::TestDescAndFn] =
$test_descs
;
)).unwrap()
}
fn is_extra(cx: &TestCtxt) -> bool {
let items = attr::find_linkage_metas(cx.crate.attrs);
......@@ -398,6 +453,7 @@ fn mk_test_descs(cx: &TestCtxt) -> @ast::expr {
}
}
#[cfg(stage0)]
fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::expr {
let span = test.span;
let path = test.path.clone();
......@@ -453,3 +509,57 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::expr {
);
e
}
#[cfg(not(stage0))]
fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::expr {
let span = test.span;
let path = test.path.clone();
debug!("encoding %s", ast_util::path_name_i(path));
let name_lit: ast::lit =
nospan(ast::lit_str(ast_util::path_name_i(path).to_managed()));
let name_expr = @ast::expr {
id: cx.sess.next_node_id(),
node: ast::expr_lit(@name_lit),
span: span
};
let fn_path = path_node_global(path);
let fn_expr = @ast::expr {
id: cx.sess.next_node_id(),
node: ast::expr_path(fn_path),
span: span,
};
let t_expr = if test.bench {
quote_expr!(cx.ext_cx, self::extra::test::StaticBenchFn($fn_expr) )
} else {
quote_expr!(cx.ext_cx, self::extra::test::StaticTestFn($fn_expr) )
};
let ignore_expr = if test.ignore {
quote_expr!(cx.ext_cx, true )
} else {
quote_expr!(cx.ext_cx, false )
};
let fail_expr = if test.should_fail {
quote_expr!(cx.ext_cx, true )
} else {
quote_expr!(cx.ext_cx, false )
};
let e = quote_expr!(cx.ext_cx,
self::extra::test::TestDescAndFn {
desc: self::extra::test::TestDesc {
name: self::extra::test::StaticTestName($name_expr),
ignore: $ignore_expr,
should_fail: $fail_expr
},
testfn: $t_expr,
}
);
e
}
......@@ -1288,24 +1288,24 @@ fn roundtrip(in_item: Option<@ast::item>) {
#[test]
fn test_basic() {
let ext_cx = mk_ctxt();
roundtrip(quote_item!(
let cx = mk_ctxt();
roundtrip(quote_item!(cx,
fn foo() {}
));
}
#[test]
fn test_smalltalk() {
let ext_cx = mk_ctxt();
roundtrip(quote_item!(
let cx = mk_ctxt();
roundtrip(quote_item!(cx,
fn foo() -> int { 3 + 4 } // first smalltalk program ever executed.
));
}
#[test]
fn test_more() {
let ext_cx = mk_ctxt();
roundtrip(quote_item!(
let cx = mk_ctxt();
roundtrip(quote_item!(cx,
fn foo(x: uint, y: uint) -> uint {
let z = x + y;
return z;
......@@ -1315,15 +1315,15 @@ fn foo(x: uint, y: uint) -> uint {
#[test]
fn test_simplification() {
let ext_cx = mk_ctxt();
let item_in = ast::ii_item(quote_item!(
let cx = mk_ctxt();
let item_in = ast::ii_item(quote_item!(cx,
fn new_int_alist<B>() -> alist<int, B> {
fn eq_int(a: int, b: int) -> bool { a == b }
return alist {eq_fn: eq_int, data: ~[]};
}
).unwrap());
let item_out = simplify_ast(&item_in);
let item_exp = ast::ii_item(quote_item!(
let item_exp = ast::ii_item(quote_item!(cx,
fn new_int_alist<B>() -> alist<int, B> {
return alist {eq_fn: eq_int, data: ~[]};
}
......
......@@ -605,17 +605,29 @@ fn lambda(&self, span: span, ids: ~[ast::ident], blk: ast::Block) -> @ast::expr
self.expr(span, ast::expr_fn_block(fn_decl, blk))
}
#[cfg(stage0)]
fn lambda0(&self, _span: span, blk: ast::Block) -> @ast::expr {
let ext_cx = *self;
let blk_e = self.expr(blk.span, ast::expr_block(blk.clone()));
quote_expr!(|| $blk_e )
}
#[cfg(not(stage0))]
fn lambda0(&self, _span: span, blk: ast::Block) -> @ast::expr {
let blk_e = self.expr(blk.span, ast::expr_block(blk.clone()));
quote_expr!(*self, || $blk_e )
}
#[cfg(stage0)]
fn lambda1(&self, _span: span, blk: ast::Block, ident: ast::ident) -> @ast::expr {
let ext_cx = *self;
let blk_e = self.expr(blk.span, ast::expr_block(blk.clone()));
quote_expr!(|$ident| $blk_e )
}
#[cfg(not(stage0))]
fn lambda1(&self, _span: span, blk: ast::Block, ident: ast::ident) -> @ast::expr {
let blk_e = self.expr(blk.span, ast::expr_block(blk.clone()));
quote_expr!(*self, |$ident| $blk_e )
}
fn lambda_expr(&self, span: span, ids: ~[ast::ident], expr: @ast::expr) -> @ast::expr {
self.lambda(span, ids, self.block_expr(expr))
......
......@@ -22,6 +22,7 @@
use std::os;
#[cfg(stage0)]
pub fn expand_option_env(ext_cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
-> base::MacResult {
let var = get_single_str_from_tts(ext_cx, sp, tts, "option_env!");
......@@ -32,25 +33,36 @@ pub fn expand_option_env(ext_cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
};
MRExpr(e)
}
#[cfg(not(stage0))]
pub fn expand_option_env(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
-> base::MacResult {
let var = get_single_str_from_tts(cx, sp, tts, "option_env!");
let e = match os::getenv(var) {
None => quote_expr!(cx, ::std::option::None::<&'static str>),
Some(s) => quote_expr!(cx, ::std::option::Some($s))
};
MRExpr(e)
}
pub fn expand_env(ext_cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
pub fn expand_env(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
-> base::MacResult {
let exprs = get_exprs_from_tts(ext_cx, sp, tts);
let exprs = get_exprs_from_tts(cx, sp, tts);
if exprs.len() == 0 {
ext_cx.span_fatal(sp, "env! takes 1 or 2 arguments");
cx.span_fatal(sp, "env! takes 1 or 2 arguments");
}
let var = expr_to_str(ext_cx, exprs[0], "expected string literal");
let var = expr_to_str(cx, exprs[0], "expected string literal");
let msg = match exprs.len() {
1 => fmt!("Environment variable %s not defined", var).to_managed(),
2 => expr_to_str(ext_cx, exprs[1], "expected string literal"),
_ => ext_cx.span_fatal(sp, "env! takes 1 or 2 arguments")
2 => expr_to_str(cx, exprs[1], "expected string literal"),
_ => cx.span_fatal(sp, "env! takes 1 or 2 arguments")
};
let e = match os::getenv(var) {
None => ext_cx.span_fatal(sp, msg),
Some(s) => ext_cx.expr_str(sp, s.to_managed())
None => cx.span_fatal(sp, msg),
Some(s) => cx.expr_str(sp, s.to_managed())
};
MRExpr(e)
}
......@@ -196,119 +196,45 @@ fn to_source(&self) -> @str {
// Alas ... we write these out instead. All redundant.
impl ToTokens for ast::ident {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl ToTokens for @ast::item {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl<'self> ToTokens for &'self [@ast::item] {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl ToTokens for ast::Ty {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl<'self> ToTokens for &'self [ast::Ty] {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl ToTokens for Generics {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl ToTokens for @ast::expr {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl ToTokens for ast::Block {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl<'self> ToTokens for &'self str {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl ToTokens for int {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl ToTokens for i8 {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl ToTokens for i16 {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl ToTokens for i32 {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl ToTokens for i64 {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl ToTokens for uint {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl ToTokens for u8 {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl ToTokens for u16 {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl ToTokens for u32 {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
impl ToTokens for u64 {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
macro_rules! impl_to_tokens(
($t:ty) => (
impl ToTokens for $t {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
)
)
macro_rules! impl_to_tokens_self(
($t:ty) => (
impl<'self> ToTokens for $t {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
}
)
)
impl_to_tokens!(ast::ident)
impl_to_tokens!(@ast::item)
impl_to_tokens_self!(&'self [@ast::item])
impl_to_tokens!(ast::Ty)
impl_to_tokens_self!(&'self [ast::Ty])
impl_to_tokens!(Generics)
impl_to_tokens!(@ast::expr)
impl_to_tokens!(ast::Block)
impl_to_tokens_self!(&'self str)
impl_to_tokens!(int)
impl_to_tokens!(i8)
impl_to_tokens!(i16)
impl_to_tokens!(i32)
impl_to_tokens!(i64)
impl_to_tokens!(uint)
impl_to_tokens!(u8)
impl_to_tokens!(u16)
impl_to_tokens!(u32)
impl_to_tokens!(u64)
pub trait ExtParseUtils {
fn parse_item(&self, s: @str) -> @ast::item;
......@@ -366,7 +292,8 @@ fn parse_tts(&self, s: @str) -> ~[ast::token_tree] {
pub fn expand_quote_tokens(cx: @ExtCtxt,
sp: span,
tts: &[ast::token_tree]) -> base::MacResult {
base::MRExpr(expand_tts(cx, sp, tts))
let (cx_expr, expr) = expand_tts(cx, sp, tts);
base::MRExpr(expand_wrapper(cx, sp, cx_expr, expr))
}
pub fn expand_quote_expr(cx: @ExtCtxt,
......@@ -640,7 +567,7 @@ fn mk_tts(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
fn expand_tts(cx: @ExtCtxt,
sp: span,
tts: &[ast::token_tree]) -> @ast::expr {
tts: &[ast::token_tree]) -> (@ast::expr, @ast::expr) {
// NB: It appears that the main parser loses its mind if we consider
// $foo as a tt_nonterminal during the main parse, so we have to re-parse
......@@ -654,17 +581,14 @@ fn expand_tts(cx: @ExtCtxt,
tts.to_owned()
);
*p.quote_depth += 1u;
let tts = p.parse_all_token_trees();
p.abort_if_errors();
// We want to emit a block expression that does a sequence of 'use's to
// import the runtime module, followed by a tt-building expression.
let cx_expr = p.parse_expr();
if !p.eat(&token::COMMA) {
p.fatal("Expected token `,`");
}
let uses = ~[ cx.view_use_glob(sp, ast::public,
ids_ext(~[~"syntax",
~"ext",
~"quote",
~"rt"])) ];
let tts = p.parse_all_token_trees();
p.abort_if_errors();
// We also bind a single value, sp, to ext_cx.call_site()
//
......@@ -683,9 +607,9 @@ fn expand_tts(cx: @ExtCtxt,
// the site the string literal occurred, which was in a source file
// _other_ than the one the user has control over. For example, an
// error in a quote from the protocol compiler, invoked in user code
// using macro_rules! for example, will be attributed to the macro_rules.rs file in
// libsyntax, which the user might not even have source to (unless they
// happen to have a compiler on hand). Over all, the phase distinction
// using macro_rules! for example, will be attributed to the macro_rules.rs
// file in libsyntax, which the user might not even have source to (unless
// they happen to have a compiler on hand). Over all, the phase distinction
// just makes quotes "hard to attribute". Possibly this could be fixed
// by recreating some of the original qq machinery in the tt regime
// (pushing fake FileMaps onto the parser to account for original sites
......@@ -705,11 +629,28 @@ fn expand_tts(cx: @ExtCtxt,
id_ext("tt"),
cx.expr_vec_uniq(sp, ~[]));
cx.expr_block(
cx.block_all(sp, uses,
~[stmt_let_sp,
stmt_let_tt] + mk_tts(cx, sp, tts),
Some(cx.expr_ident(sp, id_ext("tt")))))
let block = cx.expr_block(
cx.block_all(sp,
~[],
~[stmt_let_sp, stmt_let_tt] + mk_tts(cx, sp, tts),
Some(cx.expr_ident(sp, id_ext("tt")))));
(cx_expr, block)
}
fn expand_wrapper(cx: @ExtCtxt,
sp: span,
cx_expr: @ast::expr,
expr: @ast::expr) -> @ast::expr {
let uses = ~[ cx.view_use_glob(sp, ast::public,
ids_ext(~[~"syntax",
~"ext",
~"quote",
~"rt"])) ];
let stmt_let_ext_cx = cx.stmt_let(sp, false, id_ext("ext_cx"), cx_expr);
cx.expr_block(cx.block_all(sp, uses, ~[stmt_let_ext_cx], Some(expr)))
}
fn expand_parse_call(cx: @ExtCtxt,
......@@ -717,7 +658,7 @@ fn expand_parse_call(cx: @ExtCtxt,
parse_method: &str,
arg_exprs: ~[@ast::expr],
tts: &[ast::token_tree]) -> @ast::expr {
let tts_expr = expand_tts(cx, sp, tts);
let (cx_expr, tts_expr) = expand_tts(cx, sp, tts);
let cfg_call = || cx.expr_method_call(
sp, cx.expr_ident(sp, id_ext("ext_cx")),
......@@ -728,17 +669,12 @@ fn expand_parse_call(cx: @ExtCtxt,
id_ext("parse_sess"), ~[]);
let new_parser_call =
cx.expr_call_global(sp,
ids_ext(~[~"syntax",
~"ext",
~"quote",
~"rt",
~"new_parser_from_tts"]),
~[parse_sess_call(),
cfg_call(),
tts_expr]);
cx.expr_method_call(sp, new_parser_call,
id_ext(parse_method),
arg_exprs)
cx.expr_call(sp,
cx.expr_ident(sp, id_ext("new_parser_from_tts")),
~[parse_sess_call(), cfg_call(), tts_expr]);
let expr = cx.expr_method_call(sp, new_parser_call, id_ext(parse_method),
arg_exprs);
expand_wrapper(cx, sp, cx_expr, expr)
}
......@@ -53,12 +53,12 @@ fn mk_ctxt() -> fake_ext_ctxt {
fn main() {
let ext_cx = mk_ctxt();
let cx = mk_ctxt();
let abc = quote_expr!(23);
let abc = quote_expr!(cx, 23);
check_pp(abc, pprust::print_expr, "23");
let expr3 = quote_expr!(2 - $abcd + 7); //~ ERROR unresolved name: abcd
let expr3 = quote_expr!(cx, 2 - $abcd + 7); //~ ERROR unresolved name: abcd
check_pp(expr3, pprust::print_expr, "2 - 23 + 7");
}
......
......@@ -51,9 +51,9 @@ fn mk_ctxt() -> fake_ext_ctxt {
fn main() {
let ext_cx = mk_ctxt();
let cx = mk_ctxt();
let stmt = quote_stmt!(let x int = 20;); //~ ERROR expected end-of-string
let stmt = quote_stmt!(cx, let x int = 20;); //~ ERROR expected end-of-string
check_pp(*stmt, pprust::print_stmt, "");
}
......
......@@ -54,9 +54,9 @@ fn mk_ctxt() -> fake_ext_ctxt {
fn main() {
let ext_cx = mk_ctxt();
let s = quote_expr!(__s);
let e = quote_expr!(__e);
let f = quote_expr!($s.foo {|__e| $e});
let cx = mk_ctxt();
let s = quote_expr!(cx, __s);
let e = quote_expr!(cx, __e);
let f = quote_expr!(cx, $s.foo {|__e| $e});
log(error, pprust::expr_to_str(f));
}
......@@ -52,22 +52,22 @@ fn mk_ctxt() -> fake_ext_ctxt {
}
fn main() {
let ext_cx = mk_ctxt();
let cx = mk_ctxt();
let abc = quote_expr!(23);
let abc = quote_expr!(cx, 23);
check_pp(ext_cx, abc, pprust::print_expr, ~"23");
let ty = quote_ty!(int);
let ty = quote_ty!(cx, int);
check_pp(ext_cx, ty, pprust::print_type, ~"int");
let item = quote_item!(static x : int = 10;).get();
let item = quote_item!(cx, static x : int = 10;).get();
check_pp(ext_cx, item, pprust::print_item, ~"static x: int = 10;");
let stmt = quote_stmt!(let x = 20;);
let stmt = quote_stmt!(cx, let x = 20;);
check_pp(ext_cx, *stmt, pprust::print_stmt, ~"let x = 20;");
let pat = quote_pat!(Some(_));
let pat = quote_pat!(cx, Some(_));
check_pp(ext_cx, pat, pprust::print_pat, ~"Some(_)");
}
......
......@@ -12,15 +12,15 @@
use syntax::ext::base::ExtCtxt;
fn syntax_extension(ext_cx: @ExtCtxt) {
let e_toks : ~[syntax::ast::token_tree] = quote_tokens!(1 + 2);
let p_toks : ~[syntax::ast::token_tree] = quote_tokens!((x, 1 .. 4, *));
fn syntax_extension(cx: @ExtCtxt) {
let e_toks : ~[syntax::ast::token_tree] = quote_tokens!(cx, 1 + 2);
let p_toks : ~[syntax::ast::token_tree] = quote_tokens!(cx, (x, 1 .. 4, *));
let a: @syntax::ast::expr = quote_expr!(1 + 2);
let _b: Option<@syntax::ast::item> = quote_item!( static foo : int = $e_toks; );
let _c: @syntax::ast::pat = quote_pat!( (x, 1 .. 4, *) );
let _d: @syntax::ast::stmt = quote_stmt!( let x = $a; );
let _e: @syntax::ast::expr = quote_expr!( match foo { $p_toks => 10 } );
let a: @syntax::ast::expr = quote_expr!(cx, 1 + 2);
let _b: Option<@syntax::ast::item> = quote_item!(cx, static foo : int = $e_toks; );
let _c: @syntax::ast::pat = quote_pat!(cx, (x, 1 .. 4, *) );
let _d: @syntax::ast::stmt = quote_stmt!(cx, let x = $a; );
let _e: @syntax::ast::expr = quote_expr!(cx, match foo { $p_toks => 10 } );
}
fn main() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册