1
Fork 0

syntax: rename quote! to quote_tokens!, add quote_{expr,type,item,pat,stmt}!

r=brson, Close #3976.
This commit is contained in:
Graydon Hoare 2012-11-16 14:50:35 -08:00
parent 2bf6663cf0
commit 5005be67cc
3 changed files with 141 additions and 28 deletions

View file

@ -96,8 +96,21 @@ fn syntax_expander_table() -> HashMap<~str, syntax_extension> {
ext::log_syntax::expand_syntax_ext));
syntax_expanders.insert(~"ast",
builtin(ext::qquote::expand_ast));
syntax_expanders.insert(~"quote",
builtin_expr_tt(ext::quote::expand_quote));
// Quasi-quoting expanders
syntax_expanders.insert(~"quote_tokens",
builtin_expr_tt(ext::quote::expand_quote_tokens));
syntax_expanders.insert(~"quote_expr",
builtin_expr_tt(ext::quote::expand_quote_expr));
syntax_expanders.insert(~"quote_type",
builtin_expr_tt(ext::quote::expand_quote_type));
syntax_expanders.insert(~"quote_item",
builtin_expr_tt(ext::quote::expand_quote_item));
syntax_expanders.insert(~"quote_pat",
builtin_expr_tt(ext::quote::expand_quote_pat));
syntax_expanders.insert(~"quote_stmt",
builtin_expr_tt(ext::quote::expand_quote_stmt));
syntax_expanders.insert(~"line",
builtin(ext::source_util::expand_line));
syntax_expanders.insert(~"col",

View file

@ -16,33 +16,54 @@ use token::*;
*
*/
pub fn expand_quote(cx: ext_ctxt,
sp: span,
tts: ~[ast::token_tree]) -> base::mac_result
{
pub mod rt {
pub use ast::*;
pub use parse::token::*;
pub use parse::new_parser_from_tt;
}
// 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
// under quote_depth > 0. This is silly and should go away; the _guess_ is
// it has to do with transition away from supporting old-style macros, so
// try removing it when enough of them are gone.
let p = parse::new_parser_from_tt(cx.parse_sess(), cx.cfg(), tts);
p.quote_depth += 1u;
let tq = dvec::DVec();
while p.token != token::EOF {
tq.push(p.parse_token_tree());
}
let tts = tq.get();
pub fn expand_quote_tokens(cx: ext_ctxt,
sp: span,
tts: ~[ast::token_tree]) -> base::mac_result {
base::mr_expr(expand_tt(cx, sp, tts))
}
// We want to emit a block expression that does a sequence of 'use's to
// import the AST and token constructors, followed by a tt expression.
let uses = ~[ build::mk_glob_use(cx, sp, ids_ext(cx, ~[~"syntax",
~"ast"])),
build::mk_glob_use(cx, sp, ids_ext(cx, ~[~"syntax",
~"parse",
~"token"])) ];
base::mr_expr(build::mk_block(cx, sp, uses, ~[],
Some(mk_tt(cx, sp, &ast::tt_delim(tts)))))
pub fn expand_quote_expr(cx: ext_ctxt,
sp: span,
tts: ~[ast::token_tree]) -> base::mac_result {
base::mr_expr(expand_parse_call(cx, sp, ~"parse_expr", ~[], tts))
}
pub fn expand_quote_item(cx: ext_ctxt,
sp: span,
tts: ~[ast::token_tree]) -> base::mac_result {
let e_attrs = build::mk_uniq_vec_e(cx, sp, ~[]);
base::mr_expr(expand_parse_call(cx, sp, ~"parse_item",
~[e_attrs], tts))
}
pub fn expand_quote_pat(cx: ext_ctxt,
sp: span,
tts: ~[ast::token_tree]) -> base::mac_result {
let e_refutable = build::mk_lit(cx, sp, ast::lit_bool(true));
base::mr_expr(expand_parse_call(cx, sp, ~"parse_pat",
~[e_refutable], tts))
}
pub fn expand_quote_type(cx: ext_ctxt,
sp: span,
tts: ~[ast::token_tree]) -> base::mac_result {
let e_param_colons = build::mk_lit(cx, sp, ast::lit_bool(false));
base::mr_expr(expand_parse_call(cx, sp, ~"parse_type",
~[e_param_colons], tts))
}
pub fn expand_quote_stmt(cx: ext_ctxt,
sp: span,
tts: ~[ast::token_tree]) -> base::mac_result {
let e_attrs = build::mk_uniq_vec_e(cx, sp, ~[]);
base::mr_expr(expand_parse_call(cx, sp, ~"parse_stmt",
~[e_attrs], tts))
}
fn ids_ext(cx: ext_ctxt, strs: ~[~str]) -> ~[ast::ident] {
@ -304,4 +325,64 @@ fn mk_tt(cx: ext_ctxt, sp: span, tt: &ast::token_tree) -> @ast::expr {
ast::tt_nonterminal(sp, ident) =>
build::mk_copy(cx, sp, build::mk_path(cx, sp, ~[ident]))
}
}
}
fn expand_tt(cx: ext_ctxt,
sp: span,
tts: ~[ast::token_tree]) -> @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
// under quote_depth > 0. This is silly and should go away; the _guess_ is
// it has to do with transition away from supporting old-style macros, so
// try removing it when enough of them are gone.
let p = parse::new_parser_from_tt(cx.parse_sess(), cx.cfg(), tts);
p.quote_depth += 1u;
let tq = dvec::DVec();
while p.token != token::EOF {
tq.push(p.parse_token_tree());
}
let tts = tq.get();
// We want to emit a block expression that does a sequence of 'use's to
// import the runtime module, followed by a tt expression.
let uses = ~[ build::mk_glob_use(cx, sp, ids_ext(cx, ~[~"syntax",
~"ext",
~"quote",
~"rt"])) ];
build::mk_block(cx, sp, uses, ~[],
Some(mk_tt(cx, sp, &ast::tt_delim(tts))))
}
fn expand_parse_call(cx: ext_ctxt,
sp: span,
parse_method: ~str,
arg_exprs: ~[@ast::expr],
tts: ~[ast::token_tree]) -> @ast::expr {
let tt_expr = expand_tt(cx, sp, tts);
let cfg_call = || build::mk_call_(
cx, sp, build::mk_access(cx, sp, ids_ext(cx, ~[~"ext_cx"]),
id_ext(cx, ~"cfg")), ~[]);
let parse_sess_call = || build::mk_call_(
cx, sp, build::mk_access(cx, sp, ids_ext(cx, ~[~"ext_cx"]),
id_ext(cx, ~"parse_sess")), ~[]);
let new_parser_call =
build::mk_call(cx, sp,
ids_ext(cx, ~[~"syntax",
~"ext",
~"quote",
~"rt",
~"new_parser_from_tt"]),
~[parse_sess_call(),
cfg_call(),
build::mk_uniq_vec_e(cx, sp, ~[tt_expr])]);
build::mk_call_(cx, sp,
build::mk_access_(cx, sp, new_parser_call,
id_ext(cx, parse_method)),
arg_exprs)
}

View file

@ -0,0 +1,19 @@
extern mod syntax;
use syntax::ext::base::ext_ctxt;
fn syntax_extension(ext_cx: @ext_ctxt) {
let e_toks : syntax::ast::token_tree = quote_tokens!(1 + 2);
let p_toks : syntax::ast::token_tree = quote_tokens!((x, 1 .. 4, *));
let _a: @syntax::ast::expr = quote_expr!(1 + 2);
let _b: Option<@syntax::ast::item> = quote_item!( const foo : int = $e_toks; );
let _c: @syntax::ast::pat = quote_pat!( (x, 1 .. 4, *) );
let _d: @syntax::ast::stmt = quote_stmt!( let x = $e_toks; );
let _e: @syntax::ast::expr = quote_expr!( match foo { $p_toks => 10 } );
}
fn main() {
let _x: syntax::ast::token_tree = quote_tokens!(a::Foo::foo());
}