blob: 3e2f28cd502227dcde27eca2f128cc43d4f4a2c6 [file] [log] [blame]
Alex Crichtona914a612018-04-04 07:48:44 -07001#![cfg_attr(not(procmacro2_semver_exempt), allow(dead_code))]
Alex Crichtonaf5bad42018-03-27 14:45:10 -07002
Alex Crichton44bffbc2017-05-19 17:51:59 -07003use std::borrow::Borrow;
4use std::cell::RefCell;
David Tolnay1ebe3972018-01-02 20:14:20 -08005#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -05006use std::cmp;
Alex Crichton44bffbc2017-05-19 17:51:59 -07007use std::collections::HashMap;
8use std::fmt;
9use std::iter;
Alex Crichton44bffbc2017-05-19 17:51:59 -070010use std::rc::Rc;
11use std::str::FromStr;
12use std::vec;
13
David Tolnayb28f38a2018-03-31 22:02:29 +020014use strnom::{block_comment, skip_whitespace, whitespace, word_break, Cursor, PResult};
David Tolnayb1032662017-05-31 15:52:28 -070015use unicode_xid::UnicodeXID;
Alex Crichton44bffbc2017-05-19 17:51:59 -070016
David Tolnayb28f38a2018-03-31 22:02:29 +020017use {Delimiter, Group, Op, Spacing, TokenTree};
Alex Crichton44bffbc2017-05-19 17:51:59 -070018
David Tolnay977f8282017-05-31 17:41:33 -070019#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -070020pub struct TokenStream {
21 inner: Vec<TokenTree>,
22}
23
24#[derive(Debug)]
25pub struct LexError;
26
27impl TokenStream {
28 pub fn empty() -> TokenStream {
29 TokenStream { inner: Vec::new() }
30 }
31
32 pub fn is_empty(&self) -> bool {
33 self.inner.len() == 0
34 }
35}
36
David Tolnay1ebe3972018-01-02 20:14:20 -080037#[cfg(procmacro2_semver_exempt)]
Nika Layzella9dbc182017-12-30 14:50:13 -050038fn get_cursor(src: &str) -> Cursor {
39 // Create a dummy file & add it to the codemap
40 CODEMAP.with(|cm| {
41 let mut cm = cm.borrow_mut();
42 let name = format!("<parsed string {}>", cm.files.len());
43 let span = cm.add_file(&name, src);
44 Cursor {
45 rest: src,
46 off: span.lo,
47 }
48 })
49}
50
David Tolnay1ebe3972018-01-02 20:14:20 -080051#[cfg(not(procmacro2_semver_exempt))]
Nika Layzella9dbc182017-12-30 14:50:13 -050052fn get_cursor(src: &str) -> Cursor {
David Tolnayb28f38a2018-03-31 22:02:29 +020053 Cursor { rest: src }
Nika Layzella9dbc182017-12-30 14:50:13 -050054}
55
Alex Crichton44bffbc2017-05-19 17:51:59 -070056impl FromStr for TokenStream {
57 type Err = LexError;
58
59 fn from_str(src: &str) -> Result<TokenStream, LexError> {
Nika Layzellf8d5f212017-12-11 14:07:02 -050060 // Create a dummy file & add it to the codemap
Nika Layzella9dbc182017-12-30 14:50:13 -050061 let cursor = get_cursor(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -050062
63 match token_stream(cursor) {
David Tolnay1218e122017-06-01 11:13:45 -070064 Ok((input, output)) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -070065 if skip_whitespace(input).len() != 0 {
66 Err(LexError)
67 } else {
Alex Crichtonaf5bad42018-03-27 14:45:10 -070068 Ok(output.inner)
Alex Crichton44bffbc2017-05-19 17:51:59 -070069 }
70 }
David Tolnay1218e122017-06-01 11:13:45 -070071 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -070072 }
73 }
74}
75
76impl fmt::Display for TokenStream {
77 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78 let mut joint = false;
79 for (i, tt) in self.inner.iter().enumerate() {
80 if i != 0 && !joint {
81 write!(f, " ")?;
82 }
83 joint = false;
Alex Crichtonaf5bad42018-03-27 14:45:10 -070084 match *tt {
85 TokenTree::Group(ref tt) => {
86 let (start, end) = match tt.delimiter() {
Alex Crichton44bffbc2017-05-19 17:51:59 -070087 Delimiter::Parenthesis => ("(", ")"),
88 Delimiter::Brace => ("{", "}"),
89 Delimiter::Bracket => ("[", "]"),
90 Delimiter::None => ("", ""),
91 };
Alex Crichtonaf5bad42018-03-27 14:45:10 -070092 if tt.stream().inner.inner.len() == 0 {
Alex Crichton852d53d2017-05-19 19:25:08 -070093 write!(f, "{} {}", start, end)?
94 } else {
Alex Crichtonaf5bad42018-03-27 14:45:10 -070095 write!(f, "{} {} {}", start, tt.stream(), end)?
Alex Crichton852d53d2017-05-19 19:25:08 -070096 }
Alex Crichton44bffbc2017-05-19 17:51:59 -070097 }
Alex Crichtonaf5bad42018-03-27 14:45:10 -070098 TokenTree::Term(ref tt) => write!(f, "{}", tt.as_str())?,
99 TokenTree::Op(ref tt) => {
100 write!(f, "{}", tt.op())?;
101 match tt.spacing() {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700102 Spacing::Alone => {}
103 Spacing::Joint => joint = true,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700104 }
105 }
Alex Crichtonb2c94622018-04-04 07:36:41 -0700106 TokenTree::Literal(ref tt) => write!(f, "{}", tt)?,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700107 }
108 }
109
110 Ok(())
111 }
112}
113
Alex Crichton0e8e7f42018-02-22 06:15:13 -0800114#[cfg(feature = "proc-macro")]
115impl From<::proc_macro::TokenStream> for TokenStream {
116 fn from(inner: ::proc_macro::TokenStream) -> TokenStream {
David Tolnayb28f38a2018-03-31 22:02:29 +0200117 inner
118 .to_string()
119 .parse()
120 .expect("compiler token stream parse failed")
Alex Crichton44bffbc2017-05-19 17:51:59 -0700121 }
122}
123
Alex Crichton0e8e7f42018-02-22 06:15:13 -0800124#[cfg(feature = "proc-macro")]
125impl From<TokenStream> for ::proc_macro::TokenStream {
126 fn from(inner: TokenStream) -> ::proc_macro::TokenStream {
David Tolnayb28f38a2018-03-31 22:02:29 +0200127 inner
128 .to_string()
129 .parse()
130 .expect("failed to parse to compiler tokens")
Alex Crichton44bffbc2017-05-19 17:51:59 -0700131 }
132}
133
Alex Crichton44bffbc2017-05-19 17:51:59 -0700134impl From<TokenTree> for TokenStream {
135 fn from(tree: TokenTree) -> TokenStream {
136 TokenStream { inner: vec![tree] }
137 }
138}
139
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700140impl iter::FromIterator<TokenTree> for TokenStream {
David Tolnayb28f38a2018-03-31 22:02:29 +0200141 fn from_iter<I: IntoIterator<Item = TokenTree>>(streams: I) -> Self {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700142 let mut v = Vec::new();
143
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700144 for token in streams.into_iter() {
145 v.push(token);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700146 }
147
148 TokenStream { inner: v }
149 }
150}
151
Alex Crichton1a7f7622017-07-05 17:47:15 -0700152pub type TokenTreeIter = vec::IntoIter<TokenTree>;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700153
154impl IntoIterator for TokenStream {
155 type Item = TokenTree;
Alex Crichton1a7f7622017-07-05 17:47:15 -0700156 type IntoIter = TokenTreeIter;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700157
Alex Crichton1a7f7622017-07-05 17:47:15 -0700158 fn into_iter(self) -> TokenTreeIter {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700159 self.inner.into_iter()
160 }
161}
162
David Tolnay1ebe3972018-01-02 20:14:20 -0800163#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500164#[derive(Clone, PartialEq, Eq, Debug)]
165pub struct FileName(String);
166
David Tolnay1ebe3972018-01-02 20:14:20 -0800167#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500168impl fmt::Display for FileName {
169 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
170 self.0.fmt(f)
171 }
172}
173
David Tolnay1ebe3972018-01-02 20:14:20 -0800174#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500175#[derive(Clone, PartialEq, Eq)]
176pub struct SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500177 name: FileName,
Nika Layzellf8d5f212017-12-11 14:07:02 -0500178}
179
David Tolnay1ebe3972018-01-02 20:14:20 -0800180#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500181impl SourceFile {
182 /// Get the path to this source file as a string.
Nika Layzellb35a9a32017-12-30 14:34:35 -0500183 pub fn path(&self) -> &FileName {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500184 &self.name
185 }
186
187 pub fn is_real(&self) -> bool {
188 // XXX(nika): Support real files in the future?
189 false
190 }
191}
192
David Tolnay1ebe3972018-01-02 20:14:20 -0800193#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500194impl AsRef<FileName> for SourceFile {
195 fn as_ref(&self) -> &FileName {
196 self.path()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500197 }
198}
199
David Tolnay1ebe3972018-01-02 20:14:20 -0800200#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500201impl fmt::Debug for SourceFile {
202 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
203 f.debug_struct("SourceFile")
Nika Layzellb35a9a32017-12-30 14:34:35 -0500204 .field("path", &self.path())
Nika Layzellf8d5f212017-12-11 14:07:02 -0500205 .field("is_real", &self.is_real())
206 .finish()
207 }
208}
209
David Tolnay1ebe3972018-01-02 20:14:20 -0800210#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500211#[derive(Clone, Copy, Debug, PartialEq, Eq)]
212pub struct LineColumn {
213 pub line: usize,
214 pub column: usize,
215}
216
David Tolnay1ebe3972018-01-02 20:14:20 -0800217#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500218thread_local! {
219 static CODEMAP: RefCell<Codemap> = RefCell::new(Codemap {
220 // NOTE: We start with a single dummy file which all call_site() and
221 // def_site() spans reference.
222 files: vec![FileInfo {
223 name: "<unspecified>".to_owned(),
224 span: Span { lo: 0, hi: 0 },
225 lines: vec![0],
226 }],
227 });
228}
229
David Tolnay1ebe3972018-01-02 20:14:20 -0800230#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500231struct FileInfo {
232 name: String,
233 span: Span,
234 lines: Vec<usize>,
235}
236
David Tolnay1ebe3972018-01-02 20:14:20 -0800237#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500238impl FileInfo {
239 fn offset_line_column(&self, offset: usize) -> LineColumn {
David Tolnayb28f38a2018-03-31 22:02:29 +0200240 assert!(self.span_within(Span {
241 lo: offset as u32,
242 hi: offset as u32
243 }));
Nika Layzellf8d5f212017-12-11 14:07:02 -0500244 let offset = offset - self.span.lo as usize;
245 match self.lines.binary_search(&offset) {
246 Ok(found) => LineColumn {
247 line: found + 1,
David Tolnayb28f38a2018-03-31 22:02:29 +0200248 column: 0,
Nika Layzellf8d5f212017-12-11 14:07:02 -0500249 },
250 Err(idx) => LineColumn {
251 line: idx,
David Tolnayb28f38a2018-03-31 22:02:29 +0200252 column: offset - self.lines[idx - 1],
Nika Layzellf8d5f212017-12-11 14:07:02 -0500253 },
254 }
255 }
256
257 fn span_within(&self, span: Span) -> bool {
258 span.lo >= self.span.lo && span.hi <= self.span.hi
259 }
260}
261
Alex Crichtona914a612018-04-04 07:48:44 -0700262/// Computesthe offsets of each line in the given source string.
David Tolnay1ebe3972018-01-02 20:14:20 -0800263#[cfg(procmacro2_semver_exempt)]
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500264fn lines_offsets(s: &str) -> Vec<usize> {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500265 let mut lines = vec![0];
266 let mut prev = 0;
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500267 while let Some(len) = s[prev..].find('\n') {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500268 prev += len + 1;
269 lines.push(prev);
270 }
271 lines
272}
273
David Tolnay1ebe3972018-01-02 20:14:20 -0800274#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500275struct Codemap {
276 files: Vec<FileInfo>,
277}
278
David Tolnay1ebe3972018-01-02 20:14:20 -0800279#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500280impl Codemap {
281 fn next_start_pos(&self) -> u32 {
282 // Add 1 so there's always space between files.
283 //
284 // We'll always have at least 1 file, as we initialize our files list
285 // with a dummy file.
286 self.files.last().unwrap().span.hi + 1
287 }
288
289 fn add_file(&mut self, name: &str, src: &str) -> Span {
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500290 let lines = lines_offsets(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -0500291 let lo = self.next_start_pos();
292 // XXX(nika): Shouild we bother doing a checked cast or checked add here?
David Tolnayb28f38a2018-03-31 22:02:29 +0200293 let span = Span {
294 lo: lo,
295 hi: lo + (src.len() as u32),
296 };
Nika Layzellf8d5f212017-12-11 14:07:02 -0500297
298 self.files.push(FileInfo {
299 name: name.to_owned(),
300 span: span,
301 lines: lines,
302 });
303
304 span
305 }
306
307 fn fileinfo(&self, span: Span) -> &FileInfo {
308 for file in &self.files {
309 if file.span_within(span) {
310 return file;
311 }
312 }
313 panic!("Invalid span with no related FileInfo!");
314 }
315}
316
Nika Layzell99737982018-03-11 18:51:27 -0400317#[derive(Clone, Copy, Debug, PartialEq, Eq)]
David Tolnayddfca052017-12-31 10:41:24 -0500318pub struct Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800319 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500320 lo: u32,
David Tolnay1ebe3972018-01-02 20:14:20 -0800321 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500322 hi: u32,
323}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700324
325impl Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800326 #[cfg(not(procmacro2_semver_exempt))]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700327 pub fn call_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500328 Span {}
329 }
330
David Tolnay1ebe3972018-01-02 20:14:20 -0800331 #[cfg(procmacro2_semver_exempt)]
David Tolnay79105e52017-12-31 11:03:04 -0500332 pub fn call_site() -> Span {
333 Span { lo: 0, hi: 0 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700334 }
Alex Crichtone6085b72017-11-21 07:24:25 -0800335
336 pub fn def_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500337 Span::call_site()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500338 }
339
David Tolnay4e8e3972018-01-05 18:10:22 -0800340 pub fn resolved_at(&self, _other: Span) -> Span {
341 // Stable spans consist only of line/column information, so
342 // `resolved_at` and `located_at` only select which span the
343 // caller wants line/column information from.
344 *self
345 }
346
347 pub fn located_at(&self, other: Span) -> Span {
348 other
349 }
350
David Tolnay1ebe3972018-01-02 20:14:20 -0800351 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500352 pub fn source_file(&self) -> SourceFile {
353 CODEMAP.with(|cm| {
354 let cm = cm.borrow();
355 let fi = cm.fileinfo(*self);
356 SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500357 name: FileName(fi.name.clone()),
Nika Layzellf8d5f212017-12-11 14:07:02 -0500358 }
359 })
360 }
361
David Tolnay1ebe3972018-01-02 20:14:20 -0800362 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500363 pub fn start(&self) -> LineColumn {
364 CODEMAP.with(|cm| {
365 let cm = cm.borrow();
366 let fi = cm.fileinfo(*self);
367 fi.offset_line_column(self.lo as usize)
368 })
369 }
370
David Tolnay1ebe3972018-01-02 20:14:20 -0800371 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500372 pub fn end(&self) -> LineColumn {
373 CODEMAP.with(|cm| {
374 let cm = cm.borrow();
375 let fi = cm.fileinfo(*self);
376 fi.offset_line_column(self.hi as usize)
377 })
378 }
379
David Tolnay1ebe3972018-01-02 20:14:20 -0800380 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500381 pub fn join(&self, other: Span) -> Option<Span> {
382 CODEMAP.with(|cm| {
383 let cm = cm.borrow();
384 // If `other` is not within the same FileInfo as us, return None.
385 if !cm.fileinfo(*self).span_within(other) {
386 return None;
387 }
388 Some(Span {
389 lo: cmp::min(self.lo, other.lo),
390 hi: cmp::max(self.hi, other.hi),
391 })
392 })
Alex Crichtone6085b72017-11-21 07:24:25 -0800393 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700394}
395
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700396#[derive(Copy, Clone)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700397pub struct Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700398 intern: usize,
Alex Crichtonb2c94622018-04-04 07:36:41 -0700399 span: Span,
David Tolnay041bcd42017-06-03 09:18:04 -0700400}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700401
402thread_local!(static SYMBOLS: RefCell<Interner> = RefCell::new(Interner::new()));
403
David Tolnay10effeb2018-01-06 11:07:49 -0800404impl Term {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700405 pub fn new(string: &str, span: Span) -> Term {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700406 Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700407 intern: SYMBOLS.with(|s| s.borrow_mut().intern(string)),
Alex Crichtona914a612018-04-04 07:48:44 -0700408 span: span,
David Tolnay041bcd42017-06-03 09:18:04 -0700409 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700410 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700411
David Tolnay10effeb2018-01-06 11:07:49 -0800412 pub fn as_str(&self) -> &str {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700413 SYMBOLS.with(|interner| {
414 let interner = interner.borrow();
David Tolnay041bcd42017-06-03 09:18:04 -0700415 let s = interner.get(self.intern);
David Tolnayb28f38a2018-03-31 22:02:29 +0200416 unsafe { &*(s as *const str) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700417 })
418 }
Alex Crichtonb2c94622018-04-04 07:36:41 -0700419
420 pub fn span(&self) -> Span {
421 self.span
422 }
423
424 pub fn set_span(&mut self, span: Span) {
425 self.span = span;
426 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700427}
428
Alex Crichton1a7f7622017-07-05 17:47:15 -0700429impl fmt::Debug for Term {
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700430 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
David Tolnay10effeb2018-01-06 11:07:49 -0800431 f.debug_tuple("Term").field(&self.as_str()).finish()
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700432 }
433}
434
Alex Crichton44bffbc2017-05-19 17:51:59 -0700435struct Interner {
436 string_to_index: HashMap<MyRc, usize>,
437 index_to_string: Vec<Rc<String>>,
438}
439
440#[derive(Hash, Eq, PartialEq)]
441struct MyRc(Rc<String>);
442
443impl Borrow<str> for MyRc {
444 fn borrow(&self) -> &str {
445 &self.0
446 }
447}
448
449impl Interner {
450 fn new() -> Interner {
451 Interner {
452 string_to_index: HashMap::new(),
453 index_to_string: Vec::new(),
454 }
455 }
456
David Tolnayb28f38a2018-03-31 22:02:29 +0200457 fn intern(&mut self, s: &str) -> usize {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700458 if let Some(&idx) = self.string_to_index.get(s) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200459 return idx;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700460 }
461 let s = Rc::new(s.to_string());
462 self.index_to_string.push(s.clone());
David Tolnayb28f38a2018-03-31 22:02:29 +0200463 self.string_to_index
464 .insert(MyRc(s), self.index_to_string.len() - 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700465 self.index_to_string.len() - 1
466 }
467
David Tolnayb28f38a2018-03-31 22:02:29 +0200468 fn get(&self, idx: usize) -> &str {
469 &self.index_to_string[idx]
470 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700471}
472
David Tolnay977f8282017-05-31 17:41:33 -0700473#[derive(Clone, Debug)]
Alex Crichtonb2c94622018-04-04 07:36:41 -0700474pub struct Literal {
475 text: String,
476 span: Span,
477}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700478
Alex Crichtona914a612018-04-04 07:48:44 -0700479macro_rules! suffixed_numbers {
480 ($($name:ident => $kind:ident,)*) => ($(
481 pub fn $name(n: $kind) -> Literal {
482 Literal::_new(format!(concat!("{}", stringify!($kind)), n))
483 }
484 )*)
485}
486
487macro_rules! unsuffixed_numbers {
488 ($($name:ident => $kind:ident,)*) => ($(
489 pub fn $name(n: $kind) -> Literal {
490 Literal::_new(n.to_string())
491 }
492 )*)
493}
494
Alex Crichton852d53d2017-05-19 19:25:08 -0700495impl Literal {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700496 fn _new(text: String) -> Literal {
497 Literal {
Alex Crichtona914a612018-04-04 07:48:44 -0700498 text: text,
Alex Crichtonb2c94622018-04-04 07:36:41 -0700499 span: Span::call_site(),
500 }
501 }
502
Alex Crichtona914a612018-04-04 07:48:44 -0700503 suffixed_numbers! {
504 u8_suffixed => u8,
505 u16_suffixed => u16,
506 u32_suffixed => u32,
507 u64_suffixed => u64,
508 usize_suffixed => usize,
509 i8_suffixed => i8,
510 i16_suffixed => i16,
511 i32_suffixed => i32,
512 i64_suffixed => i64,
513 isize_suffixed => isize,
514
515 f32_suffixed => f32,
516 f64_suffixed => f64,
517 }
518
519 unsuffixed_numbers! {
520 u8_unsuffixed => u8,
521 u16_unsuffixed => u16,
522 u32_unsuffixed => u32,
523 u64_unsuffixed => u64,
524 usize_unsuffixed => usize,
525 i8_unsuffixed => i8,
526 i16_unsuffixed => i16,
527 i32_unsuffixed => i32,
528 i64_unsuffixed => i64,
529 isize_unsuffixed => isize,
530 }
531
532 pub fn f32_unsuffixed(f: f32) -> Literal {
533 let mut s = f.to_string();
534 if !s.contains(".") {
535 s.push_str(".0");
Alex Crichton76a5cc82017-05-23 07:01:44 -0700536 }
Alex Crichtona914a612018-04-04 07:48:44 -0700537 Literal::_new(s)
538 }
539
540 pub fn f64_unsuffixed(f: f64) -> Literal {
541 let mut s = f.to_string();
542 if !s.contains(".") {
543 s.push_str(".0");
544 }
545 Literal::_new(s)
546 }
547
548 pub fn string(t: &str) -> Literal {
549 let mut s = t.chars()
550 .flat_map(|c| c.escape_default())
551 .collect::<String>();
552 s.push('"');
553 s.insert(0, '"');
554 Literal::_new(s)
555 }
556
557 pub fn character(t: char) -> Literal {
558 Literal::_new(format!("'{}'", t.escape_default().collect::<String>()))
Alex Crichton76a5cc82017-05-23 07:01:44 -0700559 }
560
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700561 pub fn byte_string(bytes: &[u8]) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700562 let mut escaped = "b\"".to_string();
563 for b in bytes {
564 match *b {
565 b'\0' => escaped.push_str(r"\0"),
566 b'\t' => escaped.push_str(r"\t"),
567 b'\n' => escaped.push_str(r"\n"),
568 b'\r' => escaped.push_str(r"\r"),
569 b'"' => escaped.push_str("\\\""),
570 b'\\' => escaped.push_str("\\\\"),
David Tolnayb28f38a2018-03-31 22:02:29 +0200571 b'\x20'...b'\x7E' => escaped.push(*b as char),
Alex Crichton852d53d2017-05-19 19:25:08 -0700572 _ => escaped.push_str(&format!("\\x{:02X}", b)),
573 }
574 }
575 escaped.push('"');
Alex Crichtonb2c94622018-04-04 07:36:41 -0700576 Literal::_new(escaped)
Alex Crichton76a5cc82017-05-23 07:01:44 -0700577 }
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700578
Alex Crichtonb2c94622018-04-04 07:36:41 -0700579 pub fn span(&self) -> Span {
580 self.span
Alex Crichton31316622017-05-26 12:54:47 -0700581 }
582
Alex Crichtonb2c94622018-04-04 07:36:41 -0700583 pub fn set_span(&mut self, span: Span) {
584 self.span = span;
Alex Crichton31316622017-05-26 12:54:47 -0700585 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700586}
587
Alex Crichton44bffbc2017-05-19 17:51:59 -0700588impl fmt::Display for Literal {
589 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700590 self.text.fmt(f)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700591 }
592}
593
David Tolnay8e976c62017-06-01 12:12:29 -0700594named!(token_stream -> ::TokenStream, map!(
595 many0!(token_tree),
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700596 |trees| ::TokenStream::_new(TokenStream { inner: trees })
David Tolnay8e976c62017-06-01 12:12:29 -0700597));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700598
David Tolnay1ebe3972018-01-02 20:14:20 -0800599#[cfg(not(procmacro2_semver_exempt))]
David Tolnayddfca052017-12-31 10:41:24 -0500600fn token_tree(input: Cursor) -> PResult<TokenTree> {
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700601 token_kind(input)
David Tolnayddfca052017-12-31 10:41:24 -0500602}
603
David Tolnay1ebe3972018-01-02 20:14:20 -0800604#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500605fn token_tree(input: Cursor) -> PResult<TokenTree> {
606 let input = skip_whitespace(input);
607 let lo = input.off;
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700608 let (input, mut token) = token_kind(input)?;
Nika Layzellf8d5f212017-12-11 14:07:02 -0500609 let hi = input.off;
David Tolnayb28f38a2018-03-31 22:02:29 +0200610 token.set_span(::Span::_new(Span { lo: lo, hi: hi }));
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700611 Ok((input, token))
Nika Layzellf8d5f212017-12-11 14:07:02 -0500612}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700613
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700614named!(token_kind -> TokenTree, alt!(
615 map!(group, TokenTree::Group)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700616 |
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700617 map!(literal, TokenTree::Literal) // must be before symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700618 |
Alex Crichton52725f72017-08-28 12:20:58 -0700619 symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700620 |
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700621 map!(op, TokenTree::Op)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700622));
623
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700624named!(group -> Group, alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -0700625 delimited!(
626 punct!("("),
627 token_stream,
628 punct!(")")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700629 ) => { |ts| Group::new(Delimiter::Parenthesis, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700630 |
631 delimited!(
632 punct!("["),
633 token_stream,
634 punct!("]")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700635 ) => { |ts| Group::new(Delimiter::Bracket, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700636 |
637 delimited!(
638 punct!("{"),
639 token_stream,
640 punct!("}")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700641 ) => { |ts| Group::new(Delimiter::Brace, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700642));
643
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700644fn symbol(mut input: Cursor) -> PResult<TokenTree> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700645 input = skip_whitespace(input);
646
647 let mut chars = input.char_indices();
David Tolnaya202d502017-06-01 12:26:55 -0700648
649 let lifetime = input.starts_with("'");
650 if lifetime {
651 chars.next();
652 }
653
David Tolnaya13d1422018-03-31 21:27:48 +0200654 let raw = !lifetime && input.starts_with("r#");
655 if raw {
656 chars.next();
657 chars.next();
658 }
659
Alex Crichton44bffbc2017-05-19 17:51:59 -0700660 match chars.next() {
661 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700662 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700663 }
664
David Tolnay214c94c2017-06-01 12:42:56 -0700665 let mut end = input.len();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700666 for (i, ch) in chars {
667 if !UnicodeXID::is_xid_continue(ch) {
David Tolnay214c94c2017-06-01 12:42:56 -0700668 end = i;
669 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700670 }
671 }
672
David Tolnaya13d1422018-03-31 21:27:48 +0200673 let a = &input.rest[..end];
674 if a == "r#_" || lifetime && a != "'static" && KEYWORDS.contains(&&a[1..]) {
David Tolnay214c94c2017-06-01 12:42:56 -0700675 Err(LexError)
David Tolnaya13d1422018-03-31 21:27:48 +0200676 } else if a == "_" {
677 Ok((input.advance(end), Op::new('_', Spacing::Alone).into()))
David Tolnay214c94c2017-06-01 12:42:56 -0700678 } else {
David Tolnayb28f38a2018-03-31 22:02:29 +0200679 Ok((
680 input.advance(end),
681 ::Term::new(a, ::Span::call_site()).into(),
682 ))
David Tolnay214c94c2017-06-01 12:42:56 -0700683 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700684}
685
David Tolnay214c94c2017-06-01 12:42:56 -0700686// From https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/symbol.rs
687static KEYWORDS: &'static [&'static str] = &[
David Tolnayb28f38a2018-03-31 22:02:29 +0200688 "abstract", "alignof", "as", "become", "box", "break", "const", "continue", "crate", "do",
689 "else", "enum", "extern", "false", "final", "fn", "for", "if", "impl", "in", "let", "loop",
690 "macro", "match", "mod", "move", "mut", "offsetof", "override", "priv", "proc", "pub", "pure",
691 "ref", "return", "self", "Self", "sizeof", "static", "struct", "super", "trait", "true",
692 "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while", "yield",
David Tolnay214c94c2017-06-01 12:42:56 -0700693];
694
Nika Layzellf8d5f212017-12-11 14:07:02 -0500695fn literal(input: Cursor) -> PResult<::Literal> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700696 let input_no_ws = skip_whitespace(input);
697
698 match literal_nocapture(input_no_ws) {
David Tolnay1218e122017-06-01 11:13:45 -0700699 Ok((a, ())) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700700 let start = input.len() - input_no_ws.len();
701 let len = input_no_ws.len() - a.len();
702 let end = start + len;
David Tolnayb28f38a2018-03-31 22:02:29 +0200703 Ok((
704 a,
Alex Crichtonb2c94622018-04-04 07:36:41 -0700705 ::Literal::_new(Literal::_new(input.rest[start..end].to_string())),
David Tolnayb28f38a2018-03-31 22:02:29 +0200706 ))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700707 }
David Tolnay1218e122017-06-01 11:13:45 -0700708 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700709 }
710}
711
712named!(literal_nocapture -> (), alt!(
713 string
714 |
715 byte_string
716 |
717 byte
718 |
719 character
720 |
721 float
722 |
723 int
724 |
Alex Crichton44bffbc2017-05-19 17:51:59 -0700725 doc_comment
726));
727
728named!(string -> (), alt!(
729 quoted_string
730 |
731 preceded!(
732 punct!("r"),
733 raw_string
734 ) => { |_| () }
735));
736
737named!(quoted_string -> (), delimited!(
738 punct!("\""),
739 cooked_string,
740 tag!("\"")
741));
742
Nika Layzellf8d5f212017-12-11 14:07:02 -0500743fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700744 let mut chars = input.char_indices().peekable();
745 while let Some((byte_offset, ch)) = chars.next() {
746 match ch {
747 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500748 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700749 }
750 '\r' => {
751 if let Some((_, '\n')) = chars.next() {
752 // ...
753 } else {
754 break;
755 }
756 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200757 '\\' => match chars.next() {
758 Some((_, 'x')) => {
759 if !backslash_x_char(&mut chars) {
760 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700761 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700762 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200763 Some((_, 'n')) | Some((_, 'r')) | Some((_, 't')) | Some((_, '\\'))
764 | Some((_, '\'')) | Some((_, '"')) | Some((_, '0')) => {}
765 Some((_, 'u')) => {
766 if !backslash_u(&mut chars) {
767 break;
768 }
769 }
770 Some((_, '\n')) | Some((_, '\r')) => {
771 while let Some(&(_, ch)) = chars.peek() {
772 if ch.is_whitespace() {
773 chars.next();
774 } else {
775 break;
776 }
777 }
778 }
779 _ => break,
780 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700781 _ch => {}
782 }
783 }
David Tolnay1218e122017-06-01 11:13:45 -0700784 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700785}
786
787named!(byte_string -> (), alt!(
788 delimited!(
789 punct!("b\""),
790 cooked_byte_string,
791 tag!("\"")
792 ) => { |_| () }
793 |
794 preceded!(
795 punct!("br"),
796 raw_string
797 ) => { |_| () }
798));
799
Nika Layzellf8d5f212017-12-11 14:07:02 -0500800fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700801 let mut bytes = input.bytes().enumerate();
802 'outer: while let Some((offset, b)) = bytes.next() {
803 match b {
804 b'"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500805 return Ok((input.advance(offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700806 }
807 b'\r' => {
808 if let Some((_, b'\n')) = bytes.next() {
809 // ...
810 } else {
811 break;
812 }
813 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200814 b'\\' => match bytes.next() {
815 Some((_, b'x')) => {
816 if !backslash_x_byte(&mut bytes) {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700817 break;
818 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700819 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200820 Some((_, b'n')) | Some((_, b'r')) | Some((_, b't')) | Some((_, b'\\'))
821 | Some((_, b'0')) | Some((_, b'\'')) | Some((_, b'"')) => {}
822 Some((newline, b'\n')) | Some((newline, b'\r')) => {
823 let rest = input.advance(newline + 1);
824 for (offset, ch) in rest.char_indices() {
825 if !ch.is_whitespace() {
826 input = rest.advance(offset);
827 bytes = input.bytes().enumerate();
828 continue 'outer;
829 }
830 }
831 break;
832 }
833 _ => break,
834 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700835 b if b < 0x80 => {}
836 _ => break,
837 }
838 }
David Tolnay1218e122017-06-01 11:13:45 -0700839 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700840}
841
Nika Layzellf8d5f212017-12-11 14:07:02 -0500842fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700843 let mut chars = input.char_indices();
844 let mut n = 0;
845 while let Some((byte_offset, ch)) = chars.next() {
846 match ch {
847 '"' => {
848 n = byte_offset;
849 break;
850 }
851 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700852 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700853 }
854 }
855 for (byte_offset, ch) in chars {
856 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500857 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
858 let rest = input.advance(byte_offset + 1 + n);
David Tolnayb28f38a2018-03-31 22:02:29 +0200859 return Ok((rest, ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700860 }
861 '\r' => {}
862 _ => {}
863 }
864 }
David Tolnay1218e122017-06-01 11:13:45 -0700865 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700866}
867
868named!(byte -> (), do_parse!(
869 punct!("b") >>
870 tag!("'") >>
871 cooked_byte >>
872 tag!("'") >>
873 (())
874));
875
Nika Layzellf8d5f212017-12-11 14:07:02 -0500876fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700877 let mut bytes = input.bytes().enumerate();
878 let ok = match bytes.next().map(|(_, b)| b) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200879 Some(b'\\') => match bytes.next().map(|(_, b)| b) {
880 Some(b'x') => backslash_x_byte(&mut bytes),
881 Some(b'n') | Some(b'r') | Some(b't') | Some(b'\\') | Some(b'0') | Some(b'\'')
882 | Some(b'"') => true,
883 _ => false,
884 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700885 b => b.is_some(),
886 };
887 if ok {
888 match bytes.next() {
Alex Crichton8c030332018-01-16 08:07:36 -0800889 Some((offset, _)) => {
890 if input.chars().as_str().is_char_boundary(offset) {
891 Ok((input.advance(offset), ()))
892 } else {
893 Err(LexError)
894 }
895 }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500896 None => Ok((input.advance(input.len()), ())),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700897 }
898 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700899 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700900 }
901}
902
903named!(character -> (), do_parse!(
904 punct!("'") >>
905 cooked_char >>
906 tag!("'") >>
907 (())
908));
909
Nika Layzellf8d5f212017-12-11 14:07:02 -0500910fn cooked_char(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700911 let mut chars = input.char_indices();
912 let ok = match chars.next().map(|(_, ch)| ch) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200913 Some('\\') => match chars.next().map(|(_, ch)| ch) {
914 Some('x') => backslash_x_char(&mut chars),
915 Some('u') => backslash_u(&mut chars),
916 Some('n') | Some('r') | Some('t') | Some('\\') | Some('0') | Some('\'') | Some('"') => {
917 true
Alex Crichton44bffbc2017-05-19 17:51:59 -0700918 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200919 _ => false,
920 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700921 ch => ch.is_some(),
922 };
923 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500924 match chars.next() {
925 Some((idx, _)) => Ok((input.advance(idx), ())),
926 None => Ok((input.advance(input.len()), ())),
927 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700928 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700929 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700930 }
931}
932
933macro_rules! next_ch {
934 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
935 match $chars.next() {
936 Some((_, ch)) => match ch {
937 $pat $(| $rest)* => ch,
938 _ => return false,
939 },
940 None => return false
941 }
942 };
943}
944
945fn backslash_x_char<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +0200946where
947 I: Iterator<Item = (usize, char)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700948{
949 next_ch!(chars @ '0'...'7');
950 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
951 true
952}
953
954fn backslash_x_byte<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +0200955where
956 I: Iterator<Item = (usize, u8)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700957{
958 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
959 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
960 true
961}
962
963fn backslash_u<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +0200964where
965 I: Iterator<Item = (usize, char)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700966{
967 next_ch!(chars @ '{');
968 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
David Tolnay8d109342017-12-25 18:24:45 -0500969 loop {
970 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '_' | '}');
971 if c == '}' {
972 return true;
973 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700974 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700975}
976
Nika Layzellf8d5f212017-12-11 14:07:02 -0500977fn float(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -0700978 let (rest, ()) = float_digits(input)?;
979 for suffix in &["f32", "f64"] {
980 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500981 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -0700982 }
983 }
984 word_break(rest)
985}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700986
Nika Layzellf8d5f212017-12-11 14:07:02 -0500987fn float_digits(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700988 let mut chars = input.chars().peekable();
989 match chars.next() {
990 Some(ch) if ch >= '0' && ch <= '9' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700991 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700992 }
993
994 let mut len = 1;
995 let mut has_dot = false;
996 let mut has_exp = false;
997 while let Some(&ch) = chars.peek() {
998 match ch {
999 '0'...'9' | '_' => {
1000 chars.next();
1001 len += 1;
1002 }
1003 '.' => {
1004 if has_dot {
1005 break;
1006 }
1007 chars.next();
David Tolnayb28f38a2018-03-31 22:02:29 +02001008 if chars
1009 .peek()
1010 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1011 .unwrap_or(false)
1012 {
David Tolnay1218e122017-06-01 11:13:45 -07001013 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001014 }
1015 len += 1;
1016 has_dot = true;
1017 }
1018 'e' | 'E' => {
1019 chars.next();
1020 len += 1;
1021 has_exp = true;
1022 break;
1023 }
1024 _ => break,
1025 }
1026 }
1027
Nika Layzellf8d5f212017-12-11 14:07:02 -05001028 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001029 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001030 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001031 }
1032
1033 if has_exp {
1034 let mut has_exp_value = false;
1035 while let Some(&ch) = chars.peek() {
1036 match ch {
1037 '+' | '-' => {
1038 if has_exp_value {
1039 break;
1040 }
1041 chars.next();
1042 len += 1;
1043 }
1044 '0'...'9' => {
1045 chars.next();
1046 len += 1;
1047 has_exp_value = true;
1048 }
1049 '_' => {
1050 chars.next();
1051 len += 1;
1052 }
1053 _ => break,
1054 }
1055 }
1056 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001057 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001058 }
1059 }
1060
Nika Layzellf8d5f212017-12-11 14:07:02 -05001061 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001062}
1063
Nika Layzellf8d5f212017-12-11 14:07:02 -05001064fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001065 let (rest, ()) = digits(input)?;
1066 for suffix in &[
David Tolnayb28f38a2018-03-31 22:02:29 +02001067 "isize", "i8", "i16", "i32", "i64", "i128", "usize", "u8", "u16", "u32", "u64", "u128"
David Tolnay744a6b82017-06-01 11:34:29 -07001068 ] {
1069 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001070 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001071 }
1072 }
1073 word_break(rest)
1074}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001075
Nika Layzellf8d5f212017-12-11 14:07:02 -05001076fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001077 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001078 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001079 16
1080 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001081 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001082 8
1083 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001084 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001085 2
1086 } else {
1087 10
1088 };
1089
Alex Crichton44bffbc2017-05-19 17:51:59 -07001090 let mut len = 0;
1091 let mut empty = true;
1092 for b in input.bytes() {
1093 let digit = match b {
1094 b'0'...b'9' => (b - b'0') as u64,
1095 b'a'...b'f' => 10 + (b - b'a') as u64,
1096 b'A'...b'F' => 10 + (b - b'A') as u64,
1097 b'_' => {
1098 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001099 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001100 }
1101 len += 1;
1102 continue;
1103 }
1104 _ => break,
1105 };
1106 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001107 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001108 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001109 len += 1;
1110 empty = false;
1111 }
1112 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001113 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001114 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001115 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001116 }
1117}
1118
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001119fn op(input: Cursor) -> PResult<Op> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001120 let input = skip_whitespace(input);
1121 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001122 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001123 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001124 Ok(_) => Spacing::Joint,
1125 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001126 };
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001127 Ok((rest, Op::new(ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001128 }
David Tolnay1218e122017-06-01 11:13:45 -07001129 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001130 }
1131}
1132
Nika Layzellf8d5f212017-12-11 14:07:02 -05001133fn op_char(input: Cursor) -> PResult<char> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001134 let mut chars = input.chars();
1135 let first = match chars.next() {
1136 Some(ch) => ch,
1137 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001138 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001139 }
1140 };
1141 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1142 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001143 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001144 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001145 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001146 }
1147}
1148
Alex Crichton44bffbc2017-05-19 17:51:59 -07001149named!(doc_comment -> (), alt!(
1150 do_parse!(
1151 punct!("//!") >>
Alex Crichtond7904e52018-01-23 11:08:45 -08001152 take_until_newline_or_eof!() >>
Alex Crichton44bffbc2017-05-19 17:51:59 -07001153 (())
1154 )
1155 |
1156 do_parse!(
1157 option!(whitespace) >>
1158 peek!(tag!("/*!")) >>
1159 block_comment >>
1160 (())
1161 )
1162 |
1163 do_parse!(
1164 punct!("///") >>
1165 not!(tag!("/")) >>
Alex Crichtond7904e52018-01-23 11:08:45 -08001166 take_until_newline_or_eof!() >>
Alex Crichton44bffbc2017-05-19 17:51:59 -07001167 (())
1168 )
1169 |
1170 do_parse!(
1171 option!(whitespace) >>
1172 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1173 block_comment >>
1174 (())
1175 )
1176));