blob: b5820b17251b0e3b01caa1adc33391898d9aa639 [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
David Tolnay114990e2018-01-05 11:17:08 -0800495 pub fn float(n: f64) -> Literal {
496 if !n.is_finite() {
497 panic!("Invalid float literal {}", n);
498 }
499 let mut s = n.to_string();
500 if !s.contains('.') {
501 s += ".0";
502 }
503 Literal(s)
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700504 }
505
Alex Crichton1a7f7622017-07-05 17:47:15 -0700506 pub fn integer(s: i64) -> Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700507 Literal(s.to_string())
508 }
Alex Crichton31316622017-05-26 12:54:47 -0700509
510 pub fn raw_string(s: &str, pounds: usize) -> Literal {
511 let mut ret = format!("r");
512 ret.extend((0..pounds).map(|_| "#"));
513 ret.push('"');
514 ret.push_str(s);
515 ret.push('"');
516 ret.extend((0..pounds).map(|_| "#"));
517 Literal(ret)
518 }
519
520 pub fn raw_byte_string(s: &str, pounds: usize) -> Literal {
Alex Crichton7ed6d282017-05-26 13:42:50 -0700521 let mut ret = format!("br");
Alex Crichton31316622017-05-26 12:54:47 -0700522 ret.extend((0..pounds).map(|_| "#"));
523 ret.push('"');
524 ret.push_str(s);
525 ret.push('"');
526 ret.extend((0..pounds).map(|_| "#"));
527 Literal(ret)
528 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700529}
530
Alex Crichton44bffbc2017-05-19 17:51:59 -0700531impl fmt::Display for Literal {
532 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
533 self.0.fmt(f)
534 }
535}
536
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700537macro_rules! ints {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700538 ($($t:ty,)*) => {$(
539 impl From<$t> for Literal {
540 fn from(t: $t) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700541 Literal(format!(concat!("{}", stringify!($t)), t))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700542 }
543 }
544 )*}
545}
546
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700547ints! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700548 u8, u16, u32, u64, usize,
549 i8, i16, i32, i64, isize,
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700550}
551
552macro_rules! floats {
553 ($($t:ty,)*) => {$(
554 impl From<$t> for Literal {
555 fn from(t: $t) -> Literal {
556 assert!(!t.is_nan());
557 assert!(!t.is_infinite());
558 Literal(format!(concat!("{}", stringify!($t)), t))
559 }
560 }
561 )*}
562}
563
564floats! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700565 f32, f64,
566}
567
Alex Crichton44bffbc2017-05-19 17:51:59 -0700568impl<'a> From<&'a str> for Literal {
569 fn from(t: &'a str) -> Literal {
570 let mut s = t.chars().flat_map(|c| c.escape_default()).collect::<String>();
571 s.push('"');
572 s.insert(0, '"');
573 Literal(s)
574 }
575}
576
577impl From<char> for Literal {
578 fn from(t: char) -> Literal {
Alex Crichton2d0cf0b2017-05-26 14:00:16 -0700579 Literal(format!("'{}'", t.escape_default().collect::<String>()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700580 }
581}
582
David Tolnay8e976c62017-06-01 12:12:29 -0700583named!(token_stream -> ::TokenStream, map!(
584 many0!(token_tree),
585 |trees| ::TokenStream(TokenStream { inner: trees })
586));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700587
David Tolnay1ebe3972018-01-02 20:14:20 -0800588#[cfg(not(procmacro2_semver_exempt))]
David Tolnayddfca052017-12-31 10:41:24 -0500589fn token_tree(input: Cursor) -> PResult<TokenTree> {
590 let (input, kind) = token_kind(input)?;
591 Ok((input, TokenTree {
592 span: ::Span(Span {}),
593 kind: kind,
594 }))
595}
596
David Tolnay1ebe3972018-01-02 20:14:20 -0800597#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500598fn token_tree(input: Cursor) -> PResult<TokenTree> {
599 let input = skip_whitespace(input);
600 let lo = input.off;
601 let (input, kind) = token_kind(input)?;
602 let hi = input.off;
603 Ok((input, TokenTree {
604 span: ::Span(Span {
605 lo: lo,
606 hi: hi,
607 }),
608 kind: kind,
609 }))
610}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700611
Alex Crichton1a7f7622017-07-05 17:47:15 -0700612named!(token_kind -> TokenNode, alt!(
613 map!(delimited, |(d, s)| TokenNode::Group(d, s))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700614 |
Alex Crichton1a7f7622017-07-05 17:47:15 -0700615 map!(literal, TokenNode::Literal) // must be before symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700616 |
Alex Crichton52725f72017-08-28 12:20:58 -0700617 symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700618 |
Alex Crichton1a7f7622017-07-05 17:47:15 -0700619 map!(op, |(op, kind)| TokenNode::Op(op, kind))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700620));
621
David Tolnay8e976c62017-06-01 12:12:29 -0700622named!(delimited -> (Delimiter, ::TokenStream), alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -0700623 delimited!(
624 punct!("("),
625 token_stream,
626 punct!(")")
627 ) => { |ts| (Delimiter::Parenthesis, ts) }
628 |
629 delimited!(
630 punct!("["),
631 token_stream,
632 punct!("]")
633 ) => { |ts| (Delimiter::Bracket, ts) }
634 |
635 delimited!(
636 punct!("{"),
637 token_stream,
638 punct!("}")
639 ) => { |ts| (Delimiter::Brace, ts) }
640));
641
Nika Layzellf8d5f212017-12-11 14:07:02 -0500642fn symbol(mut input: Cursor) -> PResult<TokenNode> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700643 input = skip_whitespace(input);
644
645 let mut chars = input.char_indices();
David Tolnaya202d502017-06-01 12:26:55 -0700646
647 let lifetime = input.starts_with("'");
648 if lifetime {
649 chars.next();
650 }
651
Alex Crichton44bffbc2017-05-19 17:51:59 -0700652 match chars.next() {
653 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700654 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700655 }
656
David Tolnay214c94c2017-06-01 12:42:56 -0700657 let mut end = input.len();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700658 for (i, ch) in chars {
659 if !UnicodeXID::is_xid_continue(ch) {
David Tolnay214c94c2017-06-01 12:42:56 -0700660 end = i;
661 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700662 }
663 }
664
Nika Layzellf8d5f212017-12-11 14:07:02 -0500665 if lifetime && &input.rest[..end] != "'static" && KEYWORDS.contains(&&input.rest[1..end]) {
David Tolnay214c94c2017-06-01 12:42:56 -0700666 Err(LexError)
667 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500668 let a = &input.rest[..end];
Alex Crichton52725f72017-08-28 12:20:58 -0700669 if a == "_" {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500670 Ok((input.advance(end), TokenNode::Op('_', Spacing::Alone)))
Alex Crichton52725f72017-08-28 12:20:58 -0700671 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500672 Ok((input.advance(end), TokenNode::Term(::Term::intern(a))))
Alex Crichton52725f72017-08-28 12:20:58 -0700673 }
David Tolnay214c94c2017-06-01 12:42:56 -0700674 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700675}
676
David Tolnay214c94c2017-06-01 12:42:56 -0700677// From https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/symbol.rs
678static KEYWORDS: &'static [&'static str] = &[
679 "abstract", "alignof", "as", "become", "box", "break", "const", "continue",
680 "crate", "do", "else", "enum", "extern", "false", "final", "fn", "for",
681 "if", "impl", "in", "let", "loop", "macro", "match", "mod", "move", "mut",
682 "offsetof", "override", "priv", "proc", "pub", "pure", "ref", "return",
683 "self", "Self", "sizeof", "static", "struct", "super", "trait", "true",
684 "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while",
685 "yield",
686];
687
Nika Layzellf8d5f212017-12-11 14:07:02 -0500688fn literal(input: Cursor) -> PResult<::Literal> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700689 let input_no_ws = skip_whitespace(input);
690
691 match literal_nocapture(input_no_ws) {
David Tolnay1218e122017-06-01 11:13:45 -0700692 Ok((a, ())) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700693 let start = input.len() - input_no_ws.len();
694 let len = input_no_ws.len() - a.len();
695 let end = start + len;
Nika Layzellf8d5f212017-12-11 14:07:02 -0500696 Ok((a, ::Literal(Literal(input.rest[start..end].to_string()))))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700697 }
David Tolnay1218e122017-06-01 11:13:45 -0700698 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700699 }
700}
701
702named!(literal_nocapture -> (), alt!(
703 string
704 |
705 byte_string
706 |
707 byte
708 |
709 character
710 |
711 float
712 |
713 int
714 |
715 boolean
716 |
717 doc_comment
718));
719
720named!(string -> (), alt!(
721 quoted_string
722 |
723 preceded!(
724 punct!("r"),
725 raw_string
726 ) => { |_| () }
727));
728
729named!(quoted_string -> (), delimited!(
730 punct!("\""),
731 cooked_string,
732 tag!("\"")
733));
734
Nika Layzellf8d5f212017-12-11 14:07:02 -0500735fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700736 let mut chars = input.char_indices().peekable();
737 while let Some((byte_offset, ch)) = chars.next() {
738 match ch {
739 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500740 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700741 }
742 '\r' => {
743 if let Some((_, '\n')) = chars.next() {
744 // ...
745 } else {
746 break;
747 }
748 }
749 '\\' => {
750 match chars.next() {
751 Some((_, 'x')) => {
752 if !backslash_x_char(&mut chars) {
753 break
754 }
755 }
756 Some((_, 'n')) |
757 Some((_, 'r')) |
758 Some((_, 't')) |
759 Some((_, '\\')) |
760 Some((_, '\'')) |
761 Some((_, '"')) |
762 Some((_, '0')) => {}
763 Some((_, 'u')) => {
764 if !backslash_u(&mut chars) {
765 break
766 }
767 }
768 Some((_, '\n')) | Some((_, '\r')) => {
769 while let Some(&(_, ch)) = chars.peek() {
770 if ch.is_whitespace() {
771 chars.next();
772 } else {
773 break;
774 }
775 }
776 }
777 _ => break,
778 }
779 }
780 _ch => {}
781 }
782 }
David Tolnay1218e122017-06-01 11:13:45 -0700783 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700784}
785
786named!(byte_string -> (), alt!(
787 delimited!(
788 punct!("b\""),
789 cooked_byte_string,
790 tag!("\"")
791 ) => { |_| () }
792 |
793 preceded!(
794 punct!("br"),
795 raw_string
796 ) => { |_| () }
797));
798
Nika Layzellf8d5f212017-12-11 14:07:02 -0500799fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700800 let mut bytes = input.bytes().enumerate();
801 'outer: while let Some((offset, b)) = bytes.next() {
802 match b {
803 b'"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500804 return Ok((input.advance(offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700805 }
806 b'\r' => {
807 if let Some((_, b'\n')) = bytes.next() {
808 // ...
809 } else {
810 break;
811 }
812 }
813 b'\\' => {
814 match bytes.next() {
815 Some((_, b'x')) => {
816 if !backslash_x_byte(&mut bytes) {
817 break
818 }
819 }
820 Some((_, b'n')) |
821 Some((_, b'r')) |
822 Some((_, b't')) |
823 Some((_, b'\\')) |
824 Some((_, b'0')) |
825 Some((_, b'\'')) |
826 Some((_, b'"')) => {}
827 Some((newline, b'\n')) |
828 Some((newline, b'\r')) => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500829 let rest = input.advance(newline + 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700830 for (offset, ch) in rest.char_indices() {
831 if !ch.is_whitespace() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500832 input = rest.advance(offset);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700833 bytes = input.bytes().enumerate();
834 continue 'outer;
835 }
836 }
837 break;
838 }
839 _ => break,
840 }
841 }
842 b if b < 0x80 => {}
843 _ => break,
844 }
845 }
David Tolnay1218e122017-06-01 11:13:45 -0700846 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700847}
848
Nika Layzellf8d5f212017-12-11 14:07:02 -0500849fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700850 let mut chars = input.char_indices();
851 let mut n = 0;
852 while let Some((byte_offset, ch)) = chars.next() {
853 match ch {
854 '"' => {
855 n = byte_offset;
856 break;
857 }
858 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700859 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700860 }
861 }
862 for (byte_offset, ch) in chars {
863 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500864 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
865 let rest = input.advance(byte_offset + 1 + n);
David Tolnay1218e122017-06-01 11:13:45 -0700866 return Ok((rest, ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700867 }
868 '\r' => {}
869 _ => {}
870 }
871 }
David Tolnay1218e122017-06-01 11:13:45 -0700872 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700873}
874
875named!(byte -> (), do_parse!(
876 punct!("b") >>
877 tag!("'") >>
878 cooked_byte >>
879 tag!("'") >>
880 (())
881));
882
Nika Layzellf8d5f212017-12-11 14:07:02 -0500883fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700884 let mut bytes = input.bytes().enumerate();
885 let ok = match bytes.next().map(|(_, b)| b) {
886 Some(b'\\') => {
887 match bytes.next().map(|(_, b)| b) {
888 Some(b'x') => backslash_x_byte(&mut bytes),
889 Some(b'n') |
890 Some(b'r') |
891 Some(b't') |
892 Some(b'\\') |
893 Some(b'0') |
894 Some(b'\'') |
895 Some(b'"') => true,
896 _ => false,
897 }
898 }
899 b => b.is_some(),
900 };
901 if ok {
902 match bytes.next() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500903 Some((offset, _)) => Ok((input.advance(offset), ())),
904 None => Ok((input.advance(input.len()), ())),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700905 }
906 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700907 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700908 }
909}
910
911named!(character -> (), do_parse!(
912 punct!("'") >>
913 cooked_char >>
914 tag!("'") >>
915 (())
916));
917
Nika Layzellf8d5f212017-12-11 14:07:02 -0500918fn cooked_char(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700919 let mut chars = input.char_indices();
920 let ok = match chars.next().map(|(_, ch)| ch) {
921 Some('\\') => {
922 match chars.next().map(|(_, ch)| ch) {
923 Some('x') => backslash_x_char(&mut chars),
924 Some('u') => backslash_u(&mut chars),
925 Some('n') |
926 Some('r') |
927 Some('t') |
928 Some('\\') |
929 Some('0') |
930 Some('\'') |
931 Some('"') => true,
932 _ => false,
933 }
934 }
935 ch => ch.is_some(),
936 };
937 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500938 match chars.next() {
939 Some((idx, _)) => Ok((input.advance(idx), ())),
940 None => Ok((input.advance(input.len()), ())),
941 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700942 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700943 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700944 }
945}
946
947macro_rules! next_ch {
948 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
949 match $chars.next() {
950 Some((_, ch)) => match ch {
951 $pat $(| $rest)* => ch,
952 _ => return false,
953 },
954 None => return false
955 }
956 };
957}
958
959fn backslash_x_char<I>(chars: &mut I) -> bool
960 where I: Iterator<Item = (usize, char)>
961{
962 next_ch!(chars @ '0'...'7');
963 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
964 true
965}
966
967fn backslash_x_byte<I>(chars: &mut I) -> bool
968 where I: Iterator<Item = (usize, u8)>
969{
970 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
971 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
972 true
973}
974
975fn backslash_u<I>(chars: &mut I) -> bool
976 where I: Iterator<Item = (usize, char)>
977{
978 next_ch!(chars @ '{');
979 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
David Tolnay8d109342017-12-25 18:24:45 -0500980 loop {
981 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '_' | '}');
982 if c == '}' {
983 return true;
984 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700985 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700986}
987
Nika Layzellf8d5f212017-12-11 14:07:02 -0500988fn float(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -0700989 let (rest, ()) = float_digits(input)?;
990 for suffix in &["f32", "f64"] {
991 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500992 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -0700993 }
994 }
995 word_break(rest)
996}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700997
Nika Layzellf8d5f212017-12-11 14:07:02 -0500998fn float_digits(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700999 let mut chars = input.chars().peekable();
1000 match chars.next() {
1001 Some(ch) if ch >= '0' && ch <= '9' => {}
David Tolnay1218e122017-06-01 11:13:45 -07001002 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001003 }
1004
1005 let mut len = 1;
1006 let mut has_dot = false;
1007 let mut has_exp = false;
1008 while let Some(&ch) = chars.peek() {
1009 match ch {
1010 '0'...'9' | '_' => {
1011 chars.next();
1012 len += 1;
1013 }
1014 '.' => {
1015 if has_dot {
1016 break;
1017 }
1018 chars.next();
1019 if chars.peek()
1020 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1021 .unwrap_or(false) {
David Tolnay1218e122017-06-01 11:13:45 -07001022 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001023 }
1024 len += 1;
1025 has_dot = true;
1026 }
1027 'e' | 'E' => {
1028 chars.next();
1029 len += 1;
1030 has_exp = true;
1031 break;
1032 }
1033 _ => break,
1034 }
1035 }
1036
Nika Layzellf8d5f212017-12-11 14:07:02 -05001037 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001038 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001039 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001040 }
1041
1042 if has_exp {
1043 let mut has_exp_value = false;
1044 while let Some(&ch) = chars.peek() {
1045 match ch {
1046 '+' | '-' => {
1047 if has_exp_value {
1048 break;
1049 }
1050 chars.next();
1051 len += 1;
1052 }
1053 '0'...'9' => {
1054 chars.next();
1055 len += 1;
1056 has_exp_value = true;
1057 }
1058 '_' => {
1059 chars.next();
1060 len += 1;
1061 }
1062 _ => break,
1063 }
1064 }
1065 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001066 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001067 }
1068 }
1069
Nika Layzellf8d5f212017-12-11 14:07:02 -05001070 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001071}
1072
Nika Layzellf8d5f212017-12-11 14:07:02 -05001073fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001074 let (rest, ()) = digits(input)?;
1075 for suffix in &[
1076 "isize",
1077 "i8",
1078 "i16",
1079 "i32",
1080 "i64",
1081 "i128",
1082 "usize",
1083 "u8",
1084 "u16",
1085 "u32",
1086 "u64",
1087 "u128",
1088 ] {
1089 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001090 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001091 }
1092 }
1093 word_break(rest)
1094}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001095
Nika Layzellf8d5f212017-12-11 14:07:02 -05001096fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001097 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001098 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001099 16
1100 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001101 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001102 8
1103 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001104 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001105 2
1106 } else {
1107 10
1108 };
1109
Alex Crichton44bffbc2017-05-19 17:51:59 -07001110 let mut len = 0;
1111 let mut empty = true;
1112 for b in input.bytes() {
1113 let digit = match b {
1114 b'0'...b'9' => (b - b'0') as u64,
1115 b'a'...b'f' => 10 + (b - b'a') as u64,
1116 b'A'...b'F' => 10 + (b - b'A') as u64,
1117 b'_' => {
1118 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001119 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001120 }
1121 len += 1;
1122 continue;
1123 }
1124 _ => break,
1125 };
1126 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001127 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001128 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001129 len += 1;
1130 empty = false;
1131 }
1132 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001133 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001134 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001135 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001136 }
1137}
1138
1139named!(boolean -> (), alt!(
1140 keyword!("true") => { |_| () }
1141 |
1142 keyword!("false") => { |_| () }
1143));
1144
Nika Layzellf8d5f212017-12-11 14:07:02 -05001145fn op(input: Cursor) -> PResult<(char, Spacing)> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001146 let input = skip_whitespace(input);
1147 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001148 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001149 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001150 Ok(_) => Spacing::Joint,
1151 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001152 };
David Tolnay1218e122017-06-01 11:13:45 -07001153 Ok((rest, (ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001154 }
David Tolnay1218e122017-06-01 11:13:45 -07001155 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001156 }
1157}
1158
Nika Layzellf8d5f212017-12-11 14:07:02 -05001159fn op_char(input: Cursor) -> PResult<char> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001160 let mut chars = input.chars();
1161 let first = match chars.next() {
1162 Some(ch) => ch,
1163 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001164 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001165 }
1166 };
1167 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1168 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001169 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001170 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001171 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001172 }
1173}
1174
Alex Crichton44bffbc2017-05-19 17:51:59 -07001175named!(doc_comment -> (), alt!(
1176 do_parse!(
1177 punct!("//!") >>
1178 take_until!("\n") >>
1179 (())
1180 )
1181 |
1182 do_parse!(
1183 option!(whitespace) >>
1184 peek!(tag!("/*!")) >>
1185 block_comment >>
1186 (())
1187 )
1188 |
1189 do_parse!(
1190 punct!("///") >>
1191 not!(tag!("/")) >>
1192 take_until!("\n") >>
1193 (())
1194 )
1195 |
1196 do_parse!(
1197 option!(whitespace) >>
1198 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1199 block_comment >>
1200 (())
1201 )
1202));