blob: ad9870cea130f3a8ca3f413b4eabad4f40b81750 [file] [log] [blame]
Alex Crichtona914a612018-04-04 07:48:44 -07001#![cfg_attr(not(procmacro2_semver_exempt), allow(dead_code))]
Alex Crichtonaf5bad42018-03-27 14:45:10 -07002
Alex Crichton44bffbc2017-05-19 17:51:59 -07003use std::borrow::Borrow;
4use std::cell::RefCell;
David Tolnay1ebe3972018-01-02 20:14:20 -08005#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -05006use std::cmp;
Alex Crichton44bffbc2017-05-19 17:51:59 -07007use std::collections::HashMap;
8use std::fmt;
9use std::iter;
Alex Crichton44bffbc2017-05-19 17:51:59 -070010use std::rc::Rc;
11use std::str::FromStr;
12use std::vec;
13
David Tolnayb28f38a2018-03-31 22:02:29 +020014use strnom::{block_comment, skip_whitespace, whitespace, word_break, Cursor, PResult};
David Tolnayb1032662017-05-31 15:52:28 -070015use unicode_xid::UnicodeXID;
Alex Crichton44bffbc2017-05-19 17:51:59 -070016
David Tolnayb28f38a2018-03-31 22:02:29 +020017use {Delimiter, Group, Op, Spacing, TokenTree};
Alex Crichton44bffbc2017-05-19 17:51:59 -070018
David Tolnay977f8282017-05-31 17:41:33 -070019#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -070020pub struct TokenStream {
21 inner: Vec<TokenTree>,
22}
23
24#[derive(Debug)]
25pub struct LexError;
26
27impl TokenStream {
28 pub fn empty() -> TokenStream {
29 TokenStream { inner: Vec::new() }
30 }
31
32 pub fn is_empty(&self) -> bool {
33 self.inner.len() == 0
34 }
35}
36
David Tolnay1ebe3972018-01-02 20:14:20 -080037#[cfg(procmacro2_semver_exempt)]
Nika Layzella9dbc182017-12-30 14:50:13 -050038fn get_cursor(src: &str) -> Cursor {
39 // Create a dummy file & add it to the codemap
40 CODEMAP.with(|cm| {
41 let mut cm = cm.borrow_mut();
42 let name = format!("<parsed string {}>", cm.files.len());
43 let span = cm.add_file(&name, src);
44 Cursor {
45 rest: src,
46 off: span.lo,
47 }
48 })
49}
50
David Tolnay1ebe3972018-01-02 20:14:20 -080051#[cfg(not(procmacro2_semver_exempt))]
Nika Layzella9dbc182017-12-30 14:50:13 -050052fn get_cursor(src: &str) -> Cursor {
David Tolnayb28f38a2018-03-31 22:02:29 +020053 Cursor { rest: src }
Nika Layzella9dbc182017-12-30 14:50:13 -050054}
55
Alex Crichton44bffbc2017-05-19 17:51:59 -070056impl FromStr for TokenStream {
57 type Err = LexError;
58
59 fn from_str(src: &str) -> Result<TokenStream, LexError> {
Nika Layzellf8d5f212017-12-11 14:07:02 -050060 // Create a dummy file & add it to the codemap
Nika Layzella9dbc182017-12-30 14:50:13 -050061 let cursor = get_cursor(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -050062
63 match token_stream(cursor) {
David Tolnay1218e122017-06-01 11:13:45 -070064 Ok((input, output)) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -070065 if skip_whitespace(input).len() != 0 {
66 Err(LexError)
67 } else {
Alex Crichtonaf5bad42018-03-27 14:45:10 -070068 Ok(output.inner)
Alex Crichton44bffbc2017-05-19 17:51:59 -070069 }
70 }
David Tolnay1218e122017-06-01 11:13:45 -070071 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -070072 }
73 }
74}
75
76impl fmt::Display for TokenStream {
77 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78 let mut joint = false;
79 for (i, tt) in self.inner.iter().enumerate() {
80 if i != 0 && !joint {
81 write!(f, " ")?;
82 }
83 joint = false;
Alex Crichtonaf5bad42018-03-27 14:45:10 -070084 match *tt {
85 TokenTree::Group(ref tt) => {
86 let (start, end) = match tt.delimiter() {
Alex Crichton44bffbc2017-05-19 17:51:59 -070087 Delimiter::Parenthesis => ("(", ")"),
88 Delimiter::Brace => ("{", "}"),
89 Delimiter::Bracket => ("[", "]"),
90 Delimiter::None => ("", ""),
91 };
Alex Crichtonaf5bad42018-03-27 14:45:10 -070092 if tt.stream().inner.inner.len() == 0 {
Alex Crichton852d53d2017-05-19 19:25:08 -070093 write!(f, "{} {}", start, end)?
94 } else {
Alex Crichtonaf5bad42018-03-27 14:45:10 -070095 write!(f, "{} {} {}", start, tt.stream(), end)?
Alex Crichton852d53d2017-05-19 19:25:08 -070096 }
Alex Crichton44bffbc2017-05-19 17:51:59 -070097 }
Alex Crichtonaf5bad42018-03-27 14:45:10 -070098 TokenTree::Term(ref tt) => write!(f, "{}", tt.as_str())?,
99 TokenTree::Op(ref tt) => {
100 write!(f, "{}", tt.op())?;
101 match tt.spacing() {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700102 Spacing::Alone => {}
103 Spacing::Joint => joint = true,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700104 }
105 }
Alex Crichtonb2c94622018-04-04 07:36:41 -0700106 TokenTree::Literal(ref tt) => write!(f, "{}", tt)?,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700107 }
108 }
109
110 Ok(())
111 }
112}
113
Alex Crichton0e8e7f42018-02-22 06:15:13 -0800114#[cfg(feature = "proc-macro")]
115impl From<::proc_macro::TokenStream> for TokenStream {
116 fn from(inner: ::proc_macro::TokenStream) -> TokenStream {
David Tolnayb28f38a2018-03-31 22:02:29 +0200117 inner
118 .to_string()
119 .parse()
120 .expect("compiler token stream parse failed")
Alex Crichton44bffbc2017-05-19 17:51:59 -0700121 }
122}
123
Alex Crichton0e8e7f42018-02-22 06:15:13 -0800124#[cfg(feature = "proc-macro")]
125impl From<TokenStream> for ::proc_macro::TokenStream {
126 fn from(inner: TokenStream) -> ::proc_macro::TokenStream {
David Tolnayb28f38a2018-03-31 22:02:29 +0200127 inner
128 .to_string()
129 .parse()
130 .expect("failed to parse to compiler tokens")
Alex Crichton44bffbc2017-05-19 17:51:59 -0700131 }
132}
133
Alex Crichton44bffbc2017-05-19 17:51:59 -0700134impl From<TokenTree> for TokenStream {
135 fn from(tree: TokenTree) -> TokenStream {
136 TokenStream { inner: vec![tree] }
137 }
138}
139
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700140impl iter::FromIterator<TokenTree> for TokenStream {
David Tolnayb28f38a2018-03-31 22:02:29 +0200141 fn from_iter<I: IntoIterator<Item = TokenTree>>(streams: I) -> Self {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700142 let mut v = Vec::new();
143
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700144 for token in streams.into_iter() {
145 v.push(token);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700146 }
147
148 TokenStream { inner: v }
149 }
150}
151
Alex Crichton1a7f7622017-07-05 17:47:15 -0700152pub type TokenTreeIter = vec::IntoIter<TokenTree>;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700153
154impl IntoIterator for TokenStream {
155 type Item = TokenTree;
Alex Crichton1a7f7622017-07-05 17:47:15 -0700156 type IntoIter = TokenTreeIter;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700157
Alex Crichton1a7f7622017-07-05 17:47:15 -0700158 fn into_iter(self) -> TokenTreeIter {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700159 self.inner.into_iter()
160 }
161}
162
David Tolnay1ebe3972018-01-02 20:14:20 -0800163#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500164#[derive(Clone, PartialEq, Eq, Debug)]
165pub struct FileName(String);
166
David Tolnay1ebe3972018-01-02 20:14:20 -0800167#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500168impl fmt::Display for FileName {
169 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
170 self.0.fmt(f)
171 }
172}
173
David Tolnay1ebe3972018-01-02 20:14:20 -0800174#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500175#[derive(Clone, PartialEq, Eq)]
176pub struct SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500177 name: FileName,
Nika Layzellf8d5f212017-12-11 14:07:02 -0500178}
179
David Tolnay1ebe3972018-01-02 20:14:20 -0800180#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500181impl SourceFile {
182 /// Get the path to this source file as a string.
Nika Layzellb35a9a32017-12-30 14:34:35 -0500183 pub fn path(&self) -> &FileName {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500184 &self.name
185 }
186
187 pub fn is_real(&self) -> bool {
188 // XXX(nika): Support real files in the future?
189 false
190 }
191}
192
David Tolnay1ebe3972018-01-02 20:14:20 -0800193#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500194impl AsRef<FileName> for SourceFile {
195 fn as_ref(&self) -> &FileName {
196 self.path()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500197 }
198}
199
David Tolnay1ebe3972018-01-02 20:14:20 -0800200#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500201impl fmt::Debug for SourceFile {
202 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
203 f.debug_struct("SourceFile")
Nika Layzellb35a9a32017-12-30 14:34:35 -0500204 .field("path", &self.path())
Nika Layzellf8d5f212017-12-11 14:07:02 -0500205 .field("is_real", &self.is_real())
206 .finish()
207 }
208}
209
David Tolnay1ebe3972018-01-02 20:14:20 -0800210#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500211#[derive(Clone, Copy, Debug, PartialEq, Eq)]
212pub struct LineColumn {
213 pub line: usize,
214 pub column: usize,
215}
216
David Tolnay1ebe3972018-01-02 20:14:20 -0800217#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500218thread_local! {
219 static CODEMAP: RefCell<Codemap> = RefCell::new(Codemap {
220 // NOTE: We start with a single dummy file which all call_site() and
221 // def_site() spans reference.
222 files: vec![FileInfo {
223 name: "<unspecified>".to_owned(),
224 span: Span { lo: 0, hi: 0 },
225 lines: vec![0],
226 }],
227 });
228}
229
David Tolnay1ebe3972018-01-02 20:14:20 -0800230#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500231struct FileInfo {
232 name: String,
233 span: Span,
234 lines: Vec<usize>,
235}
236
David Tolnay1ebe3972018-01-02 20:14:20 -0800237#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500238impl FileInfo {
239 fn offset_line_column(&self, offset: usize) -> LineColumn {
David Tolnayb28f38a2018-03-31 22:02:29 +0200240 assert!(self.span_within(Span {
241 lo: offset as u32,
242 hi: offset as u32
243 }));
Nika Layzellf8d5f212017-12-11 14:07:02 -0500244 let offset = offset - self.span.lo as usize;
245 match self.lines.binary_search(&offset) {
246 Ok(found) => LineColumn {
247 line: found + 1,
David Tolnayb28f38a2018-03-31 22:02:29 +0200248 column: 0,
Nika Layzellf8d5f212017-12-11 14:07:02 -0500249 },
250 Err(idx) => LineColumn {
251 line: idx,
David Tolnayb28f38a2018-03-31 22:02:29 +0200252 column: offset - self.lines[idx - 1],
Nika Layzellf8d5f212017-12-11 14:07:02 -0500253 },
254 }
255 }
256
257 fn span_within(&self, span: Span) -> bool {
258 span.lo >= self.span.lo && span.hi <= self.span.hi
259 }
260}
261
Alex Crichtona914a612018-04-04 07:48:44 -0700262/// Computesthe offsets of each line in the given source string.
David Tolnay1ebe3972018-01-02 20:14:20 -0800263#[cfg(procmacro2_semver_exempt)]
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500264fn lines_offsets(s: &str) -> Vec<usize> {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500265 let mut lines = vec![0];
266 let mut prev = 0;
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500267 while let Some(len) = s[prev..].find('\n') {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500268 prev += len + 1;
269 lines.push(prev);
270 }
271 lines
272}
273
David Tolnay1ebe3972018-01-02 20:14:20 -0800274#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500275struct Codemap {
276 files: Vec<FileInfo>,
277}
278
David Tolnay1ebe3972018-01-02 20:14:20 -0800279#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500280impl Codemap {
281 fn next_start_pos(&self) -> u32 {
282 // Add 1 so there's always space between files.
283 //
284 // We'll always have at least 1 file, as we initialize our files list
285 // with a dummy file.
286 self.files.last().unwrap().span.hi + 1
287 }
288
289 fn add_file(&mut self, name: &str, src: &str) -> Span {
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500290 let lines = lines_offsets(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -0500291 let lo = self.next_start_pos();
292 // XXX(nika): Shouild we bother doing a checked cast or checked add here?
David Tolnayb28f38a2018-03-31 22:02:29 +0200293 let span = Span {
294 lo: lo,
295 hi: lo + (src.len() as u32),
296 };
Nika Layzellf8d5f212017-12-11 14:07:02 -0500297
298 self.files.push(FileInfo {
299 name: name.to_owned(),
300 span: span,
301 lines: lines,
302 });
303
304 span
305 }
306
307 fn fileinfo(&self, span: Span) -> &FileInfo {
308 for file in &self.files {
309 if file.span_within(span) {
310 return file;
311 }
312 }
313 panic!("Invalid span with no related FileInfo!");
314 }
315}
316
Nika Layzell99737982018-03-11 18:51:27 -0400317#[derive(Clone, Copy, Debug, PartialEq, Eq)]
David Tolnayddfca052017-12-31 10:41:24 -0500318pub struct Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800319 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500320 lo: u32,
David Tolnay1ebe3972018-01-02 20:14:20 -0800321 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500322 hi: u32,
323}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700324
325impl Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800326 #[cfg(not(procmacro2_semver_exempt))]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700327 pub fn call_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500328 Span {}
329 }
330
David Tolnay1ebe3972018-01-02 20:14:20 -0800331 #[cfg(procmacro2_semver_exempt)]
David Tolnay79105e52017-12-31 11:03:04 -0500332 pub fn call_site() -> Span {
333 Span { lo: 0, hi: 0 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700334 }
Alex Crichtone6085b72017-11-21 07:24:25 -0800335
336 pub fn def_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500337 Span::call_site()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500338 }
339
David Tolnay4e8e3972018-01-05 18:10:22 -0800340 pub fn resolved_at(&self, _other: Span) -> Span {
341 // Stable spans consist only of line/column information, so
342 // `resolved_at` and `located_at` only select which span the
343 // caller wants line/column information from.
344 *self
345 }
346
347 pub fn located_at(&self, other: Span) -> Span {
348 other
349 }
350
David Tolnay1ebe3972018-01-02 20:14:20 -0800351 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500352 pub fn source_file(&self) -> SourceFile {
353 CODEMAP.with(|cm| {
354 let cm = cm.borrow();
355 let fi = cm.fileinfo(*self);
356 SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500357 name: FileName(fi.name.clone()),
Nika Layzellf8d5f212017-12-11 14:07:02 -0500358 }
359 })
360 }
361
David Tolnay1ebe3972018-01-02 20:14:20 -0800362 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500363 pub fn start(&self) -> LineColumn {
364 CODEMAP.with(|cm| {
365 let cm = cm.borrow();
366 let fi = cm.fileinfo(*self);
367 fi.offset_line_column(self.lo as usize)
368 })
369 }
370
David Tolnay1ebe3972018-01-02 20:14:20 -0800371 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500372 pub fn end(&self) -> LineColumn {
373 CODEMAP.with(|cm| {
374 let cm = cm.borrow();
375 let fi = cm.fileinfo(*self);
376 fi.offset_line_column(self.hi as usize)
377 })
378 }
379
David Tolnay1ebe3972018-01-02 20:14:20 -0800380 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500381 pub fn join(&self, other: Span) -> Option<Span> {
382 CODEMAP.with(|cm| {
383 let cm = cm.borrow();
384 // If `other` is not within the same FileInfo as us, return None.
385 if !cm.fileinfo(*self).span_within(other) {
386 return None;
387 }
388 Some(Span {
389 lo: cmp::min(self.lo, other.lo),
390 hi: cmp::max(self.hi, other.hi),
391 })
392 })
Alex Crichtone6085b72017-11-21 07:24:25 -0800393 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700394}
395
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700396#[derive(Copy, Clone)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700397pub struct Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700398 intern: usize,
Alex Crichtonb2c94622018-04-04 07:36:41 -0700399 span: Span,
David Tolnay041bcd42017-06-03 09:18:04 -0700400}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700401
402thread_local!(static SYMBOLS: RefCell<Interner> = RefCell::new(Interner::new()));
403
David Tolnay10effeb2018-01-06 11:07:49 -0800404impl Term {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700405 pub fn new(string: &str, span: Span) -> Term {
David Tolnay489c6422018-04-07 08:37:28 -0700406 validate_term(string);
407
Alex Crichton1a7f7622017-07-05 17:47:15 -0700408 Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700409 intern: SYMBOLS.with(|s| s.borrow_mut().intern(string)),
Alex Crichtona914a612018-04-04 07:48:44 -0700410 span: span,
David Tolnay041bcd42017-06-03 09:18:04 -0700411 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700412 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700413
David Tolnay10effeb2018-01-06 11:07:49 -0800414 pub fn as_str(&self) -> &str {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700415 SYMBOLS.with(|interner| {
416 let interner = interner.borrow();
David Tolnay041bcd42017-06-03 09:18:04 -0700417 let s = interner.get(self.intern);
David Tolnayb28f38a2018-03-31 22:02:29 +0200418 unsafe { &*(s as *const str) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700419 })
420 }
Alex Crichtonb2c94622018-04-04 07:36:41 -0700421
422 pub fn span(&self) -> Span {
423 self.span
424 }
425
426 pub fn set_span(&mut self, span: Span) {
427 self.span = span;
428 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700429}
430
David Tolnay489c6422018-04-07 08:37:28 -0700431fn validate_term(string: &str) {
432 let validate = if string.starts_with('\'') {
433 &string[1..]
434 } else if string.starts_with("r#") {
435 &string[2..]
436 } else {
437 string
438 };
439
440 if validate.is_empty() {
441 panic!("Term is not allowed to be empty; use Option<Term>");
442 }
443
444 if validate.bytes().all(|digit| digit >= b'0' && digit <= b'9') {
445 panic!("Term cannot be a number; use Literal instead");
446 }
447
448 fn xid_ok(string: &str) -> bool {
449 let mut chars = string.chars();
450 let first = chars.next().unwrap();
451 if !(UnicodeXID::is_xid_start(first) || first == '_') {
452 return false;
453 }
454 for ch in chars {
455 if !UnicodeXID::is_xid_continue(ch) {
456 return false;
457 }
458 }
459 true
460 }
461
462 if !xid_ok(validate) {
463 panic!("{:?} is not a valid Term", string);
464 }
465}
466
Alex Crichton1a7f7622017-07-05 17:47:15 -0700467impl fmt::Debug for Term {
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700468 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
David Tolnay10effeb2018-01-06 11:07:49 -0800469 f.debug_tuple("Term").field(&self.as_str()).finish()
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700470 }
471}
472
Alex Crichton44bffbc2017-05-19 17:51:59 -0700473struct Interner {
474 string_to_index: HashMap<MyRc, usize>,
475 index_to_string: Vec<Rc<String>>,
476}
477
478#[derive(Hash, Eq, PartialEq)]
479struct MyRc(Rc<String>);
480
481impl Borrow<str> for MyRc {
482 fn borrow(&self) -> &str {
483 &self.0
484 }
485}
486
487impl Interner {
488 fn new() -> Interner {
489 Interner {
490 string_to_index: HashMap::new(),
491 index_to_string: Vec::new(),
492 }
493 }
494
David Tolnayb28f38a2018-03-31 22:02:29 +0200495 fn intern(&mut self, s: &str) -> usize {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700496 if let Some(&idx) = self.string_to_index.get(s) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200497 return idx;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700498 }
499 let s = Rc::new(s.to_string());
500 self.index_to_string.push(s.clone());
David Tolnayb28f38a2018-03-31 22:02:29 +0200501 self.string_to_index
502 .insert(MyRc(s), self.index_to_string.len() - 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700503 self.index_to_string.len() - 1
504 }
505
David Tolnayb28f38a2018-03-31 22:02:29 +0200506 fn get(&self, idx: usize) -> &str {
507 &self.index_to_string[idx]
508 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700509}
510
David Tolnay977f8282017-05-31 17:41:33 -0700511#[derive(Clone, Debug)]
Alex Crichtonb2c94622018-04-04 07:36:41 -0700512pub struct Literal {
513 text: String,
514 span: Span,
515}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700516
Alex Crichtona914a612018-04-04 07:48:44 -0700517macro_rules! suffixed_numbers {
518 ($($name:ident => $kind:ident,)*) => ($(
519 pub fn $name(n: $kind) -> Literal {
520 Literal::_new(format!(concat!("{}", stringify!($kind)), n))
521 }
522 )*)
523}
524
525macro_rules! unsuffixed_numbers {
526 ($($name:ident => $kind:ident,)*) => ($(
527 pub fn $name(n: $kind) -> Literal {
528 Literal::_new(n.to_string())
529 }
530 )*)
531}
532
Alex Crichton852d53d2017-05-19 19:25:08 -0700533impl Literal {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700534 fn _new(text: String) -> Literal {
535 Literal {
Alex Crichtona914a612018-04-04 07:48:44 -0700536 text: text,
Alex Crichtonb2c94622018-04-04 07:36:41 -0700537 span: Span::call_site(),
538 }
539 }
540
Alex Crichtona914a612018-04-04 07:48:44 -0700541 suffixed_numbers! {
542 u8_suffixed => u8,
543 u16_suffixed => u16,
544 u32_suffixed => u32,
545 u64_suffixed => u64,
546 usize_suffixed => usize,
547 i8_suffixed => i8,
548 i16_suffixed => i16,
549 i32_suffixed => i32,
550 i64_suffixed => i64,
551 isize_suffixed => isize,
552
553 f32_suffixed => f32,
554 f64_suffixed => f64,
555 }
556
557 unsuffixed_numbers! {
558 u8_unsuffixed => u8,
559 u16_unsuffixed => u16,
560 u32_unsuffixed => u32,
561 u64_unsuffixed => u64,
562 usize_unsuffixed => usize,
563 i8_unsuffixed => i8,
564 i16_unsuffixed => i16,
565 i32_unsuffixed => i32,
566 i64_unsuffixed => i64,
567 isize_unsuffixed => isize,
568 }
569
570 pub fn f32_unsuffixed(f: f32) -> Literal {
571 let mut s = f.to_string();
572 if !s.contains(".") {
573 s.push_str(".0");
Alex Crichton76a5cc82017-05-23 07:01:44 -0700574 }
Alex Crichtona914a612018-04-04 07:48:44 -0700575 Literal::_new(s)
576 }
577
578 pub fn f64_unsuffixed(f: f64) -> Literal {
579 let mut s = f.to_string();
580 if !s.contains(".") {
581 s.push_str(".0");
582 }
583 Literal::_new(s)
584 }
585
586 pub fn string(t: &str) -> Literal {
587 let mut s = t.chars()
588 .flat_map(|c| c.escape_default())
589 .collect::<String>();
590 s.push('"');
591 s.insert(0, '"');
592 Literal::_new(s)
593 }
594
595 pub fn character(t: char) -> Literal {
596 Literal::_new(format!("'{}'", t.escape_default().collect::<String>()))
Alex Crichton76a5cc82017-05-23 07:01:44 -0700597 }
598
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700599 pub fn byte_string(bytes: &[u8]) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700600 let mut escaped = "b\"".to_string();
601 for b in bytes {
602 match *b {
603 b'\0' => escaped.push_str(r"\0"),
604 b'\t' => escaped.push_str(r"\t"),
605 b'\n' => escaped.push_str(r"\n"),
606 b'\r' => escaped.push_str(r"\r"),
607 b'"' => escaped.push_str("\\\""),
608 b'\\' => escaped.push_str("\\\\"),
David Tolnayb28f38a2018-03-31 22:02:29 +0200609 b'\x20'...b'\x7E' => escaped.push(*b as char),
Alex Crichton852d53d2017-05-19 19:25:08 -0700610 _ => escaped.push_str(&format!("\\x{:02X}", b)),
611 }
612 }
613 escaped.push('"');
Alex Crichtonb2c94622018-04-04 07:36:41 -0700614 Literal::_new(escaped)
Alex Crichton76a5cc82017-05-23 07:01:44 -0700615 }
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700616
Alex Crichtonb2c94622018-04-04 07:36:41 -0700617 pub fn span(&self) -> Span {
618 self.span
Alex Crichton31316622017-05-26 12:54:47 -0700619 }
620
Alex Crichtonb2c94622018-04-04 07:36:41 -0700621 pub fn set_span(&mut self, span: Span) {
622 self.span = span;
Alex Crichton31316622017-05-26 12:54:47 -0700623 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700624}
625
Alex Crichton44bffbc2017-05-19 17:51:59 -0700626impl fmt::Display for Literal {
627 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700628 self.text.fmt(f)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700629 }
630}
631
Alex Crichton1eb96a02018-04-04 13:07:35 -0700632fn token_stream(mut input: Cursor) -> PResult<::TokenStream> {
633 let mut trees = Vec::new();
634 loop {
635 let input_no_ws = skip_whitespace(input);
636 if input_no_ws.rest.len() == 0 {
637 break
638 }
639 if let Ok((a, tokens)) = doc_comment(input_no_ws) {
640 input = a;
641 trees.extend(tokens);
642 continue
643 }
644
645 let (a, tt) = match token_tree(input_no_ws) {
646 Ok(p) => p,
647 Err(_) => break,
648 };
649 trees.push(tt);
650 input = a;
651 }
652 Ok((input, ::TokenStream::_new(TokenStream { inner: trees })))
653}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700654
David Tolnay1ebe3972018-01-02 20:14:20 -0800655#[cfg(not(procmacro2_semver_exempt))]
Alex Crichton1eb96a02018-04-04 13:07:35 -0700656fn spanned<'a, T>(
657 input: Cursor<'a>,
658 f: fn(Cursor<'a>) -> PResult<'a, T>,
659) -> PResult<'a, (T, ::Span)> {
660 let (a, b) = f(skip_whitespace(input))?;
661 Ok((a, ((b, ::Span::_new(Span { })))))
David Tolnayddfca052017-12-31 10:41:24 -0500662}
663
David Tolnay1ebe3972018-01-02 20:14:20 -0800664#[cfg(procmacro2_semver_exempt)]
Alex Crichton1eb96a02018-04-04 13:07:35 -0700665fn spanned<'a, T>(
666 input: Cursor<'a>,
667 f: fn(Cursor<'a>) -> PResult<'a, T>,
668) -> PResult<'a, (T, ::Span)> {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500669 let input = skip_whitespace(input);
670 let lo = input.off;
Alex Crichton1eb96a02018-04-04 13:07:35 -0700671 let (a, b) = f(input)?;
672 let hi = a.off;
673 let span = ::Span::_new(Span { lo: lo, hi: hi });
674 Ok((a, (b, span)))
675}
676
677fn token_tree(input: Cursor) -> PResult<TokenTree> {
678 let (rest, (mut tt, span)) = spanned(input, token_kind)?;
679 tt.set_span(span);
680 Ok((rest, tt))
Nika Layzellf8d5f212017-12-11 14:07:02 -0500681}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700682
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700683named!(token_kind -> TokenTree, alt!(
684 map!(group, TokenTree::Group)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700685 |
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700686 map!(literal, TokenTree::Literal) // must be before symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700687 |
Alex Crichton52725f72017-08-28 12:20:58 -0700688 symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700689 |
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700690 map!(op, TokenTree::Op)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700691));
692
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700693named!(group -> Group, alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -0700694 delimited!(
695 punct!("("),
696 token_stream,
697 punct!(")")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700698 ) => { |ts| Group::new(Delimiter::Parenthesis, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700699 |
700 delimited!(
701 punct!("["),
702 token_stream,
703 punct!("]")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700704 ) => { |ts| Group::new(Delimiter::Bracket, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700705 |
706 delimited!(
707 punct!("{"),
708 token_stream,
709 punct!("}")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700710 ) => { |ts| Group::new(Delimiter::Brace, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700711));
712
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700713fn symbol(mut input: Cursor) -> PResult<TokenTree> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700714 input = skip_whitespace(input);
715
716 let mut chars = input.char_indices();
David Tolnaya202d502017-06-01 12:26:55 -0700717
718 let lifetime = input.starts_with("'");
719 if lifetime {
720 chars.next();
721 }
722
David Tolnaya13d1422018-03-31 21:27:48 +0200723 let raw = !lifetime && input.starts_with("r#");
724 if raw {
725 chars.next();
726 chars.next();
727 }
728
Alex Crichton44bffbc2017-05-19 17:51:59 -0700729 match chars.next() {
730 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700731 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700732 }
733
David Tolnay214c94c2017-06-01 12:42:56 -0700734 let mut end = input.len();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700735 for (i, ch) in chars {
736 if !UnicodeXID::is_xid_continue(ch) {
David Tolnay214c94c2017-06-01 12:42:56 -0700737 end = i;
738 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700739 }
740 }
741
David Tolnaya13d1422018-03-31 21:27:48 +0200742 let a = &input.rest[..end];
743 if a == "r#_" || lifetime && a != "'static" && KEYWORDS.contains(&&a[1..]) {
David Tolnay214c94c2017-06-01 12:42:56 -0700744 Err(LexError)
David Tolnaya13d1422018-03-31 21:27:48 +0200745 } else if a == "_" {
746 Ok((input.advance(end), Op::new('_', Spacing::Alone).into()))
David Tolnay214c94c2017-06-01 12:42:56 -0700747 } else {
David Tolnayb28f38a2018-03-31 22:02:29 +0200748 Ok((
749 input.advance(end),
750 ::Term::new(a, ::Span::call_site()).into(),
751 ))
David Tolnay214c94c2017-06-01 12:42:56 -0700752 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700753}
754
David Tolnay214c94c2017-06-01 12:42:56 -0700755// From https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/symbol.rs
756static KEYWORDS: &'static [&'static str] = &[
David Tolnayb28f38a2018-03-31 22:02:29 +0200757 "abstract", "alignof", "as", "become", "box", "break", "const", "continue", "crate", "do",
758 "else", "enum", "extern", "false", "final", "fn", "for", "if", "impl", "in", "let", "loop",
759 "macro", "match", "mod", "move", "mut", "offsetof", "override", "priv", "proc", "pub", "pure",
760 "ref", "return", "self", "Self", "sizeof", "static", "struct", "super", "trait", "true",
761 "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while", "yield",
David Tolnay214c94c2017-06-01 12:42:56 -0700762];
763
Nika Layzellf8d5f212017-12-11 14:07:02 -0500764fn literal(input: Cursor) -> PResult<::Literal> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700765 let input_no_ws = skip_whitespace(input);
766
767 match literal_nocapture(input_no_ws) {
David Tolnay1218e122017-06-01 11:13:45 -0700768 Ok((a, ())) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700769 let start = input.len() - input_no_ws.len();
770 let len = input_no_ws.len() - a.len();
771 let end = start + len;
David Tolnayb28f38a2018-03-31 22:02:29 +0200772 Ok((
773 a,
Alex Crichtonb2c94622018-04-04 07:36:41 -0700774 ::Literal::_new(Literal::_new(input.rest[start..end].to_string())),
David Tolnayb28f38a2018-03-31 22:02:29 +0200775 ))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700776 }
David Tolnay1218e122017-06-01 11:13:45 -0700777 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700778 }
779}
780
781named!(literal_nocapture -> (), alt!(
782 string
783 |
784 byte_string
785 |
786 byte
787 |
788 character
789 |
790 float
791 |
792 int
Alex Crichton44bffbc2017-05-19 17:51:59 -0700793));
794
795named!(string -> (), alt!(
796 quoted_string
797 |
798 preceded!(
799 punct!("r"),
800 raw_string
801 ) => { |_| () }
802));
803
804named!(quoted_string -> (), delimited!(
805 punct!("\""),
806 cooked_string,
807 tag!("\"")
808));
809
Nika Layzellf8d5f212017-12-11 14:07:02 -0500810fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700811 let mut chars = input.char_indices().peekable();
812 while let Some((byte_offset, ch)) = chars.next() {
813 match ch {
814 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500815 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700816 }
817 '\r' => {
818 if let Some((_, '\n')) = chars.next() {
819 // ...
820 } else {
821 break;
822 }
823 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200824 '\\' => match chars.next() {
825 Some((_, 'x')) => {
826 if !backslash_x_char(&mut chars) {
827 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700828 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700829 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200830 Some((_, 'n')) | Some((_, 'r')) | Some((_, 't')) | Some((_, '\\'))
831 | Some((_, '\'')) | Some((_, '"')) | Some((_, '0')) => {}
832 Some((_, 'u')) => {
833 if !backslash_u(&mut chars) {
834 break;
835 }
836 }
837 Some((_, '\n')) | Some((_, '\r')) => {
838 while let Some(&(_, ch)) = chars.peek() {
839 if ch.is_whitespace() {
840 chars.next();
841 } else {
842 break;
843 }
844 }
845 }
846 _ => break,
847 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700848 _ch => {}
849 }
850 }
David Tolnay1218e122017-06-01 11:13:45 -0700851 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700852}
853
854named!(byte_string -> (), alt!(
855 delimited!(
856 punct!("b\""),
857 cooked_byte_string,
858 tag!("\"")
859 ) => { |_| () }
860 |
861 preceded!(
862 punct!("br"),
863 raw_string
864 ) => { |_| () }
865));
866
Nika Layzellf8d5f212017-12-11 14:07:02 -0500867fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700868 let mut bytes = input.bytes().enumerate();
869 'outer: while let Some((offset, b)) = bytes.next() {
870 match b {
871 b'"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500872 return Ok((input.advance(offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700873 }
874 b'\r' => {
875 if let Some((_, b'\n')) = bytes.next() {
876 // ...
877 } else {
878 break;
879 }
880 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200881 b'\\' => match bytes.next() {
882 Some((_, b'x')) => {
883 if !backslash_x_byte(&mut bytes) {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700884 break;
885 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700886 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200887 Some((_, b'n')) | Some((_, b'r')) | Some((_, b't')) | Some((_, b'\\'))
888 | Some((_, b'0')) | Some((_, b'\'')) | Some((_, b'"')) => {}
889 Some((newline, b'\n')) | Some((newline, b'\r')) => {
890 let rest = input.advance(newline + 1);
891 for (offset, ch) in rest.char_indices() {
892 if !ch.is_whitespace() {
893 input = rest.advance(offset);
894 bytes = input.bytes().enumerate();
895 continue 'outer;
896 }
897 }
898 break;
899 }
900 _ => break,
901 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700902 b if b < 0x80 => {}
903 _ => break,
904 }
905 }
David Tolnay1218e122017-06-01 11:13:45 -0700906 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700907}
908
Nika Layzellf8d5f212017-12-11 14:07:02 -0500909fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700910 let mut chars = input.char_indices();
911 let mut n = 0;
912 while let Some((byte_offset, ch)) = chars.next() {
913 match ch {
914 '"' => {
915 n = byte_offset;
916 break;
917 }
918 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700919 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700920 }
921 }
922 for (byte_offset, ch) in chars {
923 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500924 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
925 let rest = input.advance(byte_offset + 1 + n);
David Tolnayb28f38a2018-03-31 22:02:29 +0200926 return Ok((rest, ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700927 }
928 '\r' => {}
929 _ => {}
930 }
931 }
David Tolnay1218e122017-06-01 11:13:45 -0700932 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700933}
934
935named!(byte -> (), do_parse!(
936 punct!("b") >>
937 tag!("'") >>
938 cooked_byte >>
939 tag!("'") >>
940 (())
941));
942
Nika Layzellf8d5f212017-12-11 14:07:02 -0500943fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700944 let mut bytes = input.bytes().enumerate();
945 let ok = match bytes.next().map(|(_, b)| b) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200946 Some(b'\\') => match bytes.next().map(|(_, b)| b) {
947 Some(b'x') => backslash_x_byte(&mut bytes),
948 Some(b'n') | Some(b'r') | Some(b't') | Some(b'\\') | Some(b'0') | Some(b'\'')
949 | Some(b'"') => true,
950 _ => false,
951 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700952 b => b.is_some(),
953 };
954 if ok {
955 match bytes.next() {
Alex Crichton8c030332018-01-16 08:07:36 -0800956 Some((offset, _)) => {
957 if input.chars().as_str().is_char_boundary(offset) {
958 Ok((input.advance(offset), ()))
959 } else {
960 Err(LexError)
961 }
962 }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500963 None => Ok((input.advance(input.len()), ())),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700964 }
965 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700966 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700967 }
968}
969
970named!(character -> (), do_parse!(
971 punct!("'") >>
972 cooked_char >>
973 tag!("'") >>
974 (())
975));
976
Nika Layzellf8d5f212017-12-11 14:07:02 -0500977fn cooked_char(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700978 let mut chars = input.char_indices();
979 let ok = match chars.next().map(|(_, ch)| ch) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200980 Some('\\') => match chars.next().map(|(_, ch)| ch) {
981 Some('x') => backslash_x_char(&mut chars),
982 Some('u') => backslash_u(&mut chars),
983 Some('n') | Some('r') | Some('t') | Some('\\') | Some('0') | Some('\'') | Some('"') => {
984 true
Alex Crichton44bffbc2017-05-19 17:51:59 -0700985 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200986 _ => false,
987 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700988 ch => ch.is_some(),
989 };
990 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500991 match chars.next() {
992 Some((idx, _)) => Ok((input.advance(idx), ())),
993 None => Ok((input.advance(input.len()), ())),
994 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700995 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700996 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700997 }
998}
999
1000macro_rules! next_ch {
1001 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
1002 match $chars.next() {
1003 Some((_, ch)) => match ch {
1004 $pat $(| $rest)* => ch,
1005 _ => return false,
1006 },
1007 None => return false
1008 }
1009 };
1010}
1011
1012fn backslash_x_char<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +02001013where
1014 I: Iterator<Item = (usize, char)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -07001015{
1016 next_ch!(chars @ '0'...'7');
1017 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
1018 true
1019}
1020
1021fn backslash_x_byte<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +02001022where
1023 I: Iterator<Item = (usize, u8)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -07001024{
1025 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
1026 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
1027 true
1028}
1029
1030fn backslash_u<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +02001031where
1032 I: Iterator<Item = (usize, char)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -07001033{
1034 next_ch!(chars @ '{');
1035 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
David Tolnay8d109342017-12-25 18:24:45 -05001036 loop {
1037 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '_' | '}');
1038 if c == '}' {
1039 return true;
1040 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001041 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001042}
1043
Nika Layzellf8d5f212017-12-11 14:07:02 -05001044fn float(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001045 let (rest, ()) = float_digits(input)?;
1046 for suffix in &["f32", "f64"] {
1047 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001048 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001049 }
1050 }
1051 word_break(rest)
1052}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001053
Nika Layzellf8d5f212017-12-11 14:07:02 -05001054fn float_digits(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001055 let mut chars = input.chars().peekable();
1056 match chars.next() {
1057 Some(ch) if ch >= '0' && ch <= '9' => {}
David Tolnay1218e122017-06-01 11:13:45 -07001058 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001059 }
1060
1061 let mut len = 1;
1062 let mut has_dot = false;
1063 let mut has_exp = false;
1064 while let Some(&ch) = chars.peek() {
1065 match ch {
1066 '0'...'9' | '_' => {
1067 chars.next();
1068 len += 1;
1069 }
1070 '.' => {
1071 if has_dot {
1072 break;
1073 }
1074 chars.next();
David Tolnayb28f38a2018-03-31 22:02:29 +02001075 if chars
1076 .peek()
1077 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1078 .unwrap_or(false)
1079 {
David Tolnay1218e122017-06-01 11:13:45 -07001080 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001081 }
1082 len += 1;
1083 has_dot = true;
1084 }
1085 'e' | 'E' => {
1086 chars.next();
1087 len += 1;
1088 has_exp = true;
1089 break;
1090 }
1091 _ => break,
1092 }
1093 }
1094
Nika Layzellf8d5f212017-12-11 14:07:02 -05001095 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001096 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001097 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001098 }
1099
1100 if has_exp {
1101 let mut has_exp_value = false;
1102 while let Some(&ch) = chars.peek() {
1103 match ch {
1104 '+' | '-' => {
1105 if has_exp_value {
1106 break;
1107 }
1108 chars.next();
1109 len += 1;
1110 }
1111 '0'...'9' => {
1112 chars.next();
1113 len += 1;
1114 has_exp_value = true;
1115 }
1116 '_' => {
1117 chars.next();
1118 len += 1;
1119 }
1120 _ => break,
1121 }
1122 }
1123 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001124 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001125 }
1126 }
1127
Nika Layzellf8d5f212017-12-11 14:07:02 -05001128 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001129}
1130
Nika Layzellf8d5f212017-12-11 14:07:02 -05001131fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001132 let (rest, ()) = digits(input)?;
1133 for suffix in &[
David Tolnayb28f38a2018-03-31 22:02:29 +02001134 "isize", "i8", "i16", "i32", "i64", "i128", "usize", "u8", "u16", "u32", "u64", "u128"
David Tolnay744a6b82017-06-01 11:34:29 -07001135 ] {
1136 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001137 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001138 }
1139 }
1140 word_break(rest)
1141}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001142
Nika Layzellf8d5f212017-12-11 14:07:02 -05001143fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001144 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001145 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001146 16
1147 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001148 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001149 8
1150 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001151 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001152 2
1153 } else {
1154 10
1155 };
1156
Alex Crichton44bffbc2017-05-19 17:51:59 -07001157 let mut len = 0;
1158 let mut empty = true;
1159 for b in input.bytes() {
1160 let digit = match b {
1161 b'0'...b'9' => (b - b'0') as u64,
1162 b'a'...b'f' => 10 + (b - b'a') as u64,
1163 b'A'...b'F' => 10 + (b - b'A') as u64,
1164 b'_' => {
1165 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001166 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001167 }
1168 len += 1;
1169 continue;
1170 }
1171 _ => break,
1172 };
1173 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001174 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001175 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001176 len += 1;
1177 empty = false;
1178 }
1179 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001180 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001181 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001182 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001183 }
1184}
1185
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001186fn op(input: Cursor) -> PResult<Op> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001187 let input = skip_whitespace(input);
1188 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001189 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001190 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001191 Ok(_) => Spacing::Joint,
1192 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001193 };
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001194 Ok((rest, Op::new(ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001195 }
David Tolnay1218e122017-06-01 11:13:45 -07001196 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001197 }
1198}
1199
Nika Layzellf8d5f212017-12-11 14:07:02 -05001200fn op_char(input: Cursor) -> PResult<char> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001201 let mut chars = input.chars();
1202 let first = match chars.next() {
1203 Some(ch) => ch,
1204 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001205 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001206 }
1207 };
1208 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1209 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001210 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001211 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001212 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001213 }
1214}
1215
Alex Crichton1eb96a02018-04-04 13:07:35 -07001216fn doc_comment(input: Cursor) -> PResult<Vec<TokenTree>> {
1217 let mut trees = Vec::new();
1218 let (rest, ((comment, inner), span)) = spanned(input, doc_comment_contents)?;
1219 trees.push(TokenTree::Op(Op::new('#', Spacing::Alone)));
1220 if inner {
1221 trees.push(Op::new('!', Spacing::Alone).into());
1222 }
1223 let mut stream = vec![
1224 TokenTree::Term(::Term::new("doc", span)),
1225 TokenTree::Op(Op::new('=', Spacing::Alone)),
1226 TokenTree::Literal(::Literal::string(comment)),
1227 ];
1228 for tt in stream.iter_mut() {
1229 tt.set_span(span);
1230 }
1231 trees.push(Group::new(Delimiter::Bracket, stream.into_iter().collect()).into());
1232 for tt in trees.iter_mut() {
1233 tt.set_span(span);
1234 }
1235 Ok((rest, trees))
1236}
1237
1238named!(doc_comment_contents -> (&str, bool), alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -07001239 do_parse!(
1240 punct!("//!") >>
Alex Crichton1eb96a02018-04-04 13:07:35 -07001241 s: take_until_newline_or_eof!() >>
1242 ((s, true))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001243 )
1244 |
1245 do_parse!(
1246 option!(whitespace) >>
1247 peek!(tag!("/*!")) >>
Alex Crichton1eb96a02018-04-04 13:07:35 -07001248 s: block_comment >>
1249 ((s, true))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001250 )
1251 |
1252 do_parse!(
1253 punct!("///") >>
1254 not!(tag!("/")) >>
Alex Crichton1eb96a02018-04-04 13:07:35 -07001255 s: take_until_newline_or_eof!() >>
1256 ((s, false))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001257 )
1258 |
1259 do_parse!(
1260 option!(whitespace) >>
1261 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
Alex Crichton1eb96a02018-04-04 13:07:35 -07001262 s: block_comment >>
1263 ((s, false))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001264 )
1265));