]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/ext/tt/transcribe.rs
Imported Upstream version 1.3.0+dfsg1
[rustc.git] / src / libsyntax / ext / tt / transcribe.rs
CommitLineData
223e47cc
LB
1// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
1a4d82fc 10use self::LockstepIterSize::*;
223e47cc 11
223e47cc 12use ast;
1a4d82fc
JJ
13use ast::{TokenTree, TtDelimited, TtToken, TtSequence, Ident};
14use codemap::{Span, DUMMY_SP};
15use diagnostic::SpanHandler;
16use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
17use parse::token::{Eof, DocComment, Interpolated, MatchNt, SubstNt};
18use parse::token::{Token, NtIdent, SpecialMacroVar};
19use parse::token;
223e47cc
LB
20use parse::lexer::TokenAndSpan;
21
1a4d82fc
JJ
22use std::rc::Rc;
23use std::ops::Add;
24use std::collections::HashMap;
223e47cc 25
1a4d82fc
JJ
26///an unzipping of `TokenTree`s
27#[derive(Clone)]
223e47cc 28struct TtFrame {
1a4d82fc 29 forest: TokenTree,
85aaf69f 30 idx: usize,
223e47cc
LB
31 dotdotdoted: bool,
32 sep: Option<Token>,
223e47cc
LB
33}
34
1a4d82fc
JJ
35#[derive(Clone)]
36pub struct TtReader<'a> {
37 pub sp_diag: &'a SpanHandler,
38 /// the unzipped tree:
39 stack: Vec<TtFrame>,
223e47cc 40 /* for MBE-style macro transcription */
1a4d82fc
JJ
41 interpolations: HashMap<Ident, Rc<NamedMatch>>,
42 imported_from: Option<Ident>,
43
44 // Some => return imported_from as the next token
45 crate_name_next: Option<Span>,
85aaf69f
SL
46 repeat_idx: Vec<usize>,
47 repeat_len: Vec<usize>,
223e47cc 48 /* cached: */
1a4d82fc
JJ
49 pub cur_tok: Token,
50 pub cur_span: Span,
51 /// Transform doc comments. Only useful in macro invocations
52 pub desugar_doc_comments: bool,
53}
54
55/// This can do Macro-By-Example transcription. On the other hand, if
56/// `src` contains no `TtSequence`s, `MatchNt`s or `SubstNt`s, `interp` can
57/// (and should) be None.
58pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler,
59 interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
60 imported_from: Option<Ident>,
61 src: Vec<ast::TokenTree>)
62 -> TtReader<'a> {
63 new_tt_reader_with_doc_flag(sp_diag, interp, imported_from, src, false)
223e47cc
LB
64}
65
1a4d82fc
JJ
66/// The extra `desugar_doc_comments` flag enables reading doc comments
67/// like any other attribute which consists of `meta` and surrounding #[ ] tokens.
68///
69/// This can do Macro-By-Example transcription. On the other hand, if
70/// `src` contains no `TtSequence`s, `MatchNt`s or `SubstNt`s, `interp` can
71/// (and should) be None.
72pub fn new_tt_reader_with_doc_flag<'a>(sp_diag: &'a SpanHandler,
73 interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
74 imported_from: Option<Ident>,
75 src: Vec<ast::TokenTree>,
76 desugar_doc_comments: bool)
77 -> TtReader<'a> {
78 let mut r = TtReader {
223e47cc 79 sp_diag: sp_diag,
1a4d82fc
JJ
80 stack: vec!(TtFrame {
81 forest: TtSequence(DUMMY_SP, Rc::new(ast::SequenceRepetition {
82 tts: src,
83 // doesn't matter. This merely holds the root unzipping.
84 separator: None, op: ast::ZeroOrMore, num_captures: 0
85 })),
86 idx: 0,
223e47cc
LB
87 dotdotdoted: false,
88 sep: None,
1a4d82fc
JJ
89 }),
90 interpolations: match interp { /* just a convenience */
970d7e83 91 None => HashMap::new(),
1a4d82fc 92 Some(x) => x,
223e47cc 93 },
1a4d82fc
JJ
94 imported_from: imported_from,
95 crate_name_next: None,
96 repeat_idx: Vec::new(),
97 repeat_len: Vec::new(),
98 desugar_doc_comments: desugar_doc_comments,
223e47cc 99 /* dummy values, never read: */
1a4d82fc
JJ
100 cur_tok: token::Eof,
101 cur_span: DUMMY_SP,
223e47cc 102 };
1a4d82fc
JJ
103 tt_next_token(&mut r); /* get cur_tok and cur_span set up */
104 r
223e47cc
LB
105}
106
1a4d82fc
JJ
107fn lookup_cur_matched_by_matched(r: &TtReader, start: Rc<NamedMatch>) -> Rc<NamedMatch> {
108 r.repeat_idx.iter().fold(start, |ad, idx| {
109 match *ad {
110 MatchedNonterminal(_) => {
111 // end of the line; duplicate henceforth
112 ad.clone()
113 }
114 MatchedSeq(ref ads, _) => ads[*idx].clone()
223e47cc 115 }
1a4d82fc 116 })
223e47cc
LB
117}
118
1a4d82fc
JJ
119fn lookup_cur_matched(r: &TtReader, name: Ident) -> Option<Rc<NamedMatch>> {
120 let matched_opt = r.interpolations.get(&name).cloned();
121 matched_opt.map(|s| lookup_cur_matched_by_matched(r, s))
223e47cc
LB
122}
123
1a4d82fc
JJ
124#[derive(Clone)]
125enum LockstepIterSize {
126 LisUnconstrained,
85aaf69f 127 LisConstraint(usize, Ident),
1a4d82fc 128 LisContradiction(String),
223e47cc
LB
129}
130
1a4d82fc
JJ
131impl Add for LockstepIterSize {
132 type Output = LockstepIterSize;
133
134 fn add(self, other: LockstepIterSize) -> LockstepIterSize {
135 match self {
136 LisUnconstrained => other,
137 LisContradiction(_) => self,
138 LisConstraint(l_len, ref l_id) => match other {
139 LisUnconstrained => self.clone(),
140 LisContradiction(_) => other,
141 LisConstraint(r_len, _) if l_len == r_len => self.clone(),
142 LisConstraint(r_len, r_id) => {
1a4d82fc 143 LisContradiction(format!("inconsistent lockstep iteration: \
c1a9b12d
SL
144 '{}' has {} items, but '{}' has {}",
145 l_id, l_len, r_id, r_len))
1a4d82fc
JJ
146 }
147 },
970d7e83
LB
148 }
149 }
223e47cc 150}
223e47cc 151
1a4d82fc 152fn lockstep_iter_size(t: &TokenTree, r: &TtReader) -> LockstepIterSize {
970d7e83 153 match *t {
1a4d82fc
JJ
154 TtDelimited(_, ref delimed) => {
155 delimed.tts.iter().fold(LisUnconstrained, |size, tt| {
156 size + lockstep_iter_size(tt, r)
157 })
158 },
159 TtSequence(_, ref seq) => {
160 seq.tts.iter().fold(LisUnconstrained, |size, tt| {
161 size + lockstep_iter_size(tt, r)
162 })
163 },
164 TtToken(_, SubstNt(name, _)) | TtToken(_, MatchNt(name, _, _, _)) =>
165 match lookup_cur_matched(r, name) {
166 Some(matched) => match *matched {
167 MatchedNonterminal(_) => LisUnconstrained,
168 MatchedSeq(ref ads, _) => LisConstraint(ads.len(), name),
169 },
170 _ => LisUnconstrained
171 },
172 TtToken(..) => LisUnconstrained,
223e47cc
LB
173 }
174}
175
1a4d82fc
JJ
176/// Return the next token from the TtReader.
177/// EFFECT: advances the reader's token field
223e47cc 178pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
1a4d82fc 179 // FIXME(pcwalton): Bad copy?
223e47cc 180 let ret_val = TokenAndSpan {
1a4d82fc
JJ
181 tok: r.cur_tok.clone(),
182 sp: r.cur_span.clone(),
223e47cc
LB
183 };
184 loop {
1a4d82fc
JJ
185 match r.crate_name_next.take() {
186 None => (),
187 Some(sp) => {
188 r.cur_span = sp;
189 r.cur_tok = token::Ident(r.imported_from.unwrap(), token::Plain);
190 return ret_val;
191 },
223e47cc 192 }
1a4d82fc
JJ
193 let should_pop = match r.stack.last() {
194 None => {
195 assert_eq!(ret_val.tok, token::Eof);
223e47cc 196 return ret_val;
1a4d82fc
JJ
197 }
198 Some(frame) => {
199 if frame.idx < frame.forest.len() {
200 break;
223e47cc 201 }
1a4d82fc
JJ
202 !frame.dotdotdoted ||
203 *r.repeat_idx.last().unwrap() == *r.repeat_len.last().unwrap() - 1
223e47cc 204 }
1a4d82fc 205 };
223e47cc 206
1a4d82fc
JJ
207 /* done with this set; pop or repeat? */
208 if should_pop {
209 let prev = r.stack.pop().unwrap();
210 match r.stack.last_mut() {
211 None => {
212 r.cur_tok = token::Eof;
213 return ret_val;
214 }
215 Some(frame) => {
216 frame.idx += 1;
217 }
218 }
219 if prev.dotdotdoted {
220 r.repeat_idx.pop();
221 r.repeat_len.pop();
222 }
223e47cc 223 } else { /* repeat */
85aaf69f 224 *r.repeat_idx.last_mut().unwrap() += 1;
1a4d82fc
JJ
225 r.stack.last_mut().unwrap().idx = 0;
226 match r.stack.last().unwrap().sep.clone() {
227 Some(tk) => {
228 r.cur_tok = tk; /* repeat same span, I guess */
229 return ret_val;
230 }
231 None => {}
223e47cc
LB
232 }
233 }
234 }
1a4d82fc
JJ
235 loop { /* because it's easiest, this handles `TtDelimited` not starting
236 with a `TtToken`, even though it won't happen */
237 let t = {
238 let frame = r.stack.last().unwrap();
239 // FIXME(pcwalton): Bad copy.
240 frame.forest.get_tt(frame.idx)
241 };
242 match t {
243 TtSequence(sp, seq) => {
244 // FIXME(pcwalton): Bad copy.
245 match lockstep_iter_size(&TtSequence(sp, seq.clone()),
246 r) {
247 LisUnconstrained => {
9346a6ac 248 panic!(r.sp_diag.span_fatal(
1a4d82fc
JJ
249 sp.clone(), /* blame macro writer */
250 "attempted to repeat an expression \
251 containing no syntax \
9346a6ac 252 variables matched as repeating at this depth"));
1a4d82fc
JJ
253 }
254 LisContradiction(ref msg) => {
255 // FIXME #2887 blame macro invoker instead
9346a6ac 256 panic!(r.sp_diag.span_fatal(sp.clone(), &msg[..]));
1a4d82fc
JJ
257 }
258 LisConstraint(len, _) => {
259 if len == 0 {
260 if seq.op == ast::OneOrMore {
261 // FIXME #2887 blame invoker
9346a6ac
AL
262 panic!(r.sp_diag.span_fatal(sp.clone(),
263 "this must repeat at least once"));
1a4d82fc 264 }
223e47cc 265
1a4d82fc
JJ
266 r.stack.last_mut().unwrap().idx += 1;
267 return tt_next_token(r);
268 }
269 r.repeat_len.push(len);
270 r.repeat_idx.push(0);
271 r.stack.push(TtFrame {
272 idx: 0,
273 dotdotdoted: true,
274 sep: seq.separator.clone(),
275 forest: TtSequence(sp, seq),
276 });
277 }
223e47cc 278 }
223e47cc 279 }
1a4d82fc
JJ
280 // FIXME #2887: think about span stuff here
281 TtToken(sp, SubstNt(ident, namep)) => {
282 r.stack.last_mut().unwrap().idx += 1;
283 match lookup_cur_matched(r, ident) {
284 None => {
285 r.cur_span = sp;
286 r.cur_tok = SubstNt(ident, namep);
287 return ret_val;
288 // this can't be 0 length, just like TtDelimited
289 }
290 Some(cur_matched) => {
291 match *cur_matched {
292 // sidestep the interpolation tricks for ident because
293 // (a) idents can be in lots of places, so it'd be a pain
294 // (b) we actually can, since it's a token.
d9579d0f 295 MatchedNonterminal(NtIdent(ref sn, b)) => {
1a4d82fc 296 r.cur_span = sp;
d9579d0f 297 r.cur_tok = token::Ident(**sn, b);
1a4d82fc
JJ
298 return ret_val;
299 }
300 MatchedNonterminal(ref other_whole_nt) => {
301 // FIXME(pcwalton): Bad copy.
302 r.cur_span = sp;
303 r.cur_tok = token::Interpolated((*other_whole_nt).clone());
304 return ret_val;
305 }
306 MatchedSeq(..) => {
9346a6ac 307 panic!(r.sp_diag.span_fatal(
1a4d82fc 308 r.cur_span, /* blame the macro writer */
c1a9b12d
SL
309 &format!("variable '{}' is still repeating at this depth",
310 ident)));
1a4d82fc
JJ
311 }
312 }
313 }
314 }
315 }
316 // TtDelimited or any token that can be unzipped
317 seq @ TtDelimited(..) | seq @ TtToken(_, MatchNt(..)) => {
318 // do not advance the idx yet
319 r.stack.push(TtFrame {
320 forest: seq,
321 idx: 0,
322 dotdotdoted: false,
323 sep: None
324 });
325 // if this could be 0-length, we'd need to potentially recur here
326 }
327 TtToken(sp, DocComment(name)) if r.desugar_doc_comments => {
328 r.stack.push(TtFrame {
329 forest: TtToken(sp, DocComment(name)),
330 idx: 0,
331 dotdotdoted: false,
332 sep: None
333 });
334 }
335 TtToken(sp, token::SpecialVarNt(SpecialMacroVar::CrateMacroVar)) => {
336 r.stack.last_mut().unwrap().idx += 1;
337
338 if r.imported_from.is_some() {
339 r.cur_span = sp;
340 r.cur_tok = token::ModSep;
341 r.crate_name_next = Some(sp);
342 return ret_val;
343 }
344
345 // otherwise emit nothing and proceed to the next token
346 }
347 TtToken(sp, tok) => {
223e47cc 348 r.cur_span = sp;
1a4d82fc
JJ
349 r.cur_tok = tok;
350 r.stack.last_mut().unwrap().idx += 1;
223e47cc 351 return ret_val;
223e47cc 352 }
223e47cc
LB
353 }
354 }
223e47cc 355}