blob: 92227931ae248113971d254f861d716ecc63fa43 [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 Tolnay034205f2018-04-22 16:45:28 -070019#[derive(Clone)]
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 Crichton30a4e9e2018-04-27 17:02:19 -070068 Ok(output)
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 Crichton30a4e9e2018-04-27 17:02:19 -070092 if tt.stream().into_iter().next().is_none() {
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
David Tolnay034205f2018-04-22 16:45:28 -0700114impl fmt::Debug for TokenStream {
115 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116 f.write_str("TokenStream ")?;
117 f.debug_list().entries(self.clone()).finish()
118 }
119}
120
Alex Crichton0e8e7f42018-02-22 06:15:13 -0800121#[cfg(feature = "proc-macro")]
122impl From<::proc_macro::TokenStream> for TokenStream {
123 fn from(inner: ::proc_macro::TokenStream) -> TokenStream {
David Tolnayb28f38a2018-03-31 22:02:29 +0200124 inner
125 .to_string()
126 .parse()
127 .expect("compiler token stream parse failed")
Alex Crichton44bffbc2017-05-19 17:51:59 -0700128 }
129}
130
Alex Crichton0e8e7f42018-02-22 06:15:13 -0800131#[cfg(feature = "proc-macro")]
132impl From<TokenStream> for ::proc_macro::TokenStream {
133 fn from(inner: TokenStream) -> ::proc_macro::TokenStream {
David Tolnayb28f38a2018-03-31 22:02:29 +0200134 inner
135 .to_string()
136 .parse()
137 .expect("failed to parse to compiler tokens")
Alex Crichton44bffbc2017-05-19 17:51:59 -0700138 }
139}
140
Alex Crichton44bffbc2017-05-19 17:51:59 -0700141impl From<TokenTree> for TokenStream {
142 fn from(tree: TokenTree) -> TokenStream {
143 TokenStream { inner: vec![tree] }
144 }
145}
146
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700147impl iter::FromIterator<TokenTree> for TokenStream {
David Tolnayb28f38a2018-03-31 22:02:29 +0200148 fn from_iter<I: IntoIterator<Item = TokenTree>>(streams: I) -> Self {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700149 let mut v = Vec::new();
150
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700151 for token in streams.into_iter() {
152 v.push(token);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700153 }
154
155 TokenStream { inner: v }
156 }
157}
158
Alex Crichton1a7f7622017-07-05 17:47:15 -0700159pub type TokenTreeIter = vec::IntoIter<TokenTree>;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700160
161impl IntoIterator for TokenStream {
162 type Item = TokenTree;
Alex Crichton1a7f7622017-07-05 17:47:15 -0700163 type IntoIter = TokenTreeIter;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700164
Alex Crichton1a7f7622017-07-05 17:47:15 -0700165 fn into_iter(self) -> TokenTreeIter {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700166 self.inner.into_iter()
167 }
168}
169
Nika Layzellb35a9a32017-12-30 14:34:35 -0500170#[derive(Clone, PartialEq, Eq, Debug)]
171pub struct FileName(String);
172
Alex Crichton30a4e9e2018-04-27 17:02:19 -0700173pub fn file_name(s: String) -> FileName {
174 FileName(s)
175}
176
Nika Layzellb35a9a32017-12-30 14:34:35 -0500177impl fmt::Display for FileName {
178 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
179 self.0.fmt(f)
180 }
181}
182
Nika Layzellf8d5f212017-12-11 14:07:02 -0500183#[derive(Clone, PartialEq, Eq)]
184pub struct SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500185 name: FileName,
Nika Layzellf8d5f212017-12-11 14:07:02 -0500186}
187
188impl SourceFile {
189 /// Get the path to this source file as a string.
Nika Layzellb35a9a32017-12-30 14:34:35 -0500190 pub fn path(&self) -> &FileName {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500191 &self.name
192 }
193
194 pub fn is_real(&self) -> bool {
195 // XXX(nika): Support real files in the future?
196 false
197 }
198}
199
Nika Layzellb35a9a32017-12-30 14:34:35 -0500200impl AsRef<FileName> for SourceFile {
201 fn as_ref(&self) -> &FileName {
202 self.path()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500203 }
204}
205
206impl fmt::Debug for SourceFile {
207 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
208 f.debug_struct("SourceFile")
Nika Layzellb35a9a32017-12-30 14:34:35 -0500209 .field("path", &self.path())
Nika Layzellf8d5f212017-12-11 14:07:02 -0500210 .field("is_real", &self.is_real())
211 .finish()
212 }
213}
214
215#[derive(Clone, Copy, Debug, PartialEq, Eq)]
216pub struct LineColumn {
217 pub line: usize,
218 pub column: usize,
219}
220
David Tolnay1ebe3972018-01-02 20:14:20 -0800221#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500222thread_local! {
223 static CODEMAP: RefCell<Codemap> = RefCell::new(Codemap {
224 // NOTE: We start with a single dummy file which all call_site() and
225 // def_site() spans reference.
226 files: vec![FileInfo {
227 name: "<unspecified>".to_owned(),
228 span: Span { lo: 0, hi: 0 },
229 lines: vec![0],
230 }],
231 });
232}
233
David Tolnay1ebe3972018-01-02 20:14:20 -0800234#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500235struct FileInfo {
236 name: String,
237 span: Span,
238 lines: Vec<usize>,
239}
240
David Tolnay1ebe3972018-01-02 20:14:20 -0800241#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500242impl FileInfo {
243 fn offset_line_column(&self, offset: usize) -> LineColumn {
David Tolnayb28f38a2018-03-31 22:02:29 +0200244 assert!(self.span_within(Span {
245 lo: offset as u32,
246 hi: offset as u32
247 }));
Nika Layzellf8d5f212017-12-11 14:07:02 -0500248 let offset = offset - self.span.lo as usize;
249 match self.lines.binary_search(&offset) {
250 Ok(found) => LineColumn {
251 line: found + 1,
David Tolnayb28f38a2018-03-31 22:02:29 +0200252 column: 0,
Nika Layzellf8d5f212017-12-11 14:07:02 -0500253 },
254 Err(idx) => LineColumn {
255 line: idx,
David Tolnayb28f38a2018-03-31 22:02:29 +0200256 column: offset - self.lines[idx - 1],
Nika Layzellf8d5f212017-12-11 14:07:02 -0500257 },
258 }
259 }
260
261 fn span_within(&self, span: Span) -> bool {
262 span.lo >= self.span.lo && span.hi <= self.span.hi
263 }
264}
265
Alex Crichtona914a612018-04-04 07:48:44 -0700266/// Computesthe offsets of each line in the given source string.
David Tolnay1ebe3972018-01-02 20:14:20 -0800267#[cfg(procmacro2_semver_exempt)]
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500268fn lines_offsets(s: &str) -> Vec<usize> {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500269 let mut lines = vec![0];
270 let mut prev = 0;
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500271 while let Some(len) = s[prev..].find('\n') {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500272 prev += len + 1;
273 lines.push(prev);
274 }
275 lines
276}
277
David Tolnay1ebe3972018-01-02 20:14:20 -0800278#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500279struct Codemap {
280 files: Vec<FileInfo>,
281}
282
David Tolnay1ebe3972018-01-02 20:14:20 -0800283#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500284impl Codemap {
285 fn next_start_pos(&self) -> u32 {
286 // Add 1 so there's always space between files.
287 //
288 // We'll always have at least 1 file, as we initialize our files list
289 // with a dummy file.
290 self.files.last().unwrap().span.hi + 1
291 }
292
293 fn add_file(&mut self, name: &str, src: &str) -> Span {
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500294 let lines = lines_offsets(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -0500295 let lo = self.next_start_pos();
296 // XXX(nika): Shouild we bother doing a checked cast or checked add here?
David Tolnayb28f38a2018-03-31 22:02:29 +0200297 let span = Span {
298 lo: lo,
299 hi: lo + (src.len() as u32),
300 };
Nika Layzellf8d5f212017-12-11 14:07:02 -0500301
302 self.files.push(FileInfo {
303 name: name.to_owned(),
304 span: span,
305 lines: lines,
306 });
307
308 span
309 }
310
311 fn fileinfo(&self, span: Span) -> &FileInfo {
312 for file in &self.files {
313 if file.span_within(span) {
314 return file;
315 }
316 }
317 panic!("Invalid span with no related FileInfo!");
318 }
319}
320
David Tolnay034205f2018-04-22 16:45:28 -0700321#[derive(Clone, Copy, PartialEq, Eq)]
David Tolnayddfca052017-12-31 10:41:24 -0500322pub struct Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800323 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500324 lo: u32,
David Tolnay1ebe3972018-01-02 20:14:20 -0800325 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500326 hi: u32,
327}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700328
329impl Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800330 #[cfg(not(procmacro2_semver_exempt))]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700331 pub fn call_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500332 Span {}
333 }
334
David Tolnay1ebe3972018-01-02 20:14:20 -0800335 #[cfg(procmacro2_semver_exempt)]
David Tolnay79105e52017-12-31 11:03:04 -0500336 pub fn call_site() -> Span {
337 Span { lo: 0, hi: 0 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700338 }
Alex Crichtone6085b72017-11-21 07:24:25 -0800339
340 pub fn def_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500341 Span::call_site()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500342 }
343
David Tolnay4e8e3972018-01-05 18:10:22 -0800344 pub fn resolved_at(&self, _other: Span) -> Span {
345 // Stable spans consist only of line/column information, so
346 // `resolved_at` and `located_at` only select which span the
347 // caller wants line/column information from.
348 *self
349 }
350
351 pub fn located_at(&self, other: Span) -> Span {
352 other
353 }
354
David Tolnay1ebe3972018-01-02 20:14:20 -0800355 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500356 pub fn source_file(&self) -> SourceFile {
357 CODEMAP.with(|cm| {
358 let cm = cm.borrow();
359 let fi = cm.fileinfo(*self);
360 SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500361 name: FileName(fi.name.clone()),
Nika Layzellf8d5f212017-12-11 14:07:02 -0500362 }
363 })
364 }
365
David Tolnay1ebe3972018-01-02 20:14:20 -0800366 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500367 pub fn start(&self) -> LineColumn {
368 CODEMAP.with(|cm| {
369 let cm = cm.borrow();
370 let fi = cm.fileinfo(*self);
371 fi.offset_line_column(self.lo as usize)
372 })
373 }
374
David Tolnay1ebe3972018-01-02 20:14:20 -0800375 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500376 pub fn end(&self) -> LineColumn {
377 CODEMAP.with(|cm| {
378 let cm = cm.borrow();
379 let fi = cm.fileinfo(*self);
380 fi.offset_line_column(self.hi as usize)
381 })
382 }
383
David Tolnay1ebe3972018-01-02 20:14:20 -0800384 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500385 pub fn join(&self, other: Span) -> Option<Span> {
386 CODEMAP.with(|cm| {
387 let cm = cm.borrow();
388 // If `other` is not within the same FileInfo as us, return None.
389 if !cm.fileinfo(*self).span_within(other) {
390 return None;
391 }
392 Some(Span {
393 lo: cmp::min(self.lo, other.lo),
394 hi: cmp::max(self.hi, other.hi),
395 })
396 })
Alex Crichtone6085b72017-11-21 07:24:25 -0800397 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700398}
399
David Tolnay034205f2018-04-22 16:45:28 -0700400impl fmt::Debug for Span {
401 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
402 #[cfg(procmacro2_semver_exempt)]
403 return write!(f, "bytes({}..{})", self.lo, self.hi);
404
405 #[cfg(not(procmacro2_semver_exempt))]
406 write!(f, "Span")
407 }
408}
409
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700410#[derive(Copy, Clone)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700411pub struct Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700412 intern: usize,
Alex Crichtonb2c94622018-04-04 07:36:41 -0700413 span: Span,
David Tolnay041bcd42017-06-03 09:18:04 -0700414}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700415
416thread_local!(static SYMBOLS: RefCell<Interner> = RefCell::new(Interner::new()));
417
David Tolnay10effeb2018-01-06 11:07:49 -0800418impl Term {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700419 pub fn new(string: &str, span: Span) -> Term {
David Tolnay489c6422018-04-07 08:37:28 -0700420 validate_term(string);
421
Alex Crichton1a7f7622017-07-05 17:47:15 -0700422 Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700423 intern: SYMBOLS.with(|s| s.borrow_mut().intern(string)),
Alex Crichtona914a612018-04-04 07:48:44 -0700424 span: span,
David Tolnay041bcd42017-06-03 09:18:04 -0700425 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700426 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700427
David Tolnay10effeb2018-01-06 11:07:49 -0800428 pub fn as_str(&self) -> &str {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700429 SYMBOLS.with(|interner| {
430 let interner = interner.borrow();
David Tolnay041bcd42017-06-03 09:18:04 -0700431 let s = interner.get(self.intern);
David Tolnayb28f38a2018-03-31 22:02:29 +0200432 unsafe { &*(s as *const str) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700433 })
434 }
Alex Crichtonb2c94622018-04-04 07:36:41 -0700435
436 pub fn span(&self) -> Span {
437 self.span
438 }
439
440 pub fn set_span(&mut self, span: Span) {
441 self.span = span;
442 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700443}
444
David Tolnay489c6422018-04-07 08:37:28 -0700445fn validate_term(string: &str) {
446 let validate = if string.starts_with('\'') {
447 &string[1..]
448 } else if string.starts_with("r#") {
449 &string[2..]
450 } else {
451 string
452 };
453
454 if validate.is_empty() {
455 panic!("Term is not allowed to be empty; use Option<Term>");
456 }
457
458 if validate.bytes().all(|digit| digit >= b'0' && digit <= b'9') {
459 panic!("Term cannot be a number; use Literal instead");
460 }
461
462 fn xid_ok(string: &str) -> bool {
463 let mut chars = string.chars();
464 let first = chars.next().unwrap();
465 if !(UnicodeXID::is_xid_start(first) || first == '_') {
466 return false;
467 }
468 for ch in chars {
469 if !UnicodeXID::is_xid_continue(ch) {
470 return false;
471 }
472 }
473 true
474 }
475
476 if !xid_ok(validate) {
477 panic!("{:?} is not a valid Term", string);
478 }
479}
480
Alex Crichton1a7f7622017-07-05 17:47:15 -0700481impl fmt::Debug for Term {
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700482 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
David Tolnay034205f2018-04-22 16:45:28 -0700483 let mut debug = f.debug_struct("Term");
484 debug.field("sym", &format_args!("{}", self.as_str()));
485 #[cfg(procmacro2_semver_exempt)]
486 debug.field("span", &self.span);
487 debug.finish()
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700488 }
489}
490
Alex Crichton44bffbc2017-05-19 17:51:59 -0700491struct Interner {
492 string_to_index: HashMap<MyRc, usize>,
493 index_to_string: Vec<Rc<String>>,
494}
495
496#[derive(Hash, Eq, PartialEq)]
497struct MyRc(Rc<String>);
498
499impl Borrow<str> for MyRc {
500 fn borrow(&self) -> &str {
501 &self.0
502 }
503}
504
505impl Interner {
506 fn new() -> Interner {
507 Interner {
508 string_to_index: HashMap::new(),
509 index_to_string: Vec::new(),
510 }
511 }
512
David Tolnayb28f38a2018-03-31 22:02:29 +0200513 fn intern(&mut self, s: &str) -> usize {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700514 if let Some(&idx) = self.string_to_index.get(s) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200515 return idx;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700516 }
517 let s = Rc::new(s.to_string());
518 self.index_to_string.push(s.clone());
David Tolnayb28f38a2018-03-31 22:02:29 +0200519 self.string_to_index
520 .insert(MyRc(s), self.index_to_string.len() - 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700521 self.index_to_string.len() - 1
522 }
523
David Tolnayb28f38a2018-03-31 22:02:29 +0200524 fn get(&self, idx: usize) -> &str {
525 &self.index_to_string[idx]
526 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700527}
528
David Tolnay034205f2018-04-22 16:45:28 -0700529#[derive(Clone)]
Alex Crichtonb2c94622018-04-04 07:36:41 -0700530pub struct Literal {
531 text: String,
532 span: Span,
533}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700534
Alex Crichtona914a612018-04-04 07:48:44 -0700535macro_rules! suffixed_numbers {
536 ($($name:ident => $kind:ident,)*) => ($(
537 pub fn $name(n: $kind) -> Literal {
538 Literal::_new(format!(concat!("{}", stringify!($kind)), n))
539 }
540 )*)
541}
542
543macro_rules! unsuffixed_numbers {
544 ($($name:ident => $kind:ident,)*) => ($(
545 pub fn $name(n: $kind) -> Literal {
546 Literal::_new(n.to_string())
547 }
548 )*)
549}
550
Alex Crichton852d53d2017-05-19 19:25:08 -0700551impl Literal {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700552 fn _new(text: String) -> Literal {
553 Literal {
Alex Crichtona914a612018-04-04 07:48:44 -0700554 text: text,
Alex Crichtonb2c94622018-04-04 07:36:41 -0700555 span: Span::call_site(),
556 }
557 }
558
Alex Crichtona914a612018-04-04 07:48:44 -0700559 suffixed_numbers! {
560 u8_suffixed => u8,
561 u16_suffixed => u16,
562 u32_suffixed => u32,
563 u64_suffixed => u64,
564 usize_suffixed => usize,
565 i8_suffixed => i8,
566 i16_suffixed => i16,
567 i32_suffixed => i32,
568 i64_suffixed => i64,
569 isize_suffixed => isize,
570
571 f32_suffixed => f32,
572 f64_suffixed => f64,
573 }
574
575 unsuffixed_numbers! {
576 u8_unsuffixed => u8,
577 u16_unsuffixed => u16,
578 u32_unsuffixed => u32,
579 u64_unsuffixed => u64,
580 usize_unsuffixed => usize,
581 i8_unsuffixed => i8,
582 i16_unsuffixed => i16,
583 i32_unsuffixed => i32,
584 i64_unsuffixed => i64,
585 isize_unsuffixed => isize,
586 }
587
588 pub fn f32_unsuffixed(f: f32) -> Literal {
589 let mut s = f.to_string();
590 if !s.contains(".") {
591 s.push_str(".0");
Alex Crichton76a5cc82017-05-23 07:01:44 -0700592 }
Alex Crichtona914a612018-04-04 07:48:44 -0700593 Literal::_new(s)
594 }
595
596 pub fn f64_unsuffixed(f: f64) -> Literal {
597 let mut s = f.to_string();
598 if !s.contains(".") {
599 s.push_str(".0");
600 }
601 Literal::_new(s)
602 }
603
604 pub fn string(t: &str) -> Literal {
605 let mut s = t.chars()
606 .flat_map(|c| c.escape_default())
607 .collect::<String>();
608 s.push('"');
609 s.insert(0, '"');
610 Literal::_new(s)
611 }
612
613 pub fn character(t: char) -> Literal {
614 Literal::_new(format!("'{}'", t.escape_default().collect::<String>()))
Alex Crichton76a5cc82017-05-23 07:01:44 -0700615 }
616
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700617 pub fn byte_string(bytes: &[u8]) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700618 let mut escaped = "b\"".to_string();
619 for b in bytes {
620 match *b {
621 b'\0' => escaped.push_str(r"\0"),
622 b'\t' => escaped.push_str(r"\t"),
623 b'\n' => escaped.push_str(r"\n"),
624 b'\r' => escaped.push_str(r"\r"),
625 b'"' => escaped.push_str("\\\""),
626 b'\\' => escaped.push_str("\\\\"),
David Tolnayb28f38a2018-03-31 22:02:29 +0200627 b'\x20'...b'\x7E' => escaped.push(*b as char),
Alex Crichton852d53d2017-05-19 19:25:08 -0700628 _ => escaped.push_str(&format!("\\x{:02X}", b)),
629 }
630 }
631 escaped.push('"');
Alex Crichtonb2c94622018-04-04 07:36:41 -0700632 Literal::_new(escaped)
Alex Crichton76a5cc82017-05-23 07:01:44 -0700633 }
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700634
Alex Crichtonb2c94622018-04-04 07:36:41 -0700635 pub fn span(&self) -> Span {
636 self.span
Alex Crichton31316622017-05-26 12:54:47 -0700637 }
638
Alex Crichtonb2c94622018-04-04 07:36:41 -0700639 pub fn set_span(&mut self, span: Span) {
640 self.span = span;
Alex Crichton31316622017-05-26 12:54:47 -0700641 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700642}
643
Alex Crichton44bffbc2017-05-19 17:51:59 -0700644impl fmt::Display for Literal {
645 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700646 self.text.fmt(f)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700647 }
648}
649
David Tolnay034205f2018-04-22 16:45:28 -0700650impl fmt::Debug for Literal {
651 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
652 let mut debug = fmt.debug_struct("Literal");
653 debug.field("lit", &format_args!("{}", self.text));
654 #[cfg(procmacro2_semver_exempt)]
655 debug.field("span", &self.span);
656 debug.finish()
657 }
658}
659
Alex Crichton30a4e9e2018-04-27 17:02:19 -0700660fn token_stream(mut input: Cursor) -> PResult<TokenStream> {
Alex Crichton1eb96a02018-04-04 13:07:35 -0700661 let mut trees = Vec::new();
662 loop {
663 let input_no_ws = skip_whitespace(input);
664 if input_no_ws.rest.len() == 0 {
David Tolnay48ea5042018-04-23 19:17:35 -0700665 break;
Alex Crichton1eb96a02018-04-04 13:07:35 -0700666 }
667 if let Ok((a, tokens)) = doc_comment(input_no_ws) {
668 input = a;
669 trees.extend(tokens);
David Tolnay48ea5042018-04-23 19:17:35 -0700670 continue;
Alex Crichton1eb96a02018-04-04 13:07:35 -0700671 }
672
673 let (a, tt) = match token_tree(input_no_ws) {
674 Ok(p) => p,
675 Err(_) => break,
676 };
677 trees.push(tt);
678 input = a;
679 }
Alex Crichton30a4e9e2018-04-27 17:02:19 -0700680 Ok((input, TokenStream { inner: trees }))
Alex Crichton1eb96a02018-04-04 13:07:35 -0700681}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700682
David Tolnay1ebe3972018-01-02 20:14:20 -0800683#[cfg(not(procmacro2_semver_exempt))]
Alex Crichton1eb96a02018-04-04 13:07:35 -0700684fn spanned<'a, T>(
685 input: Cursor<'a>,
686 f: fn(Cursor<'a>) -> PResult<'a, T>,
687) -> PResult<'a, (T, ::Span)> {
688 let (a, b) = f(skip_whitespace(input))?;
Alex Crichton30a4e9e2018-04-27 17:02:19 -0700689 Ok((a, ((b, ::Span::_new_stable(Span {})))))
David Tolnayddfca052017-12-31 10:41:24 -0500690}
691
David Tolnay1ebe3972018-01-02 20:14:20 -0800692#[cfg(procmacro2_semver_exempt)]
Alex Crichton1eb96a02018-04-04 13:07:35 -0700693fn spanned<'a, T>(
694 input: Cursor<'a>,
695 f: fn(Cursor<'a>) -> PResult<'a, T>,
696) -> PResult<'a, (T, ::Span)> {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500697 let input = skip_whitespace(input);
698 let lo = input.off;
Alex Crichton1eb96a02018-04-04 13:07:35 -0700699 let (a, b) = f(input)?;
700 let hi = a.off;
Alex Crichton30a4e9e2018-04-27 17:02:19 -0700701 let span = ::Span::_new_stable(Span { lo: lo, hi: hi });
Alex Crichton1eb96a02018-04-04 13:07:35 -0700702 Ok((a, (b, span)))
703}
704
705fn token_tree(input: Cursor) -> PResult<TokenTree> {
706 let (rest, (mut tt, span)) = spanned(input, token_kind)?;
707 tt.set_span(span);
708 Ok((rest, tt))
Nika Layzellf8d5f212017-12-11 14:07:02 -0500709}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700710
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700711named!(token_kind -> TokenTree, alt!(
712 map!(group, TokenTree::Group)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700713 |
Alex Crichton30a4e9e2018-04-27 17:02:19 -0700714 map!(literal, |l| TokenTree::Literal(::Literal::_new_stable(l))) // must be before symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700715 |
Alex Crichton52725f72017-08-28 12:20:58 -0700716 symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700717 |
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700718 map!(op, TokenTree::Op)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700719));
720
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700721named!(group -> Group, alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -0700722 delimited!(
723 punct!("("),
724 token_stream,
725 punct!(")")
Alex Crichton30a4e9e2018-04-27 17:02:19 -0700726 ) => { |ts| Group::new(Delimiter::Parenthesis, ::TokenStream::_new_stable(ts)) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700727 |
728 delimited!(
729 punct!("["),
730 token_stream,
731 punct!("]")
Alex Crichton30a4e9e2018-04-27 17:02:19 -0700732 ) => { |ts| Group::new(Delimiter::Bracket, ::TokenStream::_new_stable(ts)) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700733 |
734 delimited!(
735 punct!("{"),
736 token_stream,
737 punct!("}")
Alex Crichton30a4e9e2018-04-27 17:02:19 -0700738 ) => { |ts| Group::new(Delimiter::Brace, ::TokenStream::_new_stable(ts)) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700739));
740
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700741fn symbol(mut input: Cursor) -> PResult<TokenTree> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700742 input = skip_whitespace(input);
743
744 let mut chars = input.char_indices();
David Tolnaya202d502017-06-01 12:26:55 -0700745
746 let lifetime = input.starts_with("'");
747 if lifetime {
748 chars.next();
749 }
750
David Tolnaya13d1422018-03-31 21:27:48 +0200751 let raw = !lifetime && input.starts_with("r#");
752 if raw {
753 chars.next();
754 chars.next();
755 }
756
Alex Crichton44bffbc2017-05-19 17:51:59 -0700757 match chars.next() {
758 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700759 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700760 }
761
David Tolnay214c94c2017-06-01 12:42:56 -0700762 let mut end = input.len();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700763 for (i, ch) in chars {
764 if !UnicodeXID::is_xid_continue(ch) {
David Tolnay214c94c2017-06-01 12:42:56 -0700765 end = i;
766 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700767 }
768 }
769
David Tolnaya13d1422018-03-31 21:27:48 +0200770 let a = &input.rest[..end];
771 if a == "r#_" || lifetime && a != "'static" && KEYWORDS.contains(&&a[1..]) {
David Tolnay214c94c2017-06-01 12:42:56 -0700772 Err(LexError)
David Tolnaya13d1422018-03-31 21:27:48 +0200773 } else if a == "_" {
774 Ok((input.advance(end), Op::new('_', Spacing::Alone).into()))
David Tolnay214c94c2017-06-01 12:42:56 -0700775 } else {
David Tolnayb28f38a2018-03-31 22:02:29 +0200776 Ok((
777 input.advance(end),
778 ::Term::new(a, ::Span::call_site()).into(),
779 ))
David Tolnay214c94c2017-06-01 12:42:56 -0700780 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700781}
782
David Tolnay214c94c2017-06-01 12:42:56 -0700783// From https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/symbol.rs
784static KEYWORDS: &'static [&'static str] = &[
David Tolnayb28f38a2018-03-31 22:02:29 +0200785 "abstract", "alignof", "as", "become", "box", "break", "const", "continue", "crate", "do",
786 "else", "enum", "extern", "false", "final", "fn", "for", "if", "impl", "in", "let", "loop",
787 "macro", "match", "mod", "move", "mut", "offsetof", "override", "priv", "proc", "pub", "pure",
788 "ref", "return", "self", "Self", "sizeof", "static", "struct", "super", "trait", "true",
789 "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while", "yield",
David Tolnay214c94c2017-06-01 12:42:56 -0700790];
791
Alex Crichton30a4e9e2018-04-27 17:02:19 -0700792fn literal(input: Cursor) -> PResult<Literal> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700793 let input_no_ws = skip_whitespace(input);
794
795 match literal_nocapture(input_no_ws) {
David Tolnay1218e122017-06-01 11:13:45 -0700796 Ok((a, ())) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700797 let start = input.len() - input_no_ws.len();
798 let len = input_no_ws.len() - a.len();
799 let end = start + len;
David Tolnayb28f38a2018-03-31 22:02:29 +0200800 Ok((
801 a,
Alex Crichton30a4e9e2018-04-27 17:02:19 -0700802 Literal::_new(input.rest[start..end].to_string()),
David Tolnayb28f38a2018-03-31 22:02:29 +0200803 ))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700804 }
David Tolnay1218e122017-06-01 11:13:45 -0700805 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700806 }
807}
808
809named!(literal_nocapture -> (), alt!(
810 string
811 |
812 byte_string
813 |
814 byte
815 |
816 character
817 |
818 float
819 |
820 int
Alex Crichton44bffbc2017-05-19 17:51:59 -0700821));
822
823named!(string -> (), alt!(
824 quoted_string
825 |
826 preceded!(
827 punct!("r"),
828 raw_string
829 ) => { |_| () }
830));
831
832named!(quoted_string -> (), delimited!(
833 punct!("\""),
834 cooked_string,
835 tag!("\"")
836));
837
Nika Layzellf8d5f212017-12-11 14:07:02 -0500838fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700839 let mut chars = input.char_indices().peekable();
840 while let Some((byte_offset, ch)) = chars.next() {
841 match ch {
842 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500843 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700844 }
845 '\r' => {
846 if let Some((_, '\n')) = chars.next() {
847 // ...
848 } else {
849 break;
850 }
851 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200852 '\\' => match chars.next() {
853 Some((_, 'x')) => {
854 if !backslash_x_char(&mut chars) {
855 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700856 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700857 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200858 Some((_, 'n')) | Some((_, 'r')) | Some((_, 't')) | Some((_, '\\'))
859 | Some((_, '\'')) | Some((_, '"')) | Some((_, '0')) => {}
860 Some((_, 'u')) => {
861 if !backslash_u(&mut chars) {
862 break;
863 }
864 }
865 Some((_, '\n')) | Some((_, '\r')) => {
866 while let Some(&(_, ch)) = chars.peek() {
867 if ch.is_whitespace() {
868 chars.next();
869 } else {
870 break;
871 }
872 }
873 }
874 _ => break,
875 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700876 _ch => {}
877 }
878 }
David Tolnay1218e122017-06-01 11:13:45 -0700879 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700880}
881
882named!(byte_string -> (), alt!(
883 delimited!(
884 punct!("b\""),
885 cooked_byte_string,
886 tag!("\"")
887 ) => { |_| () }
888 |
889 preceded!(
890 punct!("br"),
891 raw_string
892 ) => { |_| () }
893));
894
Nika Layzellf8d5f212017-12-11 14:07:02 -0500895fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700896 let mut bytes = input.bytes().enumerate();
897 'outer: while let Some((offset, b)) = bytes.next() {
898 match b {
899 b'"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500900 return Ok((input.advance(offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700901 }
902 b'\r' => {
903 if let Some((_, b'\n')) = bytes.next() {
904 // ...
905 } else {
906 break;
907 }
908 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200909 b'\\' => match bytes.next() {
910 Some((_, b'x')) => {
911 if !backslash_x_byte(&mut bytes) {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700912 break;
913 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700914 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200915 Some((_, b'n')) | Some((_, b'r')) | Some((_, b't')) | Some((_, b'\\'))
916 | Some((_, b'0')) | Some((_, b'\'')) | Some((_, b'"')) => {}
917 Some((newline, b'\n')) | Some((newline, b'\r')) => {
918 let rest = input.advance(newline + 1);
919 for (offset, ch) in rest.char_indices() {
920 if !ch.is_whitespace() {
921 input = rest.advance(offset);
922 bytes = input.bytes().enumerate();
923 continue 'outer;
924 }
925 }
926 break;
927 }
928 _ => break,
929 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700930 b if b < 0x80 => {}
931 _ => break,
932 }
933 }
David Tolnay1218e122017-06-01 11:13:45 -0700934 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700935}
936
Nika Layzellf8d5f212017-12-11 14:07:02 -0500937fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700938 let mut chars = input.char_indices();
939 let mut n = 0;
940 while let Some((byte_offset, ch)) = chars.next() {
941 match ch {
942 '"' => {
943 n = byte_offset;
944 break;
945 }
946 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700947 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700948 }
949 }
950 for (byte_offset, ch) in chars {
951 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500952 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
953 let rest = input.advance(byte_offset + 1 + n);
David Tolnayb28f38a2018-03-31 22:02:29 +0200954 return Ok((rest, ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700955 }
956 '\r' => {}
957 _ => {}
958 }
959 }
David Tolnay1218e122017-06-01 11:13:45 -0700960 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700961}
962
963named!(byte -> (), do_parse!(
964 punct!("b") >>
965 tag!("'") >>
966 cooked_byte >>
967 tag!("'") >>
968 (())
969));
970
Nika Layzellf8d5f212017-12-11 14:07:02 -0500971fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700972 let mut bytes = input.bytes().enumerate();
973 let ok = match bytes.next().map(|(_, b)| b) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200974 Some(b'\\') => match bytes.next().map(|(_, b)| b) {
975 Some(b'x') => backslash_x_byte(&mut bytes),
976 Some(b'n') | Some(b'r') | Some(b't') | Some(b'\\') | Some(b'0') | Some(b'\'')
977 | Some(b'"') => true,
978 _ => false,
979 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700980 b => b.is_some(),
981 };
982 if ok {
983 match bytes.next() {
Alex Crichton8c030332018-01-16 08:07:36 -0800984 Some((offset, _)) => {
985 if input.chars().as_str().is_char_boundary(offset) {
986 Ok((input.advance(offset), ()))
987 } else {
988 Err(LexError)
989 }
990 }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500991 None => Ok((input.advance(input.len()), ())),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700992 }
993 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700994 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700995 }
996}
997
998named!(character -> (), do_parse!(
999 punct!("'") >>
1000 cooked_char >>
1001 tag!("'") >>
1002 (())
1003));
1004
Nika Layzellf8d5f212017-12-11 14:07:02 -05001005fn cooked_char(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001006 let mut chars = input.char_indices();
1007 let ok = match chars.next().map(|(_, ch)| ch) {
David Tolnayb28f38a2018-03-31 22:02:29 +02001008 Some('\\') => match chars.next().map(|(_, ch)| ch) {
1009 Some('x') => backslash_x_char(&mut chars),
1010 Some('u') => backslash_u(&mut chars),
1011 Some('n') | Some('r') | Some('t') | Some('\\') | Some('0') | Some('\'') | Some('"') => {
1012 true
Alex Crichton44bffbc2017-05-19 17:51:59 -07001013 }
David Tolnayb28f38a2018-03-31 22:02:29 +02001014 _ => false,
1015 },
Alex Crichton44bffbc2017-05-19 17:51:59 -07001016 ch => ch.is_some(),
1017 };
1018 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001019 match chars.next() {
1020 Some((idx, _)) => Ok((input.advance(idx), ())),
1021 None => Ok((input.advance(input.len()), ())),
1022 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001023 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001024 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001025 }
1026}
1027
1028macro_rules! next_ch {
1029 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
1030 match $chars.next() {
1031 Some((_, ch)) => match ch {
1032 $pat $(| $rest)* => ch,
1033 _ => return false,
1034 },
1035 None => return false
1036 }
1037 };
1038}
1039
1040fn backslash_x_char<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +02001041where
1042 I: Iterator<Item = (usize, char)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -07001043{
1044 next_ch!(chars @ '0'...'7');
1045 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
1046 true
1047}
1048
1049fn backslash_x_byte<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +02001050where
1051 I: Iterator<Item = (usize, u8)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -07001052{
1053 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
1054 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
1055 true
1056}
1057
1058fn backslash_u<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +02001059where
1060 I: Iterator<Item = (usize, char)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -07001061{
1062 next_ch!(chars @ '{');
1063 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
David Tolnay8d109342017-12-25 18:24:45 -05001064 loop {
1065 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '_' | '}');
1066 if c == '}' {
1067 return true;
1068 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001069 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001070}
1071
Nika Layzellf8d5f212017-12-11 14:07:02 -05001072fn float(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001073 let (rest, ()) = float_digits(input)?;
1074 for suffix in &["f32", "f64"] {
1075 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001076 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001077 }
1078 }
1079 word_break(rest)
1080}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001081
Nika Layzellf8d5f212017-12-11 14:07:02 -05001082fn float_digits(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001083 let mut chars = input.chars().peekable();
1084 match chars.next() {
1085 Some(ch) if ch >= '0' && ch <= '9' => {}
David Tolnay1218e122017-06-01 11:13:45 -07001086 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001087 }
1088
1089 let mut len = 1;
1090 let mut has_dot = false;
1091 let mut has_exp = false;
1092 while let Some(&ch) = chars.peek() {
1093 match ch {
1094 '0'...'9' | '_' => {
1095 chars.next();
1096 len += 1;
1097 }
1098 '.' => {
1099 if has_dot {
1100 break;
1101 }
1102 chars.next();
David Tolnayb28f38a2018-03-31 22:02:29 +02001103 if chars
1104 .peek()
1105 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1106 .unwrap_or(false)
1107 {
David Tolnay1218e122017-06-01 11:13:45 -07001108 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001109 }
1110 len += 1;
1111 has_dot = true;
1112 }
1113 'e' | 'E' => {
1114 chars.next();
1115 len += 1;
1116 has_exp = true;
1117 break;
1118 }
1119 _ => break,
1120 }
1121 }
1122
Nika Layzellf8d5f212017-12-11 14:07:02 -05001123 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001124 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001125 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001126 }
1127
1128 if has_exp {
1129 let mut has_exp_value = false;
1130 while let Some(&ch) = chars.peek() {
1131 match ch {
1132 '+' | '-' => {
1133 if has_exp_value {
1134 break;
1135 }
1136 chars.next();
1137 len += 1;
1138 }
1139 '0'...'9' => {
1140 chars.next();
1141 len += 1;
1142 has_exp_value = true;
1143 }
1144 '_' => {
1145 chars.next();
1146 len += 1;
1147 }
1148 _ => break,
1149 }
1150 }
1151 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001152 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001153 }
1154 }
1155
Nika Layzellf8d5f212017-12-11 14:07:02 -05001156 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001157}
1158
Nika Layzellf8d5f212017-12-11 14:07:02 -05001159fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001160 let (rest, ()) = digits(input)?;
1161 for suffix in &[
David Tolnay48ea5042018-04-23 19:17:35 -07001162 "isize", "i8", "i16", "i32", "i64", "i128", "usize", "u8", "u16", "u32", "u64", "u128",
David Tolnay744a6b82017-06-01 11:34:29 -07001163 ] {
1164 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001165 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001166 }
1167 }
1168 word_break(rest)
1169}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001170
Nika Layzellf8d5f212017-12-11 14:07:02 -05001171fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001172 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001173 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001174 16
1175 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001176 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001177 8
1178 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001179 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001180 2
1181 } else {
1182 10
1183 };
1184
Alex Crichton44bffbc2017-05-19 17:51:59 -07001185 let mut len = 0;
1186 let mut empty = true;
1187 for b in input.bytes() {
1188 let digit = match b {
1189 b'0'...b'9' => (b - b'0') as u64,
1190 b'a'...b'f' => 10 + (b - b'a') as u64,
1191 b'A'...b'F' => 10 + (b - b'A') as u64,
1192 b'_' => {
1193 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001194 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001195 }
1196 len += 1;
1197 continue;
1198 }
1199 _ => break,
1200 };
1201 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001202 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001203 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001204 len += 1;
1205 empty = false;
1206 }
1207 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001208 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001209 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001210 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001211 }
1212}
1213
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001214fn op(input: Cursor) -> PResult<Op> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001215 let input = skip_whitespace(input);
1216 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001217 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001218 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001219 Ok(_) => Spacing::Joint,
1220 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001221 };
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001222 Ok((rest, Op::new(ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001223 }
David Tolnay1218e122017-06-01 11:13:45 -07001224 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001225 }
1226}
1227
Nika Layzellf8d5f212017-12-11 14:07:02 -05001228fn op_char(input: Cursor) -> PResult<char> {
David Tolnay3a592ad2018-04-22 21:20:24 -07001229 if input.starts_with("//") || input.starts_with("/*") {
1230 // Do not accept `/` of a comment as an op.
1231 return Err(LexError);
1232 }
1233
David Tolnayea75c5f2017-05-31 23:40:33 -07001234 let mut chars = input.chars();
1235 let first = match chars.next() {
1236 Some(ch) => ch,
1237 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001238 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001239 }
1240 };
1241 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1242 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001243 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001244 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001245 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001246 }
1247}
1248
Alex Crichton1eb96a02018-04-04 13:07:35 -07001249fn doc_comment(input: Cursor) -> PResult<Vec<TokenTree>> {
1250 let mut trees = Vec::new();
1251 let (rest, ((comment, inner), span)) = spanned(input, doc_comment_contents)?;
1252 trees.push(TokenTree::Op(Op::new('#', Spacing::Alone)));
1253 if inner {
1254 trees.push(Op::new('!', Spacing::Alone).into());
1255 }
1256 let mut stream = vec![
1257 TokenTree::Term(::Term::new("doc", span)),
1258 TokenTree::Op(Op::new('=', Spacing::Alone)),
1259 TokenTree::Literal(::Literal::string(comment)),
1260 ];
1261 for tt in stream.iter_mut() {
1262 tt.set_span(span);
1263 }
1264 trees.push(Group::new(Delimiter::Bracket, stream.into_iter().collect()).into());
1265 for tt in trees.iter_mut() {
1266 tt.set_span(span);
1267 }
1268 Ok((rest, trees))
1269}
1270
1271named!(doc_comment_contents -> (&str, bool), alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -07001272 do_parse!(
1273 punct!("//!") >>
Alex Crichton1eb96a02018-04-04 13:07:35 -07001274 s: take_until_newline_or_eof!() >>
1275 ((s, true))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001276 )
1277 |
1278 do_parse!(
1279 option!(whitespace) >>
1280 peek!(tag!("/*!")) >>
Alex Crichton1eb96a02018-04-04 13:07:35 -07001281 s: block_comment >>
1282 ((s, true))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001283 )
1284 |
1285 do_parse!(
1286 punct!("///") >>
1287 not!(tag!("/")) >>
Alex Crichton1eb96a02018-04-04 13:07:35 -07001288 s: take_until_newline_or_eof!() >>
1289 ((s, false))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001290 )
1291 |
1292 do_parse!(
1293 option!(whitespace) >>
1294 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
Alex Crichton1eb96a02018-04-04 13:07:35 -07001295 s: block_comment >>
1296 ((s, false))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001297 )
1298));