blob: 8bf3a9f4ffa6a505fe327cb84108e98f9a071e42 [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 |
721 boolean
722 |
723 doc_comment
724));
725
726named!(string -> (), alt!(
727 quoted_string
728 |
729 preceded!(
730 punct!("r"),
731 raw_string
732 ) => { |_| () }
733));
734
735named!(quoted_string -> (), delimited!(
736 punct!("\""),
737 cooked_string,
738 tag!("\"")
739));
740
Nika Layzellf8d5f212017-12-11 14:07:02 -0500741fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700742 let mut chars = input.char_indices().peekable();
743 while let Some((byte_offset, ch)) = chars.next() {
744 match ch {
745 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500746 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700747 }
748 '\r' => {
749 if let Some((_, '\n')) = chars.next() {
750 // ...
751 } else {
752 break;
753 }
754 }
755 '\\' => {
756 match chars.next() {
757 Some((_, 'x')) => {
758 if !backslash_x_char(&mut chars) {
759 break
760 }
761 }
762 Some((_, 'n')) |
763 Some((_, 'r')) |
764 Some((_, 't')) |
765 Some((_, '\\')) |
766 Some((_, '\'')) |
767 Some((_, '"')) |
768 Some((_, '0')) => {}
769 Some((_, 'u')) => {
770 if !backslash_u(&mut chars) {
771 break
772 }
773 }
774 Some((_, '\n')) | Some((_, '\r')) => {
775 while let Some(&(_, ch)) = chars.peek() {
776 if ch.is_whitespace() {
777 chars.next();
778 } else {
779 break;
780 }
781 }
782 }
783 _ => break,
784 }
785 }
786 _ch => {}
787 }
788 }
David Tolnay1218e122017-06-01 11:13:45 -0700789 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700790}
791
792named!(byte_string -> (), alt!(
793 delimited!(
794 punct!("b\""),
795 cooked_byte_string,
796 tag!("\"")
797 ) => { |_| () }
798 |
799 preceded!(
800 punct!("br"),
801 raw_string
802 ) => { |_| () }
803));
804
Nika Layzellf8d5f212017-12-11 14:07:02 -0500805fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700806 let mut bytes = input.bytes().enumerate();
807 'outer: while let Some((offset, b)) = bytes.next() {
808 match b {
809 b'"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500810 return Ok((input.advance(offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700811 }
812 b'\r' => {
813 if let Some((_, b'\n')) = bytes.next() {
814 // ...
815 } else {
816 break;
817 }
818 }
819 b'\\' => {
820 match bytes.next() {
821 Some((_, b'x')) => {
822 if !backslash_x_byte(&mut bytes) {
823 break
824 }
825 }
826 Some((_, b'n')) |
827 Some((_, b'r')) |
828 Some((_, b't')) |
829 Some((_, b'\\')) |
830 Some((_, b'0')) |
831 Some((_, b'\'')) |
832 Some((_, b'"')) => {}
833 Some((newline, b'\n')) |
834 Some((newline, b'\r')) => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500835 let rest = input.advance(newline + 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700836 for (offset, ch) in rest.char_indices() {
837 if !ch.is_whitespace() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500838 input = rest.advance(offset);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700839 bytes = input.bytes().enumerate();
840 continue 'outer;
841 }
842 }
843 break;
844 }
845 _ => break,
846 }
847 }
848 b if b < 0x80 => {}
849 _ => break,
850 }
851 }
David Tolnay1218e122017-06-01 11:13:45 -0700852 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700853}
854
Nika Layzellf8d5f212017-12-11 14:07:02 -0500855fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700856 let mut chars = input.char_indices();
857 let mut n = 0;
858 while let Some((byte_offset, ch)) = chars.next() {
859 match ch {
860 '"' => {
861 n = byte_offset;
862 break;
863 }
864 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700865 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700866 }
867 }
868 for (byte_offset, ch) in chars {
869 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500870 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
871 let rest = input.advance(byte_offset + 1 + n);
David Tolnay1218e122017-06-01 11:13:45 -0700872 return Ok((rest, ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700873 }
874 '\r' => {}
875 _ => {}
876 }
877 }
David Tolnay1218e122017-06-01 11:13:45 -0700878 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700879}
880
881named!(byte -> (), do_parse!(
882 punct!("b") >>
883 tag!("'") >>
884 cooked_byte >>
885 tag!("'") >>
886 (())
887));
888
Nika Layzellf8d5f212017-12-11 14:07:02 -0500889fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700890 let mut bytes = input.bytes().enumerate();
891 let ok = match bytes.next().map(|(_, b)| b) {
892 Some(b'\\') => {
893 match bytes.next().map(|(_, b)| b) {
894 Some(b'x') => backslash_x_byte(&mut bytes),
895 Some(b'n') |
896 Some(b'r') |
897 Some(b't') |
898 Some(b'\\') |
899 Some(b'0') |
900 Some(b'\'') |
901 Some(b'"') => true,
902 _ => false,
903 }
904 }
905 b => b.is_some(),
906 };
907 if ok {
908 match bytes.next() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500909 Some((offset, _)) => Ok((input.advance(offset), ())),
910 None => Ok((input.advance(input.len()), ())),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700911 }
912 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700913 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700914 }
915}
916
917named!(character -> (), do_parse!(
918 punct!("'") >>
919 cooked_char >>
920 tag!("'") >>
921 (())
922));
923
Nika Layzellf8d5f212017-12-11 14:07:02 -0500924fn cooked_char(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700925 let mut chars = input.char_indices();
926 let ok = match chars.next().map(|(_, ch)| ch) {
927 Some('\\') => {
928 match chars.next().map(|(_, ch)| ch) {
929 Some('x') => backslash_x_char(&mut chars),
930 Some('u') => backslash_u(&mut chars),
931 Some('n') |
932 Some('r') |
933 Some('t') |
934 Some('\\') |
935 Some('0') |
936 Some('\'') |
937 Some('"') => true,
938 _ => false,
939 }
940 }
941 ch => ch.is_some(),
942 };
943 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500944 match chars.next() {
945 Some((idx, _)) => Ok((input.advance(idx), ())),
946 None => Ok((input.advance(input.len()), ())),
947 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700948 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700949 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700950 }
951}
952
953macro_rules! next_ch {
954 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
955 match $chars.next() {
956 Some((_, ch)) => match ch {
957 $pat $(| $rest)* => ch,
958 _ => return false,
959 },
960 None => return false
961 }
962 };
963}
964
965fn backslash_x_char<I>(chars: &mut I) -> bool
966 where I: Iterator<Item = (usize, char)>
967{
968 next_ch!(chars @ '0'...'7');
969 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
970 true
971}
972
973fn backslash_x_byte<I>(chars: &mut I) -> bool
974 where I: Iterator<Item = (usize, u8)>
975{
976 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
977 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
978 true
979}
980
981fn backslash_u<I>(chars: &mut I) -> bool
982 where I: Iterator<Item = (usize, char)>
983{
984 next_ch!(chars @ '{');
985 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
David Tolnay8d109342017-12-25 18:24:45 -0500986 loop {
987 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '_' | '}');
988 if c == '}' {
989 return true;
990 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700991 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700992}
993
Nika Layzellf8d5f212017-12-11 14:07:02 -0500994fn float(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -0700995 let (rest, ()) = float_digits(input)?;
996 for suffix in &["f32", "f64"] {
997 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500998 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -0700999 }
1000 }
1001 word_break(rest)
1002}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001003
Nika Layzellf8d5f212017-12-11 14:07:02 -05001004fn float_digits(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001005 let mut chars = input.chars().peekable();
1006 match chars.next() {
1007 Some(ch) if ch >= '0' && ch <= '9' => {}
David Tolnay1218e122017-06-01 11:13:45 -07001008 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001009 }
1010
1011 let mut len = 1;
1012 let mut has_dot = false;
1013 let mut has_exp = false;
1014 while let Some(&ch) = chars.peek() {
1015 match ch {
1016 '0'...'9' | '_' => {
1017 chars.next();
1018 len += 1;
1019 }
1020 '.' => {
1021 if has_dot {
1022 break;
1023 }
1024 chars.next();
1025 if chars.peek()
1026 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1027 .unwrap_or(false) {
David Tolnay1218e122017-06-01 11:13:45 -07001028 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001029 }
1030 len += 1;
1031 has_dot = true;
1032 }
1033 'e' | 'E' => {
1034 chars.next();
1035 len += 1;
1036 has_exp = true;
1037 break;
1038 }
1039 _ => break,
1040 }
1041 }
1042
Nika Layzellf8d5f212017-12-11 14:07:02 -05001043 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001044 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001045 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001046 }
1047
1048 if has_exp {
1049 let mut has_exp_value = false;
1050 while let Some(&ch) = chars.peek() {
1051 match ch {
1052 '+' | '-' => {
1053 if has_exp_value {
1054 break;
1055 }
1056 chars.next();
1057 len += 1;
1058 }
1059 '0'...'9' => {
1060 chars.next();
1061 len += 1;
1062 has_exp_value = true;
1063 }
1064 '_' => {
1065 chars.next();
1066 len += 1;
1067 }
1068 _ => break,
1069 }
1070 }
1071 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001072 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001073 }
1074 }
1075
Nika Layzellf8d5f212017-12-11 14:07:02 -05001076 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001077}
1078
Nika Layzellf8d5f212017-12-11 14:07:02 -05001079fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001080 let (rest, ()) = digits(input)?;
1081 for suffix in &[
1082 "isize",
1083 "i8",
1084 "i16",
1085 "i32",
1086 "i64",
1087 "i128",
1088 "usize",
1089 "u8",
1090 "u16",
1091 "u32",
1092 "u64",
1093 "u128",
1094 ] {
1095 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001096 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001097 }
1098 }
1099 word_break(rest)
1100}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001101
Nika Layzellf8d5f212017-12-11 14:07:02 -05001102fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001103 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001104 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001105 16
1106 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001107 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001108 8
1109 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001110 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001111 2
1112 } else {
1113 10
1114 };
1115
Alex Crichton44bffbc2017-05-19 17:51:59 -07001116 let mut len = 0;
1117 let mut empty = true;
1118 for b in input.bytes() {
1119 let digit = match b {
1120 b'0'...b'9' => (b - b'0') as u64,
1121 b'a'...b'f' => 10 + (b - b'a') as u64,
1122 b'A'...b'F' => 10 + (b - b'A') as u64,
1123 b'_' => {
1124 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001125 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001126 }
1127 len += 1;
1128 continue;
1129 }
1130 _ => break,
1131 };
1132 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001133 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001134 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001135 len += 1;
1136 empty = false;
1137 }
1138 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001139 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001140 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001141 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001142 }
1143}
1144
1145named!(boolean -> (), alt!(
1146 keyword!("true") => { |_| () }
1147 |
1148 keyword!("false") => { |_| () }
1149));
1150
Nika Layzellf8d5f212017-12-11 14:07:02 -05001151fn op(input: Cursor) -> PResult<(char, Spacing)> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001152 let input = skip_whitespace(input);
1153 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001154 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001155 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001156 Ok(_) => Spacing::Joint,
1157 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001158 };
David Tolnay1218e122017-06-01 11:13:45 -07001159 Ok((rest, (ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001160 }
David Tolnay1218e122017-06-01 11:13:45 -07001161 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001162 }
1163}
1164
Nika Layzellf8d5f212017-12-11 14:07:02 -05001165fn op_char(input: Cursor) -> PResult<char> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001166 let mut chars = input.chars();
1167 let first = match chars.next() {
1168 Some(ch) => ch,
1169 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001170 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001171 }
1172 };
1173 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1174 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001175 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001176 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001177 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001178 }
1179}
1180
Alex Crichton44bffbc2017-05-19 17:51:59 -07001181named!(doc_comment -> (), alt!(
1182 do_parse!(
1183 punct!("//!") >>
1184 take_until!("\n") >>
1185 (())
1186 )
1187 |
1188 do_parse!(
1189 option!(whitespace) >>
1190 peek!(tag!("/*!")) >>
1191 block_comment >>
1192 (())
1193 )
1194 |
1195 do_parse!(
1196 punct!("///") >>
1197 not!(tag!("/")) >>
1198 take_until!("\n") >>
1199 (())
1200 )
1201 |
1202 do_parse!(
1203 option!(whitespace) >>
1204 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1205 block_comment >>
1206 (())
1207 )
1208));