blob: b04e4cac7d319b8b328bd339705d85733b7423fc [file] [log] [blame]
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001#![allow(dead_code)]
2
Alex Crichton76a5cc82017-05-23 07:01:44 -07003use std::ascii;
Alex Crichton44bffbc2017-05-19 17:51:59 -07004use std::borrow::Borrow;
5use std::cell::RefCell;
David Tolnay1ebe3972018-01-02 20:14:20 -08006#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -05007use std::cmp;
Alex Crichton44bffbc2017-05-19 17:51:59 -07008use std::collections::HashMap;
9use std::fmt;
10use std::iter;
David Tolnay041bcd42017-06-03 09:18:04 -070011use std::marker::PhantomData;
Alex Crichton44bffbc2017-05-19 17:51:59 -070012use std::rc::Rc;
13use std::str::FromStr;
14use std::vec;
15
David Tolnayb28f38a2018-03-31 22:02:29 +020016use strnom::{block_comment, skip_whitespace, whitespace, word_break, Cursor, PResult};
David Tolnayb1032662017-05-31 15:52:28 -070017use unicode_xid::UnicodeXID;
Alex Crichton44bffbc2017-05-19 17:51:59 -070018
David Tolnayb28f38a2018-03-31 22:02:29 +020019use {Delimiter, Group, Op, Spacing, TokenTree};
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 {
David Tolnayb28f38a2018-03-31 22:02:29 +020055 Cursor { rest: src }
Nika Layzella9dbc182017-12-30 14:50:13 -050056}
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 {
Alex Crichtonaf5bad42018-03-27 14:45:10 -070070 Ok(output.inner)
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;
Alex Crichtonaf5bad42018-03-27 14:45:10 -070086 match *tt {
87 TokenTree::Group(ref tt) => {
88 let (start, end) = match tt.delimiter() {
Alex Crichton44bffbc2017-05-19 17:51:59 -070089 Delimiter::Parenthesis => ("(", ")"),
90 Delimiter::Brace => ("{", "}"),
91 Delimiter::Bracket => ("[", "]"),
92 Delimiter::None => ("", ""),
93 };
Alex Crichtonaf5bad42018-03-27 14:45:10 -070094 if tt.stream().inner.inner.len() == 0 {
Alex Crichton852d53d2017-05-19 19:25:08 -070095 write!(f, "{} {}", start, end)?
96 } else {
Alex Crichtonaf5bad42018-03-27 14:45:10 -070097 write!(f, "{} {} {}", start, tt.stream(), end)?
Alex Crichton852d53d2017-05-19 19:25:08 -070098 }
Alex Crichton44bffbc2017-05-19 17:51:59 -070099 }
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700100 TokenTree::Term(ref tt) => write!(f, "{}", tt.as_str())?,
101 TokenTree::Op(ref tt) => {
102 write!(f, "{}", tt.op())?;
103 match tt.spacing() {
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 Crichtonaf5bad42018-03-27 14:45:10 -0700108 TokenTree::Literal(ref tt) => {
109 write!(f, "{}", tt)?;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700110 // handle comments
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700111 if tt.inner.0.starts_with("/") {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700112 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 {
David Tolnayb28f38a2018-03-31 22:02:29 +0200125 inner
126 .to_string()
127 .parse()
128 .expect("compiler token stream parse failed")
Alex Crichton44bffbc2017-05-19 17:51:59 -0700129 }
130}
131
Alex Crichton0e8e7f42018-02-22 06:15:13 -0800132#[cfg(feature = "proc-macro")]
133impl From<TokenStream> for ::proc_macro::TokenStream {
134 fn from(inner: TokenStream) -> ::proc_macro::TokenStream {
David Tolnayb28f38a2018-03-31 22:02:29 +0200135 inner
136 .to_string()
137 .parse()
138 .expect("failed to parse to compiler tokens")
Alex Crichton44bffbc2017-05-19 17:51:59 -0700139 }
140}
141
Alex Crichton44bffbc2017-05-19 17:51:59 -0700142impl From<TokenTree> for TokenStream {
143 fn from(tree: TokenTree) -> TokenStream {
144 TokenStream { inner: vec![tree] }
145 }
146}
147
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700148impl iter::FromIterator<TokenTree> for TokenStream {
David Tolnayb28f38a2018-03-31 22:02:29 +0200149 fn from_iter<I: IntoIterator<Item = TokenTree>>(streams: I) -> Self {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700150 let mut v = Vec::new();
151
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700152 for token in streams.into_iter() {
153 v.push(token);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700154 }
155
156 TokenStream { inner: v }
157 }
158}
159
Alex Crichton1a7f7622017-07-05 17:47:15 -0700160pub type TokenTreeIter = vec::IntoIter<TokenTree>;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700161
162impl IntoIterator for TokenStream {
163 type Item = TokenTree;
Alex Crichton1a7f7622017-07-05 17:47:15 -0700164 type IntoIter = TokenTreeIter;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700165
Alex Crichton1a7f7622017-07-05 17:47:15 -0700166 fn into_iter(self) -> TokenTreeIter {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700167 self.inner.into_iter()
168 }
169}
170
David Tolnay1ebe3972018-01-02 20:14:20 -0800171#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500172#[derive(Clone, PartialEq, Eq, Debug)]
173pub struct FileName(String);
174
David Tolnay1ebe3972018-01-02 20:14:20 -0800175#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500176impl fmt::Display for FileName {
177 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
178 self.0.fmt(f)
179 }
180}
181
David Tolnay1ebe3972018-01-02 20:14:20 -0800182#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500183#[derive(Clone, PartialEq, Eq)]
184pub struct SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500185 name: FileName,
Nika Layzellf8d5f212017-12-11 14:07:02 -0500186}
187
David Tolnay1ebe3972018-01-02 20:14:20 -0800188#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500189impl SourceFile {
190 /// Get the path to this source file as a string.
Nika Layzellb35a9a32017-12-30 14:34:35 -0500191 pub fn path(&self) -> &FileName {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500192 &self.name
193 }
194
195 pub fn is_real(&self) -> bool {
196 // XXX(nika): Support real files in the future?
197 false
198 }
199}
200
David Tolnay1ebe3972018-01-02 20:14:20 -0800201#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500202impl AsRef<FileName> for SourceFile {
203 fn as_ref(&self) -> &FileName {
204 self.path()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500205 }
206}
207
David Tolnay1ebe3972018-01-02 20:14:20 -0800208#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500209impl fmt::Debug for SourceFile {
210 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
211 f.debug_struct("SourceFile")
Nika Layzellb35a9a32017-12-30 14:34:35 -0500212 .field("path", &self.path())
Nika Layzellf8d5f212017-12-11 14:07:02 -0500213 .field("is_real", &self.is_real())
214 .finish()
215 }
216}
217
David Tolnay1ebe3972018-01-02 20:14:20 -0800218#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500219#[derive(Clone, Copy, Debug, PartialEq, Eq)]
220pub struct LineColumn {
221 pub line: usize,
222 pub column: usize,
223}
224
David Tolnay1ebe3972018-01-02 20:14:20 -0800225#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500226thread_local! {
227 static CODEMAP: RefCell<Codemap> = RefCell::new(Codemap {
228 // NOTE: We start with a single dummy file which all call_site() and
229 // def_site() spans reference.
230 files: vec![FileInfo {
231 name: "<unspecified>".to_owned(),
232 span: Span { lo: 0, hi: 0 },
233 lines: vec![0],
234 }],
235 });
236}
237
David Tolnay1ebe3972018-01-02 20:14:20 -0800238#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500239struct FileInfo {
240 name: String,
241 span: Span,
242 lines: Vec<usize>,
243}
244
David Tolnay1ebe3972018-01-02 20:14:20 -0800245#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500246impl FileInfo {
247 fn offset_line_column(&self, offset: usize) -> LineColumn {
David Tolnayb28f38a2018-03-31 22:02:29 +0200248 assert!(self.span_within(Span {
249 lo: offset as u32,
250 hi: offset as u32
251 }));
Nika Layzellf8d5f212017-12-11 14:07:02 -0500252 let offset = offset - self.span.lo as usize;
253 match self.lines.binary_search(&offset) {
254 Ok(found) => LineColumn {
255 line: found + 1,
David Tolnayb28f38a2018-03-31 22:02:29 +0200256 column: 0,
Nika Layzellf8d5f212017-12-11 14:07:02 -0500257 },
258 Err(idx) => LineColumn {
259 line: idx,
David Tolnayb28f38a2018-03-31 22:02:29 +0200260 column: offset - self.lines[idx - 1],
Nika Layzellf8d5f212017-12-11 14:07:02 -0500261 },
262 }
263 }
264
265 fn span_within(&self, span: Span) -> bool {
266 span.lo >= self.span.lo && span.hi <= self.span.hi
267 }
268}
269
270/// Computes the offsets of each line in the given source string.
David Tolnay1ebe3972018-01-02 20:14:20 -0800271#[cfg(procmacro2_semver_exempt)]
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500272fn lines_offsets(s: &str) -> Vec<usize> {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500273 let mut lines = vec![0];
274 let mut prev = 0;
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500275 while let Some(len) = s[prev..].find('\n') {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500276 prev += len + 1;
277 lines.push(prev);
278 }
279 lines
280}
281
David Tolnay1ebe3972018-01-02 20:14:20 -0800282#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500283struct Codemap {
284 files: Vec<FileInfo>,
285}
286
David Tolnay1ebe3972018-01-02 20:14:20 -0800287#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500288impl Codemap {
289 fn next_start_pos(&self) -> u32 {
290 // Add 1 so there's always space between files.
291 //
292 // We'll always have at least 1 file, as we initialize our files list
293 // with a dummy file.
294 self.files.last().unwrap().span.hi + 1
295 }
296
297 fn add_file(&mut self, name: &str, src: &str) -> Span {
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500298 let lines = lines_offsets(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -0500299 let lo = self.next_start_pos();
300 // XXX(nika): Shouild we bother doing a checked cast or checked add here?
David Tolnayb28f38a2018-03-31 22:02:29 +0200301 let span = Span {
302 lo: lo,
303 hi: lo + (src.len() as u32),
304 };
Nika Layzellf8d5f212017-12-11 14:07:02 -0500305
306 self.files.push(FileInfo {
307 name: name.to_owned(),
308 span: span,
309 lines: lines,
310 });
311
312 span
313 }
314
315 fn fileinfo(&self, span: Span) -> &FileInfo {
316 for file in &self.files {
317 if file.span_within(span) {
318 return file;
319 }
320 }
321 panic!("Invalid span with no related FileInfo!");
322 }
323}
324
Nika Layzell99737982018-03-11 18:51:27 -0400325#[derive(Clone, Copy, Debug, PartialEq, Eq)]
David Tolnayddfca052017-12-31 10:41:24 -0500326pub struct Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800327 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500328 lo: u32,
David Tolnay1ebe3972018-01-02 20:14:20 -0800329 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500330 hi: u32,
331}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700332
333impl Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800334 #[cfg(not(procmacro2_semver_exempt))]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700335 pub fn call_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500336 Span {}
337 }
338
David Tolnay1ebe3972018-01-02 20:14:20 -0800339 #[cfg(procmacro2_semver_exempt)]
David Tolnay79105e52017-12-31 11:03:04 -0500340 pub fn call_site() -> Span {
341 Span { lo: 0, hi: 0 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700342 }
Alex Crichtone6085b72017-11-21 07:24:25 -0800343
344 pub fn def_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500345 Span::call_site()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500346 }
347
David Tolnay4e8e3972018-01-05 18:10:22 -0800348 pub fn resolved_at(&self, _other: Span) -> Span {
349 // Stable spans consist only of line/column information, so
350 // `resolved_at` and `located_at` only select which span the
351 // caller wants line/column information from.
352 *self
353 }
354
355 pub fn located_at(&self, other: Span) -> Span {
356 other
357 }
358
David Tolnay1ebe3972018-01-02 20:14:20 -0800359 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500360 pub fn source_file(&self) -> SourceFile {
361 CODEMAP.with(|cm| {
362 let cm = cm.borrow();
363 let fi = cm.fileinfo(*self);
364 SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500365 name: FileName(fi.name.clone()),
Nika Layzellf8d5f212017-12-11 14:07:02 -0500366 }
367 })
368 }
369
David Tolnay1ebe3972018-01-02 20:14:20 -0800370 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500371 pub fn start(&self) -> LineColumn {
372 CODEMAP.with(|cm| {
373 let cm = cm.borrow();
374 let fi = cm.fileinfo(*self);
375 fi.offset_line_column(self.lo as usize)
376 })
377 }
378
David Tolnay1ebe3972018-01-02 20:14:20 -0800379 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500380 pub fn end(&self) -> LineColumn {
381 CODEMAP.with(|cm| {
382 let cm = cm.borrow();
383 let fi = cm.fileinfo(*self);
384 fi.offset_line_column(self.hi as usize)
385 })
386 }
387
David Tolnay1ebe3972018-01-02 20:14:20 -0800388 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500389 pub fn join(&self, other: Span) -> Option<Span> {
390 CODEMAP.with(|cm| {
391 let cm = cm.borrow();
392 // If `other` is not within the same FileInfo as us, return None.
393 if !cm.fileinfo(*self).span_within(other) {
394 return None;
395 }
396 Some(Span {
397 lo: cmp::min(self.lo, other.lo),
398 hi: cmp::max(self.hi, other.hi),
399 })
400 })
Alex Crichtone6085b72017-11-21 07:24:25 -0800401 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700402}
403
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700404#[derive(Copy, Clone)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700405pub struct Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700406 intern: usize,
407 not_send_sync: PhantomData<*const ()>,
408}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700409
410thread_local!(static SYMBOLS: RefCell<Interner> = RefCell::new(Interner::new()));
411
David Tolnay10effeb2018-01-06 11:07:49 -0800412impl Term {
413 pub fn intern(string: &str) -> Term {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700414 Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700415 intern: SYMBOLS.with(|s| s.borrow_mut().intern(string)),
416 not_send_sync: PhantomData,
417 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700418 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700419
David Tolnay10effeb2018-01-06 11:07:49 -0800420 pub fn as_str(&self) -> &str {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700421 SYMBOLS.with(|interner| {
422 let interner = interner.borrow();
David Tolnay041bcd42017-06-03 09:18:04 -0700423 let s = interner.get(self.intern);
David Tolnayb28f38a2018-03-31 22:02:29 +0200424 unsafe { &*(s as *const str) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700425 })
426 }
427}
428
Alex Crichton1a7f7622017-07-05 17:47:15 -0700429impl fmt::Debug for Term {
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700430 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
David Tolnay10effeb2018-01-06 11:07:49 -0800431 f.debug_tuple("Term").field(&self.as_str()).finish()
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700432 }
433}
434
Alex Crichton44bffbc2017-05-19 17:51:59 -0700435struct Interner {
436 string_to_index: HashMap<MyRc, usize>,
437 index_to_string: Vec<Rc<String>>,
438}
439
440#[derive(Hash, Eq, PartialEq)]
441struct MyRc(Rc<String>);
442
443impl Borrow<str> for MyRc {
444 fn borrow(&self) -> &str {
445 &self.0
446 }
447}
448
449impl Interner {
450 fn new() -> Interner {
451 Interner {
452 string_to_index: HashMap::new(),
453 index_to_string: Vec::new(),
454 }
455 }
456
David Tolnayb28f38a2018-03-31 22:02:29 +0200457 fn intern(&mut self, s: &str) -> usize {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700458 if let Some(&idx) = self.string_to_index.get(s) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200459 return idx;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700460 }
461 let s = Rc::new(s.to_string());
462 self.index_to_string.push(s.clone());
David Tolnayb28f38a2018-03-31 22:02:29 +0200463 self.string_to_index
464 .insert(MyRc(s), self.index_to_string.len() - 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700465 self.index_to_string.len() - 1
466 }
467
David Tolnayb28f38a2018-03-31 22:02:29 +0200468 fn get(&self, idx: usize) -> &str {
469 &self.index_to_string[idx]
470 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700471}
472
David Tolnay977f8282017-05-31 17:41:33 -0700473#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700474pub struct Literal(String);
475
Alex Crichton852d53d2017-05-19 19:25:08 -0700476impl Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700477 pub fn byte_char(byte: u8) -> Literal {
Alex Crichton76a5cc82017-05-23 07:01:44 -0700478 match byte {
479 0 => Literal(format!("b'\\0'")),
480 b'\"' => Literal(format!("b'\"'")),
481 n => {
482 let mut escaped = "b'".to_string();
483 escaped.extend(ascii::escape_default(n).map(|c| c as char));
484 escaped.push('\'');
485 Literal(escaped)
486 }
487 }
488 }
489
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700490 pub fn byte_string(bytes: &[u8]) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700491 let mut escaped = "b\"".to_string();
492 for b in bytes {
493 match *b {
494 b'\0' => escaped.push_str(r"\0"),
495 b'\t' => escaped.push_str(r"\t"),
496 b'\n' => escaped.push_str(r"\n"),
497 b'\r' => escaped.push_str(r"\r"),
498 b'"' => escaped.push_str("\\\""),
499 b'\\' => escaped.push_str("\\\\"),
David Tolnayb28f38a2018-03-31 22:02:29 +0200500 b'\x20'...b'\x7E' => escaped.push(*b as char),
Alex Crichton852d53d2017-05-19 19:25:08 -0700501 _ => escaped.push_str(&format!("\\x{:02X}", b)),
502 }
503 }
504 escaped.push('"');
505 Literal(escaped)
506 }
Alex Crichton76a5cc82017-05-23 07:01:44 -0700507
508 pub fn doccomment(s: &str) -> Literal {
509 Literal(s.to_string())
510 }
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700511
David Tolnay114990e2018-01-05 11:17:08 -0800512 pub fn float(n: f64) -> Literal {
513 if !n.is_finite() {
514 panic!("Invalid float literal {}", n);
515 }
516 let mut s = n.to_string();
517 if !s.contains('.') {
518 s += ".0";
519 }
520 Literal(s)
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700521 }
522
Alex Crichton1a7f7622017-07-05 17:47:15 -0700523 pub fn integer(s: i64) -> Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700524 Literal(s.to_string())
525 }
Alex Crichton31316622017-05-26 12:54:47 -0700526
527 pub fn raw_string(s: &str, pounds: usize) -> Literal {
528 let mut ret = format!("r");
529 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 }
536
537 pub fn raw_byte_string(s: &str, pounds: usize) -> Literal {
Alex Crichton7ed6d282017-05-26 13:42:50 -0700538 let mut ret = format!("br");
Alex Crichton31316622017-05-26 12:54:47 -0700539 ret.extend((0..pounds).map(|_| "#"));
540 ret.push('"');
541 ret.push_str(s);
542 ret.push('"');
543 ret.extend((0..pounds).map(|_| "#"));
544 Literal(ret)
545 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700546}
547
Alex Crichton44bffbc2017-05-19 17:51:59 -0700548impl fmt::Display for Literal {
549 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
550 self.0.fmt(f)
551 }
552}
553
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700554macro_rules! ints {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700555 ($($t:ty,)*) => {$(
556 impl From<$t> for Literal {
557 fn from(t: $t) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700558 Literal(format!(concat!("{}", stringify!($t)), t))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700559 }
560 }
561 )*}
562}
563
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700564ints! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700565 u8, u16, u32, u64, usize,
566 i8, i16, i32, i64, isize,
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700567}
568
569macro_rules! floats {
570 ($($t:ty,)*) => {$(
571 impl From<$t> for Literal {
572 fn from(t: $t) -> Literal {
573 assert!(!t.is_nan());
574 assert!(!t.is_infinite());
575 Literal(format!(concat!("{}", stringify!($t)), t))
576 }
577 }
578 )*}
579}
580
581floats! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700582 f32, f64,
583}
584
Alex Crichton44bffbc2017-05-19 17:51:59 -0700585impl<'a> From<&'a str> for Literal {
586 fn from(t: &'a str) -> Literal {
David Tolnayb28f38a2018-03-31 22:02:29 +0200587 let mut s = t.chars()
588 .flat_map(|c| c.escape_default())
589 .collect::<String>();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700590 s.push('"');
591 s.insert(0, '"');
592 Literal(s)
593 }
594}
595
596impl From<char> for Literal {
597 fn from(t: char) -> Literal {
Alex Crichton2d0cf0b2017-05-26 14:00:16 -0700598 Literal(format!("'{}'", t.escape_default().collect::<String>()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700599 }
600}
601
David Tolnay8e976c62017-06-01 12:12:29 -0700602named!(token_stream -> ::TokenStream, map!(
603 many0!(token_tree),
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700604 |trees| ::TokenStream::_new(TokenStream { inner: trees })
David Tolnay8e976c62017-06-01 12:12:29 -0700605));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700606
David Tolnay1ebe3972018-01-02 20:14:20 -0800607#[cfg(not(procmacro2_semver_exempt))]
David Tolnayddfca052017-12-31 10:41:24 -0500608fn token_tree(input: Cursor) -> PResult<TokenTree> {
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700609 token_kind(input)
David Tolnayddfca052017-12-31 10:41:24 -0500610}
611
David Tolnay1ebe3972018-01-02 20:14:20 -0800612#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500613fn token_tree(input: Cursor) -> PResult<TokenTree> {
614 let input = skip_whitespace(input);
615 let lo = input.off;
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700616 let (input, mut token) = token_kind(input)?;
Nika Layzellf8d5f212017-12-11 14:07:02 -0500617 let hi = input.off;
David Tolnayb28f38a2018-03-31 22:02:29 +0200618 token.set_span(::Span::_new(Span { lo: lo, hi: hi }));
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700619 Ok((input, token))
Nika Layzellf8d5f212017-12-11 14:07:02 -0500620}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700621
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700622named!(token_kind -> TokenTree, alt!(
623 map!(group, TokenTree::Group)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700624 |
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700625 map!(literal, TokenTree::Literal) // must be before symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700626 |
Alex Crichton52725f72017-08-28 12:20:58 -0700627 symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700628 |
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700629 map!(op, TokenTree::Op)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700630));
631
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700632named!(group -> Group, alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -0700633 delimited!(
634 punct!("("),
635 token_stream,
636 punct!(")")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700637 ) => { |ts| Group::new(Delimiter::Parenthesis, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700638 |
639 delimited!(
640 punct!("["),
641 token_stream,
642 punct!("]")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700643 ) => { |ts| Group::new(Delimiter::Bracket, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700644 |
645 delimited!(
646 punct!("{"),
647 token_stream,
648 punct!("}")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700649 ) => { |ts| Group::new(Delimiter::Brace, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700650));
651
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700652fn symbol(mut input: Cursor) -> PResult<TokenTree> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700653 input = skip_whitespace(input);
654
655 let mut chars = input.char_indices();
David Tolnaya202d502017-06-01 12:26:55 -0700656
657 let lifetime = input.starts_with("'");
658 if lifetime {
659 chars.next();
660 }
661
David Tolnaya13d1422018-03-31 21:27:48 +0200662 let raw = !lifetime && input.starts_with("r#");
663 if raw {
664 chars.next();
665 chars.next();
666 }
667
Alex Crichton44bffbc2017-05-19 17:51:59 -0700668 match chars.next() {
669 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700670 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700671 }
672
David Tolnay214c94c2017-06-01 12:42:56 -0700673 let mut end = input.len();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700674 for (i, ch) in chars {
675 if !UnicodeXID::is_xid_continue(ch) {
David Tolnay214c94c2017-06-01 12:42:56 -0700676 end = i;
677 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700678 }
679 }
680
David Tolnaya13d1422018-03-31 21:27:48 +0200681 let a = &input.rest[..end];
682 if a == "r#_" || lifetime && a != "'static" && KEYWORDS.contains(&&a[1..]) {
David Tolnay214c94c2017-06-01 12:42:56 -0700683 Err(LexError)
David Tolnaya13d1422018-03-31 21:27:48 +0200684 } else if a == "_" {
685 Ok((input.advance(end), Op::new('_', Spacing::Alone).into()))
David Tolnay214c94c2017-06-01 12:42:56 -0700686 } else {
David Tolnayb28f38a2018-03-31 22:02:29 +0200687 Ok((
688 input.advance(end),
689 ::Term::new(a, ::Span::call_site()).into(),
690 ))
David Tolnay214c94c2017-06-01 12:42:56 -0700691 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700692}
693
David Tolnay214c94c2017-06-01 12:42:56 -0700694// From https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/symbol.rs
695static KEYWORDS: &'static [&'static str] = &[
David Tolnayb28f38a2018-03-31 22:02:29 +0200696 "abstract", "alignof", "as", "become", "box", "break", "const", "continue", "crate", "do",
697 "else", "enum", "extern", "false", "final", "fn", "for", "if", "impl", "in", "let", "loop",
698 "macro", "match", "mod", "move", "mut", "offsetof", "override", "priv", "proc", "pub", "pure",
699 "ref", "return", "self", "Self", "sizeof", "static", "struct", "super", "trait", "true",
700 "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while", "yield",
David Tolnay214c94c2017-06-01 12:42:56 -0700701];
702
Nika Layzellf8d5f212017-12-11 14:07:02 -0500703fn literal(input: Cursor) -> PResult<::Literal> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700704 let input_no_ws = skip_whitespace(input);
705
706 match literal_nocapture(input_no_ws) {
David Tolnay1218e122017-06-01 11:13:45 -0700707 Ok((a, ())) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700708 let start = input.len() - input_no_ws.len();
709 let len = input_no_ws.len() - a.len();
710 let end = start + len;
David Tolnayb28f38a2018-03-31 22:02:29 +0200711 Ok((
712 a,
713 ::Literal::_new(Literal(input.rest[start..end].to_string())),
714 ))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700715 }
David Tolnay1218e122017-06-01 11:13:45 -0700716 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700717 }
718}
719
720named!(literal_nocapture -> (), alt!(
721 string
722 |
723 byte_string
724 |
725 byte
726 |
727 character
728 |
729 float
730 |
731 int
732 |
Alex Crichton44bffbc2017-05-19 17:51:59 -0700733 doc_comment
734));
735
736named!(string -> (), alt!(
737 quoted_string
738 |
739 preceded!(
740 punct!("r"),
741 raw_string
742 ) => { |_| () }
743));
744
745named!(quoted_string -> (), delimited!(
746 punct!("\""),
747 cooked_string,
748 tag!("\"")
749));
750
Nika Layzellf8d5f212017-12-11 14:07:02 -0500751fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700752 let mut chars = input.char_indices().peekable();
753 while let Some((byte_offset, ch)) = chars.next() {
754 match ch {
755 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500756 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700757 }
758 '\r' => {
759 if let Some((_, '\n')) = chars.next() {
760 // ...
761 } else {
762 break;
763 }
764 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200765 '\\' => match chars.next() {
766 Some((_, 'x')) => {
767 if !backslash_x_char(&mut chars) {
768 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700769 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700770 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200771 Some((_, 'n')) | Some((_, 'r')) | Some((_, 't')) | Some((_, '\\'))
772 | Some((_, '\'')) | Some((_, '"')) | Some((_, '0')) => {}
773 Some((_, 'u')) => {
774 if !backslash_u(&mut chars) {
775 break;
776 }
777 }
778 Some((_, '\n')) | Some((_, '\r')) => {
779 while let Some(&(_, ch)) = chars.peek() {
780 if ch.is_whitespace() {
781 chars.next();
782 } else {
783 break;
784 }
785 }
786 }
787 _ => break,
788 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700789 _ch => {}
790 }
791 }
David Tolnay1218e122017-06-01 11:13:45 -0700792 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700793}
794
795named!(byte_string -> (), alt!(
796 delimited!(
797 punct!("b\""),
798 cooked_byte_string,
799 tag!("\"")
800 ) => { |_| () }
801 |
802 preceded!(
803 punct!("br"),
804 raw_string
805 ) => { |_| () }
806));
807
Nika Layzellf8d5f212017-12-11 14:07:02 -0500808fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700809 let mut bytes = input.bytes().enumerate();
810 'outer: while let Some((offset, b)) = bytes.next() {
811 match b {
812 b'"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500813 return Ok((input.advance(offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700814 }
815 b'\r' => {
816 if let Some((_, b'\n')) = bytes.next() {
817 // ...
818 } else {
819 break;
820 }
821 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200822 b'\\' => match bytes.next() {
823 Some((_, b'x')) => {
824 if !backslash_x_byte(&mut bytes) {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700825 break;
826 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700827 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200828 Some((_, b'n')) | Some((_, b'r')) | Some((_, b't')) | Some((_, b'\\'))
829 | Some((_, b'0')) | Some((_, b'\'')) | Some((_, b'"')) => {}
830 Some((newline, b'\n')) | Some((newline, b'\r')) => {
831 let rest = input.advance(newline + 1);
832 for (offset, ch) in rest.char_indices() {
833 if !ch.is_whitespace() {
834 input = rest.advance(offset);
835 bytes = input.bytes().enumerate();
836 continue 'outer;
837 }
838 }
839 break;
840 }
841 _ => break,
842 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700843 b if b < 0x80 => {}
844 _ => break,
845 }
846 }
David Tolnay1218e122017-06-01 11:13:45 -0700847 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700848}
849
Nika Layzellf8d5f212017-12-11 14:07:02 -0500850fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700851 let mut chars = input.char_indices();
852 let mut n = 0;
853 while let Some((byte_offset, ch)) = chars.next() {
854 match ch {
855 '"' => {
856 n = byte_offset;
857 break;
858 }
859 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700860 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700861 }
862 }
863 for (byte_offset, ch) in chars {
864 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500865 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
866 let rest = input.advance(byte_offset + 1 + n);
David Tolnayb28f38a2018-03-31 22:02:29 +0200867 return Ok((rest, ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700868 }
869 '\r' => {}
870 _ => {}
871 }
872 }
David Tolnay1218e122017-06-01 11:13:45 -0700873 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700874}
875
876named!(byte -> (), do_parse!(
877 punct!("b") >>
878 tag!("'") >>
879 cooked_byte >>
880 tag!("'") >>
881 (())
882));
883
Nika Layzellf8d5f212017-12-11 14:07:02 -0500884fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700885 let mut bytes = input.bytes().enumerate();
886 let ok = match bytes.next().map(|(_, b)| b) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200887 Some(b'\\') => match bytes.next().map(|(_, b)| b) {
888 Some(b'x') => backslash_x_byte(&mut bytes),
889 Some(b'n') | Some(b'r') | Some(b't') | Some(b'\\') | Some(b'0') | Some(b'\'')
890 | Some(b'"') => true,
891 _ => false,
892 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700893 b => b.is_some(),
894 };
895 if ok {
896 match bytes.next() {
Alex Crichton8c030332018-01-16 08:07:36 -0800897 Some((offset, _)) => {
898 if input.chars().as_str().is_char_boundary(offset) {
899 Ok((input.advance(offset), ()))
900 } else {
901 Err(LexError)
902 }
903 }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500904 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) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200921 Some('\\') => match chars.next().map(|(_, ch)| ch) {
922 Some('x') => backslash_x_char(&mut chars),
923 Some('u') => backslash_u(&mut chars),
924 Some('n') | Some('r') | Some('t') | Some('\\') | Some('0') | Some('\'') | Some('"') => {
925 true
Alex Crichton44bffbc2017-05-19 17:51:59 -0700926 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200927 _ => false,
928 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700929 ch => ch.is_some(),
930 };
931 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500932 match chars.next() {
933 Some((idx, _)) => Ok((input.advance(idx), ())),
934 None => Ok((input.advance(input.len()), ())),
935 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700936 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700937 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700938 }
939}
940
941macro_rules! next_ch {
942 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
943 match $chars.next() {
944 Some((_, ch)) => match ch {
945 $pat $(| $rest)* => ch,
946 _ => return false,
947 },
948 None => return false
949 }
950 };
951}
952
953fn backslash_x_char<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +0200954where
955 I: Iterator<Item = (usize, char)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700956{
957 next_ch!(chars @ '0'...'7');
958 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
959 true
960}
961
962fn backslash_x_byte<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +0200963where
964 I: Iterator<Item = (usize, u8)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700965{
966 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
967 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
968 true
969}
970
971fn backslash_u<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +0200972where
973 I: Iterator<Item = (usize, char)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700974{
975 next_ch!(chars @ '{');
976 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
David Tolnay8d109342017-12-25 18:24:45 -0500977 loop {
978 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '_' | '}');
979 if c == '}' {
980 return true;
981 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700982 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700983}
984
Nika Layzellf8d5f212017-12-11 14:07:02 -0500985fn float(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -0700986 let (rest, ()) = float_digits(input)?;
987 for suffix in &["f32", "f64"] {
988 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500989 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -0700990 }
991 }
992 word_break(rest)
993}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700994
Nika Layzellf8d5f212017-12-11 14:07:02 -0500995fn float_digits(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700996 let mut chars = input.chars().peekable();
997 match chars.next() {
998 Some(ch) if ch >= '0' && ch <= '9' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700999 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001000 }
1001
1002 let mut len = 1;
1003 let mut has_dot = false;
1004 let mut has_exp = false;
1005 while let Some(&ch) = chars.peek() {
1006 match ch {
1007 '0'...'9' | '_' => {
1008 chars.next();
1009 len += 1;
1010 }
1011 '.' => {
1012 if has_dot {
1013 break;
1014 }
1015 chars.next();
David Tolnayb28f38a2018-03-31 22:02:29 +02001016 if chars
1017 .peek()
1018 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1019 .unwrap_or(false)
1020 {
David Tolnay1218e122017-06-01 11:13:45 -07001021 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001022 }
1023 len += 1;
1024 has_dot = true;
1025 }
1026 'e' | 'E' => {
1027 chars.next();
1028 len += 1;
1029 has_exp = true;
1030 break;
1031 }
1032 _ => break,
1033 }
1034 }
1035
Nika Layzellf8d5f212017-12-11 14:07:02 -05001036 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001037 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001038 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001039 }
1040
1041 if has_exp {
1042 let mut has_exp_value = false;
1043 while let Some(&ch) = chars.peek() {
1044 match ch {
1045 '+' | '-' => {
1046 if has_exp_value {
1047 break;
1048 }
1049 chars.next();
1050 len += 1;
1051 }
1052 '0'...'9' => {
1053 chars.next();
1054 len += 1;
1055 has_exp_value = true;
1056 }
1057 '_' => {
1058 chars.next();
1059 len += 1;
1060 }
1061 _ => break,
1062 }
1063 }
1064 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001065 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001066 }
1067 }
1068
Nika Layzellf8d5f212017-12-11 14:07:02 -05001069 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001070}
1071
Nika Layzellf8d5f212017-12-11 14:07:02 -05001072fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001073 let (rest, ()) = digits(input)?;
1074 for suffix in &[
David Tolnayb28f38a2018-03-31 22:02:29 +02001075 "isize", "i8", "i16", "i32", "i64", "i128", "usize", "u8", "u16", "u32", "u64", "u128"
David Tolnay744a6b82017-06-01 11:34:29 -07001076 ] {
1077 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001078 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001079 }
1080 }
1081 word_break(rest)
1082}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001083
Nika Layzellf8d5f212017-12-11 14:07:02 -05001084fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001085 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001086 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001087 16
1088 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001089 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001090 8
1091 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001092 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001093 2
1094 } else {
1095 10
1096 };
1097
Alex Crichton44bffbc2017-05-19 17:51:59 -07001098 let mut len = 0;
1099 let mut empty = true;
1100 for b in input.bytes() {
1101 let digit = match b {
1102 b'0'...b'9' => (b - b'0') as u64,
1103 b'a'...b'f' => 10 + (b - b'a') as u64,
1104 b'A'...b'F' => 10 + (b - b'A') as u64,
1105 b'_' => {
1106 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001107 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001108 }
1109 len += 1;
1110 continue;
1111 }
1112 _ => break,
1113 };
1114 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001115 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001116 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001117 len += 1;
1118 empty = false;
1119 }
1120 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001121 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001122 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001123 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001124 }
1125}
1126
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001127fn op(input: Cursor) -> PResult<Op> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001128 let input = skip_whitespace(input);
1129 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001130 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001131 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001132 Ok(_) => Spacing::Joint,
1133 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001134 };
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001135 Ok((rest, Op::new(ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001136 }
David Tolnay1218e122017-06-01 11:13:45 -07001137 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001138 }
1139}
1140
Nika Layzellf8d5f212017-12-11 14:07:02 -05001141fn op_char(input: Cursor) -> PResult<char> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001142 let mut chars = input.chars();
1143 let first = match chars.next() {
1144 Some(ch) => ch,
1145 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001146 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001147 }
1148 };
1149 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1150 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001151 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001152 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001153 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001154 }
1155}
1156
Alex Crichton44bffbc2017-05-19 17:51:59 -07001157named!(doc_comment -> (), alt!(
1158 do_parse!(
1159 punct!("//!") >>
Alex Crichtond7904e52018-01-23 11:08:45 -08001160 take_until_newline_or_eof!() >>
Alex Crichton44bffbc2017-05-19 17:51:59 -07001161 (())
1162 )
1163 |
1164 do_parse!(
1165 option!(whitespace) >>
1166 peek!(tag!("/*!")) >>
1167 block_comment >>
1168 (())
1169 )
1170 |
1171 do_parse!(
1172 punct!("///") >>
1173 not!(tag!("/")) >>
Alex Crichtond7904e52018-01-23 11:08:45 -08001174 take_until_newline_or_eof!() >>
Alex Crichton44bffbc2017-05-19 17:51:59 -07001175 (())
1176 )
1177 |
1178 do_parse!(
1179 option!(whitespace) >>
1180 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1181 block_comment >>
1182 (())
1183 )
1184));