blob: 6312aceb3af9fd3ade6e7ea251e82eb55d49ab34 [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() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500907 Some((offset, _)) => Ok((input.advance(offset), ())),
908 None => Ok((input.advance(input.len()), ())),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700909 }
910 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700911 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700912 }
913}
914
915named!(character -> (), do_parse!(
916 punct!("'") >>
917 cooked_char >>
918 tag!("'") >>
919 (())
920));
921
Nika Layzellf8d5f212017-12-11 14:07:02 -0500922fn cooked_char(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700923 let mut chars = input.char_indices();
924 let ok = match chars.next().map(|(_, ch)| ch) {
925 Some('\\') => {
926 match chars.next().map(|(_, ch)| ch) {
927 Some('x') => backslash_x_char(&mut chars),
928 Some('u') => backslash_u(&mut chars),
929 Some('n') |
930 Some('r') |
931 Some('t') |
932 Some('\\') |
933 Some('0') |
934 Some('\'') |
935 Some('"') => true,
936 _ => false,
937 }
938 }
939 ch => ch.is_some(),
940 };
941 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500942 match chars.next() {
943 Some((idx, _)) => Ok((input.advance(idx), ())),
944 None => Ok((input.advance(input.len()), ())),
945 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700946 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700947 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700948 }
949}
950
951macro_rules! next_ch {
952 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
953 match $chars.next() {
954 Some((_, ch)) => match ch {
955 $pat $(| $rest)* => ch,
956 _ => return false,
957 },
958 None => return false
959 }
960 };
961}
962
963fn backslash_x_char<I>(chars: &mut I) -> bool
964 where I: Iterator<Item = (usize, char)>
965{
966 next_ch!(chars @ '0'...'7');
967 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
968 true
969}
970
971fn backslash_x_byte<I>(chars: &mut I) -> bool
972 where I: Iterator<Item = (usize, u8)>
973{
974 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
975 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
976 true
977}
978
979fn backslash_u<I>(chars: &mut I) -> bool
980 where I: Iterator<Item = (usize, char)>
981{
982 next_ch!(chars @ '{');
983 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
David Tolnay8d109342017-12-25 18:24:45 -0500984 loop {
985 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '_' | '}');
986 if c == '}' {
987 return true;
988 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700989 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700990}
991
Nika Layzellf8d5f212017-12-11 14:07:02 -0500992fn float(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -0700993 let (rest, ()) = float_digits(input)?;
994 for suffix in &["f32", "f64"] {
995 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500996 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -0700997 }
998 }
999 word_break(rest)
1000}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001001
Nika Layzellf8d5f212017-12-11 14:07:02 -05001002fn float_digits(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001003 let mut chars = input.chars().peekable();
1004 match chars.next() {
1005 Some(ch) if ch >= '0' && ch <= '9' => {}
David Tolnay1218e122017-06-01 11:13:45 -07001006 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001007 }
1008
1009 let mut len = 1;
1010 let mut has_dot = false;
1011 let mut has_exp = false;
1012 while let Some(&ch) = chars.peek() {
1013 match ch {
1014 '0'...'9' | '_' => {
1015 chars.next();
1016 len += 1;
1017 }
1018 '.' => {
1019 if has_dot {
1020 break;
1021 }
1022 chars.next();
1023 if chars.peek()
1024 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1025 .unwrap_or(false) {
David Tolnay1218e122017-06-01 11:13:45 -07001026 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001027 }
1028 len += 1;
1029 has_dot = true;
1030 }
1031 'e' | 'E' => {
1032 chars.next();
1033 len += 1;
1034 has_exp = true;
1035 break;
1036 }
1037 _ => break,
1038 }
1039 }
1040
Nika Layzellf8d5f212017-12-11 14:07:02 -05001041 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001042 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001043 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001044 }
1045
1046 if has_exp {
1047 let mut has_exp_value = false;
1048 while let Some(&ch) = chars.peek() {
1049 match ch {
1050 '+' | '-' => {
1051 if has_exp_value {
1052 break;
1053 }
1054 chars.next();
1055 len += 1;
1056 }
1057 '0'...'9' => {
1058 chars.next();
1059 len += 1;
1060 has_exp_value = true;
1061 }
1062 '_' => {
1063 chars.next();
1064 len += 1;
1065 }
1066 _ => break,
1067 }
1068 }
1069 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001070 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001071 }
1072 }
1073
Nika Layzellf8d5f212017-12-11 14:07:02 -05001074 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001075}
1076
Nika Layzellf8d5f212017-12-11 14:07:02 -05001077fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001078 let (rest, ()) = digits(input)?;
1079 for suffix in &[
1080 "isize",
1081 "i8",
1082 "i16",
1083 "i32",
1084 "i64",
1085 "i128",
1086 "usize",
1087 "u8",
1088 "u16",
1089 "u32",
1090 "u64",
1091 "u128",
1092 ] {
1093 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001094 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001095 }
1096 }
1097 word_break(rest)
1098}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001099
Nika Layzellf8d5f212017-12-11 14:07:02 -05001100fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001101 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001102 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001103 16
1104 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001105 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001106 8
1107 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001108 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001109 2
1110 } else {
1111 10
1112 };
1113
Alex Crichton44bffbc2017-05-19 17:51:59 -07001114 let mut len = 0;
1115 let mut empty = true;
1116 for b in input.bytes() {
1117 let digit = match b {
1118 b'0'...b'9' => (b - b'0') as u64,
1119 b'a'...b'f' => 10 + (b - b'a') as u64,
1120 b'A'...b'F' => 10 + (b - b'A') as u64,
1121 b'_' => {
1122 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001123 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001124 }
1125 len += 1;
1126 continue;
1127 }
1128 _ => break,
1129 };
1130 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001131 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001132 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001133 len += 1;
1134 empty = false;
1135 }
1136 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001137 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001138 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001139 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001140 }
1141}
1142
Nika Layzellf8d5f212017-12-11 14:07:02 -05001143fn op(input: Cursor) -> PResult<(char, Spacing)> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001144 let input = skip_whitespace(input);
1145 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001146 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001147 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001148 Ok(_) => Spacing::Joint,
1149 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001150 };
David Tolnay1218e122017-06-01 11:13:45 -07001151 Ok((rest, (ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001152 }
David Tolnay1218e122017-06-01 11:13:45 -07001153 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001154 }
1155}
1156
Nika Layzellf8d5f212017-12-11 14:07:02 -05001157fn op_char(input: Cursor) -> PResult<char> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001158 let mut chars = input.chars();
1159 let first = match chars.next() {
1160 Some(ch) => ch,
1161 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001162 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001163 }
1164 };
1165 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1166 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001167 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001168 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001169 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001170 }
1171}
1172
Alex Crichton44bffbc2017-05-19 17:51:59 -07001173named!(doc_comment -> (), alt!(
1174 do_parse!(
1175 punct!("//!") >>
1176 take_until!("\n") >>
1177 (())
1178 )
1179 |
1180 do_parse!(
1181 option!(whitespace) >>
1182 peek!(tag!("/*!")) >>
1183 block_comment >>
1184 (())
1185 )
1186 |
1187 do_parse!(
1188 punct!("///") >>
1189 not!(tag!("/")) >>
1190 take_until!("\n") >>
1191 (())
1192 )
1193 |
1194 do_parse!(
1195 option!(whitespace) >>
1196 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1197 block_comment >>
1198 (())
1199 )
1200));