blob: ffa077a295319921699e1f88afda5c2bfa61b5e8 [file] [log] [blame]
Alex Crichton76a5cc82017-05-23 07:01:44 -07001use std::ascii;
Alex Crichton44bffbc2017-05-19 17:51:59 -07002use std::borrow::Borrow;
3use std::cell::RefCell;
David Tolnay1ebe3972018-01-02 20:14:20 -08004#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -05005use std::cmp;
Alex Crichton44bffbc2017-05-19 17:51:59 -07006use std::collections::HashMap;
7use std::fmt;
8use std::iter;
David Tolnay041bcd42017-06-03 09:18:04 -07009use std::marker::PhantomData;
Alex Crichton44bffbc2017-05-19 17:51:59 -070010use std::rc::Rc;
11use std::str::FromStr;
12use std::vec;
13
14use proc_macro;
David Tolnayb1032662017-05-31 15:52:28 -070015use unicode_xid::UnicodeXID;
Nika Layzellf8d5f212017-12-11 14:07:02 -050016use strnom::{Cursor, PResult, skip_whitespace, block_comment, whitespace, word_break};
Alex Crichton44bffbc2017-05-19 17:51:59 -070017
Alex Crichton1a7f7622017-07-05 17:47:15 -070018use {TokenTree, TokenNode, Delimiter, Spacing};
Alex Crichton44bffbc2017-05-19 17:51:59 -070019
David Tolnay977f8282017-05-31 17:41:33 -070020#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -070021pub struct TokenStream {
22 inner: Vec<TokenTree>,
23}
24
25#[derive(Debug)]
26pub struct LexError;
27
28impl TokenStream {
29 pub fn empty() -> TokenStream {
30 TokenStream { inner: Vec::new() }
31 }
32
33 pub fn is_empty(&self) -> bool {
34 self.inner.len() == 0
35 }
36}
37
David Tolnay1ebe3972018-01-02 20:14:20 -080038#[cfg(procmacro2_semver_exempt)]
Nika Layzella9dbc182017-12-30 14:50:13 -050039fn get_cursor(src: &str) -> Cursor {
40 // Create a dummy file & add it to the codemap
41 CODEMAP.with(|cm| {
42 let mut cm = cm.borrow_mut();
43 let name = format!("<parsed string {}>", cm.files.len());
44 let span = cm.add_file(&name, src);
45 Cursor {
46 rest: src,
47 off: span.lo,
48 }
49 })
50}
51
David Tolnay1ebe3972018-01-02 20:14:20 -080052#[cfg(not(procmacro2_semver_exempt))]
Nika Layzella9dbc182017-12-30 14:50:13 -050053fn get_cursor(src: &str) -> Cursor {
54 Cursor {
55 rest: src,
Nika Layzella9dbc182017-12-30 14:50:13 -050056 }
57}
58
Alex Crichton44bffbc2017-05-19 17:51:59 -070059impl FromStr for TokenStream {
60 type Err = LexError;
61
62 fn from_str(src: &str) -> Result<TokenStream, LexError> {
Nika Layzellf8d5f212017-12-11 14:07:02 -050063 // Create a dummy file & add it to the codemap
Nika Layzella9dbc182017-12-30 14:50:13 -050064 let cursor = get_cursor(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -050065
66 match token_stream(cursor) {
David Tolnay1218e122017-06-01 11:13:45 -070067 Ok((input, output)) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -070068 if skip_whitespace(input).len() != 0 {
69 Err(LexError)
70 } else {
David Tolnay8e976c62017-06-01 12:12:29 -070071 Ok(output.0)
Alex Crichton44bffbc2017-05-19 17:51:59 -070072 }
73 }
David Tolnay1218e122017-06-01 11:13:45 -070074 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -070075 }
76 }
77}
78
79impl fmt::Display for TokenStream {
80 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81 let mut joint = false;
82 for (i, tt) in self.inner.iter().enumerate() {
83 if i != 0 && !joint {
84 write!(f, " ")?;
85 }
86 joint = false;
87 match tt.kind {
Alex Crichton1a7f7622017-07-05 17:47:15 -070088 TokenNode::Group(delim, ref stream) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -070089 let (start, end) = match delim {
90 Delimiter::Parenthesis => ("(", ")"),
91 Delimiter::Brace => ("{", "}"),
92 Delimiter::Bracket => ("[", "]"),
93 Delimiter::None => ("", ""),
94 };
Alex Crichton852d53d2017-05-19 19:25:08 -070095 if stream.0.inner.len() == 0 {
96 write!(f, "{} {}", start, end)?
97 } else {
98 write!(f, "{} {} {}", start, stream, end)?
99 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700100 }
Alex Crichton1a7f7622017-07-05 17:47:15 -0700101 TokenNode::Term(ref sym) => write!(f, "{}", sym.as_str())?,
102 TokenNode::Op(ch, ref op) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700103 write!(f, "{}", ch)?;
104 match *op {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700105 Spacing::Alone => {}
106 Spacing::Joint => joint = true,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700107 }
108 }
Alex Crichton1a7f7622017-07-05 17:47:15 -0700109 TokenNode::Literal(ref literal) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700110 write!(f, "{}", literal)?;
111 // handle comments
112 if (literal.0).0.starts_with("/") {
113 write!(f, "\n")?;
114 }
115 }
116 }
117 }
118
119 Ok(())
120 }
121}
122
123impl From<proc_macro::TokenStream> for TokenStream {
124 fn from(inner: proc_macro::TokenStream) -> TokenStream {
125 inner.to_string().parse().expect("compiler token stream parse failed")
126 }
127}
128
129impl From<TokenStream> for proc_macro::TokenStream {
130 fn from(inner: TokenStream) -> proc_macro::TokenStream {
131 inner.to_string().parse().expect("failed to parse to compiler tokens")
132 }
133}
134
135
136impl From<TokenTree> for TokenStream {
137 fn from(tree: TokenTree) -> TokenStream {
138 TokenStream { inner: vec![tree] }
139 }
140}
141
142impl iter::FromIterator<TokenStream> for TokenStream {
143 fn from_iter<I: IntoIterator<Item=TokenStream>>(streams: I) -> Self {
144 let mut v = Vec::new();
145
146 for stream in streams.into_iter() {
147 v.extend(stream.inner);
148 }
149
150 TokenStream { inner: v }
151 }
152}
153
Alex Crichton1a7f7622017-07-05 17:47:15 -0700154pub type TokenTreeIter = vec::IntoIter<TokenTree>;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700155
156impl IntoIterator for TokenStream {
157 type Item = TokenTree;
Alex Crichton1a7f7622017-07-05 17:47:15 -0700158 type IntoIter = TokenTreeIter;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700159
Alex Crichton1a7f7622017-07-05 17:47:15 -0700160 fn into_iter(self) -> TokenTreeIter {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700161 self.inner.into_iter()
162 }
163}
164
David Tolnay1ebe3972018-01-02 20:14:20 -0800165#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500166#[derive(Clone, PartialEq, Eq, Debug)]
167pub struct FileName(String);
168
David Tolnay1ebe3972018-01-02 20:14:20 -0800169#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500170impl fmt::Display for FileName {
171 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
172 self.0.fmt(f)
173 }
174}
175
David Tolnay1ebe3972018-01-02 20:14:20 -0800176#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500177#[derive(Clone, PartialEq, Eq)]
178pub struct SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500179 name: FileName,
Nika Layzellf8d5f212017-12-11 14:07:02 -0500180}
181
David Tolnay1ebe3972018-01-02 20:14:20 -0800182#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500183impl SourceFile {
184 /// Get the path to this source file as a string.
Nika Layzellb35a9a32017-12-30 14:34:35 -0500185 pub fn path(&self) -> &FileName {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500186 &self.name
187 }
188
189 pub fn is_real(&self) -> bool {
190 // XXX(nika): Support real files in the future?
191 false
192 }
193}
194
David Tolnay1ebe3972018-01-02 20:14:20 -0800195#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500196impl AsRef<FileName> for SourceFile {
197 fn as_ref(&self) -> &FileName {
198 self.path()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500199 }
200}
201
David Tolnay1ebe3972018-01-02 20:14:20 -0800202#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500203impl fmt::Debug for SourceFile {
204 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
205 f.debug_struct("SourceFile")
Nika Layzellb35a9a32017-12-30 14:34:35 -0500206 .field("path", &self.path())
Nika Layzellf8d5f212017-12-11 14:07:02 -0500207 .field("is_real", &self.is_real())
208 .finish()
209 }
210}
211
David Tolnay1ebe3972018-01-02 20:14:20 -0800212#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500213#[derive(Clone, Copy, Debug, PartialEq, Eq)]
214pub struct LineColumn {
215 pub line: usize,
216 pub column: usize,
217}
218
David Tolnay1ebe3972018-01-02 20:14:20 -0800219#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500220thread_local! {
221 static CODEMAP: RefCell<Codemap> = RefCell::new(Codemap {
222 // NOTE: We start with a single dummy file which all call_site() and
223 // def_site() spans reference.
224 files: vec![FileInfo {
225 name: "<unspecified>".to_owned(),
226 span: Span { lo: 0, hi: 0 },
227 lines: vec![0],
228 }],
229 });
230}
231
David Tolnay1ebe3972018-01-02 20:14:20 -0800232#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500233struct FileInfo {
234 name: String,
235 span: Span,
236 lines: Vec<usize>,
237}
238
David Tolnay1ebe3972018-01-02 20:14:20 -0800239#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500240impl FileInfo {
241 fn offset_line_column(&self, offset: usize) -> LineColumn {
242 assert!(self.span_within(Span { lo: offset as u32, hi: offset as u32 }));
243 let offset = offset - self.span.lo as usize;
244 match self.lines.binary_search(&offset) {
245 Ok(found) => LineColumn {
246 line: found + 1,
247 column: 0
248 },
249 Err(idx) => LineColumn {
250 line: idx,
251 column: offset - self.lines[idx - 1]
252 },
253 }
254 }
255
256 fn span_within(&self, span: Span) -> bool {
257 span.lo >= self.span.lo && span.hi <= self.span.hi
258 }
259}
260
261/// Computes the offsets of each line in the given source string.
David Tolnay1ebe3972018-01-02 20:14:20 -0800262#[cfg(procmacro2_semver_exempt)]
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500263fn lines_offsets(s: &str) -> Vec<usize> {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500264 let mut lines = vec![0];
265 let mut prev = 0;
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500266 while let Some(len) = s[prev..].find('\n') {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500267 prev += len + 1;
268 lines.push(prev);
269 }
270 lines
271}
272
David Tolnay1ebe3972018-01-02 20:14:20 -0800273#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500274struct Codemap {
275 files: Vec<FileInfo>,
276}
277
David Tolnay1ebe3972018-01-02 20:14:20 -0800278#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500279impl Codemap {
280 fn next_start_pos(&self) -> u32 {
281 // Add 1 so there's always space between files.
282 //
283 // We'll always have at least 1 file, as we initialize our files list
284 // with a dummy file.
285 self.files.last().unwrap().span.hi + 1
286 }
287
288 fn add_file(&mut self, name: &str, src: &str) -> Span {
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500289 let lines = lines_offsets(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -0500290 let lo = self.next_start_pos();
291 // XXX(nika): Shouild we bother doing a checked cast or checked add here?
292 let span = Span { lo: lo, hi: lo + (src.len() as u32) };
293
294 self.files.push(FileInfo {
295 name: name.to_owned(),
296 span: span,
297 lines: lines,
298 });
299
300 span
301 }
302
303 fn fileinfo(&self, span: Span) -> &FileInfo {
304 for file in &self.files {
305 if file.span_within(span) {
306 return file;
307 }
308 }
309 panic!("Invalid span with no related FileInfo!");
310 }
311}
312
Alex Crichtone6085b72017-11-21 07:24:25 -0800313#[derive(Clone, Copy, Debug)]
David Tolnayddfca052017-12-31 10:41:24 -0500314pub struct Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800315 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500316 lo: u32,
David Tolnay1ebe3972018-01-02 20:14:20 -0800317 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500318 hi: u32,
319}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700320
321impl Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800322 #[cfg(not(procmacro2_semver_exempt))]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700323 pub fn call_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500324 Span {}
325 }
326
David Tolnay1ebe3972018-01-02 20:14:20 -0800327 #[cfg(procmacro2_semver_exempt)]
David Tolnay79105e52017-12-31 11:03:04 -0500328 pub fn call_site() -> Span {
329 Span { lo: 0, hi: 0 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700330 }
Alex Crichtone6085b72017-11-21 07:24:25 -0800331
332 pub fn def_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500333 Span::call_site()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500334 }
335
David Tolnay4e8e3972018-01-05 18:10:22 -0800336 pub fn resolved_at(&self, _other: Span) -> Span {
337 // Stable spans consist only of line/column information, so
338 // `resolved_at` and `located_at` only select which span the
339 // caller wants line/column information from.
340 *self
341 }
342
343 pub fn located_at(&self, other: Span) -> Span {
344 other
345 }
346
David Tolnay1ebe3972018-01-02 20:14:20 -0800347 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500348 pub fn source_file(&self) -> SourceFile {
349 CODEMAP.with(|cm| {
350 let cm = cm.borrow();
351 let fi = cm.fileinfo(*self);
352 SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500353 name: FileName(fi.name.clone()),
Nika Layzellf8d5f212017-12-11 14:07:02 -0500354 }
355 })
356 }
357
David Tolnay1ebe3972018-01-02 20:14:20 -0800358 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500359 pub fn start(&self) -> LineColumn {
360 CODEMAP.with(|cm| {
361 let cm = cm.borrow();
362 let fi = cm.fileinfo(*self);
363 fi.offset_line_column(self.lo as usize)
364 })
365 }
366
David Tolnay1ebe3972018-01-02 20:14:20 -0800367 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500368 pub fn end(&self) -> LineColumn {
369 CODEMAP.with(|cm| {
370 let cm = cm.borrow();
371 let fi = cm.fileinfo(*self);
372 fi.offset_line_column(self.hi as usize)
373 })
374 }
375
David Tolnay1ebe3972018-01-02 20:14:20 -0800376 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500377 pub fn join(&self, other: Span) -> Option<Span> {
378 CODEMAP.with(|cm| {
379 let cm = cm.borrow();
380 // If `other` is not within the same FileInfo as us, return None.
381 if !cm.fileinfo(*self).span_within(other) {
382 return None;
383 }
384 Some(Span {
385 lo: cmp::min(self.lo, other.lo),
386 hi: cmp::max(self.hi, other.hi),
387 })
388 })
Alex Crichtone6085b72017-11-21 07:24:25 -0800389 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700390}
391
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700392#[derive(Copy, Clone)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700393pub struct Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700394 intern: usize,
395 not_send_sync: PhantomData<*const ()>,
396}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700397
398thread_local!(static SYMBOLS: RefCell<Interner> = RefCell::new(Interner::new()));
399
David Tolnay10effeb2018-01-06 11:07:49 -0800400impl Term {
401 pub fn intern(string: &str) -> Term {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700402 Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700403 intern: SYMBOLS.with(|s| s.borrow_mut().intern(string)),
404 not_send_sync: PhantomData,
405 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700406 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700407
David Tolnay10effeb2018-01-06 11:07:49 -0800408 pub fn as_str(&self) -> &str {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700409 SYMBOLS.with(|interner| {
410 let interner = interner.borrow();
David Tolnay041bcd42017-06-03 09:18:04 -0700411 let s = interner.get(self.intern);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700412 unsafe {
413 &*(s as *const str)
414 }
415 })
416 }
417}
418
Alex Crichton1a7f7622017-07-05 17:47:15 -0700419impl fmt::Debug for Term {
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700420 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
David Tolnay10effeb2018-01-06 11:07:49 -0800421 f.debug_tuple("Term").field(&self.as_str()).finish()
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700422 }
423}
424
Alex Crichton44bffbc2017-05-19 17:51:59 -0700425struct Interner {
426 string_to_index: HashMap<MyRc, usize>,
427 index_to_string: Vec<Rc<String>>,
428}
429
430#[derive(Hash, Eq, PartialEq)]
431struct MyRc(Rc<String>);
432
433impl Borrow<str> for MyRc {
434 fn borrow(&self) -> &str {
435 &self.0
436 }
437}
438
439impl Interner {
440 fn new() -> Interner {
441 Interner {
442 string_to_index: HashMap::new(),
443 index_to_string: Vec::new(),
444 }
445 }
446
447 fn intern(&mut self, s: &str) -> usize {
448 if let Some(&idx) = self.string_to_index.get(s) {
449 return idx
450 }
451 let s = Rc::new(s.to_string());
452 self.index_to_string.push(s.clone());
453 self.string_to_index.insert(MyRc(s), self.index_to_string.len() - 1);
454 self.index_to_string.len() - 1
455 }
456
457 fn get(&self, idx: usize) -> &str {
458 &self.index_to_string[idx]
459 }
460}
461
David Tolnay977f8282017-05-31 17:41:33 -0700462#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700463pub struct Literal(String);
464
Alex Crichton852d53d2017-05-19 19:25:08 -0700465impl Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700466 pub fn byte_char(byte: u8) -> Literal {
Alex Crichton76a5cc82017-05-23 07:01:44 -0700467 match byte {
468 0 => Literal(format!("b'\\0'")),
469 b'\"' => Literal(format!("b'\"'")),
470 n => {
471 let mut escaped = "b'".to_string();
472 escaped.extend(ascii::escape_default(n).map(|c| c as char));
473 escaped.push('\'');
474 Literal(escaped)
475 }
476 }
477 }
478
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700479 pub fn byte_string(bytes: &[u8]) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700480 let mut escaped = "b\"".to_string();
481 for b in bytes {
482 match *b {
483 b'\0' => escaped.push_str(r"\0"),
484 b'\t' => escaped.push_str(r"\t"),
485 b'\n' => escaped.push_str(r"\n"),
486 b'\r' => escaped.push_str(r"\r"),
487 b'"' => escaped.push_str("\\\""),
488 b'\\' => escaped.push_str("\\\\"),
489 b'\x20' ... b'\x7E' => escaped.push(*b as char),
490 _ => escaped.push_str(&format!("\\x{:02X}", b)),
491 }
492 }
493 escaped.push('"');
494 Literal(escaped)
495 }
Alex Crichton76a5cc82017-05-23 07:01:44 -0700496
497 pub fn doccomment(s: &str) -> Literal {
498 Literal(s.to_string())
499 }
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700500
David Tolnay114990e2018-01-05 11:17:08 -0800501 pub fn float(n: f64) -> Literal {
502 if !n.is_finite() {
503 panic!("Invalid float literal {}", n);
504 }
505 let mut s = n.to_string();
506 if !s.contains('.') {
507 s += ".0";
508 }
509 Literal(s)
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700510 }
511
Alex Crichton1a7f7622017-07-05 17:47:15 -0700512 pub fn integer(s: i64) -> Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700513 Literal(s.to_string())
514 }
Alex Crichton31316622017-05-26 12:54:47 -0700515
516 pub fn raw_string(s: &str, pounds: usize) -> Literal {
517 let mut ret = format!("r");
518 ret.extend((0..pounds).map(|_| "#"));
519 ret.push('"');
520 ret.push_str(s);
521 ret.push('"');
522 ret.extend((0..pounds).map(|_| "#"));
523 Literal(ret)
524 }
525
526 pub fn raw_byte_string(s: &str, pounds: usize) -> Literal {
Alex Crichton7ed6d282017-05-26 13:42:50 -0700527 let mut ret = format!("br");
Alex Crichton31316622017-05-26 12:54:47 -0700528 ret.extend((0..pounds).map(|_| "#"));
529 ret.push('"');
530 ret.push_str(s);
531 ret.push('"');
532 ret.extend((0..pounds).map(|_| "#"));
533 Literal(ret)
534 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700535}
536
Alex Crichton44bffbc2017-05-19 17:51:59 -0700537impl fmt::Display for Literal {
538 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
539 self.0.fmt(f)
540 }
541}
542
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700543macro_rules! ints {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700544 ($($t:ty,)*) => {$(
545 impl From<$t> for Literal {
546 fn from(t: $t) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700547 Literal(format!(concat!("{}", stringify!($t)), t))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700548 }
549 }
550 )*}
551}
552
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700553ints! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700554 u8, u16, u32, u64, usize,
555 i8, i16, i32, i64, isize,
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700556}
557
558macro_rules! floats {
559 ($($t:ty,)*) => {$(
560 impl From<$t> for Literal {
561 fn from(t: $t) -> Literal {
562 assert!(!t.is_nan());
563 assert!(!t.is_infinite());
564 Literal(format!(concat!("{}", stringify!($t)), t))
565 }
566 }
567 )*}
568}
569
570floats! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700571 f32, f64,
572}
573
Alex Crichton44bffbc2017-05-19 17:51:59 -0700574impl<'a> From<&'a str> for Literal {
575 fn from(t: &'a str) -> Literal {
576 let mut s = t.chars().flat_map(|c| c.escape_default()).collect::<String>();
577 s.push('"');
578 s.insert(0, '"');
579 Literal(s)
580 }
581}
582
583impl From<char> for Literal {
584 fn from(t: char) -> Literal {
Alex Crichton2d0cf0b2017-05-26 14:00:16 -0700585 Literal(format!("'{}'", t.escape_default().collect::<String>()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700586 }
587}
588
David Tolnay8e976c62017-06-01 12:12:29 -0700589named!(token_stream -> ::TokenStream, map!(
590 many0!(token_tree),
591 |trees| ::TokenStream(TokenStream { inner: trees })
592));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700593
David Tolnay1ebe3972018-01-02 20:14:20 -0800594#[cfg(not(procmacro2_semver_exempt))]
David Tolnayddfca052017-12-31 10:41:24 -0500595fn token_tree(input: Cursor) -> PResult<TokenTree> {
596 let (input, kind) = token_kind(input)?;
597 Ok((input, TokenTree {
598 span: ::Span(Span {}),
599 kind: kind,
600 }))
601}
602
David Tolnay1ebe3972018-01-02 20:14:20 -0800603#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500604fn token_tree(input: Cursor) -> PResult<TokenTree> {
605 let input = skip_whitespace(input);
606 let lo = input.off;
607 let (input, kind) = token_kind(input)?;
608 let hi = input.off;
609 Ok((input, TokenTree {
610 span: ::Span(Span {
611 lo: lo,
612 hi: hi,
613 }),
614 kind: kind,
615 }))
616}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700617
Alex Crichton1a7f7622017-07-05 17:47:15 -0700618named!(token_kind -> TokenNode, alt!(
619 map!(delimited, |(d, s)| TokenNode::Group(d, s))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700620 |
Alex Crichton1a7f7622017-07-05 17:47:15 -0700621 map!(literal, TokenNode::Literal) // must be before symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700622 |
Alex Crichton52725f72017-08-28 12:20:58 -0700623 symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700624 |
Alex Crichton1a7f7622017-07-05 17:47:15 -0700625 map!(op, |(op, kind)| TokenNode::Op(op, kind))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700626));
627
David Tolnay8e976c62017-06-01 12:12:29 -0700628named!(delimited -> (Delimiter, ::TokenStream), alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -0700629 delimited!(
630 punct!("("),
631 token_stream,
632 punct!(")")
633 ) => { |ts| (Delimiter::Parenthesis, ts) }
634 |
635 delimited!(
636 punct!("["),
637 token_stream,
638 punct!("]")
639 ) => { |ts| (Delimiter::Bracket, ts) }
640 |
641 delimited!(
642 punct!("{"),
643 token_stream,
644 punct!("}")
645 ) => { |ts| (Delimiter::Brace, ts) }
646));
647
Nika Layzellf8d5f212017-12-11 14:07:02 -0500648fn symbol(mut input: Cursor) -> PResult<TokenNode> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700649 input = skip_whitespace(input);
650
651 let mut chars = input.char_indices();
David Tolnaya202d502017-06-01 12:26:55 -0700652
653 let lifetime = input.starts_with("'");
654 if lifetime {
655 chars.next();
656 }
657
Alex Crichton44bffbc2017-05-19 17:51:59 -0700658 match chars.next() {
659 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700660 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700661 }
662
David Tolnay214c94c2017-06-01 12:42:56 -0700663 let mut end = input.len();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700664 for (i, ch) in chars {
665 if !UnicodeXID::is_xid_continue(ch) {
David Tolnay214c94c2017-06-01 12:42:56 -0700666 end = i;
667 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700668 }
669 }
670
Nika Layzellf8d5f212017-12-11 14:07:02 -0500671 if lifetime && &input.rest[..end] != "'static" && KEYWORDS.contains(&&input.rest[1..end]) {
David Tolnay214c94c2017-06-01 12:42:56 -0700672 Err(LexError)
673 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500674 let a = &input.rest[..end];
Alex Crichton52725f72017-08-28 12:20:58 -0700675 if a == "_" {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500676 Ok((input.advance(end), TokenNode::Op('_', Spacing::Alone)))
Alex Crichton52725f72017-08-28 12:20:58 -0700677 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500678 Ok((input.advance(end), TokenNode::Term(::Term::intern(a))))
Alex Crichton52725f72017-08-28 12:20:58 -0700679 }
David Tolnay214c94c2017-06-01 12:42:56 -0700680 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700681}
682
David Tolnay214c94c2017-06-01 12:42:56 -0700683// From https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/symbol.rs
684static KEYWORDS: &'static [&'static str] = &[
685 "abstract", "alignof", "as", "become", "box", "break", "const", "continue",
686 "crate", "do", "else", "enum", "extern", "false", "final", "fn", "for",
687 "if", "impl", "in", "let", "loop", "macro", "match", "mod", "move", "mut",
688 "offsetof", "override", "priv", "proc", "pub", "pure", "ref", "return",
689 "self", "Self", "sizeof", "static", "struct", "super", "trait", "true",
690 "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while",
691 "yield",
692];
693
Nika Layzellf8d5f212017-12-11 14:07:02 -0500694fn literal(input: Cursor) -> PResult<::Literal> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700695 let input_no_ws = skip_whitespace(input);
696
697 match literal_nocapture(input_no_ws) {
David Tolnay1218e122017-06-01 11:13:45 -0700698 Ok((a, ())) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700699 let start = input.len() - input_no_ws.len();
700 let len = input_no_ws.len() - a.len();
701 let end = start + len;
Nika Layzellf8d5f212017-12-11 14:07:02 -0500702 Ok((a, ::Literal(Literal(input.rest[start..end].to_string()))))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700703 }
David Tolnay1218e122017-06-01 11:13:45 -0700704 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700705 }
706}
707
708named!(literal_nocapture -> (), alt!(
709 string
710 |
711 byte_string
712 |
713 byte
714 |
715 character
716 |
717 float
718 |
719 int
720 |
Alex Crichton44bffbc2017-05-19 17:51:59 -0700721 doc_comment
722));
723
724named!(string -> (), alt!(
725 quoted_string
726 |
727 preceded!(
728 punct!("r"),
729 raw_string
730 ) => { |_| () }
731));
732
733named!(quoted_string -> (), delimited!(
734 punct!("\""),
735 cooked_string,
736 tag!("\"")
737));
738
Nika Layzellf8d5f212017-12-11 14:07:02 -0500739fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700740 let mut chars = input.char_indices().peekable();
741 while let Some((byte_offset, ch)) = chars.next() {
742 match ch {
743 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500744 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700745 }
746 '\r' => {
747 if let Some((_, '\n')) = chars.next() {
748 // ...
749 } else {
750 break;
751 }
752 }
753 '\\' => {
754 match chars.next() {
755 Some((_, 'x')) => {
756 if !backslash_x_char(&mut chars) {
757 break
758 }
759 }
760 Some((_, 'n')) |
761 Some((_, 'r')) |
762 Some((_, 't')) |
763 Some((_, '\\')) |
764 Some((_, '\'')) |
765 Some((_, '"')) |
766 Some((_, '0')) => {}
767 Some((_, 'u')) => {
768 if !backslash_u(&mut chars) {
769 break
770 }
771 }
772 Some((_, '\n')) | Some((_, '\r')) => {
773 while let Some(&(_, ch)) = chars.peek() {
774 if ch.is_whitespace() {
775 chars.next();
776 } else {
777 break;
778 }
779 }
780 }
781 _ => break,
782 }
783 }
784 _ch => {}
785 }
786 }
David Tolnay1218e122017-06-01 11:13:45 -0700787 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700788}
789
790named!(byte_string -> (), alt!(
791 delimited!(
792 punct!("b\""),
793 cooked_byte_string,
794 tag!("\"")
795 ) => { |_| () }
796 |
797 preceded!(
798 punct!("br"),
799 raw_string
800 ) => { |_| () }
801));
802
Nika Layzellf8d5f212017-12-11 14:07:02 -0500803fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700804 let mut bytes = input.bytes().enumerate();
805 'outer: while let Some((offset, b)) = bytes.next() {
806 match b {
807 b'"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500808 return Ok((input.advance(offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700809 }
810 b'\r' => {
811 if let Some((_, b'\n')) = bytes.next() {
812 // ...
813 } else {
814 break;
815 }
816 }
817 b'\\' => {
818 match bytes.next() {
819 Some((_, b'x')) => {
820 if !backslash_x_byte(&mut bytes) {
821 break
822 }
823 }
824 Some((_, b'n')) |
825 Some((_, b'r')) |
826 Some((_, b't')) |
827 Some((_, b'\\')) |
828 Some((_, b'0')) |
829 Some((_, b'\'')) |
830 Some((_, b'"')) => {}
831 Some((newline, b'\n')) |
832 Some((newline, b'\r')) => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500833 let rest = input.advance(newline + 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700834 for (offset, ch) in rest.char_indices() {
835 if !ch.is_whitespace() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500836 input = rest.advance(offset);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700837 bytes = input.bytes().enumerate();
838 continue 'outer;
839 }
840 }
841 break;
842 }
843 _ => break,
844 }
845 }
846 b if b < 0x80 => {}
847 _ => break,
848 }
849 }
David Tolnay1218e122017-06-01 11:13:45 -0700850 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700851}
852
Nika Layzellf8d5f212017-12-11 14:07:02 -0500853fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700854 let mut chars = input.char_indices();
855 let mut n = 0;
856 while let Some((byte_offset, ch)) = chars.next() {
857 match ch {
858 '"' => {
859 n = byte_offset;
860 break;
861 }
862 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700863 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700864 }
865 }
866 for (byte_offset, ch) in chars {
867 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500868 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
869 let rest = input.advance(byte_offset + 1 + n);
David Tolnay1218e122017-06-01 11:13:45 -0700870 return Ok((rest, ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700871 }
872 '\r' => {}
873 _ => {}
874 }
875 }
David Tolnay1218e122017-06-01 11:13:45 -0700876 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700877}
878
879named!(byte -> (), do_parse!(
880 punct!("b") >>
881 tag!("'") >>
882 cooked_byte >>
883 tag!("'") >>
884 (())
885));
886
Nika Layzellf8d5f212017-12-11 14:07:02 -0500887fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700888 let mut bytes = input.bytes().enumerate();
889 let ok = match bytes.next().map(|(_, b)| b) {
890 Some(b'\\') => {
891 match bytes.next().map(|(_, b)| b) {
892 Some(b'x') => backslash_x_byte(&mut bytes),
893 Some(b'n') |
894 Some(b'r') |
895 Some(b't') |
896 Some(b'\\') |
897 Some(b'0') |
898 Some(b'\'') |
899 Some(b'"') => true,
900 _ => false,
901 }
902 }
903 b => b.is_some(),
904 };
905 if ok {
906 match bytes.next() {
Alex Crichton8c030332018-01-16 08:07:36 -0800907 Some((offset, _)) => {
908 if input.chars().as_str().is_char_boundary(offset) {
909 Ok((input.advance(offset), ()))
910 } else {
911 Err(LexError)
912 }
913 }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500914 None => Ok((input.advance(input.len()), ())),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700915 }
916 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700917 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700918 }
919}
920
921named!(character -> (), do_parse!(
922 punct!("'") >>
923 cooked_char >>
924 tag!("'") >>
925 (())
926));
927
Nika Layzellf8d5f212017-12-11 14:07:02 -0500928fn cooked_char(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700929 let mut chars = input.char_indices();
930 let ok = match chars.next().map(|(_, ch)| ch) {
931 Some('\\') => {
932 match chars.next().map(|(_, ch)| ch) {
933 Some('x') => backslash_x_char(&mut chars),
934 Some('u') => backslash_u(&mut chars),
935 Some('n') |
936 Some('r') |
937 Some('t') |
938 Some('\\') |
939 Some('0') |
940 Some('\'') |
941 Some('"') => true,
942 _ => false,
943 }
944 }
945 ch => ch.is_some(),
946 };
947 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500948 match chars.next() {
949 Some((idx, _)) => Ok((input.advance(idx), ())),
950 None => Ok((input.advance(input.len()), ())),
951 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700952 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700953 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700954 }
955}
956
957macro_rules! next_ch {
958 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
959 match $chars.next() {
960 Some((_, ch)) => match ch {
961 $pat $(| $rest)* => ch,
962 _ => return false,
963 },
964 None => return false
965 }
966 };
967}
968
969fn backslash_x_char<I>(chars: &mut I) -> bool
970 where I: Iterator<Item = (usize, char)>
971{
972 next_ch!(chars @ '0'...'7');
973 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
974 true
975}
976
977fn backslash_x_byte<I>(chars: &mut I) -> bool
978 where I: Iterator<Item = (usize, u8)>
979{
980 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
981 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
982 true
983}
984
985fn backslash_u<I>(chars: &mut I) -> bool
986 where I: Iterator<Item = (usize, char)>
987{
988 next_ch!(chars @ '{');
989 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
David Tolnay8d109342017-12-25 18:24:45 -0500990 loop {
991 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '_' | '}');
992 if c == '}' {
993 return true;
994 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700995 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700996}
997
Nika Layzellf8d5f212017-12-11 14:07:02 -0500998fn float(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -0700999 let (rest, ()) = float_digits(input)?;
1000 for suffix in &["f32", "f64"] {
1001 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001002 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001003 }
1004 }
1005 word_break(rest)
1006}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001007
Nika Layzellf8d5f212017-12-11 14:07:02 -05001008fn float_digits(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001009 let mut chars = input.chars().peekable();
1010 match chars.next() {
1011 Some(ch) if ch >= '0' && ch <= '9' => {}
David Tolnay1218e122017-06-01 11:13:45 -07001012 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001013 }
1014
1015 let mut len = 1;
1016 let mut has_dot = false;
1017 let mut has_exp = false;
1018 while let Some(&ch) = chars.peek() {
1019 match ch {
1020 '0'...'9' | '_' => {
1021 chars.next();
1022 len += 1;
1023 }
1024 '.' => {
1025 if has_dot {
1026 break;
1027 }
1028 chars.next();
1029 if chars.peek()
1030 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1031 .unwrap_or(false) {
David Tolnay1218e122017-06-01 11:13:45 -07001032 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001033 }
1034 len += 1;
1035 has_dot = true;
1036 }
1037 'e' | 'E' => {
1038 chars.next();
1039 len += 1;
1040 has_exp = true;
1041 break;
1042 }
1043 _ => break,
1044 }
1045 }
1046
Nika Layzellf8d5f212017-12-11 14:07:02 -05001047 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001048 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001049 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001050 }
1051
1052 if has_exp {
1053 let mut has_exp_value = false;
1054 while let Some(&ch) = chars.peek() {
1055 match ch {
1056 '+' | '-' => {
1057 if has_exp_value {
1058 break;
1059 }
1060 chars.next();
1061 len += 1;
1062 }
1063 '0'...'9' => {
1064 chars.next();
1065 len += 1;
1066 has_exp_value = true;
1067 }
1068 '_' => {
1069 chars.next();
1070 len += 1;
1071 }
1072 _ => break,
1073 }
1074 }
1075 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001076 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001077 }
1078 }
1079
Nika Layzellf8d5f212017-12-11 14:07:02 -05001080 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001081}
1082
Nika Layzellf8d5f212017-12-11 14:07:02 -05001083fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001084 let (rest, ()) = digits(input)?;
1085 for suffix in &[
1086 "isize",
1087 "i8",
1088 "i16",
1089 "i32",
1090 "i64",
1091 "i128",
1092 "usize",
1093 "u8",
1094 "u16",
1095 "u32",
1096 "u64",
1097 "u128",
1098 ] {
1099 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001100 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001101 }
1102 }
1103 word_break(rest)
1104}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001105
Nika Layzellf8d5f212017-12-11 14:07:02 -05001106fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001107 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001108 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001109 16
1110 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001111 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001112 8
1113 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001114 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001115 2
1116 } else {
1117 10
1118 };
1119
Alex Crichton44bffbc2017-05-19 17:51:59 -07001120 let mut len = 0;
1121 let mut empty = true;
1122 for b in input.bytes() {
1123 let digit = match b {
1124 b'0'...b'9' => (b - b'0') as u64,
1125 b'a'...b'f' => 10 + (b - b'a') as u64,
1126 b'A'...b'F' => 10 + (b - b'A') as u64,
1127 b'_' => {
1128 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001129 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001130 }
1131 len += 1;
1132 continue;
1133 }
1134 _ => break,
1135 };
1136 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001137 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001138 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001139 len += 1;
1140 empty = false;
1141 }
1142 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001143 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001144 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001145 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001146 }
1147}
1148
Nika Layzellf8d5f212017-12-11 14:07:02 -05001149fn op(input: Cursor) -> PResult<(char, Spacing)> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001150 let input = skip_whitespace(input);
1151 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001152 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001153 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001154 Ok(_) => Spacing::Joint,
1155 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001156 };
David Tolnay1218e122017-06-01 11:13:45 -07001157 Ok((rest, (ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001158 }
David Tolnay1218e122017-06-01 11:13:45 -07001159 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001160 }
1161}
1162
Nika Layzellf8d5f212017-12-11 14:07:02 -05001163fn op_char(input: Cursor) -> PResult<char> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001164 let mut chars = input.chars();
1165 let first = match chars.next() {
1166 Some(ch) => ch,
1167 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001168 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001169 }
1170 };
1171 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1172 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001173 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001174 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001175 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001176 }
1177}
1178
Alex Crichton44bffbc2017-05-19 17:51:59 -07001179named!(doc_comment -> (), alt!(
1180 do_parse!(
1181 punct!("//!") >>
1182 take_until!("\n") >>
1183 (())
1184 )
1185 |
1186 do_parse!(
1187 option!(whitespace) >>
1188 peek!(tag!("/*!")) >>
1189 block_comment >>
1190 (())
1191 )
1192 |
1193 do_parse!(
1194 punct!("///") >>
1195 not!(tag!("/")) >>
1196 take_until!("\n") >>
1197 (())
1198 )
1199 |
1200 do_parse!(
1201 option!(whitespace) >>
1202 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1203 block_comment >>
1204 (())
1205 )
1206));