From afb668863104687d8c18b61f3ff211da8bd183b7 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Thu, 15 Nov 2012 16:22:33 -0800 Subject: [PATCH] syntax: rename quote! to quote_tokens!, add quote_{expr,type,item,pat,stmt}! --- src/libsyntax/ext/base.rs | 17 +++- src/libsyntax/ext/quote.rs | 125 +++++++++++++++++++++++------- src/test/run-pass/quote-tokens.rs | 19 +++++ 3 files changed, 133 insertions(+), 28 deletions(-) create mode 100644 src/test/run-pass/quote-tokens.rs diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 3f5d0f13b31c6..eb4026c08d90c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -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", diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 68a3c4a139962..8006a756f177c 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -16,33 +16,48 @@ use token::*; * */ -pub fn expand_quote(cx: ext_ctxt, - sp: span, - tts: ~[ast::token_tree]) -> base::mac_result -{ +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)) +} - // 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_expr(cx: ext_ctxt, + sp: span, + tts: ~[ast::token_tree]) -> base::mac_result { + base::mr_expr(expand_parse_call(cx, sp, ~"parse_expr", ~[], 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_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 +319,62 @@ 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])) } -} \ No newline at end of file +} + + +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 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"])) ]; + 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", ~"parse", + ~"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) +} + diff --git a/src/test/run-pass/quote-tokens.rs b/src/test/run-pass/quote-tokens.rs new file mode 100644 index 0000000000000..7149c73be8076 --- /dev/null +++ b/src/test/run-pass/quote-tokens.rs @@ -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()); +} +