blob: 0a439eda90a2150dde510f7343292582b707c383 [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::ops;
11use std::rc::Rc;
12use std::str::FromStr;
13use std::vec;
14
15use proc_macro;
David Tolnayb1032662017-05-31 15:52:28 -070016use unicode_xid::UnicodeXID;
Nika Layzellf8d5f212017-12-11 14:07:02 -050017use strnom::{Cursor, PResult, skip_whitespace, block_comment, whitespace, word_break};
Alex Crichton44bffbc2017-05-19 17:51:59 -070018
Alex Crichton1a7f7622017-07-05 17:47:15 -070019use {TokenTree, TokenNode, Delimiter, Spacing};
Alex Crichton44bffbc2017-05-19 17:51:59 -070020
David Tolnay977f8282017-05-31 17:41:33 -070021#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -070022pub struct TokenStream {
23 inner: Vec<TokenTree>,
24}
25
26#[derive(Debug)]
27pub struct LexError;
28
29impl TokenStream {
30 pub fn empty() -> TokenStream {
31 TokenStream { inner: Vec::new() }
32 }
33
34 pub fn is_empty(&self) -> bool {
35 self.inner.len() == 0
36 }
37}
38
David Tolnay1ebe3972018-01-02 20:14:20 -080039#[cfg(procmacro2_semver_exempt)]
Nika Layzella9dbc182017-12-30 14:50:13 -050040fn get_cursor(src: &str) -> Cursor {
41 // Create a dummy file & add it to the codemap
42 CODEMAP.with(|cm| {
43 let mut cm = cm.borrow_mut();
44 let name = format!("<parsed string {}>", cm.files.len());
45 let span = cm.add_file(&name, src);
46 Cursor {
47 rest: src,
48 off: span.lo,
49 }
50 })
51}
52
David Tolnay1ebe3972018-01-02 20:14:20 -080053#[cfg(not(procmacro2_semver_exempt))]
Nika Layzella9dbc182017-12-30 14:50:13 -050054fn get_cursor(src: &str) -> Cursor {
55 Cursor {
56 rest: src,
Nika Layzella9dbc182017-12-30 14:50:13 -050057 }
58}
59
Alex Crichton44bffbc2017-05-19 17:51:59 -070060impl FromStr for TokenStream {
61 type Err = LexError;
62
63 fn from_str(src: &str) -> Result<TokenStream, LexError> {
Nika Layzellf8d5f212017-12-11 14:07:02 -050064 // Create a dummy file & add it to the codemap
Nika Layzella9dbc182017-12-30 14:50:13 -050065 let cursor = get_cursor(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -050066
67 match token_stream(cursor) {
David Tolnay1218e122017-06-01 11:13:45 -070068 Ok((input, output)) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -070069 if skip_whitespace(input).len() != 0 {
70 Err(LexError)
71 } else {
David Tolnay8e976c62017-06-01 12:12:29 -070072 Ok(output.0)
Alex Crichton44bffbc2017-05-19 17:51:59 -070073 }
74 }
David Tolnay1218e122017-06-01 11:13:45 -070075 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -070076 }
77 }
78}
79
80impl fmt::Display for TokenStream {
81 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82 let mut joint = false;
83 for (i, tt) in self.inner.iter().enumerate() {
84 if i != 0 && !joint {
85 write!(f, " ")?;
86 }
87 joint = false;
88 match tt.kind {
Alex Crichton1a7f7622017-07-05 17:47:15 -070089 TokenNode::Group(delim, ref stream) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -070090 let (start, end) = match delim {
91 Delimiter::Parenthesis => ("(", ")"),
92 Delimiter::Brace => ("{", "}"),
93 Delimiter::Bracket => ("[", "]"),
94 Delimiter::None => ("", ""),
95 };
Alex Crichton852d53d2017-05-19 19:25:08 -070096 if stream.0.inner.len() == 0 {
97 write!(f, "{} {}", start, end)?
98 } else {
99 write!(f, "{} {} {}", start, stream, end)?
100 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700101 }
Alex Crichton1a7f7622017-07-05 17:47:15 -0700102 TokenNode::Term(ref sym) => write!(f, "{}", sym.as_str())?,
103 TokenNode::Op(ch, ref op) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700104 write!(f, "{}", ch)?;
105 match *op {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700106 Spacing::Alone => {}
107 Spacing::Joint => joint = true,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700108 }
109 }
Alex Crichton1a7f7622017-07-05 17:47:15 -0700110 TokenNode::Literal(ref literal) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700111 write!(f, "{}", literal)?;
112 // handle comments
113 if (literal.0).0.starts_with("/") {
114 write!(f, "\n")?;
115 }
116 }
117 }
118 }
119
120 Ok(())
121 }
122}
123
124impl From<proc_macro::TokenStream> for TokenStream {
125 fn from(inner: proc_macro::TokenStream) -> TokenStream {
126 inner.to_string().parse().expect("compiler token stream parse failed")
127 }
128}
129
130impl From<TokenStream> for proc_macro::TokenStream {
131 fn from(inner: TokenStream) -> proc_macro::TokenStream {
132 inner.to_string().parse().expect("failed to parse to compiler tokens")
133 }
134}
135
136
137impl From<TokenTree> for TokenStream {
138 fn from(tree: TokenTree) -> TokenStream {
139 TokenStream { inner: vec![tree] }
140 }
141}
142
143impl iter::FromIterator<TokenStream> for TokenStream {
144 fn from_iter<I: IntoIterator<Item=TokenStream>>(streams: I) -> Self {
145 let mut v = Vec::new();
146
147 for stream in streams.into_iter() {
148 v.extend(stream.inner);
149 }
150
151 TokenStream { inner: v }
152 }
153}
154
Alex Crichton1a7f7622017-07-05 17:47:15 -0700155pub type TokenTreeIter = vec::IntoIter<TokenTree>;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700156
157impl IntoIterator for TokenStream {
158 type Item = TokenTree;
Alex Crichton1a7f7622017-07-05 17:47:15 -0700159 type IntoIter = TokenTreeIter;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700160
Alex Crichton1a7f7622017-07-05 17:47:15 -0700161 fn into_iter(self) -> TokenTreeIter {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700162 self.inner.into_iter()
163 }
164}
165
David Tolnay1ebe3972018-01-02 20:14:20 -0800166#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500167#[derive(Clone, PartialEq, Eq, Debug)]
168pub struct FileName(String);
169
David Tolnay1ebe3972018-01-02 20:14:20 -0800170#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500171impl fmt::Display for FileName {
172 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
173 self.0.fmt(f)
174 }
175}
176
David Tolnay1ebe3972018-01-02 20:14:20 -0800177#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500178#[derive(Clone, PartialEq, Eq)]
179pub struct SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500180 name: FileName,
Nika Layzellf8d5f212017-12-11 14:07:02 -0500181}
182
David Tolnay1ebe3972018-01-02 20:14:20 -0800183#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500184impl SourceFile {
185 /// Get the path to this source file as a string.
Nika Layzellb35a9a32017-12-30 14:34:35 -0500186 pub fn path(&self) -> &FileName {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500187 &self.name
188 }
189
190 pub fn is_real(&self) -> bool {
191 // XXX(nika): Support real files in the future?
192 false
193 }
194}
195
David Tolnay1ebe3972018-01-02 20:14:20 -0800196#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500197impl AsRef<FileName> for SourceFile {
198 fn as_ref(&self) -> &FileName {
199 self.path()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500200 }
201}
202
David Tolnay1ebe3972018-01-02 20:14:20 -0800203#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500204impl fmt::Debug for SourceFile {
205 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
206 f.debug_struct("SourceFile")
Nika Layzellb35a9a32017-12-30 14:34:35 -0500207 .field("path", &self.path())
Nika Layzellf8d5f212017-12-11 14:07:02 -0500208 .field("is_real", &self.is_real())
209 .finish()
210 }
211}
212
David Tolnay1ebe3972018-01-02 20:14:20 -0800213#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500214#[derive(Clone, Copy, Debug, PartialEq, Eq)]
215pub struct LineColumn {
216 pub line: usize,
217 pub column: usize,
218}
219
David Tolnay1ebe3972018-01-02 20:14:20 -0800220#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500221thread_local! {
222 static CODEMAP: RefCell<Codemap> = RefCell::new(Codemap {
223 // NOTE: We start with a single dummy file which all call_site() and
224 // def_site() spans reference.
225 files: vec![FileInfo {
226 name: "<unspecified>".to_owned(),
227 span: Span { lo: 0, hi: 0 },
228 lines: vec![0],
229 }],
230 });
231}
232
David Tolnay1ebe3972018-01-02 20:14:20 -0800233#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500234struct FileInfo {
235 name: String,
236 span: Span,
237 lines: Vec<usize>,
238}
239
David Tolnay1ebe3972018-01-02 20:14:20 -0800240#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500241impl FileInfo {
242 fn offset_line_column(&self, offset: usize) -> LineColumn {
243 assert!(self.span_within(Span { lo: offset as u32, hi: offset as u32 }));
244 let offset = offset - self.span.lo as usize;
245 match self.lines.binary_search(&offset) {
246 Ok(found) => LineColumn {
247 line: found + 1,
248 column: 0
249 },
250 Err(idx) => LineColumn {
251 line: idx,
252 column: offset - self.lines[idx - 1]
253 },
254 }
255 }
256
257 fn span_within(&self, span: Span) -> bool {
258 span.lo >= self.span.lo && span.hi <= self.span.hi
259 }
260}
261
262/// Computes the offsets of each line in the given source string.
David Tolnay1ebe3972018-01-02 20:14:20 -0800263#[cfg(procmacro2_semver_exempt)]
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500264fn lines_offsets(s: &str) -> Vec<usize> {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500265 let mut lines = vec![0];
266 let mut prev = 0;
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500267 while let Some(len) = s[prev..].find('\n') {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500268 prev += len + 1;
269 lines.push(prev);
270 }
271 lines
272}
273
David Tolnay1ebe3972018-01-02 20:14:20 -0800274#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500275struct Codemap {
276 files: Vec<FileInfo>,
277}
278
David Tolnay1ebe3972018-01-02 20:14:20 -0800279#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500280impl Codemap {
281 fn next_start_pos(&self) -> u32 {
282 // Add 1 so there's always space between files.
283 //
284 // We'll always have at least 1 file, as we initialize our files list
285 // with a dummy file.
286 self.files.last().unwrap().span.hi + 1
287 }
288
289 fn add_file(&mut self, name: &str, src: &str) -> Span {
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500290 let lines = lines_offsets(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -0500291 let lo = self.next_start_pos();
292 // XXX(nika): Shouild we bother doing a checked cast or checked add here?
293 let span = Span { lo: lo, hi: lo + (src.len() as u32) };
294
295 self.files.push(FileInfo {
296 name: name.to_owned(),
297 span: span,
298 lines: lines,
299 });
300
301 span
302 }
303
304 fn fileinfo(&self, span: Span) -> &FileInfo {
305 for file in &self.files {
306 if file.span_within(span) {
307 return file;
308 }
309 }
310 panic!("Invalid span with no related FileInfo!");
311 }
312}
313
Alex Crichtone6085b72017-11-21 07:24:25 -0800314#[derive(Clone, Copy, Debug)]
David Tolnayddfca052017-12-31 10:41:24 -0500315pub struct Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800316 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500317 lo: u32,
David Tolnay1ebe3972018-01-02 20:14:20 -0800318 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500319 hi: u32,
320}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700321
322impl Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800323 #[cfg(not(procmacro2_semver_exempt))]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700324 pub fn call_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500325 Span {}
326 }
327
David Tolnay1ebe3972018-01-02 20:14:20 -0800328 #[cfg(procmacro2_semver_exempt)]
David Tolnay79105e52017-12-31 11:03:04 -0500329 pub fn call_site() -> Span {
330 Span { lo: 0, hi: 0 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700331 }
Alex Crichtone6085b72017-11-21 07:24:25 -0800332
333 pub fn def_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500334 Span::call_site()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500335 }
336
David Tolnay4e8e3972018-01-05 18:10:22 -0800337 pub fn resolved_at(&self, _other: Span) -> Span {
338 // Stable spans consist only of line/column information, so
339 // `resolved_at` and `located_at` only select which span the
340 // caller wants line/column information from.
341 *self
342 }
343
344 pub fn located_at(&self, other: Span) -> Span {
345 other
346 }
347
David Tolnay1ebe3972018-01-02 20:14:20 -0800348 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500349 pub fn source_file(&self) -> SourceFile {
350 CODEMAP.with(|cm| {
351 let cm = cm.borrow();
352 let fi = cm.fileinfo(*self);
353 SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500354 name: FileName(fi.name.clone()),
Nika Layzellf8d5f212017-12-11 14:07:02 -0500355 }
356 })
357 }
358
David Tolnay1ebe3972018-01-02 20:14:20 -0800359 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500360 pub fn start(&self) -> LineColumn {
361 CODEMAP.with(|cm| {
362 let cm = cm.borrow();
363 let fi = cm.fileinfo(*self);
364 fi.offset_line_column(self.lo as usize)
365 })
366 }
367
David Tolnay1ebe3972018-01-02 20:14:20 -0800368 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500369 pub fn end(&self) -> LineColumn {
370 CODEMAP.with(|cm| {
371 let cm = cm.borrow();
372 let fi = cm.fileinfo(*self);
373 fi.offset_line_column(self.hi as usize)
374 })
375 }
376
David Tolnay1ebe3972018-01-02 20:14:20 -0800377 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500378 pub fn join(&self, other: Span) -> Option<Span> {
379 CODEMAP.with(|cm| {
380 let cm = cm.borrow();
381 // If `other` is not within the same FileInfo as us, return None.
382 if !cm.fileinfo(*self).span_within(other) {
383 return None;
384 }
385 Some(Span {
386 lo: cmp::min(self.lo, other.lo),
387 hi: cmp::max(self.hi, other.hi),
388 })
389 })
Alex Crichtone6085b72017-11-21 07:24:25 -0800390 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700391}
392
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700393#[derive(Copy, Clone)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700394pub struct Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700395 intern: usize,
396 not_send_sync: PhantomData<*const ()>,
397}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700398
399thread_local!(static SYMBOLS: RefCell<Interner> = RefCell::new(Interner::new()));
400
Alex Crichton1a7f7622017-07-05 17:47:15 -0700401impl<'a> From<&'a str> for Term {
402 fn from(string: &'a str) -> Term {
403 Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700404 intern: SYMBOLS.with(|s| s.borrow_mut().intern(string)),
405 not_send_sync: PhantomData,
406 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700407 }
408}
409
Alex Crichton1a7f7622017-07-05 17:47:15 -0700410impl ops::Deref for Term {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700411 type Target = str;
412
413 fn deref(&self) -> &str {
414 SYMBOLS.with(|interner| {
415 let interner = interner.borrow();
David Tolnay041bcd42017-06-03 09:18:04 -0700416 let s = interner.get(self.intern);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700417 unsafe {
418 &*(s as *const str)
419 }
420 })
421 }
422}
423
Alex Crichton1a7f7622017-07-05 17:47:15 -0700424impl fmt::Debug for Term {
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700425 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700426 f.debug_tuple("Term").field(&&**self).finish()
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700427 }
428}
429
Alex Crichton44bffbc2017-05-19 17:51:59 -0700430struct Interner {
431 string_to_index: HashMap<MyRc, usize>,
432 index_to_string: Vec<Rc<String>>,
433}
434
435#[derive(Hash, Eq, PartialEq)]
436struct MyRc(Rc<String>);
437
438impl Borrow<str> for MyRc {
439 fn borrow(&self) -> &str {
440 &self.0
441 }
442}
443
444impl Interner {
445 fn new() -> Interner {
446 Interner {
447 string_to_index: HashMap::new(),
448 index_to_string: Vec::new(),
449 }
450 }
451
452 fn intern(&mut self, s: &str) -> usize {
453 if let Some(&idx) = self.string_to_index.get(s) {
454 return idx
455 }
456 let s = Rc::new(s.to_string());
457 self.index_to_string.push(s.clone());
458 self.string_to_index.insert(MyRc(s), self.index_to_string.len() - 1);
459 self.index_to_string.len() - 1
460 }
461
462 fn get(&self, idx: usize) -> &str {
463 &self.index_to_string[idx]
464 }
465}
466
David Tolnay977f8282017-05-31 17:41:33 -0700467#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700468pub struct Literal(String);
469
Alex Crichton852d53d2017-05-19 19:25:08 -0700470impl Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700471 pub fn byte_char(byte: u8) -> Literal {
Alex Crichton76a5cc82017-05-23 07:01:44 -0700472 match byte {
473 0 => Literal(format!("b'\\0'")),
474 b'\"' => Literal(format!("b'\"'")),
475 n => {
476 let mut escaped = "b'".to_string();
477 escaped.extend(ascii::escape_default(n).map(|c| c as char));
478 escaped.push('\'');
479 Literal(escaped)
480 }
481 }
482 }
483
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700484 pub fn byte_string(bytes: &[u8]) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700485 let mut escaped = "b\"".to_string();
486 for b in bytes {
487 match *b {
488 b'\0' => escaped.push_str(r"\0"),
489 b'\t' => escaped.push_str(r"\t"),
490 b'\n' => escaped.push_str(r"\n"),
491 b'\r' => escaped.push_str(r"\r"),
492 b'"' => escaped.push_str("\\\""),
493 b'\\' => escaped.push_str("\\\\"),
494 b'\x20' ... b'\x7E' => escaped.push(*b as char),
495 _ => escaped.push_str(&format!("\\x{:02X}", b)),
496 }
497 }
498 escaped.push('"');
499 Literal(escaped)
500 }
Alex Crichton76a5cc82017-05-23 07:01:44 -0700501
502 pub fn doccomment(s: &str) -> Literal {
503 Literal(s.to_string())
504 }
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700505
David Tolnay114990e2018-01-05 11:17:08 -0800506 pub fn float(n: f64) -> Literal {
507 if !n.is_finite() {
508 panic!("Invalid float literal {}", n);
509 }
510 let mut s = n.to_string();
511 if !s.contains('.') {
512 s += ".0";
513 }
514 Literal(s)
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700515 }
516
Alex Crichton1a7f7622017-07-05 17:47:15 -0700517 pub fn integer(s: i64) -> Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700518 Literal(s.to_string())
519 }
Alex Crichton31316622017-05-26 12:54:47 -0700520
521 pub fn raw_string(s: &str, pounds: usize) -> Literal {
522 let mut ret = format!("r");
523 ret.extend((0..pounds).map(|_| "#"));
524 ret.push('"');
525 ret.push_str(s);
526 ret.push('"');
527 ret.extend((0..pounds).map(|_| "#"));
528 Literal(ret)
529 }
530
531 pub fn raw_byte_string(s: &str, pounds: usize) -> Literal {
Alex Crichton7ed6d282017-05-26 13:42:50 -0700532 let mut ret = format!("br");
Alex Crichton31316622017-05-26 12:54:47 -0700533 ret.extend((0..pounds).map(|_| "#"));
534 ret.push('"');
535 ret.push_str(s);
536 ret.push('"');
537 ret.extend((0..pounds).map(|_| "#"));
538 Literal(ret)
539 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700540}
541
Alex Crichton44bffbc2017-05-19 17:51:59 -0700542impl fmt::Display for Literal {
543 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
544 self.0.fmt(f)
545 }
546}
547
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700548macro_rules! ints {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700549 ($($t:ty,)*) => {$(
550 impl From<$t> for Literal {
551 fn from(t: $t) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700552 Literal(format!(concat!("{}", stringify!($t)), t))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700553 }
554 }
555 )*}
556}
557
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700558ints! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700559 u8, u16, u32, u64, usize,
560 i8, i16, i32, i64, isize,
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700561}
562
563macro_rules! floats {
564 ($($t:ty,)*) => {$(
565 impl From<$t> for Literal {
566 fn from(t: $t) -> Literal {
567 assert!(!t.is_nan());
568 assert!(!t.is_infinite());
569 Literal(format!(concat!("{}", stringify!($t)), t))
570 }
571 }
572 )*}
573}
574
575floats! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700576 f32, f64,
577}
578
Alex Crichton44bffbc2017-05-19 17:51:59 -0700579impl<'a> From<&'a str> for Literal {
580 fn from(t: &'a str) -> Literal {
581 let mut s = t.chars().flat_map(|c| c.escape_default()).collect::<String>();
582 s.push('"');
583 s.insert(0, '"');
584 Literal(s)
585 }
586}
587
588impl From<char> for Literal {
589 fn from(t: char) -> Literal {
Alex Crichton2d0cf0b2017-05-26 14:00:16 -0700590 Literal(format!("'{}'", t.escape_default().collect::<String>()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700591 }
592}
593
David Tolnay8e976c62017-06-01 12:12:29 -0700594named!(token_stream -> ::TokenStream, map!(
595 many0!(token_tree),
596 |trees| ::TokenStream(TokenStream { inner: trees })
597));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700598
David Tolnay1ebe3972018-01-02 20:14:20 -0800599#[cfg(not(procmacro2_semver_exempt))]
David Tolnayddfca052017-12-31 10:41:24 -0500600fn token_tree(input: Cursor) -> PResult<TokenTree> {
601 let (input, kind) = token_kind(input)?;
602 Ok((input, TokenTree {
603 span: ::Span(Span {}),
604 kind: kind,
605 }))
606}
607
David Tolnay1ebe3972018-01-02 20:14:20 -0800608#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500609fn token_tree(input: Cursor) -> PResult<TokenTree> {
610 let input = skip_whitespace(input);
611 let lo = input.off;
612 let (input, kind) = token_kind(input)?;
613 let hi = input.off;
614 Ok((input, TokenTree {
615 span: ::Span(Span {
616 lo: lo,
617 hi: hi,
618 }),
619 kind: kind,
620 }))
621}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700622
Alex Crichton1a7f7622017-07-05 17:47:15 -0700623named!(token_kind -> TokenNode, alt!(
624 map!(delimited, |(d, s)| TokenNode::Group(d, s))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700625 |
Alex Crichton1a7f7622017-07-05 17:47:15 -0700626 map!(literal, TokenNode::Literal) // must be before symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700627 |
Alex Crichton52725f72017-08-28 12:20:58 -0700628 symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700629 |
Alex Crichton1a7f7622017-07-05 17:47:15 -0700630 map!(op, |(op, kind)| TokenNode::Op(op, kind))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700631));
632
David Tolnay8e976c62017-06-01 12:12:29 -0700633named!(delimited -> (Delimiter, ::TokenStream), alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -0700634 delimited!(
635 punct!("("),
636 token_stream,
637 punct!(")")
638 ) => { |ts| (Delimiter::Parenthesis, ts) }
639 |
640 delimited!(
641 punct!("["),
642 token_stream,
643 punct!("]")
644 ) => { |ts| (Delimiter::Bracket, ts) }
645 |
646 delimited!(
647 punct!("{"),
648 token_stream,
649 punct!("}")
650 ) => { |ts| (Delimiter::Brace, ts) }
651));
652
Nika Layzellf8d5f212017-12-11 14:07:02 -0500653fn symbol(mut input: Cursor) -> PResult<TokenNode> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700654 input = skip_whitespace(input);
655
656 let mut chars = input.char_indices();
David Tolnaya202d502017-06-01 12:26:55 -0700657
658 let lifetime = input.starts_with("'");
659 if lifetime {
660 chars.next();
661 }
662
Alex Crichton44bffbc2017-05-19 17:51:59 -0700663 match chars.next() {
664 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700665 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700666 }
667
David Tolnay214c94c2017-06-01 12:42:56 -0700668 let mut end = input.len();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700669 for (i, ch) in chars {
670 if !UnicodeXID::is_xid_continue(ch) {
David Tolnay214c94c2017-06-01 12:42:56 -0700671 end = i;
672 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700673 }
674 }
675
Nika Layzellf8d5f212017-12-11 14:07:02 -0500676 if lifetime && &input.rest[..end] != "'static" && KEYWORDS.contains(&&input.rest[1..end]) {
David Tolnay214c94c2017-06-01 12:42:56 -0700677 Err(LexError)
678 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500679 let a = &input.rest[..end];
Alex Crichton52725f72017-08-28 12:20:58 -0700680 if a == "_" {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500681 Ok((input.advance(end), TokenNode::Op('_', Spacing::Alone)))
Alex Crichton52725f72017-08-28 12:20:58 -0700682 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500683 Ok((input.advance(end), TokenNode::Term(::Term::intern(a))))
Alex Crichton52725f72017-08-28 12:20:58 -0700684 }
David Tolnay214c94c2017-06-01 12:42:56 -0700685 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700686}
687
David Tolnay214c94c2017-06-01 12:42:56 -0700688// From https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/symbol.rs
689static KEYWORDS: &'static [&'static str] = &[
690 "abstract", "alignof", "as", "become", "box", "break", "const", "continue",
691 "crate", "do", "else", "enum", "extern", "false", "final", "fn", "for",
692 "if", "impl", "in", "let", "loop", "macro", "match", "mod", "move", "mut",
693 "offsetof", "override", "priv", "proc", "pub", "pure", "ref", "return",
694 "self", "Self", "sizeof", "static", "struct", "super", "trait", "true",
695 "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while",
696 "yield",
697];
698
Nika Layzellf8d5f212017-12-11 14:07:02 -0500699fn literal(input: Cursor) -> PResult<::Literal> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700700 let input_no_ws = skip_whitespace(input);
701
702 match literal_nocapture(input_no_ws) {
David Tolnay1218e122017-06-01 11:13:45 -0700703 Ok((a, ())) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700704 let start = input.len() - input_no_ws.len();
705 let len = input_no_ws.len() - a.len();
706 let end = start + len;
Nika Layzellf8d5f212017-12-11 14:07:02 -0500707 Ok((a, ::Literal(Literal(input.rest[start..end].to_string()))))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700708 }
David Tolnay1218e122017-06-01 11:13:45 -0700709 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700710 }
711}
712
713named!(literal_nocapture -> (), alt!(
714 string
715 |
716 byte_string
717 |
718 byte
719 |
720 character
721 |
722 float
723 |
724 int
725 |
726 boolean
727 |
728 doc_comment
729));
730
731named!(string -> (), alt!(
732 quoted_string
733 |
734 preceded!(
735 punct!("r"),
736 raw_string
737 ) => { |_| () }
738));
739
740named!(quoted_string -> (), delimited!(
741 punct!("\""),
742 cooked_string,
743 tag!("\"")
744));
745
Nika Layzellf8d5f212017-12-11 14:07:02 -0500746fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700747 let mut chars = input.char_indices().peekable();
748 while let Some((byte_offset, ch)) = chars.next() {
749 match ch {
750 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500751 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700752 }
753 '\r' => {
754 if let Some((_, '\n')) = chars.next() {
755 // ...
756 } else {
757 break;
758 }
759 }
760 '\\' => {
761 match chars.next() {
762 Some((_, 'x')) => {
763 if !backslash_x_char(&mut chars) {
764 break
765 }
766 }
767 Some((_, 'n')) |
768 Some((_, 'r')) |
769 Some((_, 't')) |
770 Some((_, '\\')) |
771 Some((_, '\'')) |
772 Some((_, '"')) |
773 Some((_, '0')) => {}
774 Some((_, 'u')) => {
775 if !backslash_u(&mut chars) {
776 break
777 }
778 }
779 Some((_, '\n')) | Some((_, '\r')) => {
780 while let Some(&(_, ch)) = chars.peek() {
781 if ch.is_whitespace() {
782 chars.next();
783 } else {
784 break;
785 }
786 }
787 }
788 _ => break,
789 }
790 }
791 _ch => {}
792 }
793 }
David Tolnay1218e122017-06-01 11:13:45 -0700794 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700795}
796
797named!(byte_string -> (), alt!(
798 delimited!(
799 punct!("b\""),
800 cooked_byte_string,
801 tag!("\"")
802 ) => { |_| () }
803 |
804 preceded!(
805 punct!("br"),
806 raw_string
807 ) => { |_| () }
808));
809
Nika Layzellf8d5f212017-12-11 14:07:02 -0500810fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700811 let mut bytes = input.bytes().enumerate();
812 'outer: while let Some((offset, b)) = bytes.next() {
813 match b {
814 b'"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500815 return Ok((input.advance(offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700816 }
817 b'\r' => {
818 if let Some((_, b'\n')) = bytes.next() {
819 // ...
820 } else {
821 break;
822 }
823 }
824 b'\\' => {
825 match bytes.next() {
826 Some((_, b'x')) => {
827 if !backslash_x_byte(&mut bytes) {
828 break
829 }
830 }
831 Some((_, b'n')) |
832 Some((_, b'r')) |
833 Some((_, b't')) |
834 Some((_, b'\\')) |
835 Some((_, b'0')) |
836 Some((_, b'\'')) |
837 Some((_, b'"')) => {}
838 Some((newline, b'\n')) |
839 Some((newline, b'\r')) => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500840 let rest = input.advance(newline + 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700841 for (offset, ch) in rest.char_indices() {
842 if !ch.is_whitespace() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500843 input = rest.advance(offset);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700844 bytes = input.bytes().enumerate();
845 continue 'outer;
846 }
847 }
848 break;
849 }
850 _ => break,
851 }
852 }
853 b if b < 0x80 => {}
854 _ => break,
855 }
856 }
David Tolnay1218e122017-06-01 11:13:45 -0700857 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700858}
859
Nika Layzellf8d5f212017-12-11 14:07:02 -0500860fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700861 let mut chars = input.char_indices();
862 let mut n = 0;
863 while let Some((byte_offset, ch)) = chars.next() {
864 match ch {
865 '"' => {
866 n = byte_offset;
867 break;
868 }
869 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700870 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700871 }
872 }
873 for (byte_offset, ch) in chars {
874 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500875 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
876 let rest = input.advance(byte_offset + 1 + n);
David Tolnay1218e122017-06-01 11:13:45 -0700877 return Ok((rest, ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700878 }
879 '\r' => {}
880 _ => {}
881 }
882 }
David Tolnay1218e122017-06-01 11:13:45 -0700883 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700884}
885
886named!(byte -> (), do_parse!(
887 punct!("b") >>
888 tag!("'") >>
889 cooked_byte >>
890 tag!("'") >>
891 (())
892));
893
Nika Layzellf8d5f212017-12-11 14:07:02 -0500894fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700895 let mut bytes = input.bytes().enumerate();
896 let ok = match bytes.next().map(|(_, b)| b) {
897 Some(b'\\') => {
898 match bytes.next().map(|(_, b)| b) {
899 Some(b'x') => backslash_x_byte(&mut bytes),
900 Some(b'n') |
901 Some(b'r') |
902 Some(b't') |
903 Some(b'\\') |
904 Some(b'0') |
905 Some(b'\'') |
906 Some(b'"') => true,
907 _ => false,
908 }
909 }
910 b => b.is_some(),
911 };
912 if ok {
913 match bytes.next() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500914 Some((offset, _)) => Ok((input.advance(offset), ())),
915 None => Ok((input.advance(input.len()), ())),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700916 }
917 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700918 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700919 }
920}
921
922named!(character -> (), do_parse!(
923 punct!("'") >>
924 cooked_char >>
925 tag!("'") >>
926 (())
927));
928
Nika Layzellf8d5f212017-12-11 14:07:02 -0500929fn cooked_char(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700930 let mut chars = input.char_indices();
931 let ok = match chars.next().map(|(_, ch)| ch) {
932 Some('\\') => {
933 match chars.next().map(|(_, ch)| ch) {
934 Some('x') => backslash_x_char(&mut chars),
935 Some('u') => backslash_u(&mut chars),
936 Some('n') |
937 Some('r') |
938 Some('t') |
939 Some('\\') |
940 Some('0') |
941 Some('\'') |
942 Some('"') => true,
943 _ => false,
944 }
945 }
946 ch => ch.is_some(),
947 };
948 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500949 match chars.next() {
950 Some((idx, _)) => Ok((input.advance(idx), ())),
951 None => Ok((input.advance(input.len()), ())),
952 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700953 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700954 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700955 }
956}
957
958macro_rules! next_ch {
959 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
960 match $chars.next() {
961 Some((_, ch)) => match ch {
962 $pat $(| $rest)* => ch,
963 _ => return false,
964 },
965 None => return false
966 }
967 };
968}
969
970fn backslash_x_char<I>(chars: &mut I) -> bool
971 where I: Iterator<Item = (usize, char)>
972{
973 next_ch!(chars @ '0'...'7');
974 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
975 true
976}
977
978fn backslash_x_byte<I>(chars: &mut I) -> bool
979 where I: Iterator<Item = (usize, u8)>
980{
981 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
982 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
983 true
984}
985
986fn backslash_u<I>(chars: &mut I) -> bool
987 where I: Iterator<Item = (usize, char)>
988{
989 next_ch!(chars @ '{');
990 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
David Tolnay8d109342017-12-25 18:24:45 -0500991 loop {
992 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '_' | '}');
993 if c == '}' {
994 return true;
995 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700996 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700997}
998
Nika Layzellf8d5f212017-12-11 14:07:02 -0500999fn float(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001000 let (rest, ()) = float_digits(input)?;
1001 for suffix in &["f32", "f64"] {
1002 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001003 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001004 }
1005 }
1006 word_break(rest)
1007}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001008
Nika Layzellf8d5f212017-12-11 14:07:02 -05001009fn float_digits(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001010 let mut chars = input.chars().peekable();
1011 match chars.next() {
1012 Some(ch) if ch >= '0' && ch <= '9' => {}
David Tolnay1218e122017-06-01 11:13:45 -07001013 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001014 }
1015
1016 let mut len = 1;
1017 let mut has_dot = false;
1018 let mut has_exp = false;
1019 while let Some(&ch) = chars.peek() {
1020 match ch {
1021 '0'...'9' | '_' => {
1022 chars.next();
1023 len += 1;
1024 }
1025 '.' => {
1026 if has_dot {
1027 break;
1028 }
1029 chars.next();
1030 if chars.peek()
1031 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1032 .unwrap_or(false) {
David Tolnay1218e122017-06-01 11:13:45 -07001033 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001034 }
1035 len += 1;
1036 has_dot = true;
1037 }
1038 'e' | 'E' => {
1039 chars.next();
1040 len += 1;
1041 has_exp = true;
1042 break;
1043 }
1044 _ => break,
1045 }
1046 }
1047
Nika Layzellf8d5f212017-12-11 14:07:02 -05001048 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001049 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001050 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001051 }
1052
1053 if has_exp {
1054 let mut has_exp_value = false;
1055 while let Some(&ch) = chars.peek() {
1056 match ch {
1057 '+' | '-' => {
1058 if has_exp_value {
1059 break;
1060 }
1061 chars.next();
1062 len += 1;
1063 }
1064 '0'...'9' => {
1065 chars.next();
1066 len += 1;
1067 has_exp_value = true;
1068 }
1069 '_' => {
1070 chars.next();
1071 len += 1;
1072 }
1073 _ => break,
1074 }
1075 }
1076 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001077 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001078 }
1079 }
1080
Nika Layzellf8d5f212017-12-11 14:07:02 -05001081 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001082}
1083
Nika Layzellf8d5f212017-12-11 14:07:02 -05001084fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001085 let (rest, ()) = digits(input)?;
1086 for suffix in &[
1087 "isize",
1088 "i8",
1089 "i16",
1090 "i32",
1091 "i64",
1092 "i128",
1093 "usize",
1094 "u8",
1095 "u16",
1096 "u32",
1097 "u64",
1098 "u128",
1099 ] {
1100 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001101 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001102 }
1103 }
1104 word_break(rest)
1105}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001106
Nika Layzellf8d5f212017-12-11 14:07:02 -05001107fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001108 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001109 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001110 16
1111 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001112 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001113 8
1114 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001115 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001116 2
1117 } else {
1118 10
1119 };
1120
Alex Crichton44bffbc2017-05-19 17:51:59 -07001121 let mut len = 0;
1122 let mut empty = true;
1123 for b in input.bytes() {
1124 let digit = match b {
1125 b'0'...b'9' => (b - b'0') as u64,
1126 b'a'...b'f' => 10 + (b - b'a') as u64,
1127 b'A'...b'F' => 10 + (b - b'A') as u64,
1128 b'_' => {
1129 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001130 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001131 }
1132 len += 1;
1133 continue;
1134 }
1135 _ => break,
1136 };
1137 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001138 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001139 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001140 len += 1;
1141 empty = false;
1142 }
1143 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001144 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001145 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001146 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001147 }
1148}
1149
1150named!(boolean -> (), alt!(
1151 keyword!("true") => { |_| () }
1152 |
1153 keyword!("false") => { |_| () }
1154));
1155
Nika Layzellf8d5f212017-12-11 14:07:02 -05001156fn op(input: Cursor) -> PResult<(char, Spacing)> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001157 let input = skip_whitespace(input);
1158 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001159 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001160 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001161 Ok(_) => Spacing::Joint,
1162 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001163 };
David Tolnay1218e122017-06-01 11:13:45 -07001164 Ok((rest, (ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001165 }
David Tolnay1218e122017-06-01 11:13:45 -07001166 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001167 }
1168}
1169
Nika Layzellf8d5f212017-12-11 14:07:02 -05001170fn op_char(input: Cursor) -> PResult<char> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001171 let mut chars = input.chars();
1172 let first = match chars.next() {
1173 Some(ch) => ch,
1174 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001175 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001176 }
1177 };
1178 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1179 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001180 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001181 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001182 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001183 }
1184}
1185
Alex Crichton44bffbc2017-05-19 17:51:59 -07001186named!(doc_comment -> (), alt!(
1187 do_parse!(
1188 punct!("//!") >>
1189 take_until!("\n") >>
1190 (())
1191 )
1192 |
1193 do_parse!(
1194 option!(whitespace) >>
1195 peek!(tag!("/*!")) >>
1196 block_comment >>
1197 (())
1198 )
1199 |
1200 do_parse!(
1201 punct!("///") >>
1202 not!(tag!("/")) >>
1203 take_until!("\n") >>
1204 (())
1205 )
1206 |
1207 do_parse!(
1208 option!(whitespace) >>
1209 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1210 block_comment >>
1211 (())
1212 )
1213));