Skip to content

Commit 70e0c6e

Browse files
committed
syntax: Permit splicing anything into a quote that implements ToTokens.
1 parent 7e98720 commit 70e0c6e

File tree

2 files changed

+192
-10
lines changed

2 files changed

+192
-10
lines changed

src/libsyntax/ext/quote.rs

+190-7
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ use token::*;
1919
*
2020
* Quasiquoting works via token trees.
2121
*
22-
* This is registered as a set of expression syntax extension called quote! that lifts
23-
* its argument token-tree to an AST representing the construction of the same
24-
* token tree, with ast::tt_nonterminal nodes interpreted as antiquotes
25-
* (splices).
22+
* This is registered as a set of expression syntax extension called quote!
23+
* that lifts its argument token-tree to an AST representing the
24+
* construction of the same token tree, with ast::tt_nonterminal nodes
25+
* interpreted as antiquotes (splices).
2626
*
2727
*/
2828

@@ -32,6 +32,176 @@ pub mod rt {
3232
pub use parse::new_parser_from_tts;
3333
pub use codemap::BytePos;
3434
pub use codemap::span;
35+
36+
use print::pprust;
37+
use pprust::{item_to_str, ty_to_str};
38+
39+
trait ToTokens {
40+
pub fn to_tokens(_cx: ext_ctxt) -> ~[token_tree];
41+
}
42+
43+
impl ~[token_tree]: ToTokens {
44+
pub fn to_tokens(_cx: ext_ctxt) -> ~[token_tree] {
45+
copy self
46+
}
47+
}
48+
49+
/* Should be (when bugs in default methods are fixed):
50+
51+
trait ToSource : ToTokens {
52+
// Takes a thing and generates a string containing rust code for it.
53+
pub fn to_source(cx: ext_ctxt) -> ~str;
54+
55+
// If you can make source, you can definitely make tokens.
56+
pub fn to_tokens(cx: ext_ctxt) -> ~[token_tree] {
57+
cx.parse_tts(self.to_source(cx))
58+
}
59+
}
60+
61+
*/
62+
63+
trait ToSource {
64+
// Takes a thing and generates a string containing rust code for it.
65+
pub fn to_source(cx: ext_ctxt) -> ~str;
66+
}
67+
68+
impl ast::ident: ToSource {
69+
fn to_source(cx: ext_ctxt) -> ~str {
70+
copy *cx.parse_sess().interner.get(self)
71+
}
72+
}
73+
74+
impl @ast::item: ToSource {
75+
fn to_source(cx: ext_ctxt) -> ~str {
76+
item_to_str(self, cx.parse_sess().interner)
77+
}
78+
}
79+
80+
impl ~[@ast::item]: ToSource {
81+
fn to_source(cx: ext_ctxt) -> ~str {
82+
str::connect(self.map(|i| i.to_source(cx)), ~"\n\n")
83+
}
84+
}
85+
86+
impl @ast::Ty: ToSource {
87+
fn to_source(cx: ext_ctxt) -> ~str {
88+
ty_to_str(self, cx.parse_sess().interner)
89+
}
90+
}
91+
92+
impl ~[@ast::Ty]: ToSource {
93+
fn to_source(cx: ext_ctxt) -> ~str {
94+
str::connect(self.map(|i| i.to_source(cx)), ~", ")
95+
}
96+
}
97+
98+
impl ~[ast::ty_param]: ToSource {
99+
fn to_source(cx: ext_ctxt) -> ~str {
100+
pprust::typarams_to_str(self, cx.parse_sess().interner)
101+
}
102+
}
103+
104+
impl @ast::expr: ToSource {
105+
fn to_source(cx: ext_ctxt) -> ~str {
106+
pprust::expr_to_str(self, cx.parse_sess().interner)
107+
}
108+
}
109+
110+
// Alas ... we write these out instead. All redundant.
111+
112+
impl ast::ident: ToTokens {
113+
fn to_tokens(cx: ext_ctxt) -> ~[token_tree] {
114+
cx.parse_tts(self.to_source(cx))
115+
}
116+
}
117+
118+
impl @ast::item: ToTokens {
119+
fn to_tokens(cx: ext_ctxt) -> ~[token_tree] {
120+
cx.parse_tts(self.to_source(cx))
121+
}
122+
}
123+
124+
impl ~[@ast::item]: ToTokens {
125+
fn to_tokens(cx: ext_ctxt) -> ~[token_tree] {
126+
cx.parse_tts(self.to_source(cx))
127+
}
128+
}
129+
130+
impl @ast::Ty: ToTokens {
131+
fn to_tokens(cx: ext_ctxt) -> ~[token_tree] {
132+
cx.parse_tts(self.to_source(cx))
133+
}
134+
}
135+
136+
impl ~[@ast::Ty]: ToTokens {
137+
fn to_tokens(cx: ext_ctxt) -> ~[token_tree] {
138+
cx.parse_tts(self.to_source(cx))
139+
}
140+
}
141+
142+
impl ~[ast::ty_param]: ToTokens {
143+
fn to_tokens(cx: ext_ctxt) -> ~[token_tree] {
144+
cx.parse_tts(self.to_source(cx))
145+
}
146+
}
147+
148+
impl @ast::expr: ToTokens {
149+
fn to_tokens(cx: ext_ctxt) -> ~[token_tree] {
150+
cx.parse_tts(self.to_source(cx))
151+
}
152+
}
153+
154+
trait ExtParseUtils {
155+
fn parse_item(s: ~str) -> @ast::item;
156+
fn parse_expr(s: ~str) -> @ast::expr;
157+
fn parse_stmt(s: ~str) -> @ast::stmt;
158+
fn parse_tts(s: ~str) -> ~[ast::token_tree];
159+
}
160+
161+
impl ext_ctxt: ExtParseUtils {
162+
163+
fn parse_item(s: ~str) -> @ast::item {
164+
let res = parse::parse_item_from_source_str(
165+
~"<quote expansion>",
166+
@(copy s),
167+
self.cfg(),
168+
~[],
169+
self.parse_sess());
170+
match res {
171+
Some(ast) => ast,
172+
None => {
173+
error!("Parse error with ```\n%s\n```", s);
174+
fail
175+
}
176+
}
177+
}
178+
179+
fn parse_stmt(s: ~str) -> @ast::stmt {
180+
parse::parse_stmt_from_source_str(
181+
~"<quote expansion>",
182+
@(copy s),
183+
self.cfg(),
184+
~[],
185+
self.parse_sess())
186+
}
187+
188+
fn parse_expr(s: ~str) -> @ast::expr {
189+
parse::parse_expr_from_source_str(
190+
~"<quote expansion>",
191+
@(copy s),
192+
self.cfg(),
193+
self.parse_sess())
194+
}
195+
196+
fn parse_tts(s: ~str) -> ~[ast::token_tree] {
197+
parse::parse_tts_from_source_str(
198+
~"<quote expansion>",
199+
@(copy s),
200+
self.cfg(),
201+
self.parse_sess())
202+
}
203+
}
204+
35205
}
36206
37207
pub fn expand_quote_tokens(cx: ext_ctxt,
@@ -288,14 +458,27 @@ fn mk_tt(cx: ext_ctxt, sp: span, tt: &ast::token_tree)
288458
ast::tt_seq(*) => fail ~"tt_seq in quote!",
289459
290460
ast::tt_nonterminal(sp, ident) => {
461+
462+
// tt.push_all_move($ident.to_tokens(ext_cx))
463+
464+
let e_to_toks =
465+
build::mk_call_(cx, sp,
466+
build::mk_access
467+
(cx, sp,
468+
~[ident],
469+
id_ext(cx, ~"to_tokens")),
470+
~[build::mk_path(cx, sp,
471+
ids_ext(cx, ~[~"ext_cx"]))]);
472+
291473
let e_push =
292474
build::mk_call_(cx, sp,
293475
build::mk_access
294476
(cx, sp,
295477
ids_ext(cx, ~[~"tt"]),
296478
id_ext(cx, ~"push_all_move")),
297-
~[build::mk_path(cx, sp, ~[ident])]);
298-
~[build::mk_stmt(cx, sp, e_push)]
479+
~[e_to_toks]);
480+
481+
~[build::mk_stmt(cx, sp, e_push)]
299482
}
300483
}
301484
}
@@ -367,7 +550,7 @@ fn expand_tts(cx: ext_ctxt,
367550
let stmt_let_sp = build::mk_local(cx, sp, false,
368551
id_ext(cx, ~"sp"),
369552
e_sp);
370-
553+
371554
let stmt_let_tt = build::mk_local(cx, sp, true,
372555
id_ext(cx, ~"tt"),
373556
build::mk_uniq_vec_e(cx, sp, ~[]));

src/test/run-pass-fulldeps/quote-tokens.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@ fn syntax_extension(ext_cx: @ext_ctxt) {
88
let e_toks : ~[syntax::ast::token_tree] = quote_tokens!(1 + 2);
99
let p_toks : ~[syntax::ast::token_tree] = quote_tokens!((x, 1 .. 4, *));
1010

11-
let _a: @syntax::ast::expr = quote_expr!(1 + 2);
11+
let a: @syntax::ast::expr = quote_expr!(1 + 2);
1212
let _b: Option<@syntax::ast::item> = quote_item!( const foo : int = $e_toks; );
1313
let _c: @syntax::ast::pat = quote_pat!( (x, 1 .. 4, *) );
14-
let _d: @syntax::ast::stmt = quote_stmt!( let x = $e_toks; );
14+
let _d: @syntax::ast::stmt = quote_stmt!( let x = $a; );
1515
let _e: @syntax::ast::expr = quote_expr!( match foo { $p_toks => 10 } );
1616
}
1717

1818
fn main() {
19-
let _x: ~[syntax::ast::token_tree] = quote_tokens!(a::Foo::foo());
2019
}
2120

0 commit comments

Comments
 (0)