libsyntax: Remove some more @fns from the macro expander

This commit is contained in:
Patrick Walton 2013-08-30 14:40:05 -07:00
parent 6a8169db0a
commit e95996399f
3 changed files with 294 additions and 103 deletions

View File

@ -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 ItemDecorator = extern "Rust" fn(@ExtCtxt,
Span,
@ast::MetaItem,
~[@ast::item])
-> ~[@ast::item];
pub type ItemDecoratorFun = @fn(@ExtCtxt,
Span,
@ast::MetaItem,
~[@ast::item])
-> ~[@ast::item];
pub struct SyntaxExpanderTT {
expander: SyntaxExpanderTTExpander,
span: Option<Span>
}
pub type SyntaxExpanderTTFun = @fn(@ExtCtxt,
Span,
&[ast::token_tree],
ast::SyntaxContext)
-> MacResult;
pub trait SyntaxExpanderTTTrait {
fn expand(&self,
ecx: @ExtCtxt,
span: Span,
token_tree: &[ast::token_tree],
context: ast::SyntaxContext)
-> MacResult;
}
pub type SyntaxExpanderTTItemFun = @fn(@ExtCtxt,
Span,
ast::Ident,
~[ast::token_tree],
ast::SyntaxContext)
-> MacResult;
pub type SyntaxExpanderTTFunNoCtxt =
extern "Rust" fn(ecx: @ExtCtxt,
span: codemap::Span,
token_tree: &[ast::token_tree])
-> 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:
enum SyntaxExpanderTTExpander {
SyntaxExpanderTTExpanderWithoutContext(SyntaxExpanderTTFunNoCtxt),
}
pub type SyntaxExpanderTTFunNoCtxt = @fn(@ExtCtxt,
Span,
&[ast::token_tree])
-> MacResult;
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)
}
}
}
}
pub type SyntaxExpanderTTItemFunNoCtxt = @fn(@ExtCtxt,
Span,
ast::Ident,
~[ast::token_tree])
-> MacResult;
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)
}

View File

@ -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))

View File

@ -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))
});