blob: 984a146600555f98ab3f4dd1cf1a32a62d6c8ba9 [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 Tolnay1ebe3972018-01-02 20:14:20 -0800337 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500338 pub fn source_file(&self) -> SourceFile {
339 CODEMAP.with(|cm| {
340 let cm = cm.borrow();
341 let fi = cm.fileinfo(*self);
342 SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500343 name: FileName(fi.name.clone()),
Nika Layzellf8d5f212017-12-11 14:07:02 -0500344 }
345 })
346 }
347
David Tolnay1ebe3972018-01-02 20:14:20 -0800348 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500349 pub fn start(&self) -> LineColumn {
350 CODEMAP.with(|cm| {
351 let cm = cm.borrow();
352 let fi = cm.fileinfo(*self);
353 fi.offset_line_column(self.lo as usize)
354 })
355 }
356
David Tolnay1ebe3972018-01-02 20:14:20 -0800357 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500358 pub fn end(&self) -> LineColumn {
359 CODEMAP.with(|cm| {
360 let cm = cm.borrow();
361 let fi = cm.fileinfo(*self);
362 fi.offset_line_column(self.hi as usize)
363 })
364 }
365
David Tolnay1ebe3972018-01-02 20:14:20 -0800366 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500367 pub fn join(&self, other: Span) -> Option<Span> {
368 CODEMAP.with(|cm| {
369 let cm = cm.borrow();
370 // If `other` is not within the same FileInfo as us, return None.
371 if !cm.fileinfo(*self).span_within(other) {
372 return None;
373 }
374 Some(Span {
375 lo: cmp::min(self.lo, other.lo),
376 hi: cmp::max(self.hi, other.hi),
377 })
378 })
Alex Crichtone6085b72017-11-21 07:24:25 -0800379 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700380}
381
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700382#[derive(Copy, Clone)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700383pub struct Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700384 intern: usize,
385 not_send_sync: PhantomData<*const ()>,
386}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700387
388thread_local!(static SYMBOLS: RefCell<Interner> = RefCell::new(Interner::new()));
389
Alex Crichton1a7f7622017-07-05 17:47:15 -0700390impl<'a> From<&'a str> for Term {
391 fn from(string: &'a str) -> Term {
392 Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700393 intern: SYMBOLS.with(|s| s.borrow_mut().intern(string)),
394 not_send_sync: PhantomData,
395 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700396 }
397}
398
Alex Crichton1a7f7622017-07-05 17:47:15 -0700399impl ops::Deref for Term {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700400 type Target = str;
401
402 fn deref(&self) -> &str {
403 SYMBOLS.with(|interner| {
404 let interner = interner.borrow();
David Tolnay041bcd42017-06-03 09:18:04 -0700405 let s = interner.get(self.intern);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700406 unsafe {
407 &*(s as *const str)
408 }
409 })
410 }
411}
412
Alex Crichton1a7f7622017-07-05 17:47:15 -0700413impl fmt::Debug for Term {
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700414 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700415 f.debug_tuple("Term").field(&&**self).finish()
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700416 }
417}
418
Alex Crichton44bffbc2017-05-19 17:51:59 -0700419struct Interner {
420 string_to_index: HashMap<MyRc, usize>,
421 index_to_string: Vec<Rc<String>>,
422}
423
424#[derive(Hash, Eq, PartialEq)]
425struct MyRc(Rc<String>);
426
427impl Borrow<str> for MyRc {
428 fn borrow(&self) -> &str {
429 &self.0
430 }
431}
432
433impl Interner {
434 fn new() -> Interner {
435 Interner {
436 string_to_index: HashMap::new(),
437 index_to_string: Vec::new(),
438 }
439 }
440
441 fn intern(&mut self, s: &str) -> usize {
442 if let Some(&idx) = self.string_to_index.get(s) {
443 return idx
444 }
445 let s = Rc::new(s.to_string());
446 self.index_to_string.push(s.clone());
447 self.string_to_index.insert(MyRc(s), self.index_to_string.len() - 1);
448 self.index_to_string.len() - 1
449 }
450
451 fn get(&self, idx: usize) -> &str {
452 &self.index_to_string[idx]
453 }
454}
455
David Tolnay977f8282017-05-31 17:41:33 -0700456#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700457pub struct Literal(String);
458
Alex Crichton852d53d2017-05-19 19:25:08 -0700459impl Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700460 pub fn byte_char(byte: u8) -> Literal {
Alex Crichton76a5cc82017-05-23 07:01:44 -0700461 match byte {
462 0 => Literal(format!("b'\\0'")),
463 b'\"' => Literal(format!("b'\"'")),
464 n => {
465 let mut escaped = "b'".to_string();
466 escaped.extend(ascii::escape_default(n).map(|c| c as char));
467 escaped.push('\'');
468 Literal(escaped)
469 }
470 }
471 }
472
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700473 pub fn byte_string(bytes: &[u8]) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700474 let mut escaped = "b\"".to_string();
475 for b in bytes {
476 match *b {
477 b'\0' => escaped.push_str(r"\0"),
478 b'\t' => escaped.push_str(r"\t"),
479 b'\n' => escaped.push_str(r"\n"),
480 b'\r' => escaped.push_str(r"\r"),
481 b'"' => escaped.push_str("\\\""),
482 b'\\' => escaped.push_str("\\\\"),
483 b'\x20' ... b'\x7E' => escaped.push(*b as char),
484 _ => escaped.push_str(&format!("\\x{:02X}", b)),
485 }
486 }
487 escaped.push('"');
488 Literal(escaped)
489 }
Alex Crichton76a5cc82017-05-23 07:01:44 -0700490
491 pub fn doccomment(s: &str) -> Literal {
492 Literal(s.to_string())
493 }
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700494
Alex Crichton1a7f7622017-07-05 17:47:15 -0700495 pub fn float(s: f64) -> Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700496 Literal(s.to_string())
497 }
498
Alex Crichton1a7f7622017-07-05 17:47:15 -0700499 pub fn integer(s: i64) -> Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700500 Literal(s.to_string())
501 }
Alex Crichton31316622017-05-26 12:54:47 -0700502
503 pub fn raw_string(s: &str, pounds: usize) -> Literal {
504 let mut ret = format!("r");
505 ret.extend((0..pounds).map(|_| "#"));
506 ret.push('"');
507 ret.push_str(s);
508 ret.push('"');
509 ret.extend((0..pounds).map(|_| "#"));
510 Literal(ret)
511 }
512
513 pub fn raw_byte_string(s: &str, pounds: usize) -> Literal {
Alex Crichton7ed6d282017-05-26 13:42:50 -0700514 let mut ret = format!("br");
Alex Crichton31316622017-05-26 12:54:47 -0700515 ret.extend((0..pounds).map(|_| "#"));
516 ret.push('"');
517 ret.push_str(s);
518 ret.push('"');
519 ret.extend((0..pounds).map(|_| "#"));
520 Literal(ret)
521 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700522}
523
Alex Crichton44bffbc2017-05-19 17:51:59 -0700524impl fmt::Display for Literal {
525 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
526 self.0.fmt(f)
527 }
528}
529
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700530macro_rules! ints {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700531 ($($t:ty,)*) => {$(
532 impl From<$t> for Literal {
533 fn from(t: $t) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700534 Literal(format!(concat!("{}", stringify!($t)), t))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700535 }
536 }
537 )*}
538}
539
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700540ints! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700541 u8, u16, u32, u64, usize,
542 i8, i16, i32, i64, isize,
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700543}
544
545macro_rules! floats {
546 ($($t:ty,)*) => {$(
547 impl From<$t> for Literal {
548 fn from(t: $t) -> Literal {
549 assert!(!t.is_nan());
550 assert!(!t.is_infinite());
551 Literal(format!(concat!("{}", stringify!($t)), t))
552 }
553 }
554 )*}
555}
556
557floats! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700558 f32, f64,
559}
560
Alex Crichton44bffbc2017-05-19 17:51:59 -0700561impl<'a> From<&'a str> for Literal {
562 fn from(t: &'a str) -> Literal {
563 let mut s = t.chars().flat_map(|c| c.escape_default()).collect::<String>();
564 s.push('"');
565 s.insert(0, '"');
566 Literal(s)
567 }
568}
569
570impl From<char> for Literal {
571 fn from(t: char) -> Literal {
Alex Crichton2d0cf0b2017-05-26 14:00:16 -0700572 Literal(format!("'{}'", t.escape_default().collect::<String>()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700573 }
574}
575
David Tolnay8e976c62017-06-01 12:12:29 -0700576named!(token_stream -> ::TokenStream, map!(
577 many0!(token_tree),
578 |trees| ::TokenStream(TokenStream { inner: trees })
579));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700580
David Tolnay1ebe3972018-01-02 20:14:20 -0800581#[cfg(not(procmacro2_semver_exempt))]
David Tolnayddfca052017-12-31 10:41:24 -0500582fn token_tree(input: Cursor) -> PResult<TokenTree> {
583 let (input, kind) = token_kind(input)?;
584 Ok((input, TokenTree {
585 span: ::Span(Span {}),
586 kind: kind,
587 }))
588}
589
David Tolnay1ebe3972018-01-02 20:14:20 -0800590#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500591fn token_tree(input: Cursor) -> PResult<TokenTree> {
592 let input = skip_whitespace(input);
593 let lo = input.off;
594 let (input, kind) = token_kind(input)?;
595 let hi = input.off;
596 Ok((input, TokenTree {
597 span: ::Span(Span {
598 lo: lo,
599 hi: hi,
600 }),
601 kind: kind,
602 }))
603}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700604
Alex Crichton1a7f7622017-07-05 17:47:15 -0700605named!(token_kind -> TokenNode, alt!(
606 map!(delimited, |(d, s)| TokenNode::Group(d, s))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700607 |
Alex Crichton1a7f7622017-07-05 17:47:15 -0700608 map!(literal, TokenNode::Literal) // must be before symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700609 |
Alex Crichton52725f72017-08-28 12:20:58 -0700610 symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700611 |
Alex Crichton1a7f7622017-07-05 17:47:15 -0700612 map!(op, |(op, kind)| TokenNode::Op(op, kind))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700613));
614
David Tolnay8e976c62017-06-01 12:12:29 -0700615named!(delimited -> (Delimiter, ::TokenStream), alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -0700616 delimited!(
617 punct!("("),
618 token_stream,
619 punct!(")")
620 ) => { |ts| (Delimiter::Parenthesis, ts) }
621 |
622 delimited!(
623 punct!("["),
624 token_stream,
625 punct!("]")
626 ) => { |ts| (Delimiter::Bracket, ts) }
627 |
628 delimited!(
629 punct!("{"),
630 token_stream,
631 punct!("}")
632 ) => { |ts| (Delimiter::Brace, ts) }
633));
634
Nika Layzellf8d5f212017-12-11 14:07:02 -0500635fn symbol(mut input: Cursor) -> PResult<TokenNode> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700636 input = skip_whitespace(input);
637
638 let mut chars = input.char_indices();
David Tolnaya202d502017-06-01 12:26:55 -0700639
640 let lifetime = input.starts_with("'");
641 if lifetime {
642 chars.next();
643 }
644
Alex Crichton44bffbc2017-05-19 17:51:59 -0700645 match chars.next() {
646 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700647 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700648 }
649
David Tolnay214c94c2017-06-01 12:42:56 -0700650 let mut end = input.len();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700651 for (i, ch) in chars {
652 if !UnicodeXID::is_xid_continue(ch) {
David Tolnay214c94c2017-06-01 12:42:56 -0700653 end = i;
654 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700655 }
656 }
657
Nika Layzellf8d5f212017-12-11 14:07:02 -0500658 if lifetime && &input.rest[..end] != "'static" && KEYWORDS.contains(&&input.rest[1..end]) {
David Tolnay214c94c2017-06-01 12:42:56 -0700659 Err(LexError)
660 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500661 let a = &input.rest[..end];
Alex Crichton52725f72017-08-28 12:20:58 -0700662 if a == "_" {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500663 Ok((input.advance(end), TokenNode::Op('_', Spacing::Alone)))
Alex Crichton52725f72017-08-28 12:20:58 -0700664 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500665 Ok((input.advance(end), TokenNode::Term(::Term::intern(a))))
Alex Crichton52725f72017-08-28 12:20:58 -0700666 }
David Tolnay214c94c2017-06-01 12:42:56 -0700667 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700668}
669
David Tolnay214c94c2017-06-01 12:42:56 -0700670// From https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/symbol.rs
671static KEYWORDS: &'static [&'static str] = &[
672 "abstract", "alignof", "as", "become", "box", "break", "const", "continue",
673 "crate", "do", "else", "enum", "extern", "false", "final", "fn", "for",
674 "if", "impl", "in", "let", "loop", "macro", "match", "mod", "move", "mut",
675 "offsetof", "override", "priv", "proc", "pub", "pure", "ref", "return",
676 "self", "Self", "sizeof", "static", "struct", "super", "trait", "true",
677 "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while",
678 "yield",
679];
680
Nika Layzellf8d5f212017-12-11 14:07:02 -0500681fn literal(input: Cursor) -> PResult<::Literal> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700682 let input_no_ws = skip_whitespace(input);
683
684 match literal_nocapture(input_no_ws) {
David Tolnay1218e122017-06-01 11:13:45 -0700685 Ok((a, ())) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700686 let start = input.len() - input_no_ws.len();
687 let len = input_no_ws.len() - a.len();
688 let end = start + len;
Nika Layzellf8d5f212017-12-11 14:07:02 -0500689 Ok((a, ::Literal(Literal(input.rest[start..end].to_string()))))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700690 }
David Tolnay1218e122017-06-01 11:13:45 -0700691 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700692 }
693}
694
695named!(literal_nocapture -> (), alt!(
696 string
697 |
698 byte_string
699 |
700 byte
701 |
702 character
703 |
704 float
705 |
706 int
707 |
708 boolean
709 |
710 doc_comment
711));
712
713named!(string -> (), alt!(
714 quoted_string
715 |
716 preceded!(
717 punct!("r"),
718 raw_string
719 ) => { |_| () }
720));
721
722named!(quoted_string -> (), delimited!(
723 punct!("\""),
724 cooked_string,
725 tag!("\"")
726));
727
Nika Layzellf8d5f212017-12-11 14:07:02 -0500728fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700729 let mut chars = input.char_indices().peekable();
730 while let Some((byte_offset, ch)) = chars.next() {
731 match ch {
732 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500733 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700734 }
735 '\r' => {
736 if let Some((_, '\n')) = chars.next() {
737 // ...
738 } else {
739 break;
740 }
741 }
742 '\\' => {
743 match chars.next() {
744 Some((_, 'x')) => {
745 if !backslash_x_char(&mut chars) {
746 break
747 }
748 }
749 Some((_, 'n')) |
750 Some((_, 'r')) |
751 Some((_, 't')) |
752 Some((_, '\\')) |
753 Some((_, '\'')) |
754 Some((_, '"')) |
755 Some((_, '0')) => {}
756 Some((_, 'u')) => {
757 if !backslash_u(&mut chars) {
758 break
759 }
760 }
761 Some((_, '\n')) | Some((_, '\r')) => {
762 while let Some(&(_, ch)) = chars.peek() {
763 if ch.is_whitespace() {
764 chars.next();
765 } else {
766 break;
767 }
768 }
769 }
770 _ => break,
771 }
772 }
773 _ch => {}
774 }
775 }
David Tolnay1218e122017-06-01 11:13:45 -0700776 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700777}
778
779named!(byte_string -> (), alt!(
780 delimited!(
781 punct!("b\""),
782 cooked_byte_string,
783 tag!("\"")
784 ) => { |_| () }
785 |
786 preceded!(
787 punct!("br"),
788 raw_string
789 ) => { |_| () }
790));
791
Nika Layzellf8d5f212017-12-11 14:07:02 -0500792fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700793 let mut bytes = input.bytes().enumerate();
794 'outer: while let Some((offset, b)) = bytes.next() {
795 match b {
796 b'"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500797 return Ok((input.advance(offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700798 }
799 b'\r' => {
800 if let Some((_, b'\n')) = bytes.next() {
801 // ...
802 } else {
803 break;
804 }
805 }
806 b'\\' => {
807 match bytes.next() {
808 Some((_, b'x')) => {
809 if !backslash_x_byte(&mut bytes) {
810 break
811 }
812 }
813 Some((_, b'n')) |
814 Some((_, b'r')) |
815 Some((_, b't')) |
816 Some((_, b'\\')) |
817 Some((_, b'0')) |
818 Some((_, b'\'')) |
819 Some((_, b'"')) => {}
820 Some((newline, b'\n')) |
821 Some((newline, b'\r')) => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500822 let rest = input.advance(newline + 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700823 for (offset, ch) in rest.char_indices() {
824 if !ch.is_whitespace() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500825 input = rest.advance(offset);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700826 bytes = input.bytes().enumerate();
827 continue 'outer;
828 }
829 }
830 break;
831 }
832 _ => break,
833 }
834 }
835 b if b < 0x80 => {}
836 _ => break,
837 }
838 }
David Tolnay1218e122017-06-01 11:13:45 -0700839 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700840}
841
Nika Layzellf8d5f212017-12-11 14:07:02 -0500842fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700843 let mut chars = input.char_indices();
844 let mut n = 0;
845 while let Some((byte_offset, ch)) = chars.next() {
846 match ch {
847 '"' => {
848 n = byte_offset;
849 break;
850 }
851 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700852 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700853 }
854 }
855 for (byte_offset, ch) in chars {
856 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500857 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
858 let rest = input.advance(byte_offset + 1 + n);
David Tolnay1218e122017-06-01 11:13:45 -0700859 return Ok((rest, ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700860 }
861 '\r' => {}
862 _ => {}
863 }
864 }
David Tolnay1218e122017-06-01 11:13:45 -0700865 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700866}
867
868named!(byte -> (), do_parse!(
869 punct!("b") >>
870 tag!("'") >>
871 cooked_byte >>
872 tag!("'") >>
873 (())
874));
875
Nika Layzellf8d5f212017-12-11 14:07:02 -0500876fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700877 let mut bytes = input.bytes().enumerate();
878 let ok = match bytes.next().map(|(_, b)| b) {
879 Some(b'\\') => {
880 match bytes.next().map(|(_, b)| b) {
881 Some(b'x') => backslash_x_byte(&mut bytes),
882 Some(b'n') |
883 Some(b'r') |
884 Some(b't') |
885 Some(b'\\') |
886 Some(b'0') |
887 Some(b'\'') |
888 Some(b'"') => true,
889 _ => false,
890 }
891 }
892 b => b.is_some(),
893 };
894 if ok {
895 match bytes.next() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500896 Some((offset, _)) => Ok((input.advance(offset), ())),
897 None => Ok((input.advance(input.len()), ())),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700898 }
899 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700900 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700901 }
902}
903
904named!(character -> (), do_parse!(
905 punct!("'") >>
906 cooked_char >>
907 tag!("'") >>
908 (())
909));
910
Nika Layzellf8d5f212017-12-11 14:07:02 -0500911fn cooked_char(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700912 let mut chars = input.char_indices();
913 let ok = match chars.next().map(|(_, ch)| ch) {
914 Some('\\') => {
915 match chars.next().map(|(_, ch)| ch) {
916 Some('x') => backslash_x_char(&mut chars),
917 Some('u') => backslash_u(&mut chars),
918 Some('n') |
919 Some('r') |
920 Some('t') |
921 Some('\\') |
922 Some('0') |
923 Some('\'') |
924 Some('"') => true,
925 _ => false,
926 }
927 }
928 ch => ch.is_some(),
929 };
930 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500931 match chars.next() {
932 Some((idx, _)) => Ok((input.advance(idx), ())),
933 None => Ok((input.advance(input.len()), ())),
934 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700935 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700936 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700937 }
938}
939
940macro_rules! next_ch {
941 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
942 match $chars.next() {
943 Some((_, ch)) => match ch {
944 $pat $(| $rest)* => ch,
945 _ => return false,
946 },
947 None => return false
948 }
949 };
950}
951
952fn backslash_x_char<I>(chars: &mut I) -> bool
953 where I: Iterator<Item = (usize, char)>
954{
955 next_ch!(chars @ '0'...'7');
956 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
957 true
958}
959
960fn backslash_x_byte<I>(chars: &mut I) -> bool
961 where I: Iterator<Item = (usize, u8)>
962{
963 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
964 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
965 true
966}
967
968fn backslash_u<I>(chars: &mut I) -> bool
969 where I: Iterator<Item = (usize, char)>
970{
971 next_ch!(chars @ '{');
972 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
David Tolnay8d109342017-12-25 18:24:45 -0500973 loop {
974 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '_' | '}');
975 if c == '}' {
976 return true;
977 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700978 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700979}
980
Nika Layzellf8d5f212017-12-11 14:07:02 -0500981fn float(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -0700982 let (rest, ()) = float_digits(input)?;
983 for suffix in &["f32", "f64"] {
984 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500985 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -0700986 }
987 }
988 word_break(rest)
989}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700990
Nika Layzellf8d5f212017-12-11 14:07:02 -0500991fn float_digits(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700992 let mut chars = input.chars().peekable();
993 match chars.next() {
994 Some(ch) if ch >= '0' && ch <= '9' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700995 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700996 }
997
998 let mut len = 1;
999 let mut has_dot = false;
1000 let mut has_exp = false;
1001 while let Some(&ch) = chars.peek() {
1002 match ch {
1003 '0'...'9' | '_' => {
1004 chars.next();
1005 len += 1;
1006 }
1007 '.' => {
1008 if has_dot {
1009 break;
1010 }
1011 chars.next();
1012 if chars.peek()
1013 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1014 .unwrap_or(false) {
David Tolnay1218e122017-06-01 11:13:45 -07001015 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001016 }
1017 len += 1;
1018 has_dot = true;
1019 }
1020 'e' | 'E' => {
1021 chars.next();
1022 len += 1;
1023 has_exp = true;
1024 break;
1025 }
1026 _ => break,
1027 }
1028 }
1029
Nika Layzellf8d5f212017-12-11 14:07:02 -05001030 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001031 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001032 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001033 }
1034
1035 if has_exp {
1036 let mut has_exp_value = false;
1037 while let Some(&ch) = chars.peek() {
1038 match ch {
1039 '+' | '-' => {
1040 if has_exp_value {
1041 break;
1042 }
1043 chars.next();
1044 len += 1;
1045 }
1046 '0'...'9' => {
1047 chars.next();
1048 len += 1;
1049 has_exp_value = true;
1050 }
1051 '_' => {
1052 chars.next();
1053 len += 1;
1054 }
1055 _ => break,
1056 }
1057 }
1058 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001059 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001060 }
1061 }
1062
Nika Layzellf8d5f212017-12-11 14:07:02 -05001063 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001064}
1065
Nika Layzellf8d5f212017-12-11 14:07:02 -05001066fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001067 let (rest, ()) = digits(input)?;
1068 for suffix in &[
1069 "isize",
1070 "i8",
1071 "i16",
1072 "i32",
1073 "i64",
1074 "i128",
1075 "usize",
1076 "u8",
1077 "u16",
1078 "u32",
1079 "u64",
1080 "u128",
1081 ] {
1082 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001083 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001084 }
1085 }
1086 word_break(rest)
1087}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001088
Nika Layzellf8d5f212017-12-11 14:07:02 -05001089fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001090 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001091 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001092 16
1093 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001094 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001095 8
1096 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001097 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001098 2
1099 } else {
1100 10
1101 };
1102
Alex Crichton44bffbc2017-05-19 17:51:59 -07001103 let mut len = 0;
1104 let mut empty = true;
1105 for b in input.bytes() {
1106 let digit = match b {
1107 b'0'...b'9' => (b - b'0') as u64,
1108 b'a'...b'f' => 10 + (b - b'a') as u64,
1109 b'A'...b'F' => 10 + (b - b'A') as u64,
1110 b'_' => {
1111 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001112 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001113 }
1114 len += 1;
1115 continue;
1116 }
1117 _ => break,
1118 };
1119 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001120 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001121 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001122 len += 1;
1123 empty = false;
1124 }
1125 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001126 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001127 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001128 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001129 }
1130}
1131
1132named!(boolean -> (), alt!(
1133 keyword!("true") => { |_| () }
1134 |
1135 keyword!("false") => { |_| () }
1136));
1137
Nika Layzellf8d5f212017-12-11 14:07:02 -05001138fn op(input: Cursor) -> PResult<(char, Spacing)> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001139 let input = skip_whitespace(input);
1140 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001141 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001142 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001143 Ok(_) => Spacing::Joint,
1144 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001145 };
David Tolnay1218e122017-06-01 11:13:45 -07001146 Ok((rest, (ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001147 }
David Tolnay1218e122017-06-01 11:13:45 -07001148 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001149 }
1150}
1151
Nika Layzellf8d5f212017-12-11 14:07:02 -05001152fn op_char(input: Cursor) -> PResult<char> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001153 let mut chars = input.chars();
1154 let first = match chars.next() {
1155 Some(ch) => ch,
1156 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001157 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001158 }
1159 };
1160 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1161 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001162 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001163 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001164 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001165 }
1166}
1167
Alex Crichton44bffbc2017-05-19 17:51:59 -07001168named!(doc_comment -> (), alt!(
1169 do_parse!(
1170 punct!("//!") >>
1171 take_until!("\n") >>
1172 (())
1173 )
1174 |
1175 do_parse!(
1176 option!(whitespace) >>
1177 peek!(tag!("/*!")) >>
1178 block_comment >>
1179 (())
1180 )
1181 |
1182 do_parse!(
1183 punct!("///") >>
1184 not!(tag!("/")) >>
1185 take_until!("\n") >>
1186 (())
1187 )
1188 |
1189 do_parse!(
1190 option!(whitespace) >>
1191 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1192 block_comment >>
1193 (())
1194 )
1195));