blob: d7d35d00ee71f707c38c3586573854333f36cabe [file] [log] [blame]
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001#![allow(dead_code)]
2
Alex Crichton76a5cc82017-05-23 07:01:44 -07003use std::ascii;
Alex Crichton44bffbc2017-05-19 17:51:59 -07004use std::borrow::Borrow;
5use std::cell::RefCell;
David Tolnay1ebe3972018-01-02 20:14:20 -08006#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -05007use std::cmp;
Alex Crichton44bffbc2017-05-19 17:51:59 -07008use std::collections::HashMap;
9use std::fmt;
10use std::iter;
David Tolnay041bcd42017-06-03 09:18:04 -070011use std::marker::PhantomData;
Alex Crichton44bffbc2017-05-19 17:51:59 -070012use std::rc::Rc;
13use std::str::FromStr;
14use std::vec;
15
David Tolnayb1032662017-05-31 15:52:28 -070016use unicode_xid::UnicodeXID;
Nika Layzellf8d5f212017-12-11 14:07:02 -050017use strnom::{Cursor, PResult, skip_whitespace, block_comment, whitespace, word_break};
Alex Crichton44bffbc2017-05-19 17:51:59 -070018
Alex Crichtonaf5bad42018-03-27 14:45:10 -070019use {TokenTree, Delimiter, Spacing, Group, Op};
Alex Crichton44bffbc2017-05-19 17:51:59 -070020
David Tolnay977f8282017-05-31 17:41:33 -070021#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -070022pub struct TokenStream {
23 inner: Vec<TokenTree>,
24}
25
26#[derive(Debug)]
27pub struct LexError;
28
29impl TokenStream {
30 pub fn empty() -> TokenStream {
31 TokenStream { inner: Vec::new() }
32 }
33
34 pub fn is_empty(&self) -> bool {
35 self.inner.len() == 0
36 }
37}
38
David Tolnay1ebe3972018-01-02 20:14:20 -080039#[cfg(procmacro2_semver_exempt)]
Nika Layzella9dbc182017-12-30 14:50:13 -050040fn get_cursor(src: &str) -> Cursor {
41 // Create a dummy file & add it to the codemap
42 CODEMAP.with(|cm| {
43 let mut cm = cm.borrow_mut();
44 let name = format!("<parsed string {}>", cm.files.len());
45 let span = cm.add_file(&name, src);
46 Cursor {
47 rest: src,
48 off: span.lo,
49 }
50 })
51}
52
David Tolnay1ebe3972018-01-02 20:14:20 -080053#[cfg(not(procmacro2_semver_exempt))]
Nika Layzella9dbc182017-12-30 14:50:13 -050054fn get_cursor(src: &str) -> Cursor {
55 Cursor {
56 rest: src,
Nika Layzella9dbc182017-12-30 14:50:13 -050057 }
58}
59
Alex Crichton44bffbc2017-05-19 17:51:59 -070060impl FromStr for TokenStream {
61 type Err = LexError;
62
63 fn from_str(src: &str) -> Result<TokenStream, LexError> {
Nika Layzellf8d5f212017-12-11 14:07:02 -050064 // Create a dummy file & add it to the codemap
Nika Layzella9dbc182017-12-30 14:50:13 -050065 let cursor = get_cursor(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -050066
67 match token_stream(cursor) {
David Tolnay1218e122017-06-01 11:13:45 -070068 Ok((input, output)) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -070069 if skip_whitespace(input).len() != 0 {
70 Err(LexError)
71 } else {
Alex Crichtonaf5bad42018-03-27 14:45:10 -070072 Ok(output.inner)
Alex Crichton44bffbc2017-05-19 17:51:59 -070073 }
74 }
David Tolnay1218e122017-06-01 11:13:45 -070075 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -070076 }
77 }
78}
79
80impl fmt::Display for TokenStream {
81 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82 let mut joint = false;
83 for (i, tt) in self.inner.iter().enumerate() {
84 if i != 0 && !joint {
85 write!(f, " ")?;
86 }
87 joint = false;
Alex Crichtonaf5bad42018-03-27 14:45:10 -070088 match *tt {
89 TokenTree::Group(ref tt) => {
90 let (start, end) = match tt.delimiter() {
Alex Crichton44bffbc2017-05-19 17:51:59 -070091 Delimiter::Parenthesis => ("(", ")"),
92 Delimiter::Brace => ("{", "}"),
93 Delimiter::Bracket => ("[", "]"),
94 Delimiter::None => ("", ""),
95 };
Alex Crichtonaf5bad42018-03-27 14:45:10 -070096 if tt.stream().inner.inner.len() == 0 {
Alex Crichton852d53d2017-05-19 19:25:08 -070097 write!(f, "{} {}", start, end)?
98 } else {
Alex Crichtonaf5bad42018-03-27 14:45:10 -070099 write!(f, "{} {} {}", start, tt.stream(), end)?
Alex Crichton852d53d2017-05-19 19:25:08 -0700100 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700101 }
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700102 TokenTree::Term(ref tt) => write!(f, "{}", tt.as_str())?,
103 TokenTree::Op(ref tt) => {
104 write!(f, "{}", tt.op())?;
105 match tt.spacing() {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700106 Spacing::Alone => {}
107 Spacing::Joint => joint = true,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700108 }
109 }
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700110 TokenTree::Literal(ref tt) => {
111 write!(f, "{}", tt)?;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700112 // handle comments
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700113 if tt.inner.0.starts_with("/") {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700114 write!(f, "\n")?;
115 }
116 }
117 }
118 }
119
120 Ok(())
121 }
122}
123
Alex Crichton0e8e7f42018-02-22 06:15:13 -0800124#[cfg(feature = "proc-macro")]
125impl From<::proc_macro::TokenStream> for TokenStream {
126 fn from(inner: ::proc_macro::TokenStream) -> TokenStream {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700127 inner.to_string().parse().expect("compiler token stream parse failed")
128 }
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 {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700134 inner.to_string().parse().expect("failed to parse to compiler tokens")
135 }
136}
137
138
139impl From<TokenTree> for TokenStream {
140 fn from(tree: TokenTree) -> TokenStream {
141 TokenStream { inner: vec![tree] }
142 }
143}
144
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700145impl iter::FromIterator<TokenTree> for TokenStream {
146 fn from_iter<I: IntoIterator<Item=TokenTree>>(streams: I) -> Self {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700147 let mut v = Vec::new();
148
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700149 for token in streams.into_iter() {
150 v.push(token);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700151 }
152
153 TokenStream { inner: v }
154 }
155}
156
Alex Crichton1a7f7622017-07-05 17:47:15 -0700157pub type TokenTreeIter = vec::IntoIter<TokenTree>;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700158
159impl IntoIterator for TokenStream {
160 type Item = TokenTree;
Alex Crichton1a7f7622017-07-05 17:47:15 -0700161 type IntoIter = TokenTreeIter;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700162
Alex Crichton1a7f7622017-07-05 17:47:15 -0700163 fn into_iter(self) -> TokenTreeIter {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700164 self.inner.into_iter()
165 }
166}
167
David Tolnay1ebe3972018-01-02 20:14:20 -0800168#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500169#[derive(Clone, PartialEq, Eq, Debug)]
170pub struct FileName(String);
171
David Tolnay1ebe3972018-01-02 20:14:20 -0800172#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500173impl fmt::Display for FileName {
174 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
175 self.0.fmt(f)
176 }
177}
178
David Tolnay1ebe3972018-01-02 20:14:20 -0800179#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500180#[derive(Clone, PartialEq, Eq)]
181pub struct SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500182 name: FileName,
Nika Layzellf8d5f212017-12-11 14:07:02 -0500183}
184
David Tolnay1ebe3972018-01-02 20:14:20 -0800185#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500186impl SourceFile {
187 /// Get the path to this source file as a string.
Nika Layzellb35a9a32017-12-30 14:34:35 -0500188 pub fn path(&self) -> &FileName {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500189 &self.name
190 }
191
192 pub fn is_real(&self) -> bool {
193 // XXX(nika): Support real files in the future?
194 false
195 }
196}
197
David Tolnay1ebe3972018-01-02 20:14:20 -0800198#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500199impl AsRef<FileName> for SourceFile {
200 fn as_ref(&self) -> &FileName {
201 self.path()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500202 }
203}
204
David Tolnay1ebe3972018-01-02 20:14:20 -0800205#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500206impl fmt::Debug for SourceFile {
207 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
208 f.debug_struct("SourceFile")
Nika Layzellb35a9a32017-12-30 14:34:35 -0500209 .field("path", &self.path())
Nika Layzellf8d5f212017-12-11 14:07:02 -0500210 .field("is_real", &self.is_real())
211 .finish()
212 }
213}
214
David Tolnay1ebe3972018-01-02 20:14:20 -0800215#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500216#[derive(Clone, Copy, Debug, PartialEq, Eq)]
217pub struct LineColumn {
218 pub line: usize,
219 pub column: usize,
220}
221
David Tolnay1ebe3972018-01-02 20:14:20 -0800222#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500223thread_local! {
224 static CODEMAP: RefCell<Codemap> = RefCell::new(Codemap {
225 // NOTE: We start with a single dummy file which all call_site() and
226 // def_site() spans reference.
227 files: vec![FileInfo {
228 name: "<unspecified>".to_owned(),
229 span: Span { lo: 0, hi: 0 },
230 lines: vec![0],
231 }],
232 });
233}
234
David Tolnay1ebe3972018-01-02 20:14:20 -0800235#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500236struct FileInfo {
237 name: String,
238 span: Span,
239 lines: Vec<usize>,
240}
241
David Tolnay1ebe3972018-01-02 20:14:20 -0800242#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500243impl FileInfo {
244 fn offset_line_column(&self, offset: usize) -> LineColumn {
245 assert!(self.span_within(Span { lo: offset as u32, hi: offset as u32 }));
246 let offset = offset - self.span.lo as usize;
247 match self.lines.binary_search(&offset) {
248 Ok(found) => LineColumn {
249 line: found + 1,
250 column: 0
251 },
252 Err(idx) => LineColumn {
253 line: idx,
254 column: offset - self.lines[idx - 1]
255 },
256 }
257 }
258
259 fn span_within(&self, span: Span) -> bool {
260 span.lo >= self.span.lo && span.hi <= self.span.hi
261 }
262}
263
264/// Computes the offsets of each line in the given source string.
David Tolnay1ebe3972018-01-02 20:14:20 -0800265#[cfg(procmacro2_semver_exempt)]
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500266fn lines_offsets(s: &str) -> Vec<usize> {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500267 let mut lines = vec![0];
268 let mut prev = 0;
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500269 while let Some(len) = s[prev..].find('\n') {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500270 prev += len + 1;
271 lines.push(prev);
272 }
273 lines
274}
275
David Tolnay1ebe3972018-01-02 20:14:20 -0800276#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500277struct Codemap {
278 files: Vec<FileInfo>,
279}
280
David Tolnay1ebe3972018-01-02 20:14:20 -0800281#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500282impl Codemap {
283 fn next_start_pos(&self) -> u32 {
284 // Add 1 so there's always space between files.
285 //
286 // We'll always have at least 1 file, as we initialize our files list
287 // with a dummy file.
288 self.files.last().unwrap().span.hi + 1
289 }
290
291 fn add_file(&mut self, name: &str, src: &str) -> Span {
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500292 let lines = lines_offsets(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -0500293 let lo = self.next_start_pos();
294 // XXX(nika): Shouild we bother doing a checked cast or checked add here?
295 let span = Span { lo: lo, hi: lo + (src.len() as u32) };
296
297 self.files.push(FileInfo {
298 name: name.to_owned(),
299 span: span,
300 lines: lines,
301 });
302
303 span
304 }
305
306 fn fileinfo(&self, span: Span) -> &FileInfo {
307 for file in &self.files {
308 if file.span_within(span) {
309 return file;
310 }
311 }
312 panic!("Invalid span with no related FileInfo!");
313 }
314}
315
Nika Layzell99737982018-03-11 18:51:27 -0400316#[derive(Clone, Copy, Debug, PartialEq, Eq)]
David Tolnayddfca052017-12-31 10:41:24 -0500317pub struct Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800318 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500319 lo: u32,
David Tolnay1ebe3972018-01-02 20:14:20 -0800320 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500321 hi: u32,
322}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700323
324impl Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800325 #[cfg(not(procmacro2_semver_exempt))]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700326 pub fn call_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500327 Span {}
328 }
329
David Tolnay1ebe3972018-01-02 20:14:20 -0800330 #[cfg(procmacro2_semver_exempt)]
David Tolnay79105e52017-12-31 11:03:04 -0500331 pub fn call_site() -> Span {
332 Span { lo: 0, hi: 0 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700333 }
Alex Crichtone6085b72017-11-21 07:24:25 -0800334
335 pub fn def_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500336 Span::call_site()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500337 }
338
David Tolnay4e8e3972018-01-05 18:10:22 -0800339 pub fn resolved_at(&self, _other: Span) -> Span {
340 // Stable spans consist only of line/column information, so
341 // `resolved_at` and `located_at` only select which span the
342 // caller wants line/column information from.
343 *self
344 }
345
346 pub fn located_at(&self, other: Span) -> Span {
347 other
348 }
349
David Tolnay1ebe3972018-01-02 20:14:20 -0800350 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500351 pub fn source_file(&self) -> SourceFile {
352 CODEMAP.with(|cm| {
353 let cm = cm.borrow();
354 let fi = cm.fileinfo(*self);
355 SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500356 name: FileName(fi.name.clone()),
Nika Layzellf8d5f212017-12-11 14:07:02 -0500357 }
358 })
359 }
360
David Tolnay1ebe3972018-01-02 20:14:20 -0800361 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500362 pub fn start(&self) -> LineColumn {
363 CODEMAP.with(|cm| {
364 let cm = cm.borrow();
365 let fi = cm.fileinfo(*self);
366 fi.offset_line_column(self.lo as usize)
367 })
368 }
369
David Tolnay1ebe3972018-01-02 20:14:20 -0800370 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500371 pub fn end(&self) -> LineColumn {
372 CODEMAP.with(|cm| {
373 let cm = cm.borrow();
374 let fi = cm.fileinfo(*self);
375 fi.offset_line_column(self.hi as usize)
376 })
377 }
378
David Tolnay1ebe3972018-01-02 20:14:20 -0800379 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500380 pub fn join(&self, other: Span) -> Option<Span> {
381 CODEMAP.with(|cm| {
382 let cm = cm.borrow();
383 // If `other` is not within the same FileInfo as us, return None.
384 if !cm.fileinfo(*self).span_within(other) {
385 return None;
386 }
387 Some(Span {
388 lo: cmp::min(self.lo, other.lo),
389 hi: cmp::max(self.hi, other.hi),
390 })
391 })
Alex Crichtone6085b72017-11-21 07:24:25 -0800392 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700393}
394
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700395#[derive(Copy, Clone)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700396pub struct Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700397 intern: usize,
398 not_send_sync: PhantomData<*const ()>,
399}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700400
401thread_local!(static SYMBOLS: RefCell<Interner> = RefCell::new(Interner::new()));
402
David Tolnay10effeb2018-01-06 11:07:49 -0800403impl Term {
404 pub fn intern(string: &str) -> Term {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700405 Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700406 intern: SYMBOLS.with(|s| s.borrow_mut().intern(string)),
407 not_send_sync: PhantomData,
408 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700409 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700410
David Tolnay10effeb2018-01-06 11:07:49 -0800411 pub fn as_str(&self) -> &str {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700412 SYMBOLS.with(|interner| {
413 let interner = interner.borrow();
David Tolnay041bcd42017-06-03 09:18:04 -0700414 let s = interner.get(self.intern);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700415 unsafe {
416 &*(s as *const str)
417 }
418 })
419 }
420}
421
Alex Crichton1a7f7622017-07-05 17:47:15 -0700422impl fmt::Debug for Term {
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700423 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
David Tolnay10effeb2018-01-06 11:07:49 -0800424 f.debug_tuple("Term").field(&self.as_str()).finish()
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700425 }
426}
427
Alex Crichton44bffbc2017-05-19 17:51:59 -0700428struct Interner {
429 string_to_index: HashMap<MyRc, usize>,
430 index_to_string: Vec<Rc<String>>,
431}
432
433#[derive(Hash, Eq, PartialEq)]
434struct MyRc(Rc<String>);
435
436impl Borrow<str> for MyRc {
437 fn borrow(&self) -> &str {
438 &self.0
439 }
440}
441
442impl Interner {
443 fn new() -> Interner {
444 Interner {
445 string_to_index: HashMap::new(),
446 index_to_string: Vec::new(),
447 }
448 }
449
450 fn intern(&mut self, s: &str) -> usize {
451 if let Some(&idx) = self.string_to_index.get(s) {
452 return idx
453 }
454 let s = Rc::new(s.to_string());
455 self.index_to_string.push(s.clone());
456 self.string_to_index.insert(MyRc(s), self.index_to_string.len() - 1);
457 self.index_to_string.len() - 1
458 }
459
460 fn get(&self, idx: usize) -> &str {
461 &self.index_to_string[idx]
462 }
463}
464
David Tolnay977f8282017-05-31 17:41:33 -0700465#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700466pub struct Literal(String);
467
Alex Crichton852d53d2017-05-19 19:25:08 -0700468impl Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700469 pub fn byte_char(byte: u8) -> Literal {
Alex Crichton76a5cc82017-05-23 07:01:44 -0700470 match byte {
471 0 => Literal(format!("b'\\0'")),
472 b'\"' => Literal(format!("b'\"'")),
473 n => {
474 let mut escaped = "b'".to_string();
475 escaped.extend(ascii::escape_default(n).map(|c| c as char));
476 escaped.push('\'');
477 Literal(escaped)
478 }
479 }
480 }
481
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700482 pub fn byte_string(bytes: &[u8]) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700483 let mut escaped = "b\"".to_string();
484 for b in bytes {
485 match *b {
486 b'\0' => escaped.push_str(r"\0"),
487 b'\t' => escaped.push_str(r"\t"),
488 b'\n' => escaped.push_str(r"\n"),
489 b'\r' => escaped.push_str(r"\r"),
490 b'"' => escaped.push_str("\\\""),
491 b'\\' => escaped.push_str("\\\\"),
492 b'\x20' ... b'\x7E' => escaped.push(*b as char),
493 _ => escaped.push_str(&format!("\\x{:02X}", b)),
494 }
495 }
496 escaped.push('"');
497 Literal(escaped)
498 }
Alex Crichton76a5cc82017-05-23 07:01:44 -0700499
500 pub fn doccomment(s: &str) -> Literal {
501 Literal(s.to_string())
502 }
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700503
David Tolnay114990e2018-01-05 11:17:08 -0800504 pub fn float(n: f64) -> Literal {
505 if !n.is_finite() {
506 panic!("Invalid float literal {}", n);
507 }
508 let mut s = n.to_string();
509 if !s.contains('.') {
510 s += ".0";
511 }
512 Literal(s)
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700513 }
514
Alex Crichton1a7f7622017-07-05 17:47:15 -0700515 pub fn integer(s: i64) -> Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700516 Literal(s.to_string())
517 }
Alex Crichton31316622017-05-26 12:54:47 -0700518
519 pub fn raw_string(s: &str, pounds: usize) -> Literal {
520 let mut ret = format!("r");
521 ret.extend((0..pounds).map(|_| "#"));
522 ret.push('"');
523 ret.push_str(s);
524 ret.push('"');
525 ret.extend((0..pounds).map(|_| "#"));
526 Literal(ret)
527 }
528
529 pub fn raw_byte_string(s: &str, pounds: usize) -> Literal {
Alex Crichton7ed6d282017-05-26 13:42:50 -0700530 let mut ret = format!("br");
Alex Crichton31316622017-05-26 12:54:47 -0700531 ret.extend((0..pounds).map(|_| "#"));
532 ret.push('"');
533 ret.push_str(s);
534 ret.push('"');
535 ret.extend((0..pounds).map(|_| "#"));
536 Literal(ret)
537 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700538}
539
Alex Crichton44bffbc2017-05-19 17:51:59 -0700540impl fmt::Display for Literal {
541 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
542 self.0.fmt(f)
543 }
544}
545
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700546macro_rules! ints {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700547 ($($t:ty,)*) => {$(
548 impl From<$t> for Literal {
549 fn from(t: $t) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700550 Literal(format!(concat!("{}", stringify!($t)), t))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700551 }
552 }
553 )*}
554}
555
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700556ints! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700557 u8, u16, u32, u64, usize,
558 i8, i16, i32, i64, isize,
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700559}
560
561macro_rules! floats {
562 ($($t:ty,)*) => {$(
563 impl From<$t> for Literal {
564 fn from(t: $t) -> Literal {
565 assert!(!t.is_nan());
566 assert!(!t.is_infinite());
567 Literal(format!(concat!("{}", stringify!($t)), t))
568 }
569 }
570 )*}
571}
572
573floats! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700574 f32, f64,
575}
576
Alex Crichton44bffbc2017-05-19 17:51:59 -0700577impl<'a> From<&'a str> for Literal {
578 fn from(t: &'a str) -> Literal {
579 let mut s = t.chars().flat_map(|c| c.escape_default()).collect::<String>();
580 s.push('"');
581 s.insert(0, '"');
582 Literal(s)
583 }
584}
585
586impl From<char> for Literal {
587 fn from(t: char) -> Literal {
Alex Crichton2d0cf0b2017-05-26 14:00:16 -0700588 Literal(format!("'{}'", t.escape_default().collect::<String>()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700589 }
590}
591
David Tolnay8e976c62017-06-01 12:12:29 -0700592named!(token_stream -> ::TokenStream, map!(
593 many0!(token_tree),
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700594 |trees| ::TokenStream::_new(TokenStream { inner: trees })
David Tolnay8e976c62017-06-01 12:12:29 -0700595));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700596
David Tolnay1ebe3972018-01-02 20:14:20 -0800597#[cfg(not(procmacro2_semver_exempt))]
David Tolnayddfca052017-12-31 10:41:24 -0500598fn token_tree(input: Cursor) -> PResult<TokenTree> {
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700599 token_kind(input)
David Tolnayddfca052017-12-31 10:41:24 -0500600}
601
David Tolnay1ebe3972018-01-02 20:14:20 -0800602#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500603fn token_tree(input: Cursor) -> PResult<TokenTree> {
604 let input = skip_whitespace(input);
605 let lo = input.off;
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700606 let (input, mut token) = token_kind(input)?;
Nika Layzellf8d5f212017-12-11 14:07:02 -0500607 let hi = input.off;
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700608 token.set_span(::Span::_new(Span {
609 lo: lo,
610 hi: hi,
611 }));
612 Ok((input, token))
Nika Layzellf8d5f212017-12-11 14:07:02 -0500613}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700614
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700615named!(token_kind -> TokenTree, alt!(
616 map!(group, TokenTree::Group)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700617 |
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700618 map!(literal, TokenTree::Literal) // must be before symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700619 |
Alex Crichton52725f72017-08-28 12:20:58 -0700620 symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700621 |
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700622 map!(op, TokenTree::Op)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700623));
624
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700625named!(group -> Group, alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -0700626 delimited!(
627 punct!("("),
628 token_stream,
629 punct!(")")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700630 ) => { |ts| Group::new(Delimiter::Parenthesis, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700631 |
632 delimited!(
633 punct!("["),
634 token_stream,
635 punct!("]")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700636 ) => { |ts| Group::new(Delimiter::Bracket, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700637 |
638 delimited!(
639 punct!("{"),
640 token_stream,
641 punct!("}")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700642 ) => { |ts| Group::new(Delimiter::Brace, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700643));
644
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700645fn symbol(mut input: Cursor) -> PResult<TokenTree> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700646 input = skip_whitespace(input);
647
648 let mut chars = input.char_indices();
David Tolnaya202d502017-06-01 12:26:55 -0700649
650 let lifetime = input.starts_with("'");
651 if lifetime {
652 chars.next();
653 }
654
Alex Crichton44bffbc2017-05-19 17:51:59 -0700655 match chars.next() {
656 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700657 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700658 }
659
David Tolnay214c94c2017-06-01 12:42:56 -0700660 let mut end = input.len();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700661 for (i, ch) in chars {
662 if !UnicodeXID::is_xid_continue(ch) {
David Tolnay214c94c2017-06-01 12:42:56 -0700663 end = i;
664 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700665 }
666 }
667
Nika Layzellf8d5f212017-12-11 14:07:02 -0500668 if lifetime && &input.rest[..end] != "'static" && KEYWORDS.contains(&&input.rest[1..end]) {
David Tolnay214c94c2017-06-01 12:42:56 -0700669 Err(LexError)
670 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500671 let a = &input.rest[..end];
Alex Crichton52725f72017-08-28 12:20:58 -0700672 if a == "_" {
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700673 Ok((input.advance(end), Op::new('_', Spacing::Alone).into()))
Alex Crichton52725f72017-08-28 12:20:58 -0700674 } else {
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700675 Ok((input.advance(end), ::Term::new(a, ::Span::call_site()).into()))
Alex Crichton52725f72017-08-28 12:20:58 -0700676 }
David Tolnay214c94c2017-06-01 12:42:56 -0700677 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700678}
679
David Tolnay214c94c2017-06-01 12:42:56 -0700680// From https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/symbol.rs
681static KEYWORDS: &'static [&'static str] = &[
682 "abstract", "alignof", "as", "become", "box", "break", "const", "continue",
683 "crate", "do", "else", "enum", "extern", "false", "final", "fn", "for",
684 "if", "impl", "in", "let", "loop", "macro", "match", "mod", "move", "mut",
685 "offsetof", "override", "priv", "proc", "pub", "pure", "ref", "return",
686 "self", "Self", "sizeof", "static", "struct", "super", "trait", "true",
687 "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while",
688 "yield",
689];
690
Nika Layzellf8d5f212017-12-11 14:07:02 -0500691fn literal(input: Cursor) -> PResult<::Literal> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700692 let input_no_ws = skip_whitespace(input);
693
694 match literal_nocapture(input_no_ws) {
David Tolnay1218e122017-06-01 11:13:45 -0700695 Ok((a, ())) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700696 let start = input.len() - input_no_ws.len();
697 let len = input_no_ws.len() - a.len();
698 let end = start + len;
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700699 Ok((a, ::Literal::_new(Literal(input.rest[start..end].to_string()))))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700700 }
David Tolnay1218e122017-06-01 11:13:45 -0700701 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700702 }
703}
704
705named!(literal_nocapture -> (), alt!(
706 string
707 |
708 byte_string
709 |
710 byte
711 |
712 character
713 |
714 float
715 |
716 int
717 |
Alex Crichton44bffbc2017-05-19 17:51:59 -0700718 doc_comment
719));
720
721named!(string -> (), alt!(
722 quoted_string
723 |
724 preceded!(
725 punct!("r"),
726 raw_string
727 ) => { |_| () }
728));
729
730named!(quoted_string -> (), delimited!(
731 punct!("\""),
732 cooked_string,
733 tag!("\"")
734));
735
Nika Layzellf8d5f212017-12-11 14:07:02 -0500736fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700737 let mut chars = input.char_indices().peekable();
738 while let Some((byte_offset, ch)) = chars.next() {
739 match ch {
740 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500741 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700742 }
743 '\r' => {
744 if let Some((_, '\n')) = chars.next() {
745 // ...
746 } else {
747 break;
748 }
749 }
750 '\\' => {
751 match chars.next() {
752 Some((_, 'x')) => {
753 if !backslash_x_char(&mut chars) {
754 break
755 }
756 }
757 Some((_, 'n')) |
758 Some((_, 'r')) |
759 Some((_, 't')) |
760 Some((_, '\\')) |
761 Some((_, '\'')) |
762 Some((_, '"')) |
763 Some((_, '0')) => {}
764 Some((_, 'u')) => {
765 if !backslash_u(&mut chars) {
766 break
767 }
768 }
769 Some((_, '\n')) | Some((_, '\r')) => {
770 while let Some(&(_, ch)) = chars.peek() {
771 if ch.is_whitespace() {
772 chars.next();
773 } else {
774 break;
775 }
776 }
777 }
778 _ => break,
779 }
780 }
781 _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 }
814 b'\\' => {
815 match bytes.next() {
816 Some((_, b'x')) => {
817 if !backslash_x_byte(&mut bytes) {
818 break
819 }
820 }
821 Some((_, b'n')) |
822 Some((_, b'r')) |
823 Some((_, b't')) |
824 Some((_, b'\\')) |
825 Some((_, b'0')) |
826 Some((_, b'\'')) |
827 Some((_, b'"')) => {}
828 Some((newline, b'\n')) |
829 Some((newline, b'\r')) => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500830 let rest = input.advance(newline + 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700831 for (offset, ch) in rest.char_indices() {
832 if !ch.is_whitespace() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500833 input = rest.advance(offset);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700834 bytes = input.bytes().enumerate();
835 continue 'outer;
836 }
837 }
838 break;
839 }
840 _ => break,
841 }
842 }
843 b if b < 0x80 => {}
844 _ => break,
845 }
846 }
David Tolnay1218e122017-06-01 11:13:45 -0700847 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700848}
849
Nika Layzellf8d5f212017-12-11 14:07:02 -0500850fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700851 let mut chars = input.char_indices();
852 let mut n = 0;
853 while let Some((byte_offset, ch)) = chars.next() {
854 match ch {
855 '"' => {
856 n = byte_offset;
857 break;
858 }
859 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700860 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700861 }
862 }
863 for (byte_offset, ch) in chars {
864 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500865 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
866 let rest = input.advance(byte_offset + 1 + n);
David Tolnay1218e122017-06-01 11:13:45 -0700867 return Ok((rest, ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700868 }
869 '\r' => {}
870 _ => {}
871 }
872 }
David Tolnay1218e122017-06-01 11:13:45 -0700873 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700874}
875
876named!(byte -> (), do_parse!(
877 punct!("b") >>
878 tag!("'") >>
879 cooked_byte >>
880 tag!("'") >>
881 (())
882));
883
Nika Layzellf8d5f212017-12-11 14:07:02 -0500884fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700885 let mut bytes = input.bytes().enumerate();
886 let ok = match bytes.next().map(|(_, b)| b) {
887 Some(b'\\') => {
888 match bytes.next().map(|(_, b)| b) {
889 Some(b'x') => backslash_x_byte(&mut bytes),
890 Some(b'n') |
891 Some(b'r') |
892 Some(b't') |
893 Some(b'\\') |
894 Some(b'0') |
895 Some(b'\'') |
896 Some(b'"') => true,
897 _ => false,
898 }
899 }
900 b => b.is_some(),
901 };
902 if ok {
903 match bytes.next() {
Alex Crichton8c030332018-01-16 08:07:36 -0800904 Some((offset, _)) => {
905 if input.chars().as_str().is_char_boundary(offset) {
906 Ok((input.advance(offset), ()))
907 } else {
908 Err(LexError)
909 }
910 }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500911 None => Ok((input.advance(input.len()), ())),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700912 }
913 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700914 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700915 }
916}
917
918named!(character -> (), do_parse!(
919 punct!("'") >>
920 cooked_char >>
921 tag!("'") >>
922 (())
923));
924
Nika Layzellf8d5f212017-12-11 14:07:02 -0500925fn cooked_char(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700926 let mut chars = input.char_indices();
927 let ok = match chars.next().map(|(_, ch)| ch) {
928 Some('\\') => {
929 match chars.next().map(|(_, ch)| ch) {
930 Some('x') => backslash_x_char(&mut chars),
931 Some('u') => backslash_u(&mut chars),
932 Some('n') |
933 Some('r') |
934 Some('t') |
935 Some('\\') |
936 Some('0') |
937 Some('\'') |
938 Some('"') => true,
939 _ => false,
940 }
941 }
942 ch => ch.is_some(),
943 };
944 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500945 match chars.next() {
946 Some((idx, _)) => Ok((input.advance(idx), ())),
947 None => Ok((input.advance(input.len()), ())),
948 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700949 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700950 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700951 }
952}
953
954macro_rules! next_ch {
955 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
956 match $chars.next() {
957 Some((_, ch)) => match ch {
958 $pat $(| $rest)* => ch,
959 _ => return false,
960 },
961 None => return false
962 }
963 };
964}
965
966fn backslash_x_char<I>(chars: &mut I) -> bool
967 where I: Iterator<Item = (usize, char)>
968{
969 next_ch!(chars @ '0'...'7');
970 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
971 true
972}
973
974fn backslash_x_byte<I>(chars: &mut I) -> bool
975 where I: Iterator<Item = (usize, u8)>
976{
977 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
978 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
979 true
980}
981
982fn backslash_u<I>(chars: &mut I) -> bool
983 where I: Iterator<Item = (usize, char)>
984{
985 next_ch!(chars @ '{');
986 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
David Tolnay8d109342017-12-25 18:24:45 -0500987 loop {
988 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '_' | '}');
989 if c == '}' {
990 return true;
991 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700992 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700993}
994
Nika Layzellf8d5f212017-12-11 14:07:02 -0500995fn float(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -0700996 let (rest, ()) = float_digits(input)?;
997 for suffix in &["f32", "f64"] {
998 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500999 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001000 }
1001 }
1002 word_break(rest)
1003}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001004
Nika Layzellf8d5f212017-12-11 14:07:02 -05001005fn float_digits(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001006 let mut chars = input.chars().peekable();
1007 match chars.next() {
1008 Some(ch) if ch >= '0' && ch <= '9' => {}
David Tolnay1218e122017-06-01 11:13:45 -07001009 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001010 }
1011
1012 let mut len = 1;
1013 let mut has_dot = false;
1014 let mut has_exp = false;
1015 while let Some(&ch) = chars.peek() {
1016 match ch {
1017 '0'...'9' | '_' => {
1018 chars.next();
1019 len += 1;
1020 }
1021 '.' => {
1022 if has_dot {
1023 break;
1024 }
1025 chars.next();
1026 if chars.peek()
1027 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1028 .unwrap_or(false) {
David Tolnay1218e122017-06-01 11:13:45 -07001029 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001030 }
1031 len += 1;
1032 has_dot = true;
1033 }
1034 'e' | 'E' => {
1035 chars.next();
1036 len += 1;
1037 has_exp = true;
1038 break;
1039 }
1040 _ => break,
1041 }
1042 }
1043
Nika Layzellf8d5f212017-12-11 14:07:02 -05001044 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001045 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001046 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001047 }
1048
1049 if has_exp {
1050 let mut has_exp_value = false;
1051 while let Some(&ch) = chars.peek() {
1052 match ch {
1053 '+' | '-' => {
1054 if has_exp_value {
1055 break;
1056 }
1057 chars.next();
1058 len += 1;
1059 }
1060 '0'...'9' => {
1061 chars.next();
1062 len += 1;
1063 has_exp_value = true;
1064 }
1065 '_' => {
1066 chars.next();
1067 len += 1;
1068 }
1069 _ => break,
1070 }
1071 }
1072 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001073 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001074 }
1075 }
1076
Nika Layzellf8d5f212017-12-11 14:07:02 -05001077 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001078}
1079
Nika Layzellf8d5f212017-12-11 14:07:02 -05001080fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001081 let (rest, ()) = digits(input)?;
1082 for suffix in &[
1083 "isize",
1084 "i8",
1085 "i16",
1086 "i32",
1087 "i64",
1088 "i128",
1089 "usize",
1090 "u8",
1091 "u16",
1092 "u32",
1093 "u64",
1094 "u128",
1095 ] {
1096 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001097 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001098 }
1099 }
1100 word_break(rest)
1101}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001102
Nika Layzellf8d5f212017-12-11 14:07:02 -05001103fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001104 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001105 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001106 16
1107 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001108 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001109 8
1110 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001111 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001112 2
1113 } else {
1114 10
1115 };
1116
Alex Crichton44bffbc2017-05-19 17:51:59 -07001117 let mut len = 0;
1118 let mut empty = true;
1119 for b in input.bytes() {
1120 let digit = match b {
1121 b'0'...b'9' => (b - b'0') as u64,
1122 b'a'...b'f' => 10 + (b - b'a') as u64,
1123 b'A'...b'F' => 10 + (b - b'A') as u64,
1124 b'_' => {
1125 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001126 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001127 }
1128 len += 1;
1129 continue;
1130 }
1131 _ => break,
1132 };
1133 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001134 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001135 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001136 len += 1;
1137 empty = false;
1138 }
1139 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001140 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001141 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001142 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001143 }
1144}
1145
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001146fn op(input: Cursor) -> PResult<Op> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001147 let input = skip_whitespace(input);
1148 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001149 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001150 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001151 Ok(_) => Spacing::Joint,
1152 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001153 };
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001154 Ok((rest, Op::new(ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001155 }
David Tolnay1218e122017-06-01 11:13:45 -07001156 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001157 }
1158}
1159
Nika Layzellf8d5f212017-12-11 14:07:02 -05001160fn op_char(input: Cursor) -> PResult<char> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001161 let mut chars = input.chars();
1162 let first = match chars.next() {
1163 Some(ch) => ch,
1164 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001165 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001166 }
1167 };
1168 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1169 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001170 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001171 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001172 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001173 }
1174}
1175
Alex Crichton44bffbc2017-05-19 17:51:59 -07001176named!(doc_comment -> (), alt!(
1177 do_parse!(
1178 punct!("//!") >>
Alex Crichtond7904e52018-01-23 11:08:45 -08001179 take_until_newline_or_eof!() >>
Alex Crichton44bffbc2017-05-19 17:51:59 -07001180 (())
1181 )
1182 |
1183 do_parse!(
1184 option!(whitespace) >>
1185 peek!(tag!("/*!")) >>
1186 block_comment >>
1187 (())
1188 )
1189 |
1190 do_parse!(
1191 punct!("///") >>
1192 not!(tag!("/")) >>
Alex Crichtond7904e52018-01-23 11:08:45 -08001193 take_until_newline_or_eof!() >>
Alex Crichton44bffbc2017-05-19 17:51:59 -07001194 (())
1195 )
1196 |
1197 do_parse!(
1198 option!(whitespace) >>
1199 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1200 block_comment >>
1201 (())
1202 )
1203));