capturing macros now implemented
This commit is contained in:
parent
2c51e262f3
commit
b9bb4abcb6
5 changed files with 222 additions and 85 deletions
|
|
@ -33,6 +33,10 @@ pub struct MacroDef {
|
|||
ext: SyntaxExtension
|
||||
}
|
||||
|
||||
// No context arg for an Item Decorator macro, simply because
|
||||
// adding it would require adding a ctxt field to all items.
|
||||
// we could do this if it turns out to be useful.
|
||||
|
||||
pub type ItemDecoratorFun = @fn(@ExtCtxt,
|
||||
Span,
|
||||
@ast::MetaItem,
|
||||
|
|
@ -41,15 +45,34 @@ pub type ItemDecoratorFun = @fn(@ExtCtxt,
|
|||
|
||||
pub type SyntaxExpanderTTFun = @fn(@ExtCtxt,
|
||||
Span,
|
||||
&[ast::token_tree])
|
||||
&[ast::token_tree],
|
||||
ast::SyntaxContext)
|
||||
-> MacResult;
|
||||
|
||||
pub type SyntaxExpanderTTItemFun = @fn(@ExtCtxt,
|
||||
Span,
|
||||
ast::Ident,
|
||||
~[ast::token_tree],
|
||||
ast::SyntaxContext)
|
||||
-> MacResult;
|
||||
|
||||
// oog... in order to make the presentation of builtin_normal_tt_no_ctxt
|
||||
// and builtin_ident_tt_no_ctxt palatable, we need one-off types for
|
||||
// functions that don't consume a ctxt:
|
||||
|
||||
pub type SyntaxExpanderTTFunNoCtxt = @fn(@ExtCtxt,
|
||||
Span,
|
||||
&[ast::token_tree])
|
||||
-> MacResult;
|
||||
|
||||
pub type SyntaxExpanderTTItemFunNoCtxt = @fn(@ExtCtxt,
|
||||
Span,
|
||||
ast::Ident,
|
||||
~[ast::token_tree])
|
||||
-> MacResult;
|
||||
|
||||
|
||||
|
||||
pub enum MacResult {
|
||||
MRExpr(@ast::Expr),
|
||||
MRItem(@ast::item),
|
||||
|
|
@ -78,6 +101,7 @@ pub enum SyntaxExtension {
|
|||
IdentTT(SyntaxExpanderTTItemFun, Option<Span>),
|
||||
}
|
||||
|
||||
|
||||
// The SyntaxEnv is the environment that's threaded through the expansion
|
||||
// of macros. It contains bindings for macros, and also a special binding
|
||||
// for " block" (not a legal identifier) that maps to a BlockInfo
|
||||
|
|
@ -109,12 +133,16 @@ type RenameList = ~[(ast::Ident,Name)];
|
|||
// AST nodes into full ASTs
|
||||
pub fn syntax_expander_table() -> SyntaxEnv {
|
||||
// utility function to simplify creating NormalTT syntax extensions
|
||||
fn builtin_normal_tt(f: SyntaxExpanderTTFun) -> @Transformer {
|
||||
@SE(NormalTT(f, None))
|
||||
// that ignore their contexts
|
||||
fn builtin_normal_tt_no_ctxt(f: SyntaxExpanderTTFunNoCtxt) -> @Transformer {
|
||||
let wrapped_expander : SyntaxExpanderTTFun = |a,b,c,d|{f(a,b,c)};
|
||||
@SE(NormalTT(wrapped_expander, None))
|
||||
}
|
||||
// utility function to simplify creating IdentTT syntax extensions
|
||||
fn builtin_item_tt(f: SyntaxExpanderTTItemFun) -> @Transformer {
|
||||
@SE(IdentTT(f, None))
|
||||
// that ignore their contexts
|
||||
fn builtin_item_tt_no_ctxt(f: SyntaxExpanderTTItemFunNoCtxt) -> @Transformer {
|
||||
let wrapped_expander : SyntaxExpanderTTItemFun = |a,b,c,d,e|{f(a,b,c,d)};
|
||||
@SE(IdentTT(wrapped_expander, None))
|
||||
}
|
||||
let mut syntax_expanders = HashMap::new();
|
||||
// NB identifier starts with space, and can't conflict with legal idents
|
||||
|
|
@ -124,16 +152,16 @@ pub fn syntax_expander_table() -> SyntaxEnv {
|
|||
pending_renames : @mut ~[]
|
||||
}));
|
||||
syntax_expanders.insert(intern(&"macro_rules"),
|
||||
builtin_item_tt(
|
||||
builtin_item_tt_no_ctxt(
|
||||
ext::tt::macro_rules::add_new_extension));
|
||||
syntax_expanders.insert(intern(&"fmt"),
|
||||
builtin_normal_tt(ext::fmt::expand_syntax_ext));
|
||||
builtin_normal_tt_no_ctxt(ext::fmt::expand_syntax_ext));
|
||||
syntax_expanders.insert(intern(&"format"),
|
||||
builtin_normal_tt(ext::ifmt::expand_format));
|
||||
builtin_normal_tt_no_ctxt(ext::ifmt::expand_format));
|
||||
syntax_expanders.insert(intern(&"write"),
|
||||
builtin_normal_tt(ext::ifmt::expand_write));
|
||||
builtin_normal_tt_no_ctxt(ext::ifmt::expand_write));
|
||||
syntax_expanders.insert(intern(&"writeln"),
|
||||
builtin_normal_tt(ext::ifmt::expand_writeln));
|
||||
builtin_normal_tt_no_ctxt(ext::ifmt::expand_writeln));
|
||||
syntax_expanders.insert(
|
||||
intern(&"auto_encode"),
|
||||
@SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
|
||||
|
|
@ -141,16 +169,16 @@ pub fn syntax_expander_table() -> SyntaxEnv {
|
|||
intern(&"auto_decode"),
|
||||
@SE(ItemDecorator(ext::auto_encode::expand_auto_decode)));
|
||||
syntax_expanders.insert(intern(&"env"),
|
||||
builtin_normal_tt(ext::env::expand_env));
|
||||
builtin_normal_tt_no_ctxt(ext::env::expand_env));
|
||||
syntax_expanders.insert(intern(&"option_env"),
|
||||
builtin_normal_tt(ext::env::expand_option_env));
|
||||
builtin_normal_tt_no_ctxt(ext::env::expand_option_env));
|
||||
syntax_expanders.insert(intern("bytes"),
|
||||
builtin_normal_tt(ext::bytes::expand_syntax_ext));
|
||||
builtin_normal_tt_no_ctxt(ext::bytes::expand_syntax_ext));
|
||||
syntax_expanders.insert(intern("concat_idents"),
|
||||
builtin_normal_tt(
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::concat_idents::expand_syntax_ext));
|
||||
syntax_expanders.insert(intern(&"log_syntax"),
|
||||
builtin_normal_tt(
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::log_syntax::expand_syntax_ext));
|
||||
syntax_expanders.insert(intern(&"deriving"),
|
||||
@SE(ItemDecorator(
|
||||
|
|
@ -158,49 +186,49 @@ pub fn syntax_expander_table() -> SyntaxEnv {
|
|||
|
||||
// Quasi-quoting expanders
|
||||
syntax_expanders.insert(intern(&"quote_tokens"),
|
||||
builtin_normal_tt(ext::quote::expand_quote_tokens));
|
||||
@SE(NormalTT(ext::quote::expand_quote_tokens, None)));
|
||||
syntax_expanders.insert(intern(&"quote_expr"),
|
||||
builtin_normal_tt(ext::quote::expand_quote_expr));
|
||||
@SE(NormalTT(ext::quote::expand_quote_expr, None)));
|
||||
syntax_expanders.insert(intern(&"quote_ty"),
|
||||
builtin_normal_tt(ext::quote::expand_quote_ty));
|
||||
@SE(NormalTT(ext::quote::expand_quote_ty, None)));
|
||||
syntax_expanders.insert(intern(&"quote_item"),
|
||||
builtin_normal_tt(ext::quote::expand_quote_item));
|
||||
@SE(NormalTT(ext::quote::expand_quote_item, None)));
|
||||
syntax_expanders.insert(intern(&"quote_pat"),
|
||||
builtin_normal_tt(ext::quote::expand_quote_pat));
|
||||
@SE(NormalTT(ext::quote::expand_quote_pat, None)));
|
||||
syntax_expanders.insert(intern(&"quote_stmt"),
|
||||
builtin_normal_tt(ext::quote::expand_quote_stmt));
|
||||
@SE(NormalTT(ext::quote::expand_quote_stmt, None)));
|
||||
|
||||
syntax_expanders.insert(intern(&"line"),
|
||||
builtin_normal_tt(
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::source_util::expand_line));
|
||||
syntax_expanders.insert(intern(&"col"),
|
||||
builtin_normal_tt(
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::source_util::expand_col));
|
||||
syntax_expanders.insert(intern(&"file"),
|
||||
builtin_normal_tt(
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::source_util::expand_file));
|
||||
syntax_expanders.insert(intern(&"stringify"),
|
||||
builtin_normal_tt(
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::source_util::expand_stringify));
|
||||
syntax_expanders.insert(intern(&"include"),
|
||||
builtin_normal_tt(
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::source_util::expand_include));
|
||||
syntax_expanders.insert(intern(&"include_str"),
|
||||
builtin_normal_tt(
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::source_util::expand_include_str));
|
||||
syntax_expanders.insert(intern(&"include_bin"),
|
||||
builtin_normal_tt(
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::source_util::expand_include_bin));
|
||||
syntax_expanders.insert(intern(&"module_path"),
|
||||
builtin_normal_tt(
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::source_util::expand_mod));
|
||||
syntax_expanders.insert(intern(&"asm"),
|
||||
builtin_normal_tt(ext::asm::expand_asm));
|
||||
builtin_normal_tt_no_ctxt(ext::asm::expand_asm));
|
||||
syntax_expanders.insert(intern(&"cfg"),
|
||||
builtin_normal_tt(ext::cfg::expand_cfg));
|
||||
builtin_normal_tt_no_ctxt(ext::cfg::expand_cfg));
|
||||
syntax_expanders.insert(
|
||||
intern(&"trace_macros"),
|
||||
builtin_normal_tt(ext::trace_macros::expand_trace_macros));
|
||||
builtin_normal_tt_no_ctxt(ext::trace_macros::expand_trace_macros));
|
||||
MapChain::new(~syntax_expanders)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use ast::{Block, Crate, NodeId, DeclLocal, EMPTY_CTXT, Expr_, ExprMac};
|
||||
use ast::{Block, Crate, NodeId, DeclLocal, EMPTY_CTXT, Expr_, ExprMac, SyntaxContext};
|
||||
use ast::{Local, Ident, mac_invoc_tt};
|
||||
use ast::{item_mac, Mrk, Stmt_, StmtDecl, StmtMac, StmtExpr, StmtSemi};
|
||||
use ast::{ILLEGAL_CTXT, SCTable, token_tree};
|
||||
|
|
@ -42,6 +42,11 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
|
|||
// entry-point for all syntax extensions.
|
||||
ExprMac(ref mac) => {
|
||||
match (*mac).node {
|
||||
// it would almost certainly be cleaner to pass the whole
|
||||
// macro invocation in, rather than pulling it apart and
|
||||
// marking the tts and the ctxt separately. This also goes
|
||||
// for the other three macro invocation chunks of code
|
||||
// in this file.
|
||||
// Token-tree macros:
|
||||
mac_invoc_tt(ref pth, ref tts, ctxt) => {
|
||||
if (pth.segments.len() > 1u) {
|
||||
|
|
@ -70,7 +75,8 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
|
|||
let fm = fresh_mark();
|
||||
// mark before:
|
||||
let marked_before = mark_tts(*tts,fm);
|
||||
let expanded = match expandfun(cx, mac.span, marked_before) {
|
||||
let marked_ctxt = new_mark(fm, ctxt);
|
||||
let expanded = match expandfun(cx, mac.span, marked_before, marked_ctxt) {
|
||||
MRExpr(e) => e,
|
||||
MRAny(expr_maker,_,_) => expr_maker(),
|
||||
_ => {
|
||||
|
|
@ -367,9 +373,9 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
|
|||
cx: @ExtCtxt, it: @ast::item,
|
||||
fld: @ast_fold)
|
||||
-> Option<@ast::item> {
|
||||
let (pth, tts) = match it.node {
|
||||
let (pth, tts, ctxt) = match it.node {
|
||||
item_mac(codemap::Spanned { node: mac_invoc_tt(ref pth, ref tts, ctxt), _}) => {
|
||||
(pth, (*tts).clone())
|
||||
(pth, (*tts).clone(), ctxt)
|
||||
}
|
||||
_ => cx.span_bug(it.span, "invalid item macro invocation")
|
||||
};
|
||||
|
|
@ -396,10 +402,9 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
|
|||
}
|
||||
});
|
||||
// mark before expansion:
|
||||
let marked_tts = mark_tts(tts,fm);
|
||||
// mark after expansion:
|
||||
// RIGHT HERE: can't apply mark_item to MacResult ... :(
|
||||
expander(cx, it.span, marked_tts)
|
||||
let marked_before = mark_tts(tts,fm);
|
||||
let marked_ctxt = new_mark(fm,ctxt);
|
||||
expander(cx, it.span, marked_before, marked_ctxt)
|
||||
}
|
||||
Some(@SE(IdentTT(expander, span))) => {
|
||||
if it.ident.name == parse::token::special_idents::invalid.name {
|
||||
|
|
@ -417,7 +422,8 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
|
|||
let fm = fresh_mark();
|
||||
// mark before expansion:
|
||||
let marked_tts = mark_tts(tts,fm);
|
||||
expander(cx, it.span, it.ident, marked_tts)
|
||||
let marked_ctxt = new_mark(fm,ctxt);
|
||||
expander(cx, it.span, it.ident, marked_tts, marked_ctxt)
|
||||
}
|
||||
_ => cx.span_fatal(
|
||||
it.span, fmt!("%s! is not legal in item position", extnamestr))
|
||||
|
|
@ -468,11 +474,11 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
|
|||
-> (Option<Stmt_>, Span) {
|
||||
// why the copying here and not in expand_expr?
|
||||
// looks like classic changed-in-only-one-place
|
||||
let (mac, pth, tts, semi) = match *s {
|
||||
let (mac, pth, tts, semi, ctxt) = match *s {
|
||||
StmtMac(ref mac, semi) => {
|
||||
match mac.node {
|
||||
mac_invoc_tt(ref pth, ref tts, ctxt) => {
|
||||
((*mac).clone(), pth, (*tts).clone(), semi)
|
||||
((*mac).clone(), pth, (*tts).clone(), semi, ctxt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -498,7 +504,8 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
|
|||
let fm = fresh_mark();
|
||||
// mark before expansion:
|
||||
let marked_tts = mark_tts(tts,fm);
|
||||
let expanded = match expandfun(cx, mac.span, marked_tts) {
|
||||
let marked_ctxt = new_mark(fm,ctxt);
|
||||
let expanded = match expandfun(cx, mac.span, marked_tts, marked_ctxt) {
|
||||
MRExpr(e) =>
|
||||
@codemap::Spanned { node: StmtExpr(e, cx.next_id()),
|
||||
span: e.span},
|
||||
|
|
@ -893,25 +900,6 @@ pub fn new_path_finder(paths: @mut ~[ast::Path]) -> @mut Visitor<()> {
|
|||
context as @mut Visitor<()>
|
||||
}
|
||||
|
||||
// given a mutable list of renames, return a tree-folder that applies those
|
||||
// renames.
|
||||
// FIXME #4536: currently pub to allow testing
|
||||
pub fn renames_to_fold(renames : @mut ~[(ast::Ident,ast::Name)]) -> @ast_fold {
|
||||
let afp = default_ast_fold();
|
||||
let f_pre = @AstFoldFns {
|
||||
fold_ident: |id,_| {
|
||||
// the individual elements are memoized... it would
|
||||
// also be possible to memoize on the whole list at once.
|
||||
let new_ctxt = renames.iter().fold(id.ctxt,|ctxt,&(from,to)| {
|
||||
new_rename(from,to,ctxt)
|
||||
});
|
||||
ast::Ident{name:id.name,ctxt:new_ctxt}
|
||||
},
|
||||
.. *afp
|
||||
};
|
||||
make_fold(f_pre)
|
||||
}
|
||||
|
||||
// expand a block. pushes a new exts_frame, then calls expand_block_elts
|
||||
pub fn expand_block(extsbox: @mut SyntaxEnv,
|
||||
_cx: @ExtCtxt,
|
||||
|
|
@ -1427,6 +1415,7 @@ pub trait CtxtFn{
|
|||
fn f(&self, ast::SyntaxContext) -> ast::SyntaxContext;
|
||||
}
|
||||
|
||||
// a renamer adds a rename to the syntax context
|
||||
pub struct Renamer {
|
||||
from : ast::Ident,
|
||||
to : ast::Name
|
||||
|
|
@ -1438,6 +1427,22 @@ impl CtxtFn for Renamer {
|
|||
}
|
||||
}
|
||||
|
||||
// a renamer that performs a whole bunch of renames
|
||||
pub struct MultiRenamer {
|
||||
renames : @mut ~[(ast::Ident,ast::Name)]
|
||||
}
|
||||
|
||||
impl CtxtFn for MultiRenamer {
|
||||
fn f(&self, starting_ctxt : ast::SyntaxContext) -> ast::SyntaxContext {
|
||||
// the individual elements are memoized... it would
|
||||
// also be possible to memoize on the whole list at once.
|
||||
self.renames.iter().fold(starting_ctxt,|ctxt,&(from,to)| {
|
||||
new_rename(from,to,ctxt)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// a marker adds the given mark to the syntax context
|
||||
pub struct Marker { mark : Mrk }
|
||||
|
||||
impl CtxtFn for Marker {
|
||||
|
|
@ -1446,6 +1451,15 @@ impl CtxtFn for Marker {
|
|||
}
|
||||
}
|
||||
|
||||
// a repainter just replaces the given context with the one it's closed over
|
||||
pub struct Repainter { ctxt : SyntaxContext }
|
||||
|
||||
impl CtxtFn for Repainter {
|
||||
fn f(&self, ctxt : ast::SyntaxContext) -> ast::SyntaxContext {
|
||||
self.ctxt
|
||||
}
|
||||
}
|
||||
|
||||
// given a function from ctxts to ctxts, produce
|
||||
// an ast_fold that applies that function to all ctxts:
|
||||
pub fn fun_to_ctxt_folder<T : 'static + CtxtFn>(cf: @T) -> @AstFoldFns {
|
||||
|
|
@ -1454,7 +1468,7 @@ pub fn fun_to_ctxt_folder<T : 'static + CtxtFn>(cf: @T) -> @AstFoldFns {
|
|||
|ast::Ident{name, ctxt}, _| {
|
||||
ast::Ident{name:name,ctxt:cf.f(ctxt)}
|
||||
};
|
||||
let fm : @fn(&ast::mac_, span, @ast_fold) -> (ast::mac_,span) =
|
||||
let fm : @fn(&ast::mac_, Span, @ast_fold) -> (ast::mac_,Span) =
|
||||
|m, sp, fld| {
|
||||
match *m {
|
||||
mac_invoc_tt(ref path, ref tts, ctxt) =>
|
||||
|
|
@ -1472,6 +1486,15 @@ pub fn fun_to_ctxt_folder<T : 'static + CtxtFn>(cf: @T) -> @AstFoldFns {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// given a mutable list of renames, return a tree-folder that applies those
|
||||
// renames.
|
||||
// FIXME #4536: currently pub to allow testing
|
||||
pub fn renames_to_fold(renames : @mut ~[(ast::Ident,ast::Name)]) -> @AstFoldFns {
|
||||
fun_to_ctxt_folder(@MultiRenamer{renames : renames})
|
||||
}
|
||||
|
||||
// just a convenience:
|
||||
pub fn new_mark_folder(m : Mrk) -> @AstFoldFns { fun_to_ctxt_folder(@Marker{mark:m}) }
|
||||
pub fn new_rename_folder(from : ast::Ident, to : ast::Name) -> @AstFoldFns {
|
||||
|
|
@ -1513,6 +1536,12 @@ fn mark_item(expr : @ast::item, m : Mrk) -> Option<@ast::item> {
|
|||
new_mark_folder(m).fold_item(expr)
|
||||
}
|
||||
|
||||
// replace all contexts in a given expr with the given mark. Used
|
||||
// for capturing macros
|
||||
pub fn replace_ctxts(expr : @ast::Expr, ctxt : SyntaxContext) -> @ast::Expr {
|
||||
fun_to_ctxt_folder(@Repainter{ctxt:ctxt}).fold_expr(expr)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
@ -1522,7 +1551,7 @@ mod test {
|
|||
use codemap;
|
||||
use codemap::Spanned;
|
||||
use parse;
|
||||
use parse::token::{gensym, intern, get_ident_interner};
|
||||
use parse::token::{gensym, intern, get_ident_interner, ident_to_str};
|
||||
use print::pprust;
|
||||
use std;
|
||||
use std::vec;
|
||||
|
|
@ -1656,8 +1685,9 @@ mod test {
|
|||
}
|
||||
}
|
||||
|
||||
fn fake_print_crate(s: @pprust::ps, crate: &ast::Crate) {
|
||||
pprust::print_mod(s, &crate.module, crate.attrs);
|
||||
fn fake_print_crate(crate: @ast::Crate) {
|
||||
let s = pprust::rust_printer(std::io::stderr(),get_ident_interner());
|
||||
pprust::print_crate_(s, crate);
|
||||
}
|
||||
|
||||
fn expand_crate_str(crate_str: @str) -> @ast::Crate {
|
||||
|
|
@ -1784,6 +1814,57 @@ mod test {
|
|||
}
|
||||
}
|
||||
|
||||
#[test] fn quote_expr_test() {
|
||||
quote_ext_cx_test(@"fn main(){let ext_cx = 13; quote_expr!(dontcare);}");
|
||||
}
|
||||
#[test] fn quote_item_test() {
|
||||
quote_ext_cx_test(@"fn main(){let ext_cx = 13; quote_item!(dontcare);}");
|
||||
}
|
||||
#[test] fn quote_pat_test() {
|
||||
quote_ext_cx_test(@"fn main(){let ext_cx = 13; quote_pat!(dontcare);}");
|
||||
}
|
||||
#[test] fn quote_ty_test() {
|
||||
quote_ext_cx_test(@"fn main(){let ext_cx = 13; quote_ty!(dontcare);}");
|
||||
}
|
||||
#[test] fn quote_tokens_test() {
|
||||
quote_ext_cx_test(@"fn main(){let ext_cx = 13; quote_tokens!(dontcare);}");
|
||||
}
|
||||
|
||||
fn quote_ext_cx_test(crate_str : @str) {
|
||||
let crate = expand_crate_str(crate_str);
|
||||
// find the ext_cx binding
|
||||
let bindings = @mut ~[];
|
||||
visit::walk_crate(&mut new_name_finder(bindings), crate, ());
|
||||
let cxbinds : ~[&ast::Ident] = bindings.iter().filter(|b|{@"ext_cx" == (ident_to_str(*b))}).collect();
|
||||
let cxbind = match cxbinds {
|
||||
[b] => b,
|
||||
_ => fail!("expected just one binding for ext_cx")
|
||||
};
|
||||
let resolved_binding = mtwt_resolve(*cxbind);
|
||||
// find all the ext_cx varrefs:
|
||||
let varrefs = @mut ~[];
|
||||
visit::walk_crate(&mut new_path_finder(varrefs), crate, ());
|
||||
// the ext_cx binding should bind all of the ext_cx varrefs:
|
||||
for (idx,v) in varrefs.iter().filter(|p|{ p.segments.len() == 1
|
||||
&& (@"ext_cx" == (ident_to_str(&p.segments[0].identifier)))
|
||||
}).enumerate() {
|
||||
if (mtwt_resolve(v.segments[0].identifier) != resolved_binding) {
|
||||
std::io::println("uh oh, ext_cx binding didn't match ext_cx varref:");
|
||||
std::io::println(fmt!("this is varref # %?",idx));
|
||||
std::io::println(fmt!("binding: %?",cxbind));
|
||||
std::io::println(fmt!("resolves to: %?",resolved_binding));
|
||||
std::io::println(fmt!("varref: %?",v.segments[0]));
|
||||
std::io::println(fmt!("resolves to: %?",mtwt_resolve(v.segments[0].identifier)));
|
||||
let table = get_sctable();
|
||||
std::io::println("SC table:");
|
||||
for (idx,val) in table.table.iter().enumerate() {
|
||||
std::io::println(fmt!("%4u : %?",idx,val));
|
||||
}
|
||||
}
|
||||
assert_eq!(mtwt_resolve(v.segments[0].identifier),resolved_binding);
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pat_idents(){
|
||||
let pat = string_to_pat(@"(a,Foo{x:c @ (b,9),y:Bar(4,d)})");
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use ast;
|
|||
use codemap::{BytePos, Pos, Span};
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::base;
|
||||
use ext::expand;
|
||||
use ext::build::AstBuilder;
|
||||
use parse::token::*;
|
||||
use parse::token;
|
||||
|
|
@ -291,47 +292,73 @@ pub mod rt {
|
|||
|
||||
pub fn expand_quote_tokens(cx: @ExtCtxt,
|
||||
sp: Span,
|
||||
tts: &[ast::token_tree]) -> base::MacResult {
|
||||
tts: &[ast::token_tree],
|
||||
ctxt: ast::SyntaxContext) -> base::MacResult {
|
||||
let (cx_expr, expr) = expand_tts(cx, sp, tts);
|
||||
base::MRExpr(expand_wrapper(cx, sp, cx_expr, expr))
|
||||
let expanded = expand_wrapper(cx, sp, cx_expr, expr);
|
||||
// repaint the expanded code so it's as though it was the original text.
|
||||
let repainted = expand::replace_ctxts(expanded,ctxt);
|
||||
base::MRExpr(repainted)
|
||||
}
|
||||
|
||||
pub fn expand_quote_expr(cx: @ExtCtxt,
|
||||
sp: Span,
|
||||
tts: &[ast::token_tree]) -> base::MacResult {
|
||||
base::MRExpr(expand_parse_call(cx, sp, "parse_expr", ~[], tts))
|
||||
tts: &[ast::token_tree],
|
||||
ctxt: ast::SyntaxContext) -> base::MacResult {
|
||||
let expanded = expand_parse_call(cx, sp, "parse_expr", ~[], tts);
|
||||
// repaint the expanded code so it's as though it was the original text.
|
||||
let repainted = expand::replace_ctxts(expanded,ctxt);
|
||||
base::MRExpr(repainted)
|
||||
}
|
||||
|
||||
// these probably need to be capturing, too...
|
||||
|
||||
pub fn expand_quote_item(cx: @ExtCtxt,
|
||||
sp: Span,
|
||||
tts: &[ast::token_tree]) -> base::MacResult {
|
||||
tts: &[ast::token_tree],
|
||||
ctxt: ast::SyntaxContext) -> base::MacResult {
|
||||
let e_attrs = cx.expr_vec_uniq(sp, ~[]);
|
||||
base::MRExpr(expand_parse_call(cx, sp, "parse_item",
|
||||
~[e_attrs], tts))
|
||||
let expanded = expand_parse_call(cx, sp, "parse_item",
|
||||
~[e_attrs], tts);
|
||||
// repaint the expanded code so it's as though it was the original text.
|
||||
let repainted = expand::replace_ctxts(expanded,ctxt);
|
||||
base::MRExpr(repainted)
|
||||
}
|
||||
|
||||
pub fn expand_quote_pat(cx: @ExtCtxt,
|
||||
sp: Span,
|
||||
tts: &[ast::token_tree]) -> base::MacResult {
|
||||
tts: &[ast::token_tree],
|
||||
ctxt: ast::SyntaxContext) -> base::MacResult {
|
||||
let e_refutable = cx.expr_lit(sp, ast::lit_bool(true));
|
||||
base::MRExpr(expand_parse_call(cx, sp, "parse_pat",
|
||||
~[e_refutable], tts))
|
||||
let expanded = expand_parse_call(cx, sp, "parse_pat",
|
||||
~[e_refutable], tts);
|
||||
// repaint the expanded code so it's as though it was the original text.
|
||||
let repainted = expand::replace_ctxts(expanded,ctxt);
|
||||
base::MRExpr(repainted)
|
||||
}
|
||||
|
||||
pub fn expand_quote_ty(cx: @ExtCtxt,
|
||||
sp: Span,
|
||||
tts: &[ast::token_tree]) -> base::MacResult {
|
||||
tts: &[ast::token_tree],
|
||||
ctxt: ast::SyntaxContext) -> base::MacResult {
|
||||
let e_param_colons = cx.expr_lit(sp, ast::lit_bool(false));
|
||||
base::MRExpr(expand_parse_call(cx, sp, "parse_ty",
|
||||
~[e_param_colons], tts))
|
||||
let expanded = expand_parse_call(cx, sp, "parse_ty",
|
||||
~[e_param_colons], tts);
|
||||
// repaint the expanded code so it's as though it was the original text.
|
||||
let repainted = expand::replace_ctxts(expanded,ctxt);
|
||||
base::MRExpr(repainted)
|
||||
}
|
||||
|
||||
pub fn expand_quote_stmt(cx: @ExtCtxt,
|
||||
sp: Span,
|
||||
tts: &[ast::token_tree]) -> base::MacResult {
|
||||
tts: &[ast::token_tree],
|
||||
ctxt: ast::SyntaxContext) -> base::MacResult {
|
||||
let e_attrs = cx.expr_vec_uniq(sp, ~[]);
|
||||
base::MRExpr(expand_parse_call(cx, sp, "parse_stmt",
|
||||
~[e_attrs], tts))
|
||||
let expanded = expand_parse_call(cx, sp, "parse_stmt",
|
||||
~[e_attrs], tts);
|
||||
// repaint the expanded code so it's as though it was the original text.
|
||||
let repainted = expand::replace_ctxts(expanded,ctxt);
|
||||
base::MRExpr(repainted)
|
||||
}
|
||||
|
||||
fn ids_ext(strs: ~[~str]) -> ~[ast::Ident] {
|
||||
|
|
|
|||
|
|
@ -150,8 +150,8 @@ pub fn add_new_extension(cx: @ExtCtxt,
|
|||
cx.span_fatal(best_fail_spot, best_fail_msg);
|
||||
}
|
||||
|
||||
let exp: @fn(@ExtCtxt, Span, &[ast::token_tree]) -> MacResult =
|
||||
|cx, sp, arg| generic_extension(cx, sp, name, arg, *lhses, *rhses);
|
||||
let exp: @fn(@ExtCtxt, Span, &[ast::token_tree], ctxt: ast::SyntaxContext) -> MacResult =
|
||||
|cx, sp, arg, _ctxt| generic_extension(cx, sp, name, arg, *lhses, *rhses);
|
||||
|
||||
return MRDef(MacroDef{
|
||||
name: ident_to_str(&name),
|
||||
|
|
|
|||
|
|
@ -209,6 +209,7 @@ pub fn noop_fold_crate(c: &Crate, fld: @ast_fold) -> Crate {
|
|||
}
|
||||
|
||||
fn noop_fold_view_item(vi: &view_item_, _fld: @ast_fold) -> view_item_ {
|
||||
// FIXME #7654: doesn't iterate over idents in a view_item_use
|
||||
return /* FIXME (#2543) */ (*vi).clone();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue