blob: 8ce8c33d53d9f3c37265d4a1a610dcbed1c23e58 [file] [log] [blame]
Alex Crichtonccbb45d2017-05-23 10:58:24 -07001#[cfg(feature = "extra-traits")]
2use std::fmt;
3
David Tolnayf4bbbd92016-09-23 14:41:55 -07004use super::*;
5
Alex Crichtonccbb45d2017-05-23 10:58:24 -07006use proc_macro2::{TokenKind, Delimiter};
7
Alex Crichton62a0a592017-05-22 13:58:53 -07008ast_struct! {
9 /// Represents a macro invocation. The Path indicates which macro
10 /// is being invoked, and the vector of token-trees contains the source
11 /// of the macro invocation.
12 ///
13 /// NB: the additional ident for a `macro_rules`-style macro is actually
14 /// stored in the enclosing item. Oog.
15 pub struct Mac {
16 pub path: Path,
Alex Crichtonccbb45d2017-05-23 10:58:24 -070017 pub bang_token: tokens::Bang,
18 pub tokens: Vec<TokenTree>,
Alex Crichton62a0a592017-05-22 13:58:53 -070019 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070020}
21
Alex Crichtonccbb45d2017-05-23 10:58:24 -070022#[cfg_attr(feature = "clone-impls", derive(Clone))]
23pub struct TokenTree(pub proc_macro2::TokenTree);
24
25impl Mac {
26 pub fn is_braced(&self) -> bool {
27 match self.tokens.last() {
28 Some(t) => t.is_braced(),
29 None => false,
30 }
Alex Crichton62a0a592017-05-22 13:58:53 -070031 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070032}
33
Alex Crichtonccbb45d2017-05-23 10:58:24 -070034impl TokenTree {
35 pub fn is_braced(&self) -> bool {
36 match self.0.kind {
37 TokenKind::Sequence(Delimiter::Brace, _) => true,
38 _ => false,
39 }
Alex Crichton62a0a592017-05-22 13:58:53 -070040 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070041}
42
Alex Crichtonccbb45d2017-05-23 10:58:24 -070043#[cfg(feature = "extra-traits")]
44impl PartialEq for TokenTree {
45 fn eq(&self, other: &TokenTree) -> bool {
46 use proc_macro2::OpKind;
David Tolnayf4bbbd92016-09-23 14:41:55 -070047
Alex Crichtonccbb45d2017-05-23 10:58:24 -070048 match (&self.0.kind, &other.0.kind) {
49 (&TokenKind::Sequence(d1, ref s1), &TokenKind::Sequence(d2, ref s2)) => {
50 match (d1, d2) {
51 (Delimiter::Parenthesis, Delimiter::Parenthesis) |
52 (Delimiter::Brace, Delimiter::Brace) |
53 (Delimiter::Bracket, Delimiter::Bracket) => {}
54 (Delimiter::None, Delimiter::None) => {}
55 _ => return false,
56 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070057
Alex Crichtonccbb45d2017-05-23 10:58:24 -070058 let s1 = s1.clone().into_iter();
59 let mut s2 = s2.clone().into_iter();
David Tolnayf4bbbd92016-09-23 14:41:55 -070060
Alex Crichtonccbb45d2017-05-23 10:58:24 -070061 for item1 in s1 {
62 let item2 = match s2.next() {
63 Some(item) => item,
64 None => return false,
65 };
66 if TokenTree(item1) != TokenTree(item2) {
67 return false
68 }
69 }
70 s2.next().is_none()
71 }
72 (&TokenKind::Op(o1, k1), &TokenKind::Op(o2, k2)) => {
73 o1 == o2 && match (k1, k2) {
74 (OpKind::Alone, OpKind::Alone) |
75 (OpKind::Joint, OpKind::Joint) => true,
76 _ => false,
77 }
78 }
79 (&TokenKind::Literal(ref l1), &TokenKind::Literal(ref l2)) => {
80 l1.to_string() == l2.to_string()
81 }
82 (&TokenKind::Word(ref s1), &TokenKind::Word(ref s2)) => {
83 s1.as_str() == s2.as_str()
84 }
85 _ => false,
86 }
Alex Crichton62a0a592017-05-22 13:58:53 -070087 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070088}
89
Alex Crichtonccbb45d2017-05-23 10:58:24 -070090#[cfg(feature = "extra-traits")]
91impl Eq for TokenTree {}
92
93#[cfg(feature = "extra-traits")]
94impl ::std::hash::Hash for TokenTree {
95 fn hash<H: ::std::hash::Hasher>(&self, h: &mut H) {
96 use proc_macro2::OpKind;
97
98 match self.0.kind {
99 TokenKind::Sequence(delim, ref stream) => {
100 0u8.hash(h);
101 match delim {
102 Delimiter::Parenthesis => 0u8.hash(h),
103 Delimiter::Brace => 1u8.hash(h),
104 Delimiter::Bracket => 2u8.hash(h),
105 Delimiter::None => 3u8.hash(h),
106 }
107
108 for item in stream.clone().into_iter() {
109 TokenTree(item).hash(h);
110 }
111 0xffu8.hash(h); // terminator w/ a variant we don't normally hash
112 }
113 TokenKind::Op(op, kind) => {
114 1u8.hash(h);
115 op.hash(h);
116 match kind {
117 OpKind::Alone => 0u8.hash(h),
118 OpKind::Joint => 1u8.hash(h),
119 }
120 }
121 TokenKind::Literal(ref lit) => (2u8, lit.to_string()).hash(h),
122 TokenKind::Word(ref word) => (3u8, word.as_str()).hash(h),
123 }
Alex Crichton62a0a592017-05-22 13:58:53 -0700124 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700125}
126
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700127#[cfg(feature = "extra-traits")]
128impl fmt::Debug for TokenTree {
129 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
130 self.0.to_string().fmt(f)
Alex Crichton62a0a592017-05-22 13:58:53 -0700131 }
David Tolnay84aa0752016-10-02 23:01:13 -0700132}
133
134#[cfg(feature = "parsing")]
135pub mod parsing {
136 use super::*;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700137 use {Lifetime};
David Tolnay84aa0752016-10-02 23:01:13 -0700138 use generics::parsing::lifetime;
David Tolnay5d55ef72016-12-21 20:20:04 -0500139 use ident::parsing::word;
David Tolnay84aa0752016-10-02 23:01:13 -0700140 use lit::parsing::lit;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700141 use synom::IResult;
142 use synom::space::{block_comment, whitespace, skip_whitespace};
David Tolnay5d55ef72016-12-21 20:20:04 -0500143 use ty::parsing::path;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700144 use proc_macro2::{self, TokenStream, TokenKind, Delimiter, OpKind, Literal};
145
146 fn tt(kind: TokenKind) -> TokenTree {
147 TokenTree(proc_macro2::TokenTree {
148 kind: kind,
149 span: Default::default(),
150 })
151 }
David Tolnay84aa0752016-10-02 23:01:13 -0700152
153 named!(pub mac -> Mac, do_parse!(
David Tolnay5d55ef72016-12-21 20:20:04 -0500154 what: path >>
David Tolnay84aa0752016-10-02 23:01:13 -0700155 punct!("!") >>
156 body: delimited >>
157 (Mac {
David Tolnay5d55ef72016-12-21 20:20:04 -0500158 path: what,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700159 bang_token: tokens::Bang::default(),
160 tokens: vec![body],
David Tolnay84aa0752016-10-02 23:01:13 -0700161 })
162 ));
163
David Tolnayf5fdfa02016-10-23 15:25:17 -0700164 named!(pub token_trees -> Vec<TokenTree>, many0!(token_tree));
Simon Sapin095a42b2016-10-20 15:54:23 +0200165
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700166 named!(pub token_stream -> TokenStream,
167 map!(token_trees, |t: Vec<TokenTree>| t.into_iter().map(|t| t.0).collect()));
168
169 named!(pub delimited -> TokenTree, alt!(
David Tolnay84aa0752016-10-02 23:01:13 -0700170 delimited!(
171 punct!("("),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700172 token_stream,
David Tolnay84aa0752016-10-02 23:01:13 -0700173 punct!(")")
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700174 ) => { |ts| tt(TokenKind::Sequence(Delimiter::Parenthesis, ts)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700175 |
176 delimited!(
177 punct!("["),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700178 token_stream,
David Tolnay84aa0752016-10-02 23:01:13 -0700179 punct!("]")
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700180 ) => { |ts| tt(TokenKind::Sequence(Delimiter::Bracket, ts)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700181 |
182 delimited!(
183 punct!("{"),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700184 token_stream,
David Tolnay84aa0752016-10-02 23:01:13 -0700185 punct!("}")
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700186 ) => { |ts| tt(TokenKind::Sequence(Delimiter::Brace, ts)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700187 ));
188
David Tolnay5fe14fc2017-01-27 16:22:08 -0800189 named!(pub token_tree -> TokenTree, alt!(
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700190 token
David Tolnay84aa0752016-10-02 23:01:13 -0700191 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700192 delimited
David Tolnay84aa0752016-10-02 23:01:13 -0700193 ));
194
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700195 macro_rules! punct1 {
196 ($i:expr, $punct:expr) => {
197 punct1($i, $punct)
198 }
199 }
200
201 fn punct1<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, char> {
202 let input = skip_whitespace(input);
203 if input.starts_with(token) {
204 IResult::Done(&input[1..], token.chars().next().unwrap())
205 } else {
206 IResult::Error
207 }
208 }
209
210 named!(token -> TokenTree, alt!(
211 keyword!("_") => { |_| tt(TokenKind::Op('_', OpKind::Alone)) }
David Tolnay59b23c52016-10-02 23:17:55 -0700212 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700213 punct1!("&&") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) } // must be before BinOp
David Tolnay2165b042016-10-08 00:04:23 -0700214 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700215 punct1!("||") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) } // must be before BinOp
David Tolnaye6042a62016-10-08 22:22:10 -0700216 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700217 punct1!("->") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) } // must be before BinOp
David Tolnaye6042a62016-10-08 22:22:10 -0700218 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700219 punct1!("<-") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) } // must be before Lt
David Tolnaye6042a62016-10-08 22:22:10 -0700220 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700221 punct1!("=>") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) } // must be before Eq
David Tolnaye6042a62016-10-08 22:22:10 -0700222 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700223 punct1!("...") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) } // must be before DotDot
David Tolnaye6042a62016-10-08 22:22:10 -0700224 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700225 punct1!("..") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) } // must be before Dot
David Tolnaye6042a62016-10-08 22:22:10 -0700226 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700227 punct1!(".") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay2165b042016-10-08 00:04:23 -0700228 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700229 // must be before bin_op
230 map!(doc_comment, |s: String| tt(TokenKind::Literal(Literal::doccomment(&s))))
David Tolnay29833aa2016-10-25 21:08:03 -0700231 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700232 bin_op_eq // must be before bin_op
David Tolnay84aa0752016-10-02 23:01:13 -0700233 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700234 bin_op
David Tolnay84aa0752016-10-02 23:01:13 -0700235 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700236 map!(lit, |l: Lit| l.into_token_tree())
David Tolnay84aa0752016-10-02 23:01:13 -0700237 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700238 map!(word, |w: Ident| tt(TokenKind::Word(w.sym)))
David Tolnay59b23c52016-10-02 23:17:55 -0700239 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700240 map!(lifetime, |lt: Lifetime| tt(TokenKind::Word(lt.ident.sym)))
David Tolnay59b23c52016-10-02 23:17:55 -0700241 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700242 punct1!("<=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700243 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700244 punct1!("==") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700245 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700246 punct1!("!=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700247 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700248 punct1!(">=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700249 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700250 punct1!("::") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700251 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700252 punct1!("=") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay59b23c52016-10-02 23:17:55 -0700253 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700254 punct1!("<") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay59b23c52016-10-02 23:17:55 -0700255 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700256 punct1!(">") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay59b23c52016-10-02 23:17:55 -0700257 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700258 punct1!("!") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay59b23c52016-10-02 23:17:55 -0700259 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700260 punct1!("~") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay59b23c52016-10-02 23:17:55 -0700261 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700262 punct1!("@") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay59b23c52016-10-02 23:17:55 -0700263 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700264 punct1!(",") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay59b23c52016-10-02 23:17:55 -0700265 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700266 punct1!(";") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay59b23c52016-10-02 23:17:55 -0700267 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700268 punct1!(":") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay59b23c52016-10-02 23:17:55 -0700269 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700270 punct1!("#") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700271 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700272 punct1!("$") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700273 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700274 punct1!("?") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700275 ));
276
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700277 named!(bin_op -> TokenTree, alt!(
278 punct1!("+") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700279 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700280 punct1!("-") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700281 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700282 punct1!("*") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700283 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700284 punct1!("/") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700285 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700286 punct1!("%") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700287 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700288 punct1!("^") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700289 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700290 punct1!("&") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700291 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700292 punct1!("|") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700293 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700294 punct1!("<<") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700295 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700296 punct1!(">>") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700297 ));
298
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700299 named!(bin_op_eq -> TokenTree, alt!(
300 punct1!("+=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700301 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700302 punct1!("-=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700303 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700304 punct1!("*=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700305 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700306 punct1!("/=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700307 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700308 punct1!("%=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700309 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700310 punct1!("^=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700311 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700312 punct1!("&=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700313 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700314 punct1!("|=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700315 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700316 punct1!("<<=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700317 |
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700318 punct1!(">>=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
David Tolnay84aa0752016-10-02 23:01:13 -0700319 ));
320
321 named!(doc_comment -> String, alt!(
Michael Layzell416724e2017-05-24 21:12:34 -0400322 inner_doc_comment
David Tolnay84aa0752016-10-02 23:01:13 -0700323 |
Michael Layzell416724e2017-05-24 21:12:34 -0400324 outer_doc_comment
David Tolnay84aa0752016-10-02 23:01:13 -0700325 ));
David Tolnayf4bbbd92016-09-23 14:41:55 -0700326}
David Tolnayf8cf9632016-10-02 23:15:25 -0700327
328#[cfg(feature = "printing")]
329mod printing {
330 use super::*;
331 use quote::{Tokens, ToTokens};
332
333 impl ToTokens for Mac {
334 fn to_tokens(&self, tokens: &mut Tokens) {
335 self.path.to_tokens(tokens);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700336 self.bang_token.to_tokens(tokens);
337 tokens.append_all(&self.tokens);
David Tolnayf8cf9632016-10-02 23:15:25 -0700338 }
339 }
340
341 impl ToTokens for TokenTree {
342 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700343 self.0.to_tokens(tokens);
David Tolnayf8cf9632016-10-02 23:15:25 -0700344 }
345 }
346}