Skip to content

Commit

Permalink
syntax: rename quote! to quote_tokens!, add quote_{expr,type,item,pat…
Browse files Browse the repository at this point in the history
…,stmt}!

r=brson, Close #3976.
  • Loading branch information
graydon committed Nov 16, 2012
1 parent 2bf6663 commit 5005be6
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 28 deletions.
17 changes: 15 additions & 2 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
133 changes: 107 additions & 26 deletions src/libsyntax/ext/quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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] {
Expand Down Expand Up @@ -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)
}

19 changes: 19 additions & 0 deletions src/test/run-pass-fulldeps/quote-tokens.rs
Original file line number Diff line number Diff line change
@@ -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());
}

0 comments on commit 5005be6

Please sign in to comment.