diff options
| author | Patrick Walton <pcwalton@mimiga.net> | 2013-08-30 14:40:05 -0700 |
|---|---|---|
| committer | Patrick Walton <pcwalton@mimiga.net> | 2013-09-23 18:23:21 -0700 |
| commit | e95996399fe6d306a206082eb1a49189c5afe878 (patch) | |
| tree | 98d045bbdcff2897d53a0e1e064ff17277058b8f /src/libsyntax/ext | |
| parent | 6a8169db0a201b9fc2fbf581f507e143f0482aae (diff) | |
| download | rust-e95996399fe6d306a206082eb1a49189c5afe878.tar.gz rust-e95996399fe6d306a206082eb1a49189c5afe878.zip | |
libsyntax: Remove some more `@fn`s from the macro expander
Diffstat (limited to 'src/libsyntax/ext')
| -rw-r--r-- | src/libsyntax/ext/base.rs | 238 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 30 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/macro_rules.rs | 141 |
3 files changed, 300 insertions, 109 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 2bcfafc3bb4..63816072c29 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -33,62 +33,120 @@ 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, - ~[@ast::item]) - -> ~[@ast::item]; - -pub type SyntaxExpanderTTFun = @fn(@ExtCtxt, - Span, - &[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 type ItemDecorator = extern "Rust" fn(@ExtCtxt, + Span, + @ast::MetaItem, + ~[@ast::item]) + -> ~[@ast::item]; + +pub struct SyntaxExpanderTT { + expander: SyntaxExpanderTTExpander, + span: Option<Span> +} + +pub trait SyntaxExpanderTTTrait { + fn expand(&self, + ecx: @ExtCtxt, + span: Span, + token_tree: &[ast::token_tree], + context: ast::SyntaxContext) + -> MacResult; +} + +pub type SyntaxExpanderTTFunNoCtxt = + extern "Rust" fn(ecx: @ExtCtxt, + span: codemap::Span, + token_tree: &[ast::token_tree]) + -> MacResult; + +enum SyntaxExpanderTTExpander { + SyntaxExpanderTTExpanderWithoutContext(SyntaxExpanderTTFunNoCtxt), +} + +impl SyntaxExpanderTTTrait for SyntaxExpanderTT { + fn expand(&self, + ecx: @ExtCtxt, + span: Span, + token_tree: &[ast::token_tree], + _: ast::SyntaxContext) + -> MacResult { + match self.expander { + SyntaxExpanderTTExpanderWithoutContext(f) => { + f(ecx, span, token_tree) + } + } + } +} +enum SyntaxExpanderTTItemExpander { + SyntaxExpanderTTItemExpanderWithContext(SyntaxExpanderTTItemFun), + SyntaxExpanderTTItemExpanderWithoutContext(SyntaxExpanderTTItemFunNoCtxt), +} +pub struct SyntaxExpanderTTItem { + expander: SyntaxExpanderTTItemExpander, + span: Option<Span> +} + +pub trait SyntaxExpanderTTItemTrait { + fn expand(&self, + cx: @ExtCtxt, + sp: Span, + ident: ast::Ident, + token_tree: ~[ast::token_tree], + context: ast::SyntaxContext) + -> MacResult; +} + +impl SyntaxExpanderTTItemTrait for SyntaxExpanderTTItem { + fn expand(&self, + cx: @ExtCtxt, + sp: Span, + ident: ast::Ident, + token_tree: ~[ast::token_tree], + context: ast::SyntaxContext) + -> MacResult { + match self.expander { + SyntaxExpanderTTItemExpanderWithContext(fun) => { + fun(cx, sp, ident, token_tree, context) + } + SyntaxExpanderTTItemExpanderWithoutContext(fun) => { + fun(cx, sp, ident, token_tree) + } + } + } +} + +pub type SyntaxExpanderTTItemFun = extern "Rust" fn(@ExtCtxt, + Span, + ast::Ident, + ~[ast::token_tree], + ast::SyntaxContext) + -> MacResult; + +pub type SyntaxExpanderTTItemFunNoCtxt = + extern "Rust" fn(@ExtCtxt, Span, ast::Ident, ~[ast::token_tree]) + -> MacResult; + +pub trait AnyMacro { + fn make_expr(&self) -> @ast::Expr; + fn make_item(&self) -> Option<@ast::item>; + fn make_stmt(&self) -> @ast::Stmt; +} pub enum MacResult { MRExpr(@ast::Expr), MRItem(@ast::item), - MRAny(@fn() -> @ast::Expr, - @fn() -> Option<@ast::item>, - @fn() -> @ast::Stmt), - MRDef(MacroDef) + MRAny(@AnyMacro), + MRDef(MacroDef), } pub enum SyntaxExtension { - // #[auto_encode] and such - ItemDecorator(ItemDecoratorFun), + ItemDecorator(ItemDecorator), // Token-tree expanders - NormalTT(SyntaxExpanderTTFun, Option<Span>), + NormalTT(@SyntaxExpanderTTTrait, Option<Span>), // An IdentTT is a macro that has an // identifier in between the name of the @@ -98,7 +156,7 @@ pub enum SyntaxExtension { // perhaps macro_rules! will lose its odd special identifier argument, // and this can go away also - IdentTT(SyntaxExpanderTTItemFun, Option<Span>), + IdentTT(@SyntaxExpanderTTItemTrait, Option<Span>), } @@ -133,16 +191,22 @@ type RenameList = ~[(ast::Ident,Name)]; // AST nodes into full ASTs pub fn syntax_expander_table() -> SyntaxEnv { // utility function to simplify creating NormalTT syntax extensions - // 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)) + fn builtin_normal_tt_no_ctxt(f: SyntaxExpanderTTFunNoCtxt) + -> @Transformer { + @SE(NormalTT(@SyntaxExpanderTT{ + expander: SyntaxExpanderTTExpanderWithoutContext(f), + span: None, + } as @SyntaxExpanderTTTrait, + None)) } // utility function to simplify creating IdentTT syntax extensions // 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)) + @SE(IdentTT(@SyntaxExpanderTTItem { + expander: SyntaxExpanderTTItemExpanderWithoutContext(f), + span: None, + } as @SyntaxExpanderTTItemTrait, + None)) } let mut syntax_expanders = HashMap::new(); // NB identifier starts with space, and can't conflict with legal idents @@ -152,11 +216,17 @@ pub fn syntax_expander_table() -> SyntaxEnv { pending_renames : @mut ~[] })); syntax_expanders.insert(intern(&"macro_rules"), - @SE(IdentTT(ext::tt::macro_rules::add_new_extension, None))); + @SE(IdentTT(@SyntaxExpanderTTItem { + expander: SyntaxExpanderTTItemExpanderWithContext(ext::tt::macro_rules::add_new_extension), + span: None, + } as @SyntaxExpanderTTItemTrait, + None))); syntax_expanders.insert(intern(&"fmt"), - builtin_normal_tt_no_ctxt(ext::fmt::expand_syntax_ext)); + builtin_normal_tt_no_ctxt( + ext::fmt::expand_syntax_ext)); syntax_expanders.insert(intern(&"format_args"), - builtin_normal_tt_no_ctxt(ext::format::expand_args)); + builtin_normal_tt_no_ctxt( + ext::format::expand_args)); syntax_expanders.insert( intern(&"auto_encode"), @SE(ItemDecorator(ext::auto_encode::expand_auto_encode))); @@ -164,67 +234,77 @@ 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_no_ctxt(ext::env::expand_env)); + builtin_normal_tt_no_ctxt( + ext::env::expand_env)); syntax_expanders.insert(intern(&"option_env"), - builtin_normal_tt_no_ctxt(ext::env::expand_option_env)); + builtin_normal_tt_no_ctxt( + ext::env::expand_option_env)); syntax_expanders.insert(intern("bytes"), - builtin_normal_tt_no_ctxt(ext::bytes::expand_syntax_ext)); + builtin_normal_tt_no_ctxt( + ext::bytes::expand_syntax_ext)); syntax_expanders.insert(intern("concat_idents"), builtin_normal_tt_no_ctxt( - ext::concat_idents::expand_syntax_ext)); + ext::concat_idents::expand_syntax_ext)); syntax_expanders.insert(intern(&"log_syntax"), builtin_normal_tt_no_ctxt( - ext::log_syntax::expand_syntax_ext)); + ext::log_syntax::expand_syntax_ext)); syntax_expanders.insert(intern(&"deriving"), @SE(ItemDecorator( ext::deriving::expand_meta_deriving))); // Quasi-quoting expanders syntax_expanders.insert(intern(&"quote_tokens"), - builtin_normal_tt_no_ctxt( - ext::quote::expand_quote_tokens)); + builtin_normal_tt_no_ctxt( + ext::quote::expand_quote_tokens)); syntax_expanders.insert(intern(&"quote_expr"), - builtin_normal_tt_no_ctxt(ext::quote::expand_quote_expr)); + builtin_normal_tt_no_ctxt( + ext::quote::expand_quote_expr)); syntax_expanders.insert(intern(&"quote_ty"), - builtin_normal_tt_no_ctxt(ext::quote::expand_quote_ty)); + builtin_normal_tt_no_ctxt( + ext::quote::expand_quote_ty)); syntax_expanders.insert(intern(&"quote_item"), - builtin_normal_tt_no_ctxt(ext::quote::expand_quote_item)); + builtin_normal_tt_no_ctxt( + ext::quote::expand_quote_item)); syntax_expanders.insert(intern(&"quote_pat"), - builtin_normal_tt_no_ctxt(ext::quote::expand_quote_pat)); + builtin_normal_tt_no_ctxt( + ext::quote::expand_quote_pat)); syntax_expanders.insert(intern(&"quote_stmt"), - builtin_normal_tt_no_ctxt(ext::quote::expand_quote_stmt)); + builtin_normal_tt_no_ctxt( + ext::quote::expand_quote_stmt)); syntax_expanders.insert(intern(&"line"), builtin_normal_tt_no_ctxt( - ext::source_util::expand_line)); + ext::source_util::expand_line)); syntax_expanders.insert(intern(&"col"), builtin_normal_tt_no_ctxt( - ext::source_util::expand_col)); + ext::source_util::expand_col)); syntax_expanders.insert(intern(&"file"), builtin_normal_tt_no_ctxt( - ext::source_util::expand_file)); + ext::source_util::expand_file)); syntax_expanders.insert(intern(&"stringify"), builtin_normal_tt_no_ctxt( - ext::source_util::expand_stringify)); + ext::source_util::expand_stringify)); syntax_expanders.insert(intern(&"include"), builtin_normal_tt_no_ctxt( - ext::source_util::expand_include)); + ext::source_util::expand_include)); syntax_expanders.insert(intern(&"include_str"), builtin_normal_tt_no_ctxt( - ext::source_util::expand_include_str)); + ext::source_util::expand_include_str)); syntax_expanders.insert(intern(&"include_bin"), builtin_normal_tt_no_ctxt( - ext::source_util::expand_include_bin)); + ext::source_util::expand_include_bin)); syntax_expanders.insert(intern(&"module_path"), builtin_normal_tt_no_ctxt( - ext::source_util::expand_mod)); + ext::source_util::expand_mod)); syntax_expanders.insert(intern(&"asm"), - builtin_normal_tt_no_ctxt(ext::asm::expand_asm)); + builtin_normal_tt_no_ctxt( + ext::asm::expand_asm)); syntax_expanders.insert(intern(&"cfg"), - builtin_normal_tt_no_ctxt(ext::cfg::expand_cfg)); - syntax_expanders.insert( - intern(&"trace_macros"), - builtin_normal_tt_no_ctxt(ext::trace_macros::expand_trace_macros)); + builtin_normal_tt_no_ctxt( + ext::cfg::expand_cfg)); + syntax_expanders.insert(intern(&"trace_macros"), + builtin_normal_tt_no_ctxt( + ext::trace_macros::expand_trace_macros)); MapChain::new(~syntax_expanders) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 0aefbe31338..60aa7cc5f92 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -83,10 +83,12 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, let mac_span = original_span(cx); let expanded = - match expandfun(cx, mac_span.call_site, - marked_before, marked_ctxt) { + match expandfun.expand(cx, + mac_span.call_site, + marked_before, + marked_ctxt) { MRExpr(e) => e, - MRAny(expr_maker,_,_) => expr_maker(), + MRAny(any_macro) => any_macro.make_expr(), _ => { cx.span_fatal( pth.span, @@ -370,7 +372,7 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv, // mark before expansion: let marked_before = mark_tts(tts,fm); let marked_ctxt = new_mark(fm,ctxt); - expander(cx, it.span, marked_before, marked_ctxt) + expander.expand(cx, it.span, marked_before, marked_ctxt) } Some(@SE(IdentTT(expander, span))) => { if it.ident.name == parse::token::special_idents::invalid.name { @@ -388,7 +390,7 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv, // mark before expansion: let marked_tts = mark_tts(tts,fm); let marked_ctxt = new_mark(fm,ctxt); - expander(cx, it.span, it.ident, marked_tts, marked_ctxt) + expander.expand(cx, it.span, it.ident, marked_tts, marked_ctxt) } _ => cx.span_fatal( it.span, fmt!("%s! is not legal in item position", extnamestr)) @@ -402,10 +404,10 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv, MRExpr(_) => { cx.span_fatal(pth.span, fmt!("expr macro in item position: %s", extnamestr)) } - MRAny(_, item_maker, _) => { - item_maker() - .and_then(|i| mark_item(i,fm)) - .and_then(|i| fld.fold_item(i)) + MRAny(any_macro) => { + any_macro.make_item() + .and_then(|i| mark_item(i,fm)) + .and_then(|i| fld.fold_item(i)) } MRDef(ref mdef) => { // yikes... no idea how to apply the mark to this. I'm afraid @@ -481,17 +483,17 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv, // not the current mac.span. let mac_span = original_span(cx); - let expanded = match expandfun(cx, - mac_span.call_site, - marked_tts, - marked_ctxt) { + let expanded = match expandfun.expand(cx, + mac_span.call_site, + marked_tts, + marked_ctxt) { MRExpr(e) => { @codemap::Spanned { node: StmtExpr(e, ast::DUMMY_NODE_ID), span: e.span, } } - MRAny(_,_,stmt_mkr) => stmt_mkr(), + MRAny(any_macro) => any_macro.make_stmt(), _ => cx.span_fatal( pth.span, fmt!("non-stmt macro in stmt pos: %s", extnamestr)) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 74de8eaa09e..3fd394b3652 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -12,9 +12,9 @@ use ast::{Ident, matcher_, matcher, match_tok, match_nonterminal, match_seq}; use ast::{tt_delim}; use ast; use codemap::{Span, Spanned, dummy_sp}; -use ext::base::{ExtCtxt, MacResult, MRAny, MRDef, MacroDef, NormalTT}; +use ext::base::{AnyMacro, ExtCtxt, MacResult, MRAny, MRDef, MacroDef}; +use ext::base::{NormalTT, SyntaxExpanderTTTrait}; use ext::base; -use ext::expand; use ext::tt::macro_parser::{error}; use ext::tt::macro_parser::{named_match, matched_seq, matched_nonterminal}; use ext::tt::macro_parser::{parse, parse_or_else, success, failure}; @@ -24,6 +24,112 @@ use parse::token::{get_ident_interner, special_idents, gensym_ident, ident_to_st use parse::token::{FAT_ARROW, SEMI, nt_matchers, nt_tt}; use print; +struct ParserAnyMacro { + parser: @Parser, +} + +impl AnyMacro for ParserAnyMacro { + fn make_expr(&self) -> @ast::Expr { + self.parser.parse_expr() + } + fn make_item(&self) -> Option<@ast::item> { + self.parser.parse_item(~[]) // no attrs + } + fn make_stmt(&self) -> @ast::Stmt { + self.parser.parse_stmt(~[]) // no attrs + } +} + +struct MacroRulesSyntaxExpanderTTFun { + name: Ident, + lhses: @~[@named_match], + rhses: @~[@named_match], +} + +impl SyntaxExpanderTTTrait for MacroRulesSyntaxExpanderTTFun { + fn expand(&self, + cx: @ExtCtxt, + sp: Span, + arg: &[ast::token_tree], + _: ast::SyntaxContext) + -> MacResult { + generic_extension(cx, sp, self.name, arg, *self.lhses, *self.rhses) + } +} + +// Given `lhses` and `rhses`, this is the new macro we create +fn generic_extension(cx: @ExtCtxt, + sp: Span, + name: Ident, + arg: &[ast::token_tree], + lhses: &[@named_match], + rhses: &[@named_match]) + -> MacResult { + if cx.trace_macros() { + printfln!("%s! { %s }", + cx.str_of(name), + print::pprust::tt_to_str( + &ast::tt_delim(@mut arg.to_owned()), + get_ident_interner())); + } + + // Which arm's failure should we report? (the one furthest along) + let mut best_fail_spot = dummy_sp(); + let mut best_fail_msg = ~"internal error: ran no matchers"; + + let s_d = cx.parse_sess().span_diagnostic; + + for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers + match *lhs { + @matched_nonterminal(nt_matchers(ref mtcs)) => { + // `none` is because we're not interpolating + let arg_rdr = new_tt_reader( + s_d, + None, + arg.to_owned() + ) as @mut reader; + match parse(cx.parse_sess(), cx.cfg(), arg_rdr, *mtcs) { + success(named_matches) => { + let rhs = match rhses[i] { + // okay, what's your transcriber? + @matched_nonterminal(nt_tt(@ref tt)) => { + match (*tt) { + // cut off delimiters; don't parse 'em + tt_delim(ref tts) => { + (*tts).slice(1u,(*tts).len()-1u).to_owned() + } + _ => cx.span_fatal( + sp, "macro rhs must be delimited") + } + }, + _ => cx.span_bug(sp, "bad thing in rhs") + }; + // rhs has holes ( `$id` and `$(...)` that need filled) + let trncbr = new_tt_reader(s_d, Some(named_matches), + rhs); + let p = @Parser(cx.parse_sess(), + cx.cfg(), + trncbr as @mut reader); + + // Let the context choose how to interpret the result. + // Weird, but useful for X-macros. + return MRAny(@ParserAnyMacro { + parser: p, + } as @AnyMacro) + } + failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo { + best_fail_spot = sp; + best_fail_msg = (*msg).clone(); + }, + error(sp, ref msg) => cx.span_fatal(sp, (*msg)) + } + } + _ => cx.bug("non-matcher found in parsed lhses") + } + } + cx.span_fatal(best_fail_spot, best_fail_msg); +} + // this procedure performs the expansion of the // macro_rules! macro. It parses the RHS and adds // an extension to the current context. @@ -31,10 +137,8 @@ pub fn add_new_extension(cx: @ExtCtxt, sp: Span, name: Ident, arg: ~[ast::token_tree], - stx_ctxt: ast::SyntaxContext) - -> base::MacResult { - let arg = expand::mtwt_cancel_outer_mark(arg,stx_ctxt); - // Wrap a matcher_ in a spanned to produce a matcher. + _: ast::SyntaxContext) + -> base::MacResult { // these spans won't matter, anyways fn ms(m: matcher_) -> matcher { Spanned { @@ -82,11 +186,13 @@ pub fn add_new_extension(cx: @ExtCtxt, }; // Given `lhses` and `rhses`, this is the new macro we create - fn generic_extension(cx: @ExtCtxt, sp: Span, name: Ident, + fn generic_extension(cx: @ExtCtxt, + sp: Span, + name: Ident, arg: &[ast::token_tree], - lhses: &[@named_match], rhses: &[@named_match]) - -> MacResult { - + lhses: &[@named_match], + rhses: &[@named_match]) + -> MacResult { if cx.trace_macros() { printfln!("%s! { %s }", cx.str_of(name), @@ -135,9 +241,9 @@ pub fn add_new_extension(cx: @ExtCtxt, // Let the context choose how to interpret the result. // Weird, but useful for X-macros. - return MRAny(|| p.parse_expr(), - || p.parse_item(~[/* no attrs*/]), - || p.parse_stmt(~[/* no attrs*/])); + return MRAny(@ParserAnyMacro { + parser: p + } as @AnyMacro); } failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo { best_fail_spot = sp; @@ -152,10 +258,13 @@ pub fn add_new_extension(cx: @ExtCtxt, cx.span_fatal(best_fail_spot, best_fail_msg); } - let exp: @fn(@ExtCtxt, Span, &[ast::token_tree], ctxt: ast::SyntaxContext) -> MacResult = - |cx, sp, arg, _ctxt| generic_extension(cx, sp, name, arg, *lhses, *rhses); + let exp = @MacroRulesSyntaxExpanderTTFun { + name: name, + lhses: lhses, + rhses: rhses, + } as @SyntaxExpanderTTTrait; - return MRDef(MacroDef{ + return MRDef(MacroDef { name: ident_to_str(&name), ext: NormalTT(exp, Some(sp)) }); |
