blob: b4b7eaeb9c4429632e82be890b7836af397e17b3 [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
David Tolnaya13d1422018-03-31 21:27:48 +0200655 let raw = !lifetime && input.starts_with("r#");
656 if raw {
657 chars.next();
658 chars.next();
659 }
660
Alex Crichton44bffbc2017-05-19 17:51:59 -0700661 match chars.next() {
662 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700663 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700664 }
665
David Tolnay214c94c2017-06-01 12:42:56 -0700666 let mut end = input.len();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700667 for (i, ch) in chars {
668 if !UnicodeXID::is_xid_continue(ch) {
David Tolnay214c94c2017-06-01 12:42:56 -0700669 end = i;
670 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700671 }
672 }
673
David Tolnaya13d1422018-03-31 21:27:48 +0200674 let a = &input.rest[..end];
675 if a == "r#_" || lifetime && a != "'static" && KEYWORDS.contains(&&a[1..]) {
David Tolnay214c94c2017-06-01 12:42:56 -0700676 Err(LexError)
David Tolnaya13d1422018-03-31 21:27:48 +0200677 } else if a == "_" {
678 Ok((input.advance(end), Op::new('_', Spacing::Alone).into()))
David Tolnay214c94c2017-06-01 12:42:56 -0700679 } else {
David Tolnaya13d1422018-03-31 21:27:48 +0200680 Ok((input.advance(end), ::Term::new(a, ::Span::call_site()).into()))
David Tolnay214c94c2017-06-01 12:42:56 -0700681 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700682}
683
David Tolnay214c94c2017-06-01 12:42:56 -0700684// From https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/symbol.rs
685static KEYWORDS: &'static [&'static str] = &[
686 "abstract", "alignof", "as", "become", "box", "break", "const", "continue",
687 "crate", "do", "else", "enum", "extern", "false", "final", "fn", "for",
688 "if", "impl", "in", "let", "loop", "macro", "match", "mod", "move", "mut",
689 "offsetof", "override", "priv", "proc", "pub", "pure", "ref", "return",
690 "self", "Self", "sizeof", "static", "struct", "super", "trait", "true",
691 "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while",
692 "yield",
693];
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;
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700703 Ok((a, ::Literal::_new(Literal(input.rest[start..end].to_string()))))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700704 }
David Tolnay1218e122017-06-01 11:13:45 -0700705 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700706 }
707}
708
709named!(literal_nocapture -> (), alt!(
710 string
711 |
712 byte_string
713 |
714 byte
715 |
716 character
717 |
718 float
719 |
720 int
721 |
Alex Crichton44bffbc2017-05-19 17:51:59 -0700722 doc_comment
723));
724
725named!(string -> (), alt!(
726 quoted_string
727 |
728 preceded!(
729 punct!("r"),
730 raw_string
731 ) => { |_| () }
732));
733
734named!(quoted_string -> (), delimited!(
735 punct!("\""),
736 cooked_string,
737 tag!("\"")
738));
739
Nika Layzellf8d5f212017-12-11 14:07:02 -0500740fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700741 let mut chars = input.char_indices().peekable();
742 while let Some((byte_offset, ch)) = chars.next() {
743 match ch {
744 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500745 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700746 }
747 '\r' => {
748 if let Some((_, '\n')) = chars.next() {
749 // ...
750 } else {
751 break;
752 }
753 }
754 '\\' => {
755 match chars.next() {
756 Some((_, 'x')) => {
757 if !backslash_x_char(&mut chars) {
758 break
759 }
760 }
761 Some((_, 'n')) |
762 Some((_, 'r')) |
763 Some((_, 't')) |
764 Some((_, '\\')) |
765 Some((_, '\'')) |
766 Some((_, '"')) |
767 Some((_, '0')) => {}
768 Some((_, 'u')) => {
769 if !backslash_u(&mut chars) {
770 break
771 }
772 }
773 Some((_, '\n')) | Some((_, '\r')) => {
774 while let Some(&(_, ch)) = chars.peek() {
775 if ch.is_whitespace() {
776 chars.next();
777 } else {
778 break;
779 }
780 }
781 }
782 _ => break,
783 }
784 }
785 _ch => {}
786 }
787 }
David Tolnay1218e122017-06-01 11:13:45 -0700788 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700789}
790
791named!(byte_string -> (), alt!(
792 delimited!(
793 punct!("b\""),
794 cooked_byte_string,
795 tag!("\"")
796 ) => { |_| () }
797 |
798 preceded!(
799 punct!("br"),
800 raw_string
801 ) => { |_| () }
802));
803
Nika Layzellf8d5f212017-12-11 14:07:02 -0500804fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700805 let mut bytes = input.bytes().enumerate();
806 'outer: while let Some((offset, b)) = bytes.next() {
807 match b {
808 b'"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500809 return Ok((input.advance(offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700810 }
811 b'\r' => {
812 if let Some((_, b'\n')) = bytes.next() {
813 // ...
814 } else {
815 break;
816 }
817 }
818 b'\\' => {
819 match bytes.next() {
820 Some((_, b'x')) => {
821 if !backslash_x_byte(&mut bytes) {
822 break
823 }
824 }
825 Some((_, b'n')) |
826 Some((_, b'r')) |
827 Some((_, b't')) |
828 Some((_, b'\\')) |
829 Some((_, b'0')) |
830 Some((_, b'\'')) |
831 Some((_, b'"')) => {}
832 Some((newline, b'\n')) |
833 Some((newline, b'\r')) => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500834 let rest = input.advance(newline + 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700835 for (offset, ch) in rest.char_indices() {
836 if !ch.is_whitespace() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500837 input = rest.advance(offset);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700838 bytes = input.bytes().enumerate();
839 continue 'outer;
840 }
841 }
842 break;
843 }
844 _ => break,
845 }
846 }
847 b if b < 0x80 => {}
848 _ => break,
849 }
850 }
David Tolnay1218e122017-06-01 11:13:45 -0700851 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700852}
853
Nika Layzellf8d5f212017-12-11 14:07:02 -0500854fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700855 let mut chars = input.char_indices();
856 let mut n = 0;
857 while let Some((byte_offset, ch)) = chars.next() {
858 match ch {
859 '"' => {
860 n = byte_offset;
861 break;
862 }
863 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700864 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700865 }
866 }
867 for (byte_offset, ch) in chars {
868 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500869 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
870 let rest = input.advance(byte_offset + 1 + n);
David Tolnay1218e122017-06-01 11:13:45 -0700871 return Ok((rest, ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700872 }
873 '\r' => {}
874 _ => {}
875 }
876 }
David Tolnay1218e122017-06-01 11:13:45 -0700877 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700878}
879
880named!(byte -> (), do_parse!(
881 punct!("b") >>
882 tag!("'") >>
883 cooked_byte >>
884 tag!("'") >>
885 (())
886));
887
Nika Layzellf8d5f212017-12-11 14:07:02 -0500888fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700889 let mut bytes = input.bytes().enumerate();
890 let ok = match bytes.next().map(|(_, b)| b) {
891 Some(b'\\') => {
892 match bytes.next().map(|(_, b)| b) {
893 Some(b'x') => backslash_x_byte(&mut bytes),
894 Some(b'n') |
895 Some(b'r') |
896 Some(b't') |
897 Some(b'\\') |
898 Some(b'0') |
899 Some(b'\'') |
900 Some(b'"') => true,
901 _ => false,
902 }
903 }
904 b => b.is_some(),
905 };
906 if ok {
907 match bytes.next() {
Alex Crichton8c030332018-01-16 08:07:36 -0800908 Some((offset, _)) => {
909 if input.chars().as_str().is_char_boundary(offset) {
910 Ok((input.advance(offset), ()))
911 } else {
912 Err(LexError)
913 }
914 }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500915 None => Ok((input.advance(input.len()), ())),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700916 }
917 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700918 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700919 }
920}
921
922named!(character -> (), do_parse!(
923 punct!("'") >>
924 cooked_char >>
925 tag!("'") >>
926 (())
927));
928
Nika Layzellf8d5f212017-12-11 14:07:02 -0500929fn cooked_char(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700930 let mut chars = input.char_indices();
931 let ok = match chars.next().map(|(_, ch)| ch) {
932 Some('\\') => {
933 match chars.next().map(|(_, ch)| ch) {
934 Some('x') => backslash_x_char(&mut chars),
935 Some('u') => backslash_u(&mut chars),
936 Some('n') |
937 Some('r') |
938 Some('t') |
939 Some('\\') |
940 Some('0') |
941 Some('\'') |
942 Some('"') => true,
943 _ => false,
944 }
945 }
946 ch => ch.is_some(),
947 };
948 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500949 match chars.next() {
950 Some((idx, _)) => Ok((input.advance(idx), ())),
951 None => Ok((input.advance(input.len()), ())),
952 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700953 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700954 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700955 }
956}
957
958macro_rules! next_ch {
959 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
960 match $chars.next() {
961 Some((_, ch)) => match ch {
962 $pat $(| $rest)* => ch,
963 _ => return false,
964 },
965 None => return false
966 }
967 };
968}
969
970fn backslash_x_char<I>(chars: &mut I) -> bool
971 where I: Iterator<Item = (usize, char)>
972{
973 next_ch!(chars @ '0'...'7');
974 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
975 true
976}
977
978fn backslash_x_byte<I>(chars: &mut I) -> bool
979 where I: Iterator<Item = (usize, u8)>
980{
981 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
982 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
983 true
984}
985
986fn backslash_u<I>(chars: &mut I) -> bool
987 where I: Iterator<Item = (usize, char)>
988{
989 next_ch!(chars @ '{');
990 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
David Tolnay8d109342017-12-25 18:24:45 -0500991 loop {
992 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '_' | '}');
993 if c == '}' {
994 return true;
995 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700996 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700997}
998
Nika Layzellf8d5f212017-12-11 14:07:02 -0500999fn float(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001000 let (rest, ()) = float_digits(input)?;
1001 for suffix in &["f32", "f64"] {
1002 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001003 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001004 }
1005 }
1006 word_break(rest)
1007}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001008
Nika Layzellf8d5f212017-12-11 14:07:02 -05001009fn float_digits(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001010 let mut chars = input.chars().peekable();
1011 match chars.next() {
1012 Some(ch) if ch >= '0' && ch <= '9' => {}
David Tolnay1218e122017-06-01 11:13:45 -07001013 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001014 }
1015
1016 let mut len = 1;
1017 let mut has_dot = false;
1018 let mut has_exp = false;
1019 while let Some(&ch) = chars.peek() {
1020 match ch {
1021 '0'...'9' | '_' => {
1022 chars.next();
1023 len += 1;
1024 }
1025 '.' => {
1026 if has_dot {
1027 break;
1028 }
1029 chars.next();
1030 if chars.peek()
1031 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1032 .unwrap_or(false) {
David Tolnay1218e122017-06-01 11:13:45 -07001033 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001034 }
1035 len += 1;
1036 has_dot = true;
1037 }
1038 'e' | 'E' => {
1039 chars.next();
1040 len += 1;
1041 has_exp = true;
1042 break;
1043 }
1044 _ => break,
1045 }
1046 }
1047
Nika Layzellf8d5f212017-12-11 14:07:02 -05001048 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001049 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001050 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001051 }
1052
1053 if has_exp {
1054 let mut has_exp_value = false;
1055 while let Some(&ch) = chars.peek() {
1056 match ch {
1057 '+' | '-' => {
1058 if has_exp_value {
1059 break;
1060 }
1061 chars.next();
1062 len += 1;
1063 }
1064 '0'...'9' => {
1065 chars.next();
1066 len += 1;
1067 has_exp_value = true;
1068 }
1069 '_' => {
1070 chars.next();
1071 len += 1;
1072 }
1073 _ => break,
1074 }
1075 }
1076 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001077 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001078 }
1079 }
1080
Nika Layzellf8d5f212017-12-11 14:07:02 -05001081 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001082}
1083
Nika Layzellf8d5f212017-12-11 14:07:02 -05001084fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001085 let (rest, ()) = digits(input)?;
1086 for suffix in &[
1087 "isize",
1088 "i8",
1089 "i16",
1090 "i32",
1091 "i64",
1092 "i128",
1093 "usize",
1094 "u8",
1095 "u16",
1096 "u32",
1097 "u64",
1098 "u128",
1099 ] {
1100 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001101 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001102 }
1103 }
1104 word_break(rest)
1105}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001106
Nika Layzellf8d5f212017-12-11 14:07:02 -05001107fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001108 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001109 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001110 16
1111 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001112 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001113 8
1114 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001115 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001116 2
1117 } else {
1118 10
1119 };
1120
Alex Crichton44bffbc2017-05-19 17:51:59 -07001121 let mut len = 0;
1122 let mut empty = true;
1123 for b in input.bytes() {
1124 let digit = match b {
1125 b'0'...b'9' => (b - b'0') as u64,
1126 b'a'...b'f' => 10 + (b - b'a') as u64,
1127 b'A'...b'F' => 10 + (b - b'A') as u64,
1128 b'_' => {
1129 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001130 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001131 }
1132 len += 1;
1133 continue;
1134 }
1135 _ => break,
1136 };
1137 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001138 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001139 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001140 len += 1;
1141 empty = false;
1142 }
1143 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001144 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001145 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001146 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001147 }
1148}
1149
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001150fn op(input: Cursor) -> PResult<Op> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001151 let input = skip_whitespace(input);
1152 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001153 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001154 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001155 Ok(_) => Spacing::Joint,
1156 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001157 };
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001158 Ok((rest, Op::new(ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001159 }
David Tolnay1218e122017-06-01 11:13:45 -07001160 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001161 }
1162}
1163
Nika Layzellf8d5f212017-12-11 14:07:02 -05001164fn op_char(input: Cursor) -> PResult<char> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001165 let mut chars = input.chars();
1166 let first = match chars.next() {
1167 Some(ch) => ch,
1168 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001169 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001170 }
1171 };
1172 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1173 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001174 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001175 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001176 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001177 }
1178}
1179
Alex Crichton44bffbc2017-05-19 17:51:59 -07001180named!(doc_comment -> (), alt!(
1181 do_parse!(
1182 punct!("//!") >>
Alex Crichtond7904e52018-01-23 11:08:45 -08001183 take_until_newline_or_eof!() >>
Alex Crichton44bffbc2017-05-19 17:51:59 -07001184 (())
1185 )
1186 |
1187 do_parse!(
1188 option!(whitespace) >>
1189 peek!(tag!("/*!")) >>
1190 block_comment >>
1191 (())
1192 )
1193 |
1194 do_parse!(
1195 punct!("///") >>
1196 not!(tag!("/")) >>
Alex Crichtond7904e52018-01-23 11:08:45 -08001197 take_until_newline_or_eof!() >>
Alex Crichton44bffbc2017-05-19 17:51:59 -07001198 (())
1199 )
1200 |
1201 do_parse!(
1202 option!(whitespace) >>
1203 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1204 block_comment >>
1205 (())
1206 )
1207));