blob: abfeab36951c0e29d1df2c435c6121ceaea64bef [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 {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700406 Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700407 intern: SYMBOLS.with(|s| s.borrow_mut().intern(string)),
Alex Crichtona914a612018-04-04 07:48:44 -0700408 span: span,
David Tolnay041bcd42017-06-03 09:18:04 -0700409 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700410 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700411
David Tolnay10effeb2018-01-06 11:07:49 -0800412 pub fn as_str(&self) -> &str {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700413 SYMBOLS.with(|interner| {
414 let interner = interner.borrow();
David Tolnay041bcd42017-06-03 09:18:04 -0700415 let s = interner.get(self.intern);
David Tolnayb28f38a2018-03-31 22:02:29 +0200416 unsafe { &*(s as *const str) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700417 })
418 }
Alex Crichtonb2c94622018-04-04 07:36:41 -0700419
420 pub fn span(&self) -> Span {
421 self.span
422 }
423
424 pub fn set_span(&mut self, span: Span) {
425 self.span = span;
426 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700427}
428
Alex Crichton1a7f7622017-07-05 17:47:15 -0700429impl fmt::Debug for Term {
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700430 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
David Tolnay10effeb2018-01-06 11:07:49 -0800431 f.debug_tuple("Term").field(&self.as_str()).finish()
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700432 }
433}
434
Alex Crichton44bffbc2017-05-19 17:51:59 -0700435struct Interner {
436 string_to_index: HashMap<MyRc, usize>,
437 index_to_string: Vec<Rc<String>>,
438}
439
440#[derive(Hash, Eq, PartialEq)]
441struct MyRc(Rc<String>);
442
443impl Borrow<str> for MyRc {
444 fn borrow(&self) -> &str {
445 &self.0
446 }
447}
448
449impl Interner {
450 fn new() -> Interner {
451 Interner {
452 string_to_index: HashMap::new(),
453 index_to_string: Vec::new(),
454 }
455 }
456
David Tolnayb28f38a2018-03-31 22:02:29 +0200457 fn intern(&mut self, s: &str) -> usize {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700458 if let Some(&idx) = self.string_to_index.get(s) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200459 return idx;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700460 }
461 let s = Rc::new(s.to_string());
462 self.index_to_string.push(s.clone());
David Tolnayb28f38a2018-03-31 22:02:29 +0200463 self.string_to_index
464 .insert(MyRc(s), self.index_to_string.len() - 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700465 self.index_to_string.len() - 1
466 }
467
David Tolnayb28f38a2018-03-31 22:02:29 +0200468 fn get(&self, idx: usize) -> &str {
469 &self.index_to_string[idx]
470 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700471}
472
David Tolnay977f8282017-05-31 17:41:33 -0700473#[derive(Clone, Debug)]
Alex Crichtonb2c94622018-04-04 07:36:41 -0700474pub struct Literal {
475 text: String,
476 span: Span,
477}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700478
Alex Crichtona914a612018-04-04 07:48:44 -0700479macro_rules! suffixed_numbers {
480 ($($name:ident => $kind:ident,)*) => ($(
481 pub fn $name(n: $kind) -> Literal {
482 Literal::_new(format!(concat!("{}", stringify!($kind)), n))
483 }
484 )*)
485}
486
487macro_rules! unsuffixed_numbers {
488 ($($name:ident => $kind:ident,)*) => ($(
489 pub fn $name(n: $kind) -> Literal {
490 Literal::_new(n.to_string())
491 }
492 )*)
493}
494
Alex Crichton852d53d2017-05-19 19:25:08 -0700495impl Literal {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700496 fn _new(text: String) -> Literal {
497 Literal {
Alex Crichtona914a612018-04-04 07:48:44 -0700498 text: text,
Alex Crichtonb2c94622018-04-04 07:36:41 -0700499 span: Span::call_site(),
500 }
501 }
502
Alex Crichtona914a612018-04-04 07:48:44 -0700503 suffixed_numbers! {
504 u8_suffixed => u8,
505 u16_suffixed => u16,
506 u32_suffixed => u32,
507 u64_suffixed => u64,
508 usize_suffixed => usize,
509 i8_suffixed => i8,
510 i16_suffixed => i16,
511 i32_suffixed => i32,
512 i64_suffixed => i64,
513 isize_suffixed => isize,
514
515 f32_suffixed => f32,
516 f64_suffixed => f64,
517 }
518
519 unsuffixed_numbers! {
520 u8_unsuffixed => u8,
521 u16_unsuffixed => u16,
522 u32_unsuffixed => u32,
523 u64_unsuffixed => u64,
524 usize_unsuffixed => usize,
525 i8_unsuffixed => i8,
526 i16_unsuffixed => i16,
527 i32_unsuffixed => i32,
528 i64_unsuffixed => i64,
529 isize_unsuffixed => isize,
530 }
531
532 pub fn f32_unsuffixed(f: f32) -> Literal {
533 let mut s = f.to_string();
534 if !s.contains(".") {
535 s.push_str(".0");
Alex Crichton76a5cc82017-05-23 07:01:44 -0700536 }
Alex Crichtona914a612018-04-04 07:48:44 -0700537 Literal::_new(s)
538 }
539
540 pub fn f64_unsuffixed(f: f64) -> Literal {
541 let mut s = f.to_string();
542 if !s.contains(".") {
543 s.push_str(".0");
544 }
545 Literal::_new(s)
546 }
547
548 pub fn string(t: &str) -> Literal {
549 let mut s = t.chars()
550 .flat_map(|c| c.escape_default())
551 .collect::<String>();
552 s.push('"');
553 s.insert(0, '"');
554 Literal::_new(s)
555 }
556
557 pub fn character(t: char) -> Literal {
558 Literal::_new(format!("'{}'", t.escape_default().collect::<String>()))
Alex Crichton76a5cc82017-05-23 07:01:44 -0700559 }
560
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700561 pub fn byte_string(bytes: &[u8]) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700562 let mut escaped = "b\"".to_string();
563 for b in bytes {
564 match *b {
565 b'\0' => escaped.push_str(r"\0"),
566 b'\t' => escaped.push_str(r"\t"),
567 b'\n' => escaped.push_str(r"\n"),
568 b'\r' => escaped.push_str(r"\r"),
569 b'"' => escaped.push_str("\\\""),
570 b'\\' => escaped.push_str("\\\\"),
David Tolnayb28f38a2018-03-31 22:02:29 +0200571 b'\x20'...b'\x7E' => escaped.push(*b as char),
Alex Crichton852d53d2017-05-19 19:25:08 -0700572 _ => escaped.push_str(&format!("\\x{:02X}", b)),
573 }
574 }
575 escaped.push('"');
Alex Crichtonb2c94622018-04-04 07:36:41 -0700576 Literal::_new(escaped)
Alex Crichton76a5cc82017-05-23 07:01:44 -0700577 }
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700578
Alex Crichtonb2c94622018-04-04 07:36:41 -0700579 pub fn span(&self) -> Span {
580 self.span
Alex Crichton31316622017-05-26 12:54:47 -0700581 }
582
Alex Crichtonb2c94622018-04-04 07:36:41 -0700583 pub fn set_span(&mut self, span: Span) {
584 self.span = span;
Alex Crichton31316622017-05-26 12:54:47 -0700585 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700586}
587
Alex Crichton44bffbc2017-05-19 17:51:59 -0700588impl fmt::Display for Literal {
589 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700590 self.text.fmt(f)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700591 }
592}
593
Alex Crichton1eb96a02018-04-04 13:07:35 -0700594fn token_stream(mut input: Cursor) -> PResult<::TokenStream> {
595 let mut trees = Vec::new();
596 loop {
597 let input_no_ws = skip_whitespace(input);
598 if input_no_ws.rest.len() == 0 {
599 break
600 }
601 if let Ok((a, tokens)) = doc_comment(input_no_ws) {
602 input = a;
603 trees.extend(tokens);
604 continue
605 }
606
607 let (a, tt) = match token_tree(input_no_ws) {
608 Ok(p) => p,
609 Err(_) => break,
610 };
611 trees.push(tt);
612 input = a;
613 }
614 Ok((input, ::TokenStream::_new(TokenStream { inner: trees })))
615}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700616
David Tolnay1ebe3972018-01-02 20:14:20 -0800617#[cfg(not(procmacro2_semver_exempt))]
Alex Crichton1eb96a02018-04-04 13:07:35 -0700618fn spanned<'a, T>(
619 input: Cursor<'a>,
620 f: fn(Cursor<'a>) -> PResult<'a, T>,
621) -> PResult<'a, (T, ::Span)> {
622 let (a, b) = f(skip_whitespace(input))?;
623 Ok((a, ((b, ::Span::_new(Span { })))))
David Tolnayddfca052017-12-31 10:41:24 -0500624}
625
David Tolnay1ebe3972018-01-02 20:14:20 -0800626#[cfg(procmacro2_semver_exempt)]
Alex Crichton1eb96a02018-04-04 13:07:35 -0700627fn spanned<'a, T>(
628 input: Cursor<'a>,
629 f: fn(Cursor<'a>) -> PResult<'a, T>,
630) -> PResult<'a, (T, ::Span)> {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500631 let input = skip_whitespace(input);
632 let lo = input.off;
Alex Crichton1eb96a02018-04-04 13:07:35 -0700633 let (a, b) = f(input)?;
634 let hi = a.off;
635 let span = ::Span::_new(Span { lo: lo, hi: hi });
636 Ok((a, (b, span)))
637}
638
639fn token_tree(input: Cursor) -> PResult<TokenTree> {
640 let (rest, (mut tt, span)) = spanned(input, token_kind)?;
641 tt.set_span(span);
642 Ok((rest, tt))
Nika Layzellf8d5f212017-12-11 14:07:02 -0500643}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700644
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700645named!(token_kind -> TokenTree, alt!(
646 map!(group, TokenTree::Group)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700647 |
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700648 map!(literal, TokenTree::Literal) // must be before symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700649 |
Alex Crichton52725f72017-08-28 12:20:58 -0700650 symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700651 |
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700652 map!(op, TokenTree::Op)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700653));
654
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700655named!(group -> Group, alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -0700656 delimited!(
657 punct!("("),
658 token_stream,
659 punct!(")")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700660 ) => { |ts| Group::new(Delimiter::Parenthesis, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700661 |
662 delimited!(
663 punct!("["),
664 token_stream,
665 punct!("]")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700666 ) => { |ts| Group::new(Delimiter::Bracket, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700667 |
668 delimited!(
669 punct!("{"),
670 token_stream,
671 punct!("}")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700672 ) => { |ts| Group::new(Delimiter::Brace, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700673));
674
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700675fn symbol(mut input: Cursor) -> PResult<TokenTree> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700676 input = skip_whitespace(input);
677
678 let mut chars = input.char_indices();
David Tolnaya202d502017-06-01 12:26:55 -0700679
680 let lifetime = input.starts_with("'");
681 if lifetime {
682 chars.next();
683 }
684
David Tolnaya13d1422018-03-31 21:27:48 +0200685 let raw = !lifetime && input.starts_with("r#");
686 if raw {
687 chars.next();
688 chars.next();
689 }
690
Alex Crichton44bffbc2017-05-19 17:51:59 -0700691 match chars.next() {
692 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700693 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700694 }
695
David Tolnay214c94c2017-06-01 12:42:56 -0700696 let mut end = input.len();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700697 for (i, ch) in chars {
698 if !UnicodeXID::is_xid_continue(ch) {
David Tolnay214c94c2017-06-01 12:42:56 -0700699 end = i;
700 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700701 }
702 }
703
David Tolnaya13d1422018-03-31 21:27:48 +0200704 let a = &input.rest[..end];
705 if a == "r#_" || lifetime && a != "'static" && KEYWORDS.contains(&&a[1..]) {
David Tolnay214c94c2017-06-01 12:42:56 -0700706 Err(LexError)
David Tolnaya13d1422018-03-31 21:27:48 +0200707 } else if a == "_" {
708 Ok((input.advance(end), Op::new('_', Spacing::Alone).into()))
David Tolnay214c94c2017-06-01 12:42:56 -0700709 } else {
David Tolnayb28f38a2018-03-31 22:02:29 +0200710 Ok((
711 input.advance(end),
712 ::Term::new(a, ::Span::call_site()).into(),
713 ))
David Tolnay214c94c2017-06-01 12:42:56 -0700714 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700715}
716
David Tolnay214c94c2017-06-01 12:42:56 -0700717// From https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/symbol.rs
718static KEYWORDS: &'static [&'static str] = &[
David Tolnayb28f38a2018-03-31 22:02:29 +0200719 "abstract", "alignof", "as", "become", "box", "break", "const", "continue", "crate", "do",
720 "else", "enum", "extern", "false", "final", "fn", "for", "if", "impl", "in", "let", "loop",
721 "macro", "match", "mod", "move", "mut", "offsetof", "override", "priv", "proc", "pub", "pure",
722 "ref", "return", "self", "Self", "sizeof", "static", "struct", "super", "trait", "true",
723 "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while", "yield",
David Tolnay214c94c2017-06-01 12:42:56 -0700724];
725
Nika Layzellf8d5f212017-12-11 14:07:02 -0500726fn literal(input: Cursor) -> PResult<::Literal> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700727 let input_no_ws = skip_whitespace(input);
728
729 match literal_nocapture(input_no_ws) {
David Tolnay1218e122017-06-01 11:13:45 -0700730 Ok((a, ())) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700731 let start = input.len() - input_no_ws.len();
732 let len = input_no_ws.len() - a.len();
733 let end = start + len;
David Tolnayb28f38a2018-03-31 22:02:29 +0200734 Ok((
735 a,
Alex Crichtonb2c94622018-04-04 07:36:41 -0700736 ::Literal::_new(Literal::_new(input.rest[start..end].to_string())),
David Tolnayb28f38a2018-03-31 22:02:29 +0200737 ))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700738 }
David Tolnay1218e122017-06-01 11:13:45 -0700739 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700740 }
741}
742
743named!(literal_nocapture -> (), alt!(
744 string
745 |
746 byte_string
747 |
748 byte
749 |
750 character
751 |
752 float
753 |
754 int
Alex Crichton44bffbc2017-05-19 17:51:59 -0700755));
756
757named!(string -> (), alt!(
758 quoted_string
759 |
760 preceded!(
761 punct!("r"),
762 raw_string
763 ) => { |_| () }
764));
765
766named!(quoted_string -> (), delimited!(
767 punct!("\""),
768 cooked_string,
769 tag!("\"")
770));
771
Nika Layzellf8d5f212017-12-11 14:07:02 -0500772fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700773 let mut chars = input.char_indices().peekable();
774 while let Some((byte_offset, ch)) = chars.next() {
775 match ch {
776 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500777 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700778 }
779 '\r' => {
780 if let Some((_, '\n')) = chars.next() {
781 // ...
782 } else {
783 break;
784 }
785 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200786 '\\' => match chars.next() {
787 Some((_, 'x')) => {
788 if !backslash_x_char(&mut chars) {
789 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700790 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700791 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200792 Some((_, 'n')) | Some((_, 'r')) | Some((_, 't')) | Some((_, '\\'))
793 | Some((_, '\'')) | Some((_, '"')) | Some((_, '0')) => {}
794 Some((_, 'u')) => {
795 if !backslash_u(&mut chars) {
796 break;
797 }
798 }
799 Some((_, '\n')) | Some((_, '\r')) => {
800 while let Some(&(_, ch)) = chars.peek() {
801 if ch.is_whitespace() {
802 chars.next();
803 } else {
804 break;
805 }
806 }
807 }
808 _ => break,
809 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700810 _ch => {}
811 }
812 }
David Tolnay1218e122017-06-01 11:13:45 -0700813 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700814}
815
816named!(byte_string -> (), alt!(
817 delimited!(
818 punct!("b\""),
819 cooked_byte_string,
820 tag!("\"")
821 ) => { |_| () }
822 |
823 preceded!(
824 punct!("br"),
825 raw_string
826 ) => { |_| () }
827));
828
Nika Layzellf8d5f212017-12-11 14:07:02 -0500829fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700830 let mut bytes = input.bytes().enumerate();
831 'outer: while let Some((offset, b)) = bytes.next() {
832 match b {
833 b'"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500834 return Ok((input.advance(offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700835 }
836 b'\r' => {
837 if let Some((_, b'\n')) = bytes.next() {
838 // ...
839 } else {
840 break;
841 }
842 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200843 b'\\' => match bytes.next() {
844 Some((_, b'x')) => {
845 if !backslash_x_byte(&mut bytes) {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700846 break;
847 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700848 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200849 Some((_, b'n')) | Some((_, b'r')) | Some((_, b't')) | Some((_, b'\\'))
850 | Some((_, b'0')) | Some((_, b'\'')) | Some((_, b'"')) => {}
851 Some((newline, b'\n')) | Some((newline, b'\r')) => {
852 let rest = input.advance(newline + 1);
853 for (offset, ch) in rest.char_indices() {
854 if !ch.is_whitespace() {
855 input = rest.advance(offset);
856 bytes = input.bytes().enumerate();
857 continue 'outer;
858 }
859 }
860 break;
861 }
862 _ => break,
863 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700864 b if b < 0x80 => {}
865 _ => break,
866 }
867 }
David Tolnay1218e122017-06-01 11:13:45 -0700868 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700869}
870
Nika Layzellf8d5f212017-12-11 14:07:02 -0500871fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700872 let mut chars = input.char_indices();
873 let mut n = 0;
874 while let Some((byte_offset, ch)) = chars.next() {
875 match ch {
876 '"' => {
877 n = byte_offset;
878 break;
879 }
880 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700881 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700882 }
883 }
884 for (byte_offset, ch) in chars {
885 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500886 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
887 let rest = input.advance(byte_offset + 1 + n);
David Tolnayb28f38a2018-03-31 22:02:29 +0200888 return Ok((rest, ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700889 }
890 '\r' => {}
891 _ => {}
892 }
893 }
David Tolnay1218e122017-06-01 11:13:45 -0700894 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700895}
896
897named!(byte -> (), do_parse!(
898 punct!("b") >>
899 tag!("'") >>
900 cooked_byte >>
901 tag!("'") >>
902 (())
903));
904
Nika Layzellf8d5f212017-12-11 14:07:02 -0500905fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700906 let mut bytes = input.bytes().enumerate();
907 let ok = match bytes.next().map(|(_, b)| b) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200908 Some(b'\\') => match bytes.next().map(|(_, b)| b) {
909 Some(b'x') => backslash_x_byte(&mut bytes),
910 Some(b'n') | Some(b'r') | Some(b't') | Some(b'\\') | Some(b'0') | Some(b'\'')
911 | Some(b'"') => true,
912 _ => false,
913 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700914 b => b.is_some(),
915 };
916 if ok {
917 match bytes.next() {
Alex Crichton8c030332018-01-16 08:07:36 -0800918 Some((offset, _)) => {
919 if input.chars().as_str().is_char_boundary(offset) {
920 Ok((input.advance(offset), ()))
921 } else {
922 Err(LexError)
923 }
924 }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500925 None => Ok((input.advance(input.len()), ())),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700926 }
927 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700928 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700929 }
930}
931
932named!(character -> (), do_parse!(
933 punct!("'") >>
934 cooked_char >>
935 tag!("'") >>
936 (())
937));
938
Nika Layzellf8d5f212017-12-11 14:07:02 -0500939fn cooked_char(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700940 let mut chars = input.char_indices();
941 let ok = match chars.next().map(|(_, ch)| ch) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200942 Some('\\') => match chars.next().map(|(_, ch)| ch) {
943 Some('x') => backslash_x_char(&mut chars),
944 Some('u') => backslash_u(&mut chars),
945 Some('n') | Some('r') | Some('t') | Some('\\') | Some('0') | Some('\'') | Some('"') => {
946 true
Alex Crichton44bffbc2017-05-19 17:51:59 -0700947 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200948 _ => false,
949 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700950 ch => ch.is_some(),
951 };
952 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500953 match chars.next() {
954 Some((idx, _)) => Ok((input.advance(idx), ())),
955 None => Ok((input.advance(input.len()), ())),
956 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700957 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700958 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700959 }
960}
961
962macro_rules! next_ch {
963 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
964 match $chars.next() {
965 Some((_, ch)) => match ch {
966 $pat $(| $rest)* => ch,
967 _ => return false,
968 },
969 None => return false
970 }
971 };
972}
973
974fn backslash_x_char<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +0200975where
976 I: Iterator<Item = (usize, char)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700977{
978 next_ch!(chars @ '0'...'7');
979 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
980 true
981}
982
983fn backslash_x_byte<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +0200984where
985 I: Iterator<Item = (usize, u8)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700986{
987 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
988 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
989 true
990}
991
992fn backslash_u<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +0200993where
994 I: Iterator<Item = (usize, char)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700995{
996 next_ch!(chars @ '{');
997 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
David Tolnay8d109342017-12-25 18:24:45 -0500998 loop {
999 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '_' | '}');
1000 if c == '}' {
1001 return true;
1002 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001003 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001004}
1005
Nika Layzellf8d5f212017-12-11 14:07:02 -05001006fn float(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001007 let (rest, ()) = float_digits(input)?;
1008 for suffix in &["f32", "f64"] {
1009 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001010 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001011 }
1012 }
1013 word_break(rest)
1014}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001015
Nika Layzellf8d5f212017-12-11 14:07:02 -05001016fn float_digits(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001017 let mut chars = input.chars().peekable();
1018 match chars.next() {
1019 Some(ch) if ch >= '0' && ch <= '9' => {}
David Tolnay1218e122017-06-01 11:13:45 -07001020 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001021 }
1022
1023 let mut len = 1;
1024 let mut has_dot = false;
1025 let mut has_exp = false;
1026 while let Some(&ch) = chars.peek() {
1027 match ch {
1028 '0'...'9' | '_' => {
1029 chars.next();
1030 len += 1;
1031 }
1032 '.' => {
1033 if has_dot {
1034 break;
1035 }
1036 chars.next();
David Tolnayb28f38a2018-03-31 22:02:29 +02001037 if chars
1038 .peek()
1039 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1040 .unwrap_or(false)
1041 {
David Tolnay1218e122017-06-01 11:13:45 -07001042 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001043 }
1044 len += 1;
1045 has_dot = true;
1046 }
1047 'e' | 'E' => {
1048 chars.next();
1049 len += 1;
1050 has_exp = true;
1051 break;
1052 }
1053 _ => break,
1054 }
1055 }
1056
Nika Layzellf8d5f212017-12-11 14:07:02 -05001057 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001058 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001059 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001060 }
1061
1062 if has_exp {
1063 let mut has_exp_value = false;
1064 while let Some(&ch) = chars.peek() {
1065 match ch {
1066 '+' | '-' => {
1067 if has_exp_value {
1068 break;
1069 }
1070 chars.next();
1071 len += 1;
1072 }
1073 '0'...'9' => {
1074 chars.next();
1075 len += 1;
1076 has_exp_value = true;
1077 }
1078 '_' => {
1079 chars.next();
1080 len += 1;
1081 }
1082 _ => break,
1083 }
1084 }
1085 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001086 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001087 }
1088 }
1089
Nika Layzellf8d5f212017-12-11 14:07:02 -05001090 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001091}
1092
Nika Layzellf8d5f212017-12-11 14:07:02 -05001093fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001094 let (rest, ()) = digits(input)?;
1095 for suffix in &[
David Tolnayb28f38a2018-03-31 22:02:29 +02001096 "isize", "i8", "i16", "i32", "i64", "i128", "usize", "u8", "u16", "u32", "u64", "u128"
David Tolnay744a6b82017-06-01 11:34:29 -07001097 ] {
1098 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001099 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001100 }
1101 }
1102 word_break(rest)
1103}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001104
Nika Layzellf8d5f212017-12-11 14:07:02 -05001105fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001106 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001107 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001108 16
1109 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001110 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001111 8
1112 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001113 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001114 2
1115 } else {
1116 10
1117 };
1118
Alex Crichton44bffbc2017-05-19 17:51:59 -07001119 let mut len = 0;
1120 let mut empty = true;
1121 for b in input.bytes() {
1122 let digit = match b {
1123 b'0'...b'9' => (b - b'0') as u64,
1124 b'a'...b'f' => 10 + (b - b'a') as u64,
1125 b'A'...b'F' => 10 + (b - b'A') as u64,
1126 b'_' => {
1127 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001128 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001129 }
1130 len += 1;
1131 continue;
1132 }
1133 _ => break,
1134 };
1135 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001136 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001137 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001138 len += 1;
1139 empty = false;
1140 }
1141 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001142 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001143 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001144 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001145 }
1146}
1147
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001148fn op(input: Cursor) -> PResult<Op> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001149 let input = skip_whitespace(input);
1150 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001151 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001152 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001153 Ok(_) => Spacing::Joint,
1154 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001155 };
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001156 Ok((rest, Op::new(ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001157 }
David Tolnay1218e122017-06-01 11:13:45 -07001158 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001159 }
1160}
1161
Nika Layzellf8d5f212017-12-11 14:07:02 -05001162fn op_char(input: Cursor) -> PResult<char> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001163 let mut chars = input.chars();
1164 let first = match chars.next() {
1165 Some(ch) => ch,
1166 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001167 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001168 }
1169 };
1170 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1171 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001172 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001173 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001174 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001175 }
1176}
1177
Alex Crichton1eb96a02018-04-04 13:07:35 -07001178fn doc_comment(input: Cursor) -> PResult<Vec<TokenTree>> {
1179 let mut trees = Vec::new();
1180 let (rest, ((comment, inner), span)) = spanned(input, doc_comment_contents)?;
1181 trees.push(TokenTree::Op(Op::new('#', Spacing::Alone)));
1182 if inner {
1183 trees.push(Op::new('!', Spacing::Alone).into());
1184 }
1185 let mut stream = vec![
1186 TokenTree::Term(::Term::new("doc", span)),
1187 TokenTree::Op(Op::new('=', Spacing::Alone)),
1188 TokenTree::Literal(::Literal::string(comment)),
1189 ];
1190 for tt in stream.iter_mut() {
1191 tt.set_span(span);
1192 }
1193 trees.push(Group::new(Delimiter::Bracket, stream.into_iter().collect()).into());
1194 for tt in trees.iter_mut() {
1195 tt.set_span(span);
1196 }
1197 Ok((rest, trees))
1198}
1199
1200named!(doc_comment_contents -> (&str, bool), alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -07001201 do_parse!(
1202 punct!("//!") >>
Alex Crichton1eb96a02018-04-04 13:07:35 -07001203 s: take_until_newline_or_eof!() >>
1204 ((s, true))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001205 )
1206 |
1207 do_parse!(
1208 option!(whitespace) >>
1209 peek!(tag!("/*!")) >>
Alex Crichton1eb96a02018-04-04 13:07:35 -07001210 s: block_comment >>
1211 ((s, true))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001212 )
1213 |
1214 do_parse!(
1215 punct!("///") >>
1216 not!(tag!("/")) >>
Alex Crichton1eb96a02018-04-04 13:07:35 -07001217 s: take_until_newline_or_eof!() >>
1218 ((s, false))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001219 )
1220 |
1221 do_parse!(
1222 option!(whitespace) >>
1223 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
Alex Crichton1eb96a02018-04-04 13:07:35 -07001224 s: block_comment >>
1225 ((s, false))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001226 )
1227));