blob: 2fb422a1b35de586c4f380650cd0c96771a4e1d6 [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 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
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
David Tolnay1ebe3972018-01-02 20:14:20 -0800170#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500171#[derive(Clone, PartialEq, Eq, Debug)]
172pub struct FileName(String);
173
David Tolnay1ebe3972018-01-02 20:14:20 -0800174#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500175impl fmt::Display for FileName {
176 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
177 self.0.fmt(f)
178 }
179}
180
David Tolnay1ebe3972018-01-02 20:14:20 -0800181#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500182#[derive(Clone, PartialEq, Eq)]
183pub struct SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500184 name: FileName,
Nika Layzellf8d5f212017-12-11 14:07:02 -0500185}
186
David Tolnay1ebe3972018-01-02 20:14:20 -0800187#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500188impl 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
David Tolnay1ebe3972018-01-02 20:14:20 -0800200#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500201impl AsRef<FileName> for SourceFile {
202 fn as_ref(&self) -> &FileName {
203 self.path()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500204 }
205}
206
David Tolnay1ebe3972018-01-02 20:14:20 -0800207#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500208impl fmt::Debug for SourceFile {
209 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
210 f.debug_struct("SourceFile")
Nika Layzellb35a9a32017-12-30 14:34:35 -0500211 .field("path", &self.path())
Nika Layzellf8d5f212017-12-11 14:07:02 -0500212 .field("is_real", &self.is_real())
213 .finish()
214 }
215}
216
David Tolnay1ebe3972018-01-02 20:14:20 -0800217#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500218#[derive(Clone, Copy, Debug, PartialEq, Eq)]
219pub struct LineColumn {
220 pub line: usize,
221 pub column: usize,
222}
223
David Tolnay1ebe3972018-01-02 20:14:20 -0800224#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500225thread_local! {
226 static CODEMAP: RefCell<Codemap> = RefCell::new(Codemap {
227 // NOTE: We start with a single dummy file which all call_site() and
228 // def_site() spans reference.
229 files: vec![FileInfo {
230 name: "<unspecified>".to_owned(),
231 span: Span { lo: 0, hi: 0 },
232 lines: vec![0],
233 }],
234 });
235}
236
David Tolnay1ebe3972018-01-02 20:14:20 -0800237#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500238struct FileInfo {
239 name: String,
240 span: Span,
241 lines: Vec<usize>,
242}
243
David Tolnay1ebe3972018-01-02 20:14:20 -0800244#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500245impl FileInfo {
246 fn offset_line_column(&self, offset: usize) -> LineColumn {
David Tolnayb28f38a2018-03-31 22:02:29 +0200247 assert!(self.span_within(Span {
248 lo: offset as u32,
249 hi: offset as u32
250 }));
Nika Layzellf8d5f212017-12-11 14:07:02 -0500251 let offset = offset - self.span.lo as usize;
252 match self.lines.binary_search(&offset) {
253 Ok(found) => LineColumn {
254 line: found + 1,
David Tolnayb28f38a2018-03-31 22:02:29 +0200255 column: 0,
Nika Layzellf8d5f212017-12-11 14:07:02 -0500256 },
257 Err(idx) => LineColumn {
258 line: idx,
David Tolnayb28f38a2018-03-31 22:02:29 +0200259 column: offset - self.lines[idx - 1],
Nika Layzellf8d5f212017-12-11 14:07:02 -0500260 },
261 }
262 }
263
264 fn span_within(&self, span: Span) -> bool {
265 span.lo >= self.span.lo && span.hi <= self.span.hi
266 }
267}
268
Alex Crichtona914a612018-04-04 07:48:44 -0700269/// Computesthe offsets of each line in the given source string.
David Tolnay1ebe3972018-01-02 20:14:20 -0800270#[cfg(procmacro2_semver_exempt)]
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500271fn lines_offsets(s: &str) -> Vec<usize> {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500272 let mut lines = vec![0];
273 let mut prev = 0;
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500274 while let Some(len) = s[prev..].find('\n') {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500275 prev += len + 1;
276 lines.push(prev);
277 }
278 lines
279}
280
David Tolnay1ebe3972018-01-02 20:14:20 -0800281#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500282struct Codemap {
283 files: Vec<FileInfo>,
284}
285
David Tolnay1ebe3972018-01-02 20:14:20 -0800286#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500287impl Codemap {
288 fn next_start_pos(&self) -> u32 {
289 // Add 1 so there's always space between files.
290 //
291 // We'll always have at least 1 file, as we initialize our files list
292 // with a dummy file.
293 self.files.last().unwrap().span.hi + 1
294 }
295
296 fn add_file(&mut self, name: &str, src: &str) -> Span {
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500297 let lines = lines_offsets(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -0500298 let lo = self.next_start_pos();
299 // XXX(nika): Shouild we bother doing a checked cast or checked add here?
David Tolnayb28f38a2018-03-31 22:02:29 +0200300 let span = Span {
301 lo: lo,
302 hi: lo + (src.len() as u32),
303 };
Nika Layzellf8d5f212017-12-11 14:07:02 -0500304
305 self.files.push(FileInfo {
306 name: name.to_owned(),
307 span: span,
308 lines: lines,
309 });
310
311 span
312 }
313
314 fn fileinfo(&self, span: Span) -> &FileInfo {
315 for file in &self.files {
316 if file.span_within(span) {
317 return file;
318 }
319 }
320 panic!("Invalid span with no related FileInfo!");
321 }
322}
323
David Tolnay034205f2018-04-22 16:45:28 -0700324#[derive(Clone, Copy, PartialEq, Eq)]
David Tolnayddfca052017-12-31 10:41:24 -0500325pub struct Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800326 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500327 lo: u32,
David Tolnay1ebe3972018-01-02 20:14:20 -0800328 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500329 hi: u32,
330}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700331
332impl Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800333 #[cfg(not(procmacro2_semver_exempt))]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700334 pub fn call_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500335 Span {}
336 }
337
David Tolnay1ebe3972018-01-02 20:14:20 -0800338 #[cfg(procmacro2_semver_exempt)]
David Tolnay79105e52017-12-31 11:03:04 -0500339 pub fn call_site() -> Span {
340 Span { lo: 0, hi: 0 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700341 }
Alex Crichtone6085b72017-11-21 07:24:25 -0800342
343 pub fn def_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500344 Span::call_site()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500345 }
346
David Tolnay4e8e3972018-01-05 18:10:22 -0800347 pub fn resolved_at(&self, _other: Span) -> Span {
348 // Stable spans consist only of line/column information, so
349 // `resolved_at` and `located_at` only select which span the
350 // caller wants line/column information from.
351 *self
352 }
353
354 pub fn located_at(&self, other: Span) -> Span {
355 other
356 }
357
David Tolnay1ebe3972018-01-02 20:14:20 -0800358 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500359 pub fn source_file(&self) -> SourceFile {
360 CODEMAP.with(|cm| {
361 let cm = cm.borrow();
362 let fi = cm.fileinfo(*self);
363 SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500364 name: FileName(fi.name.clone()),
Nika Layzellf8d5f212017-12-11 14:07:02 -0500365 }
366 })
367 }
368
David Tolnay1ebe3972018-01-02 20:14:20 -0800369 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500370 pub fn start(&self) -> LineColumn {
371 CODEMAP.with(|cm| {
372 let cm = cm.borrow();
373 let fi = cm.fileinfo(*self);
374 fi.offset_line_column(self.lo as usize)
375 })
376 }
377
David Tolnay1ebe3972018-01-02 20:14:20 -0800378 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500379 pub fn end(&self) -> LineColumn {
380 CODEMAP.with(|cm| {
381 let cm = cm.borrow();
382 let fi = cm.fileinfo(*self);
383 fi.offset_line_column(self.hi as usize)
384 })
385 }
386
David Tolnay1ebe3972018-01-02 20:14:20 -0800387 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500388 pub fn join(&self, other: Span) -> Option<Span> {
389 CODEMAP.with(|cm| {
390 let cm = cm.borrow();
391 // If `other` is not within the same FileInfo as us, return None.
392 if !cm.fileinfo(*self).span_within(other) {
393 return None;
394 }
395 Some(Span {
396 lo: cmp::min(self.lo, other.lo),
397 hi: cmp::max(self.hi, other.hi),
398 })
399 })
Alex Crichtone6085b72017-11-21 07:24:25 -0800400 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700401}
402
David Tolnay034205f2018-04-22 16:45:28 -0700403impl fmt::Debug for Span {
404 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
405 #[cfg(procmacro2_semver_exempt)]
406 return write!(f, "bytes({}..{})", self.lo, self.hi);
407
408 #[cfg(not(procmacro2_semver_exempt))]
409 write!(f, "Span")
410 }
411}
412
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700413#[derive(Copy, Clone)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700414pub struct Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700415 intern: usize,
Alex Crichtonb2c94622018-04-04 07:36:41 -0700416 span: Span,
David Tolnay041bcd42017-06-03 09:18:04 -0700417}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700418
419thread_local!(static SYMBOLS: RefCell<Interner> = RefCell::new(Interner::new()));
420
David Tolnay10effeb2018-01-06 11:07:49 -0800421impl Term {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700422 pub fn new(string: &str, span: Span) -> Term {
David Tolnay489c6422018-04-07 08:37:28 -0700423 validate_term(string);
424
Alex Crichton1a7f7622017-07-05 17:47:15 -0700425 Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700426 intern: SYMBOLS.with(|s| s.borrow_mut().intern(string)),
Alex Crichtona914a612018-04-04 07:48:44 -0700427 span: span,
David Tolnay041bcd42017-06-03 09:18:04 -0700428 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700429 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700430
David Tolnay10effeb2018-01-06 11:07:49 -0800431 pub fn as_str(&self) -> &str {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700432 SYMBOLS.with(|interner| {
433 let interner = interner.borrow();
David Tolnay041bcd42017-06-03 09:18:04 -0700434 let s = interner.get(self.intern);
David Tolnayb28f38a2018-03-31 22:02:29 +0200435 unsafe { &*(s as *const str) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700436 })
437 }
Alex Crichtonb2c94622018-04-04 07:36:41 -0700438
439 pub fn span(&self) -> Span {
440 self.span
441 }
442
443 pub fn set_span(&mut self, span: Span) {
444 self.span = span;
445 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700446}
447
David Tolnay489c6422018-04-07 08:37:28 -0700448fn validate_term(string: &str) {
449 let validate = if string.starts_with('\'') {
450 &string[1..]
451 } else if string.starts_with("r#") {
452 &string[2..]
453 } else {
454 string
455 };
456
457 if validate.is_empty() {
458 panic!("Term is not allowed to be empty; use Option<Term>");
459 }
460
461 if validate.bytes().all(|digit| digit >= b'0' && digit <= b'9') {
462 panic!("Term cannot be a number; use Literal instead");
463 }
464
465 fn xid_ok(string: &str) -> bool {
466 let mut chars = string.chars();
467 let first = chars.next().unwrap();
468 if !(UnicodeXID::is_xid_start(first) || first == '_') {
469 return false;
470 }
471 for ch in chars {
472 if !UnicodeXID::is_xid_continue(ch) {
473 return false;
474 }
475 }
476 true
477 }
478
479 if !xid_ok(validate) {
480 panic!("{:?} is not a valid Term", string);
481 }
482}
483
Alex Crichton1a7f7622017-07-05 17:47:15 -0700484impl fmt::Debug for Term {
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700485 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
David Tolnay034205f2018-04-22 16:45:28 -0700486 let mut debug = f.debug_struct("Term");
487 debug.field("sym", &format_args!("{}", self.as_str()));
488 #[cfg(procmacro2_semver_exempt)]
489 debug.field("span", &self.span);
490 debug.finish()
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700491 }
492}
493
Alex Crichton44bffbc2017-05-19 17:51:59 -0700494struct Interner {
495 string_to_index: HashMap<MyRc, usize>,
496 index_to_string: Vec<Rc<String>>,
497}
498
499#[derive(Hash, Eq, PartialEq)]
500struct MyRc(Rc<String>);
501
502impl Borrow<str> for MyRc {
503 fn borrow(&self) -> &str {
504 &self.0
505 }
506}
507
508impl Interner {
509 fn new() -> Interner {
510 Interner {
511 string_to_index: HashMap::new(),
512 index_to_string: Vec::new(),
513 }
514 }
515
David Tolnayb28f38a2018-03-31 22:02:29 +0200516 fn intern(&mut self, s: &str) -> usize {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700517 if let Some(&idx) = self.string_to_index.get(s) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200518 return idx;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700519 }
520 let s = Rc::new(s.to_string());
521 self.index_to_string.push(s.clone());
David Tolnayb28f38a2018-03-31 22:02:29 +0200522 self.string_to_index
523 .insert(MyRc(s), self.index_to_string.len() - 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700524 self.index_to_string.len() - 1
525 }
526
David Tolnayb28f38a2018-03-31 22:02:29 +0200527 fn get(&self, idx: usize) -> &str {
528 &self.index_to_string[idx]
529 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700530}
531
David Tolnay034205f2018-04-22 16:45:28 -0700532#[derive(Clone)]
Alex Crichtonb2c94622018-04-04 07:36:41 -0700533pub struct Literal {
534 text: String,
535 span: Span,
536}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700537
Alex Crichtona914a612018-04-04 07:48:44 -0700538macro_rules! suffixed_numbers {
539 ($($name:ident => $kind:ident,)*) => ($(
540 pub fn $name(n: $kind) -> Literal {
541 Literal::_new(format!(concat!("{}", stringify!($kind)), n))
542 }
543 )*)
544}
545
546macro_rules! unsuffixed_numbers {
547 ($($name:ident => $kind:ident,)*) => ($(
548 pub fn $name(n: $kind) -> Literal {
549 Literal::_new(n.to_string())
550 }
551 )*)
552}
553
Alex Crichton852d53d2017-05-19 19:25:08 -0700554impl Literal {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700555 fn _new(text: String) -> Literal {
556 Literal {
Alex Crichtona914a612018-04-04 07:48:44 -0700557 text: text,
Alex Crichtonb2c94622018-04-04 07:36:41 -0700558 span: Span::call_site(),
559 }
560 }
561
Alex Crichtona914a612018-04-04 07:48:44 -0700562 suffixed_numbers! {
563 u8_suffixed => u8,
564 u16_suffixed => u16,
565 u32_suffixed => u32,
566 u64_suffixed => u64,
567 usize_suffixed => usize,
568 i8_suffixed => i8,
569 i16_suffixed => i16,
570 i32_suffixed => i32,
571 i64_suffixed => i64,
572 isize_suffixed => isize,
573
574 f32_suffixed => f32,
575 f64_suffixed => f64,
576 }
577
578 unsuffixed_numbers! {
579 u8_unsuffixed => u8,
580 u16_unsuffixed => u16,
581 u32_unsuffixed => u32,
582 u64_unsuffixed => u64,
583 usize_unsuffixed => usize,
584 i8_unsuffixed => i8,
585 i16_unsuffixed => i16,
586 i32_unsuffixed => i32,
587 i64_unsuffixed => i64,
588 isize_unsuffixed => isize,
589 }
590
591 pub fn f32_unsuffixed(f: f32) -> Literal {
592 let mut s = f.to_string();
593 if !s.contains(".") {
594 s.push_str(".0");
Alex Crichton76a5cc82017-05-23 07:01:44 -0700595 }
Alex Crichtona914a612018-04-04 07:48:44 -0700596 Literal::_new(s)
597 }
598
599 pub fn f64_unsuffixed(f: f64) -> Literal {
600 let mut s = f.to_string();
601 if !s.contains(".") {
602 s.push_str(".0");
603 }
604 Literal::_new(s)
605 }
606
607 pub fn string(t: &str) -> Literal {
608 let mut s = t.chars()
609 .flat_map(|c| c.escape_default())
610 .collect::<String>();
611 s.push('"');
612 s.insert(0, '"');
613 Literal::_new(s)
614 }
615
616 pub fn character(t: char) -> Literal {
617 Literal::_new(format!("'{}'", t.escape_default().collect::<String>()))
Alex Crichton76a5cc82017-05-23 07:01:44 -0700618 }
619
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700620 pub fn byte_string(bytes: &[u8]) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700621 let mut escaped = "b\"".to_string();
622 for b in bytes {
623 match *b {
624 b'\0' => escaped.push_str(r"\0"),
625 b'\t' => escaped.push_str(r"\t"),
626 b'\n' => escaped.push_str(r"\n"),
627 b'\r' => escaped.push_str(r"\r"),
628 b'"' => escaped.push_str("\\\""),
629 b'\\' => escaped.push_str("\\\\"),
David Tolnayb28f38a2018-03-31 22:02:29 +0200630 b'\x20'...b'\x7E' => escaped.push(*b as char),
Alex Crichton852d53d2017-05-19 19:25:08 -0700631 _ => escaped.push_str(&format!("\\x{:02X}", b)),
632 }
633 }
634 escaped.push('"');
Alex Crichtonb2c94622018-04-04 07:36:41 -0700635 Literal::_new(escaped)
Alex Crichton76a5cc82017-05-23 07:01:44 -0700636 }
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700637
Alex Crichtonb2c94622018-04-04 07:36:41 -0700638 pub fn span(&self) -> Span {
639 self.span
Alex Crichton31316622017-05-26 12:54:47 -0700640 }
641
Alex Crichtonb2c94622018-04-04 07:36:41 -0700642 pub fn set_span(&mut self, span: Span) {
643 self.span = span;
Alex Crichton31316622017-05-26 12:54:47 -0700644 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700645}
646
Alex Crichton44bffbc2017-05-19 17:51:59 -0700647impl fmt::Display for Literal {
648 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700649 self.text.fmt(f)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700650 }
651}
652
David Tolnay034205f2018-04-22 16:45:28 -0700653impl fmt::Debug for Literal {
654 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
655 let mut debug = fmt.debug_struct("Literal");
656 debug.field("lit", &format_args!("{}", self.text));
657 #[cfg(procmacro2_semver_exempt)]
658 debug.field("span", &self.span);
659 debug.finish()
660 }
661}
662
Alex Crichton1eb96a02018-04-04 13:07:35 -0700663fn token_stream(mut input: Cursor) -> PResult<::TokenStream> {
664 let mut trees = Vec::new();
665 loop {
666 let input_no_ws = skip_whitespace(input);
667 if input_no_ws.rest.len() == 0 {
David Tolnay48ea5042018-04-23 19:17:35 -0700668 break;
Alex Crichton1eb96a02018-04-04 13:07:35 -0700669 }
670 if let Ok((a, tokens)) = doc_comment(input_no_ws) {
671 input = a;
672 trees.extend(tokens);
David Tolnay48ea5042018-04-23 19:17:35 -0700673 continue;
Alex Crichton1eb96a02018-04-04 13:07:35 -0700674 }
675
676 let (a, tt) = match token_tree(input_no_ws) {
677 Ok(p) => p,
678 Err(_) => break,
679 };
680 trees.push(tt);
681 input = a;
682 }
683 Ok((input, ::TokenStream::_new(TokenStream { inner: trees })))
684}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700685
David Tolnay1ebe3972018-01-02 20:14:20 -0800686#[cfg(not(procmacro2_semver_exempt))]
Alex Crichton1eb96a02018-04-04 13:07:35 -0700687fn spanned<'a, T>(
688 input: Cursor<'a>,
689 f: fn(Cursor<'a>) -> PResult<'a, T>,
690) -> PResult<'a, (T, ::Span)> {
691 let (a, b) = f(skip_whitespace(input))?;
David Tolnay48ea5042018-04-23 19:17:35 -0700692 Ok((a, ((b, ::Span::_new(Span {})))))
David Tolnayddfca052017-12-31 10:41:24 -0500693}
694
David Tolnay1ebe3972018-01-02 20:14:20 -0800695#[cfg(procmacro2_semver_exempt)]
Alex Crichton1eb96a02018-04-04 13:07:35 -0700696fn spanned<'a, T>(
697 input: Cursor<'a>,
698 f: fn(Cursor<'a>) -> PResult<'a, T>,
699) -> PResult<'a, (T, ::Span)> {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500700 let input = skip_whitespace(input);
701 let lo = input.off;
Alex Crichton1eb96a02018-04-04 13:07:35 -0700702 let (a, b) = f(input)?;
703 let hi = a.off;
704 let span = ::Span::_new(Span { lo: lo, hi: hi });
705 Ok((a, (b, span)))
706}
707
708fn token_tree(input: Cursor) -> PResult<TokenTree> {
709 let (rest, (mut tt, span)) = spanned(input, token_kind)?;
710 tt.set_span(span);
711 Ok((rest, tt))
Nika Layzellf8d5f212017-12-11 14:07:02 -0500712}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700713
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700714named!(token_kind -> TokenTree, alt!(
715 map!(group, TokenTree::Group)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700716 |
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700717 map!(literal, TokenTree::Literal) // must be before symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700718 |
Alex Crichton52725f72017-08-28 12:20:58 -0700719 symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700720 |
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700721 map!(op, TokenTree::Op)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700722));
723
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700724named!(group -> Group, alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -0700725 delimited!(
726 punct!("("),
727 token_stream,
728 punct!(")")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700729 ) => { |ts| Group::new(Delimiter::Parenthesis, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700730 |
731 delimited!(
732 punct!("["),
733 token_stream,
734 punct!("]")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700735 ) => { |ts| Group::new(Delimiter::Bracket, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700736 |
737 delimited!(
738 punct!("{"),
739 token_stream,
740 punct!("}")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700741 ) => { |ts| Group::new(Delimiter::Brace, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700742));
743
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700744fn symbol(mut input: Cursor) -> PResult<TokenTree> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700745 input = skip_whitespace(input);
746
747 let mut chars = input.char_indices();
David Tolnaya202d502017-06-01 12:26:55 -0700748
749 let lifetime = input.starts_with("'");
750 if lifetime {
751 chars.next();
752 }
753
David Tolnaya13d1422018-03-31 21:27:48 +0200754 let raw = !lifetime && input.starts_with("r#");
755 if raw {
756 chars.next();
757 chars.next();
758 }
759
Alex Crichton44bffbc2017-05-19 17:51:59 -0700760 match chars.next() {
761 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700762 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700763 }
764
David Tolnay214c94c2017-06-01 12:42:56 -0700765 let mut end = input.len();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700766 for (i, ch) in chars {
767 if !UnicodeXID::is_xid_continue(ch) {
David Tolnay214c94c2017-06-01 12:42:56 -0700768 end = i;
769 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700770 }
771 }
772
David Tolnaya13d1422018-03-31 21:27:48 +0200773 let a = &input.rest[..end];
774 if a == "r#_" || lifetime && a != "'static" && KEYWORDS.contains(&&a[1..]) {
David Tolnay214c94c2017-06-01 12:42:56 -0700775 Err(LexError)
David Tolnaya13d1422018-03-31 21:27:48 +0200776 } else if a == "_" {
777 Ok((input.advance(end), Op::new('_', Spacing::Alone).into()))
David Tolnay214c94c2017-06-01 12:42:56 -0700778 } else {
David Tolnayb28f38a2018-03-31 22:02:29 +0200779 Ok((
780 input.advance(end),
781 ::Term::new(a, ::Span::call_site()).into(),
782 ))
David Tolnay214c94c2017-06-01 12:42:56 -0700783 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700784}
785
David Tolnay214c94c2017-06-01 12:42:56 -0700786// From https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/symbol.rs
787static KEYWORDS: &'static [&'static str] = &[
David Tolnayb28f38a2018-03-31 22:02:29 +0200788 "abstract", "alignof", "as", "become", "box", "break", "const", "continue", "crate", "do",
789 "else", "enum", "extern", "false", "final", "fn", "for", "if", "impl", "in", "let", "loop",
790 "macro", "match", "mod", "move", "mut", "offsetof", "override", "priv", "proc", "pub", "pure",
791 "ref", "return", "self", "Self", "sizeof", "static", "struct", "super", "trait", "true",
792 "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while", "yield",
David Tolnay214c94c2017-06-01 12:42:56 -0700793];
794
Nika Layzellf8d5f212017-12-11 14:07:02 -0500795fn literal(input: Cursor) -> PResult<::Literal> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700796 let input_no_ws = skip_whitespace(input);
797
798 match literal_nocapture(input_no_ws) {
David Tolnay1218e122017-06-01 11:13:45 -0700799 Ok((a, ())) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700800 let start = input.len() - input_no_ws.len();
801 let len = input_no_ws.len() - a.len();
802 let end = start + len;
David Tolnayb28f38a2018-03-31 22:02:29 +0200803 Ok((
804 a,
Alex Crichtonb2c94622018-04-04 07:36:41 -0700805 ::Literal::_new(Literal::_new(input.rest[start..end].to_string())),
David Tolnayb28f38a2018-03-31 22:02:29 +0200806 ))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700807 }
David Tolnay1218e122017-06-01 11:13:45 -0700808 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700809 }
810}
811
812named!(literal_nocapture -> (), alt!(
813 string
814 |
815 byte_string
816 |
817 byte
818 |
819 character
820 |
821 float
822 |
823 int
Alex Crichton44bffbc2017-05-19 17:51:59 -0700824));
825
826named!(string -> (), alt!(
827 quoted_string
828 |
829 preceded!(
830 punct!("r"),
831 raw_string
832 ) => { |_| () }
833));
834
835named!(quoted_string -> (), delimited!(
836 punct!("\""),
837 cooked_string,
838 tag!("\"")
839));
840
Nika Layzellf8d5f212017-12-11 14:07:02 -0500841fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700842 let mut chars = input.char_indices().peekable();
843 while let Some((byte_offset, ch)) = chars.next() {
844 match ch {
845 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500846 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700847 }
848 '\r' => {
849 if let Some((_, '\n')) = chars.next() {
850 // ...
851 } else {
852 break;
853 }
854 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200855 '\\' => match chars.next() {
856 Some((_, 'x')) => {
857 if !backslash_x_char(&mut chars) {
858 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700859 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700860 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200861 Some((_, 'n')) | Some((_, 'r')) | Some((_, 't')) | Some((_, '\\'))
862 | Some((_, '\'')) | Some((_, '"')) | Some((_, '0')) => {}
863 Some((_, 'u')) => {
864 if !backslash_u(&mut chars) {
865 break;
866 }
867 }
868 Some((_, '\n')) | Some((_, '\r')) => {
869 while let Some(&(_, ch)) = chars.peek() {
870 if ch.is_whitespace() {
871 chars.next();
872 } else {
873 break;
874 }
875 }
876 }
877 _ => break,
878 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700879 _ch => {}
880 }
881 }
David Tolnay1218e122017-06-01 11:13:45 -0700882 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700883}
884
885named!(byte_string -> (), alt!(
886 delimited!(
887 punct!("b\""),
888 cooked_byte_string,
889 tag!("\"")
890 ) => { |_| () }
891 |
892 preceded!(
893 punct!("br"),
894 raw_string
895 ) => { |_| () }
896));
897
Nika Layzellf8d5f212017-12-11 14:07:02 -0500898fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700899 let mut bytes = input.bytes().enumerate();
900 'outer: while let Some((offset, b)) = bytes.next() {
901 match b {
902 b'"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500903 return Ok((input.advance(offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700904 }
905 b'\r' => {
906 if let Some((_, b'\n')) = bytes.next() {
907 // ...
908 } else {
909 break;
910 }
911 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200912 b'\\' => match bytes.next() {
913 Some((_, b'x')) => {
914 if !backslash_x_byte(&mut bytes) {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700915 break;
916 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700917 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200918 Some((_, b'n')) | Some((_, b'r')) | Some((_, b't')) | Some((_, b'\\'))
919 | Some((_, b'0')) | Some((_, b'\'')) | Some((_, b'"')) => {}
920 Some((newline, b'\n')) | Some((newline, b'\r')) => {
921 let rest = input.advance(newline + 1);
922 for (offset, ch) in rest.char_indices() {
923 if !ch.is_whitespace() {
924 input = rest.advance(offset);
925 bytes = input.bytes().enumerate();
926 continue 'outer;
927 }
928 }
929 break;
930 }
931 _ => break,
932 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700933 b if b < 0x80 => {}
934 _ => break,
935 }
936 }
David Tolnay1218e122017-06-01 11:13:45 -0700937 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700938}
939
Nika Layzellf8d5f212017-12-11 14:07:02 -0500940fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700941 let mut chars = input.char_indices();
942 let mut n = 0;
943 while let Some((byte_offset, ch)) = chars.next() {
944 match ch {
945 '"' => {
946 n = byte_offset;
947 break;
948 }
949 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700950 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700951 }
952 }
953 for (byte_offset, ch) in chars {
954 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500955 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
956 let rest = input.advance(byte_offset + 1 + n);
David Tolnayb28f38a2018-03-31 22:02:29 +0200957 return Ok((rest, ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700958 }
959 '\r' => {}
960 _ => {}
961 }
962 }
David Tolnay1218e122017-06-01 11:13:45 -0700963 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700964}
965
966named!(byte -> (), do_parse!(
967 punct!("b") >>
968 tag!("'") >>
969 cooked_byte >>
970 tag!("'") >>
971 (())
972));
973
Nika Layzellf8d5f212017-12-11 14:07:02 -0500974fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700975 let mut bytes = input.bytes().enumerate();
976 let ok = match bytes.next().map(|(_, b)| b) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200977 Some(b'\\') => match bytes.next().map(|(_, b)| b) {
978 Some(b'x') => backslash_x_byte(&mut bytes),
979 Some(b'n') | Some(b'r') | Some(b't') | Some(b'\\') | Some(b'0') | Some(b'\'')
980 | Some(b'"') => true,
981 _ => false,
982 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700983 b => b.is_some(),
984 };
985 if ok {
986 match bytes.next() {
Alex Crichton8c030332018-01-16 08:07:36 -0800987 Some((offset, _)) => {
988 if input.chars().as_str().is_char_boundary(offset) {
989 Ok((input.advance(offset), ()))
990 } else {
991 Err(LexError)
992 }
993 }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500994 None => Ok((input.advance(input.len()), ())),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700995 }
996 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700997 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700998 }
999}
1000
1001named!(character -> (), do_parse!(
1002 punct!("'") >>
1003 cooked_char >>
1004 tag!("'") >>
1005 (())
1006));
1007
Nika Layzellf8d5f212017-12-11 14:07:02 -05001008fn cooked_char(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001009 let mut chars = input.char_indices();
1010 let ok = match chars.next().map(|(_, ch)| ch) {
David Tolnayb28f38a2018-03-31 22:02:29 +02001011 Some('\\') => match chars.next().map(|(_, ch)| ch) {
1012 Some('x') => backslash_x_char(&mut chars),
1013 Some('u') => backslash_u(&mut chars),
1014 Some('n') | Some('r') | Some('t') | Some('\\') | Some('0') | Some('\'') | Some('"') => {
1015 true
Alex Crichton44bffbc2017-05-19 17:51:59 -07001016 }
David Tolnayb28f38a2018-03-31 22:02:29 +02001017 _ => false,
1018 },
Alex Crichton44bffbc2017-05-19 17:51:59 -07001019 ch => ch.is_some(),
1020 };
1021 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001022 match chars.next() {
1023 Some((idx, _)) => Ok((input.advance(idx), ())),
1024 None => Ok((input.advance(input.len()), ())),
1025 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001026 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001027 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001028 }
1029}
1030
1031macro_rules! next_ch {
1032 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
1033 match $chars.next() {
1034 Some((_, ch)) => match ch {
1035 $pat $(| $rest)* => ch,
1036 _ => return false,
1037 },
1038 None => return false
1039 }
1040 };
1041}
1042
1043fn backslash_x_char<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +02001044where
1045 I: Iterator<Item = (usize, char)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -07001046{
1047 next_ch!(chars @ '0'...'7');
1048 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
1049 true
1050}
1051
1052fn backslash_x_byte<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +02001053where
1054 I: Iterator<Item = (usize, u8)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -07001055{
1056 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
1057 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
1058 true
1059}
1060
1061fn backslash_u<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +02001062where
1063 I: Iterator<Item = (usize, char)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -07001064{
1065 next_ch!(chars @ '{');
1066 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
David Tolnay8d109342017-12-25 18:24:45 -05001067 loop {
1068 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '_' | '}');
1069 if c == '}' {
1070 return true;
1071 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001072 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001073}
1074
Nika Layzellf8d5f212017-12-11 14:07:02 -05001075fn float(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001076 let (rest, ()) = float_digits(input)?;
1077 for suffix in &["f32", "f64"] {
1078 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001079 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001080 }
1081 }
1082 word_break(rest)
1083}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001084
Nika Layzellf8d5f212017-12-11 14:07:02 -05001085fn float_digits(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001086 let mut chars = input.chars().peekable();
1087 match chars.next() {
1088 Some(ch) if ch >= '0' && ch <= '9' => {}
David Tolnay1218e122017-06-01 11:13:45 -07001089 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001090 }
1091
1092 let mut len = 1;
1093 let mut has_dot = false;
1094 let mut has_exp = false;
1095 while let Some(&ch) = chars.peek() {
1096 match ch {
1097 '0'...'9' | '_' => {
1098 chars.next();
1099 len += 1;
1100 }
1101 '.' => {
1102 if has_dot {
1103 break;
1104 }
1105 chars.next();
David Tolnayb28f38a2018-03-31 22:02:29 +02001106 if chars
1107 .peek()
1108 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1109 .unwrap_or(false)
1110 {
David Tolnay1218e122017-06-01 11:13:45 -07001111 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001112 }
1113 len += 1;
1114 has_dot = true;
1115 }
1116 'e' | 'E' => {
1117 chars.next();
1118 len += 1;
1119 has_exp = true;
1120 break;
1121 }
1122 _ => break,
1123 }
1124 }
1125
Nika Layzellf8d5f212017-12-11 14:07:02 -05001126 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001127 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001128 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001129 }
1130
1131 if has_exp {
1132 let mut has_exp_value = false;
1133 while let Some(&ch) = chars.peek() {
1134 match ch {
1135 '+' | '-' => {
1136 if has_exp_value {
1137 break;
1138 }
1139 chars.next();
1140 len += 1;
1141 }
1142 '0'...'9' => {
1143 chars.next();
1144 len += 1;
1145 has_exp_value = true;
1146 }
1147 '_' => {
1148 chars.next();
1149 len += 1;
1150 }
1151 _ => break,
1152 }
1153 }
1154 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001155 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001156 }
1157 }
1158
Nika Layzellf8d5f212017-12-11 14:07:02 -05001159 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001160}
1161
Nika Layzellf8d5f212017-12-11 14:07:02 -05001162fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001163 let (rest, ()) = digits(input)?;
1164 for suffix in &[
David Tolnay48ea5042018-04-23 19:17:35 -07001165 "isize", "i8", "i16", "i32", "i64", "i128", "usize", "u8", "u16", "u32", "u64", "u128",
David Tolnay744a6b82017-06-01 11:34:29 -07001166 ] {
1167 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001168 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001169 }
1170 }
1171 word_break(rest)
1172}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001173
Nika Layzellf8d5f212017-12-11 14:07:02 -05001174fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001175 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001176 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001177 16
1178 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001179 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001180 8
1181 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001182 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001183 2
1184 } else {
1185 10
1186 };
1187
Alex Crichton44bffbc2017-05-19 17:51:59 -07001188 let mut len = 0;
1189 let mut empty = true;
1190 for b in input.bytes() {
1191 let digit = match b {
1192 b'0'...b'9' => (b - b'0') as u64,
1193 b'a'...b'f' => 10 + (b - b'a') as u64,
1194 b'A'...b'F' => 10 + (b - b'A') as u64,
1195 b'_' => {
1196 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001197 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001198 }
1199 len += 1;
1200 continue;
1201 }
1202 _ => break,
1203 };
1204 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001205 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001206 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001207 len += 1;
1208 empty = false;
1209 }
1210 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001211 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001212 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001213 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001214 }
1215}
1216
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001217fn op(input: Cursor) -> PResult<Op> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001218 let input = skip_whitespace(input);
1219 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001220 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001221 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001222 Ok(_) => Spacing::Joint,
1223 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001224 };
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001225 Ok((rest, Op::new(ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001226 }
David Tolnay1218e122017-06-01 11:13:45 -07001227 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001228 }
1229}
1230
Nika Layzellf8d5f212017-12-11 14:07:02 -05001231fn op_char(input: Cursor) -> PResult<char> {
David Tolnay3a592ad2018-04-22 21:20:24 -07001232 if input.starts_with("//") || input.starts_with("/*") {
1233 // Do not accept `/` of a comment as an op.
1234 return Err(LexError);
1235 }
1236
David Tolnayea75c5f2017-05-31 23:40:33 -07001237 let mut chars = input.chars();
1238 let first = match chars.next() {
1239 Some(ch) => ch,
1240 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001241 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001242 }
1243 };
1244 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1245 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001246 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001247 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001248 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001249 }
1250}
1251
Alex Crichton1eb96a02018-04-04 13:07:35 -07001252fn doc_comment(input: Cursor) -> PResult<Vec<TokenTree>> {
1253 let mut trees = Vec::new();
1254 let (rest, ((comment, inner), span)) = spanned(input, doc_comment_contents)?;
1255 trees.push(TokenTree::Op(Op::new('#', Spacing::Alone)));
1256 if inner {
1257 trees.push(Op::new('!', Spacing::Alone).into());
1258 }
1259 let mut stream = vec![
1260 TokenTree::Term(::Term::new("doc", span)),
1261 TokenTree::Op(Op::new('=', Spacing::Alone)),
1262 TokenTree::Literal(::Literal::string(comment)),
1263 ];
1264 for tt in stream.iter_mut() {
1265 tt.set_span(span);
1266 }
1267 trees.push(Group::new(Delimiter::Bracket, stream.into_iter().collect()).into());
1268 for tt in trees.iter_mut() {
1269 tt.set_span(span);
1270 }
1271 Ok((rest, trees))
1272}
1273
1274named!(doc_comment_contents -> (&str, bool), alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -07001275 do_parse!(
1276 punct!("//!") >>
Alex Crichton1eb96a02018-04-04 13:07:35 -07001277 s: take_until_newline_or_eof!() >>
1278 ((s, true))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001279 )
1280 |
1281 do_parse!(
1282 option!(whitespace) >>
1283 peek!(tag!("/*!")) >>
Alex Crichton1eb96a02018-04-04 13:07:35 -07001284 s: block_comment >>
1285 ((s, true))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001286 )
1287 |
1288 do_parse!(
1289 punct!("///") >>
1290 not!(tag!("/")) >>
Alex Crichton1eb96a02018-04-04 13:07:35 -07001291 s: take_until_newline_or_eof!() >>
1292 ((s, false))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001293 )
1294 |
1295 do_parse!(
1296 option!(whitespace) >>
1297 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
Alex Crichton1eb96a02018-04-04 13:07:35 -07001298 s: block_comment >>
1299 ((s, false))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001300 )
1301));