blob: 54210600762a01d8a2668f8ce76c181d6d9f8cfe [file] [log] [blame]
Alex Crichton76a5cc82017-05-23 07:01:44 -07001use std::ascii;
Alex Crichton44bffbc2017-05-19 17:51:59 -07002use std::borrow::Borrow;
3use std::cell::RefCell;
David Tolnay1ebe3972018-01-02 20:14:20 -08004#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -05005use std::cmp;
Alex Crichton44bffbc2017-05-19 17:51:59 -07006use std::collections::HashMap;
7use std::fmt;
8use std::iter;
David Tolnay041bcd42017-06-03 09:18:04 -07009use std::marker::PhantomData;
Alex Crichton44bffbc2017-05-19 17:51:59 -070010use std::rc::Rc;
11use std::str::FromStr;
12use std::vec;
13
David Tolnayb1032662017-05-31 15:52:28 -070014use unicode_xid::UnicodeXID;
Nika Layzellf8d5f212017-12-11 14:07:02 -050015use strnom::{Cursor, PResult, skip_whitespace, block_comment, whitespace, word_break};
Alex Crichton44bffbc2017-05-19 17:51:59 -070016
Alex Crichton1a7f7622017-07-05 17:47:15 -070017use {TokenTree, TokenNode, Delimiter, Spacing};
Alex Crichton44bffbc2017-05-19 17:51:59 -070018
David Tolnay977f8282017-05-31 17:41:33 -070019#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -070020pub struct TokenStream {
21 inner: Vec<TokenTree>,
22}
23
24#[derive(Debug)]
25pub struct LexError;
26
27impl TokenStream {
28 pub fn empty() -> TokenStream {
29 TokenStream { inner: Vec::new() }
30 }
31
32 pub fn is_empty(&self) -> bool {
33 self.inner.len() == 0
34 }
35}
36
David Tolnay1ebe3972018-01-02 20:14:20 -080037#[cfg(procmacro2_semver_exempt)]
Nika Layzella9dbc182017-12-30 14:50:13 -050038fn get_cursor(src: &str) -> Cursor {
39 // Create a dummy file & add it to the codemap
40 CODEMAP.with(|cm| {
41 let mut cm = cm.borrow_mut();
42 let name = format!("<parsed string {}>", cm.files.len());
43 let span = cm.add_file(&name, src);
44 Cursor {
45 rest: src,
46 off: span.lo,
47 }
48 })
49}
50
David Tolnay1ebe3972018-01-02 20:14:20 -080051#[cfg(not(procmacro2_semver_exempt))]
Nika Layzella9dbc182017-12-30 14:50:13 -050052fn get_cursor(src: &str) -> Cursor {
53 Cursor {
54 rest: src,
Nika Layzella9dbc182017-12-30 14:50:13 -050055 }
56}
57
Alex Crichton44bffbc2017-05-19 17:51:59 -070058impl FromStr for TokenStream {
59 type Err = LexError;
60
61 fn from_str(src: &str) -> Result<TokenStream, LexError> {
Nika Layzellf8d5f212017-12-11 14:07:02 -050062 // Create a dummy file & add it to the codemap
Nika Layzella9dbc182017-12-30 14:50:13 -050063 let cursor = get_cursor(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -050064
65 match token_stream(cursor) {
David Tolnay1218e122017-06-01 11:13:45 -070066 Ok((input, output)) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -070067 if skip_whitespace(input).len() != 0 {
68 Err(LexError)
69 } else {
David Tolnay8e976c62017-06-01 12:12:29 -070070 Ok(output.0)
Alex Crichton44bffbc2017-05-19 17:51:59 -070071 }
72 }
David Tolnay1218e122017-06-01 11:13:45 -070073 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -070074 }
75 }
76}
77
78impl fmt::Display for TokenStream {
79 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80 let mut joint = false;
81 for (i, tt) in self.inner.iter().enumerate() {
82 if i != 0 && !joint {
83 write!(f, " ")?;
84 }
85 joint = false;
86 match tt.kind {
Alex Crichton1a7f7622017-07-05 17:47:15 -070087 TokenNode::Group(delim, ref stream) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -070088 let (start, end) = match delim {
89 Delimiter::Parenthesis => ("(", ")"),
90 Delimiter::Brace => ("{", "}"),
91 Delimiter::Bracket => ("[", "]"),
92 Delimiter::None => ("", ""),
93 };
Alex Crichton852d53d2017-05-19 19:25:08 -070094 if stream.0.inner.len() == 0 {
95 write!(f, "{} {}", start, end)?
96 } else {
97 write!(f, "{} {} {}", start, stream, end)?
98 }
Alex Crichton44bffbc2017-05-19 17:51:59 -070099 }
Alex Crichton1a7f7622017-07-05 17:47:15 -0700100 TokenNode::Term(ref sym) => write!(f, "{}", sym.as_str())?,
101 TokenNode::Op(ch, ref op) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700102 write!(f, "{}", ch)?;
103 match *op {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700104 Spacing::Alone => {}
105 Spacing::Joint => joint = true,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700106 }
107 }
Alex Crichton1a7f7622017-07-05 17:47:15 -0700108 TokenNode::Literal(ref literal) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700109 write!(f, "{}", literal)?;
110 // handle comments
111 if (literal.0).0.starts_with("/") {
112 write!(f, "\n")?;
113 }
114 }
115 }
116 }
117
118 Ok(())
119 }
120}
121
Alex Crichton0e8e7f42018-02-22 06:15:13 -0800122#[cfg(feature = "proc-macro")]
123impl From<::proc_macro::TokenStream> for TokenStream {
124 fn from(inner: ::proc_macro::TokenStream) -> TokenStream {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700125 inner.to_string().parse().expect("compiler token stream parse failed")
126 }
127}
128
Alex Crichton0e8e7f42018-02-22 06:15:13 -0800129#[cfg(feature = "proc-macro")]
130impl From<TokenStream> for ::proc_macro::TokenStream {
131 fn from(inner: TokenStream) -> ::proc_macro::TokenStream {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700132 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
David Tolnay10effeb2018-01-06 11:07:49 -0800401impl Term {
402 pub fn intern(string: &str) -> Term {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700403 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 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700408
David Tolnay10effeb2018-01-06 11:07:49 -0800409 pub fn as_str(&self) -> &str {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700410 SYMBOLS.with(|interner| {
411 let interner = interner.borrow();
David Tolnay041bcd42017-06-03 09:18:04 -0700412 let s = interner.get(self.intern);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700413 unsafe {
414 &*(s as *const str)
415 }
416 })
417 }
418}
419
Alex Crichton1a7f7622017-07-05 17:47:15 -0700420impl fmt::Debug for Term {
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700421 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
David Tolnay10effeb2018-01-06 11:07:49 -0800422 f.debug_tuple("Term").field(&self.as_str()).finish()
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700423 }
424}
425
Alex Crichton44bffbc2017-05-19 17:51:59 -0700426struct Interner {
427 string_to_index: HashMap<MyRc, usize>,
428 index_to_string: Vec<Rc<String>>,
429}
430
431#[derive(Hash, Eq, PartialEq)]
432struct MyRc(Rc<String>);
433
434impl Borrow<str> for MyRc {
435 fn borrow(&self) -> &str {
436 &self.0
437 }
438}
439
440impl Interner {
441 fn new() -> Interner {
442 Interner {
443 string_to_index: HashMap::new(),
444 index_to_string: Vec::new(),
445 }
446 }
447
448 fn intern(&mut self, s: &str) -> usize {
449 if let Some(&idx) = self.string_to_index.get(s) {
450 return idx
451 }
452 let s = Rc::new(s.to_string());
453 self.index_to_string.push(s.clone());
454 self.string_to_index.insert(MyRc(s), self.index_to_string.len() - 1);
455 self.index_to_string.len() - 1
456 }
457
458 fn get(&self, idx: usize) -> &str {
459 &self.index_to_string[idx]
460 }
461}
462
David Tolnay977f8282017-05-31 17:41:33 -0700463#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700464pub struct Literal(String);
465
Alex Crichton852d53d2017-05-19 19:25:08 -0700466impl Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700467 pub fn byte_char(byte: u8) -> Literal {
Alex Crichton76a5cc82017-05-23 07:01:44 -0700468 match byte {
469 0 => Literal(format!("b'\\0'")),
470 b'\"' => Literal(format!("b'\"'")),
471 n => {
472 let mut escaped = "b'".to_string();
473 escaped.extend(ascii::escape_default(n).map(|c| c as char));
474 escaped.push('\'');
475 Literal(escaped)
476 }
477 }
478 }
479
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700480 pub fn byte_string(bytes: &[u8]) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700481 let mut escaped = "b\"".to_string();
482 for b in bytes {
483 match *b {
484 b'\0' => escaped.push_str(r"\0"),
485 b'\t' => escaped.push_str(r"\t"),
486 b'\n' => escaped.push_str(r"\n"),
487 b'\r' => escaped.push_str(r"\r"),
488 b'"' => escaped.push_str("\\\""),
489 b'\\' => escaped.push_str("\\\\"),
490 b'\x20' ... b'\x7E' => escaped.push(*b as char),
491 _ => escaped.push_str(&format!("\\x{:02X}", b)),
492 }
493 }
494 escaped.push('"');
495 Literal(escaped)
496 }
Alex Crichton76a5cc82017-05-23 07:01:44 -0700497
498 pub fn doccomment(s: &str) -> Literal {
499 Literal(s.to_string())
500 }
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700501
David Tolnay114990e2018-01-05 11:17:08 -0800502 pub fn float(n: f64) -> Literal {
503 if !n.is_finite() {
504 panic!("Invalid float literal {}", n);
505 }
506 let mut s = n.to_string();
507 if !s.contains('.') {
508 s += ".0";
509 }
510 Literal(s)
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700511 }
512
Alex Crichton1a7f7622017-07-05 17:47:15 -0700513 pub fn integer(s: i64) -> Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700514 Literal(s.to_string())
515 }
Alex Crichton31316622017-05-26 12:54:47 -0700516
517 pub fn raw_string(s: &str, pounds: usize) -> Literal {
518 let mut ret = format!("r");
519 ret.extend((0..pounds).map(|_| "#"));
520 ret.push('"');
521 ret.push_str(s);
522 ret.push('"');
523 ret.extend((0..pounds).map(|_| "#"));
524 Literal(ret)
525 }
526
527 pub fn raw_byte_string(s: &str, pounds: usize) -> Literal {
Alex Crichton7ed6d282017-05-26 13:42:50 -0700528 let mut ret = format!("br");
Alex Crichton31316622017-05-26 12:54:47 -0700529 ret.extend((0..pounds).map(|_| "#"));
530 ret.push('"');
531 ret.push_str(s);
532 ret.push('"');
533 ret.extend((0..pounds).map(|_| "#"));
534 Literal(ret)
535 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700536}
537
Alex Crichton44bffbc2017-05-19 17:51:59 -0700538impl fmt::Display for Literal {
539 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
540 self.0.fmt(f)
541 }
542}
543
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700544macro_rules! ints {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700545 ($($t:ty,)*) => {$(
546 impl From<$t> for Literal {
547 fn from(t: $t) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700548 Literal(format!(concat!("{}", stringify!($t)), t))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700549 }
550 }
551 )*}
552}
553
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700554ints! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700555 u8, u16, u32, u64, usize,
556 i8, i16, i32, i64, isize,
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700557}
558
559macro_rules! floats {
560 ($($t:ty,)*) => {$(
561 impl From<$t> for Literal {
562 fn from(t: $t) -> Literal {
563 assert!(!t.is_nan());
564 assert!(!t.is_infinite());
565 Literal(format!(concat!("{}", stringify!($t)), t))
566 }
567 }
568 )*}
569}
570
571floats! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700572 f32, f64,
573}
574
Alex Crichton44bffbc2017-05-19 17:51:59 -0700575impl<'a> From<&'a str> for Literal {
576 fn from(t: &'a str) -> Literal {
577 let mut s = t.chars().flat_map(|c| c.escape_default()).collect::<String>();
578 s.push('"');
579 s.insert(0, '"');
580 Literal(s)
581 }
582}
583
584impl From<char> for Literal {
585 fn from(t: char) -> Literal {
Alex Crichton2d0cf0b2017-05-26 14:00:16 -0700586 Literal(format!("'{}'", t.escape_default().collect::<String>()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700587 }
588}
589
David Tolnay8e976c62017-06-01 12:12:29 -0700590named!(token_stream -> ::TokenStream, map!(
591 many0!(token_tree),
592 |trees| ::TokenStream(TokenStream { inner: trees })
593));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700594
David Tolnay1ebe3972018-01-02 20:14:20 -0800595#[cfg(not(procmacro2_semver_exempt))]
David Tolnayddfca052017-12-31 10:41:24 -0500596fn token_tree(input: Cursor) -> PResult<TokenTree> {
597 let (input, kind) = token_kind(input)?;
598 Ok((input, TokenTree {
599 span: ::Span(Span {}),
600 kind: kind,
601 }))
602}
603
David Tolnay1ebe3972018-01-02 20:14:20 -0800604#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500605fn token_tree(input: Cursor) -> PResult<TokenTree> {
606 let input = skip_whitespace(input);
607 let lo = input.off;
608 let (input, kind) = token_kind(input)?;
609 let hi = input.off;
610 Ok((input, TokenTree {
611 span: ::Span(Span {
612 lo: lo,
613 hi: hi,
614 }),
615 kind: kind,
616 }))
617}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700618
Alex Crichton1a7f7622017-07-05 17:47:15 -0700619named!(token_kind -> TokenNode, alt!(
620 map!(delimited, |(d, s)| TokenNode::Group(d, s))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700621 |
Alex Crichton1a7f7622017-07-05 17:47:15 -0700622 map!(literal, TokenNode::Literal) // must be before symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700623 |
Alex Crichton52725f72017-08-28 12:20:58 -0700624 symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700625 |
Alex Crichton1a7f7622017-07-05 17:47:15 -0700626 map!(op, |(op, kind)| TokenNode::Op(op, kind))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700627));
628
David Tolnay8e976c62017-06-01 12:12:29 -0700629named!(delimited -> (Delimiter, ::TokenStream), alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -0700630 delimited!(
631 punct!("("),
632 token_stream,
633 punct!(")")
634 ) => { |ts| (Delimiter::Parenthesis, ts) }
635 |
636 delimited!(
637 punct!("["),
638 token_stream,
639 punct!("]")
640 ) => { |ts| (Delimiter::Bracket, ts) }
641 |
642 delimited!(
643 punct!("{"),
644 token_stream,
645 punct!("}")
646 ) => { |ts| (Delimiter::Brace, ts) }
647));
648
Nika Layzellf8d5f212017-12-11 14:07:02 -0500649fn symbol(mut input: Cursor) -> PResult<TokenNode> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700650 input = skip_whitespace(input);
651
652 let mut chars = input.char_indices();
David Tolnaya202d502017-06-01 12:26:55 -0700653
654 let lifetime = input.starts_with("'");
655 if lifetime {
656 chars.next();
657 }
658
Alex Crichton44bffbc2017-05-19 17:51:59 -0700659 match chars.next() {
660 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700661 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700662 }
663
David Tolnay214c94c2017-06-01 12:42:56 -0700664 let mut end = input.len();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700665 for (i, ch) in chars {
666 if !UnicodeXID::is_xid_continue(ch) {
David Tolnay214c94c2017-06-01 12:42:56 -0700667 end = i;
668 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700669 }
670 }
671
Nika Layzellf8d5f212017-12-11 14:07:02 -0500672 if lifetime && &input.rest[..end] != "'static" && KEYWORDS.contains(&&input.rest[1..end]) {
David Tolnay214c94c2017-06-01 12:42:56 -0700673 Err(LexError)
674 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500675 let a = &input.rest[..end];
Alex Crichton52725f72017-08-28 12:20:58 -0700676 if a == "_" {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500677 Ok((input.advance(end), TokenNode::Op('_', Spacing::Alone)))
Alex Crichton52725f72017-08-28 12:20:58 -0700678 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500679 Ok((input.advance(end), TokenNode::Term(::Term::intern(a))))
Alex Crichton52725f72017-08-28 12:20:58 -0700680 }
David Tolnay214c94c2017-06-01 12:42:56 -0700681 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700682}
683
David Tolnay214c94c2017-06-01 12:42:56 -0700684// From https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/symbol.rs
685static KEYWORDS: &'static [&'static str] = &[
686 "abstract", "alignof", "as", "become", "box", "break", "const", "continue",
687 "crate", "do", "else", "enum", "extern", "false", "final", "fn", "for",
688 "if", "impl", "in", "let", "loop", "macro", "match", "mod", "move", "mut",
689 "offsetof", "override", "priv", "proc", "pub", "pure", "ref", "return",
690 "self", "Self", "sizeof", "static", "struct", "super", "trait", "true",
691 "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while",
692 "yield",
693];
694
Nika Layzellf8d5f212017-12-11 14:07:02 -0500695fn literal(input: Cursor) -> PResult<::Literal> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700696 let input_no_ws = skip_whitespace(input);
697
698 match literal_nocapture(input_no_ws) {
David Tolnay1218e122017-06-01 11:13:45 -0700699 Ok((a, ())) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700700 let start = input.len() - input_no_ws.len();
701 let len = input_no_ws.len() - a.len();
702 let end = start + len;
Nika Layzellf8d5f212017-12-11 14:07:02 -0500703 Ok((a, ::Literal(Literal(input.rest[start..end].to_string()))))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700704 }
David Tolnay1218e122017-06-01 11:13:45 -0700705 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700706 }
707}
708
709named!(literal_nocapture -> (), alt!(
710 string
711 |
712 byte_string
713 |
714 byte
715 |
716 character
717 |
718 float
719 |
720 int
721 |
Alex Crichton44bffbc2017-05-19 17:51:59 -0700722 doc_comment
723));
724
725named!(string -> (), alt!(
726 quoted_string
727 |
728 preceded!(
729 punct!("r"),
730 raw_string
731 ) => { |_| () }
732));
733
734named!(quoted_string -> (), delimited!(
735 punct!("\""),
736 cooked_string,
737 tag!("\"")
738));
739
Nika Layzellf8d5f212017-12-11 14:07:02 -0500740fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700741 let mut chars = input.char_indices().peekable();
742 while let Some((byte_offset, ch)) = chars.next() {
743 match ch {
744 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500745 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700746 }
747 '\r' => {
748 if let Some((_, '\n')) = chars.next() {
749 // ...
750 } else {
751 break;
752 }
753 }
754 '\\' => {
755 match chars.next() {
756 Some((_, 'x')) => {
757 if !backslash_x_char(&mut chars) {
758 break
759 }
760 }
761 Some((_, 'n')) |
762 Some((_, 'r')) |
763 Some((_, 't')) |
764 Some((_, '\\')) |
765 Some((_, '\'')) |
766 Some((_, '"')) |
767 Some((_, '0')) => {}
768 Some((_, 'u')) => {
769 if !backslash_u(&mut chars) {
770 break
771 }
772 }
773 Some((_, '\n')) | Some((_, '\r')) => {
774 while let Some(&(_, ch)) = chars.peek() {
775 if ch.is_whitespace() {
776 chars.next();
777 } else {
778 break;
779 }
780 }
781 }
782 _ => break,
783 }
784 }
785 _ch => {}
786 }
787 }
David Tolnay1218e122017-06-01 11:13:45 -0700788 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700789}
790
791named!(byte_string -> (), alt!(
792 delimited!(
793 punct!("b\""),
794 cooked_byte_string,
795 tag!("\"")
796 ) => { |_| () }
797 |
798 preceded!(
799 punct!("br"),
800 raw_string
801 ) => { |_| () }
802));
803
Nika Layzellf8d5f212017-12-11 14:07:02 -0500804fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700805 let mut bytes = input.bytes().enumerate();
806 'outer: while let Some((offset, b)) = bytes.next() {
807 match b {
808 b'"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500809 return Ok((input.advance(offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700810 }
811 b'\r' => {
812 if let Some((_, b'\n')) = bytes.next() {
813 // ...
814 } else {
815 break;
816 }
817 }
818 b'\\' => {
819 match bytes.next() {
820 Some((_, b'x')) => {
821 if !backslash_x_byte(&mut bytes) {
822 break
823 }
824 }
825 Some((_, b'n')) |
826 Some((_, b'r')) |
827 Some((_, b't')) |
828 Some((_, b'\\')) |
829 Some((_, b'0')) |
830 Some((_, b'\'')) |
831 Some((_, b'"')) => {}
832 Some((newline, b'\n')) |
833 Some((newline, b'\r')) => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500834 let rest = input.advance(newline + 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700835 for (offset, ch) in rest.char_indices() {
836 if !ch.is_whitespace() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500837 input = rest.advance(offset);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700838 bytes = input.bytes().enumerate();
839 continue 'outer;
840 }
841 }
842 break;
843 }
844 _ => break,
845 }
846 }
847 b if b < 0x80 => {}
848 _ => break,
849 }
850 }
David Tolnay1218e122017-06-01 11:13:45 -0700851 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700852}
853
Nika Layzellf8d5f212017-12-11 14:07:02 -0500854fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700855 let mut chars = input.char_indices();
856 let mut n = 0;
857 while let Some((byte_offset, ch)) = chars.next() {
858 match ch {
859 '"' => {
860 n = byte_offset;
861 break;
862 }
863 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700864 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700865 }
866 }
867 for (byte_offset, ch) in chars {
868 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500869 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
870 let rest = input.advance(byte_offset + 1 + n);
David Tolnay1218e122017-06-01 11:13:45 -0700871 return Ok((rest, ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700872 }
873 '\r' => {}
874 _ => {}
875 }
876 }
David Tolnay1218e122017-06-01 11:13:45 -0700877 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700878}
879
880named!(byte -> (), do_parse!(
881 punct!("b") >>
882 tag!("'") >>
883 cooked_byte >>
884 tag!("'") >>
885 (())
886));
887
Nika Layzellf8d5f212017-12-11 14:07:02 -0500888fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700889 let mut bytes = input.bytes().enumerate();
890 let ok = match bytes.next().map(|(_, b)| b) {
891 Some(b'\\') => {
892 match bytes.next().map(|(_, b)| b) {
893 Some(b'x') => backslash_x_byte(&mut bytes),
894 Some(b'n') |
895 Some(b'r') |
896 Some(b't') |
897 Some(b'\\') |
898 Some(b'0') |
899 Some(b'\'') |
900 Some(b'"') => true,
901 _ => false,
902 }
903 }
904 b => b.is_some(),
905 };
906 if ok {
907 match bytes.next() {
Alex Crichton8c030332018-01-16 08:07:36 -0800908 Some((offset, _)) => {
909 if input.chars().as_str().is_char_boundary(offset) {
910 Ok((input.advance(offset), ()))
911 } else {
912 Err(LexError)
913 }
914 }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500915 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
Nika Layzellf8d5f212017-12-11 14:07:02 -05001150fn op(input: Cursor) -> PResult<(char, Spacing)> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001151 let input = skip_whitespace(input);
1152 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001153 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001154 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001155 Ok(_) => Spacing::Joint,
1156 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001157 };
David Tolnay1218e122017-06-01 11:13:45 -07001158 Ok((rest, (ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001159 }
David Tolnay1218e122017-06-01 11:13:45 -07001160 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001161 }
1162}
1163
Nika Layzellf8d5f212017-12-11 14:07:02 -05001164fn op_char(input: Cursor) -> PResult<char> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001165 let mut chars = input.chars();
1166 let first = match chars.next() {
1167 Some(ch) => ch,
1168 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001169 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001170 }
1171 };
1172 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1173 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001174 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001175 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001176 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001177 }
1178}
1179
Alex Crichton44bffbc2017-05-19 17:51:59 -07001180named!(doc_comment -> (), alt!(
1181 do_parse!(
1182 punct!("//!") >>
Alex Crichtond7904e52018-01-23 11:08:45 -08001183 take_until_newline_or_eof!() >>
Alex Crichton44bffbc2017-05-19 17:51:59 -07001184 (())
1185 )
1186 |
1187 do_parse!(
1188 option!(whitespace) >>
1189 peek!(tag!("/*!")) >>
1190 block_comment >>
1191 (())
1192 )
1193 |
1194 do_parse!(
1195 punct!("///") >>
1196 not!(tag!("/")) >>
Alex Crichtond7904e52018-01-23 11:08:45 -08001197 take_until_newline_or_eof!() >>
Alex Crichton44bffbc2017-05-19 17:51:59 -07001198 (())
1199 )
1200 |
1201 do_parse!(
1202 option!(whitespace) >>
1203 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1204 block_comment >>
1205 (())
1206 )
1207));