blob: 8741d51ecf2aa35be55042b8b012725b2562c1b0 [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;
Alex Crichton44bffbc2017-05-19 17:51:59 -070011use std::rc::Rc;
12use std::str::FromStr;
13use std::vec;
14
David Tolnayb28f38a2018-03-31 22:02:29 +020015use strnom::{block_comment, skip_whitespace, whitespace, word_break, Cursor, PResult};
David Tolnayb1032662017-05-31 15:52:28 -070016use unicode_xid::UnicodeXID;
Alex Crichton44bffbc2017-05-19 17:51:59 -070017
David Tolnayb28f38a2018-03-31 22:02:29 +020018use {Delimiter, Group, Op, Spacing, TokenTree};
Alex Crichton44bffbc2017-05-19 17:51:59 -070019
David Tolnay977f8282017-05-31 17:41:33 -070020#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -070021pub struct TokenStream {
22 inner: Vec<TokenTree>,
23}
24
25#[derive(Debug)]
26pub struct LexError;
27
28impl TokenStream {
29 pub fn empty() -> TokenStream {
30 TokenStream { inner: Vec::new() }
31 }
32
33 pub fn is_empty(&self) -> bool {
34 self.inner.len() == 0
35 }
36}
37
David Tolnay1ebe3972018-01-02 20:14:20 -080038#[cfg(procmacro2_semver_exempt)]
Nika Layzella9dbc182017-12-30 14:50:13 -050039fn get_cursor(src: &str) -> Cursor {
40 // Create a dummy file & add it to the codemap
41 CODEMAP.with(|cm| {
42 let mut cm = cm.borrow_mut();
43 let name = format!("<parsed string {}>", cm.files.len());
44 let span = cm.add_file(&name, src);
45 Cursor {
46 rest: src,
47 off: span.lo,
48 }
49 })
50}
51
David Tolnay1ebe3972018-01-02 20:14:20 -080052#[cfg(not(procmacro2_semver_exempt))]
Nika Layzella9dbc182017-12-30 14:50:13 -050053fn get_cursor(src: &str) -> Cursor {
David Tolnayb28f38a2018-03-31 22:02:29 +020054 Cursor { rest: src }
Nika Layzella9dbc182017-12-30 14:50:13 -050055}
56
Alex Crichton44bffbc2017-05-19 17:51:59 -070057impl FromStr for TokenStream {
58 type Err = LexError;
59
60 fn from_str(src: &str) -> Result<TokenStream, LexError> {
Nika Layzellf8d5f212017-12-11 14:07:02 -050061 // Create a dummy file & add it to the codemap
Nika Layzella9dbc182017-12-30 14:50:13 -050062 let cursor = get_cursor(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -050063
64 match token_stream(cursor) {
David Tolnay1218e122017-06-01 11:13:45 -070065 Ok((input, output)) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -070066 if skip_whitespace(input).len() != 0 {
67 Err(LexError)
68 } else {
Alex Crichtonaf5bad42018-03-27 14:45:10 -070069 Ok(output.inner)
Alex Crichton44bffbc2017-05-19 17:51:59 -070070 }
71 }
David Tolnay1218e122017-06-01 11:13:45 -070072 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -070073 }
74 }
75}
76
77impl fmt::Display for TokenStream {
78 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79 let mut joint = false;
80 for (i, tt) in self.inner.iter().enumerate() {
81 if i != 0 && !joint {
82 write!(f, " ")?;
83 }
84 joint = false;
Alex Crichtonaf5bad42018-03-27 14:45:10 -070085 match *tt {
86 TokenTree::Group(ref tt) => {
87 let (start, end) = match tt.delimiter() {
Alex Crichton44bffbc2017-05-19 17:51:59 -070088 Delimiter::Parenthesis => ("(", ")"),
89 Delimiter::Brace => ("{", "}"),
90 Delimiter::Bracket => ("[", "]"),
91 Delimiter::None => ("", ""),
92 };
Alex Crichtonaf5bad42018-03-27 14:45:10 -070093 if tt.stream().inner.inner.len() == 0 {
Alex Crichton852d53d2017-05-19 19:25:08 -070094 write!(f, "{} {}", start, end)?
95 } else {
Alex Crichtonaf5bad42018-03-27 14:45:10 -070096 write!(f, "{} {} {}", start, tt.stream(), end)?
Alex Crichton852d53d2017-05-19 19:25:08 -070097 }
Alex Crichton44bffbc2017-05-19 17:51:59 -070098 }
Alex Crichtonaf5bad42018-03-27 14:45:10 -070099 TokenTree::Term(ref tt) => write!(f, "{}", tt.as_str())?,
100 TokenTree::Op(ref tt) => {
101 write!(f, "{}", tt.op())?;
102 match tt.spacing() {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700103 Spacing::Alone => {}
104 Spacing::Joint => joint = true,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700105 }
106 }
Alex Crichtonb2c94622018-04-04 07:36:41 -0700107 TokenTree::Literal(ref tt) => write!(f, "{}", tt)?,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700108 }
109 }
110
111 Ok(())
112 }
113}
114
Alex Crichton0e8e7f42018-02-22 06:15:13 -0800115#[cfg(feature = "proc-macro")]
116impl From<::proc_macro::TokenStream> for TokenStream {
117 fn from(inner: ::proc_macro::TokenStream) -> TokenStream {
David Tolnayb28f38a2018-03-31 22:02:29 +0200118 inner
119 .to_string()
120 .parse()
121 .expect("compiler token stream parse failed")
Alex Crichton44bffbc2017-05-19 17:51:59 -0700122 }
123}
124
Alex Crichton0e8e7f42018-02-22 06:15:13 -0800125#[cfg(feature = "proc-macro")]
126impl From<TokenStream> for ::proc_macro::TokenStream {
127 fn from(inner: TokenStream) -> ::proc_macro::TokenStream {
David Tolnayb28f38a2018-03-31 22:02:29 +0200128 inner
129 .to_string()
130 .parse()
131 .expect("failed to parse to compiler tokens")
Alex Crichton44bffbc2017-05-19 17:51:59 -0700132 }
133}
134
Alex Crichton44bffbc2017-05-19 17:51:59 -0700135impl From<TokenTree> for TokenStream {
136 fn from(tree: TokenTree) -> TokenStream {
137 TokenStream { inner: vec![tree] }
138 }
139}
140
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700141impl iter::FromIterator<TokenTree> for TokenStream {
David Tolnayb28f38a2018-03-31 22:02:29 +0200142 fn from_iter<I: IntoIterator<Item = TokenTree>>(streams: I) -> Self {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700143 let mut v = Vec::new();
144
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700145 for token in streams.into_iter() {
146 v.push(token);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700147 }
148
149 TokenStream { inner: v }
150 }
151}
152
Alex Crichton1a7f7622017-07-05 17:47:15 -0700153pub type TokenTreeIter = vec::IntoIter<TokenTree>;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700154
155impl IntoIterator for TokenStream {
156 type Item = TokenTree;
Alex Crichton1a7f7622017-07-05 17:47:15 -0700157 type IntoIter = TokenTreeIter;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700158
Alex Crichton1a7f7622017-07-05 17:47:15 -0700159 fn into_iter(self) -> TokenTreeIter {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700160 self.inner.into_iter()
161 }
162}
163
David Tolnay1ebe3972018-01-02 20:14:20 -0800164#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500165#[derive(Clone, PartialEq, Eq, Debug)]
166pub struct FileName(String);
167
David Tolnay1ebe3972018-01-02 20:14:20 -0800168#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500169impl fmt::Display for FileName {
170 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
171 self.0.fmt(f)
172 }
173}
174
David Tolnay1ebe3972018-01-02 20:14:20 -0800175#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500176#[derive(Clone, PartialEq, Eq)]
177pub struct SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500178 name: FileName,
Nika Layzellf8d5f212017-12-11 14:07:02 -0500179}
180
David Tolnay1ebe3972018-01-02 20:14:20 -0800181#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500182impl SourceFile {
183 /// Get the path to this source file as a string.
Nika Layzellb35a9a32017-12-30 14:34:35 -0500184 pub fn path(&self) -> &FileName {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500185 &self.name
186 }
187
188 pub fn is_real(&self) -> bool {
189 // XXX(nika): Support real files in the future?
190 false
191 }
192}
193
David Tolnay1ebe3972018-01-02 20:14:20 -0800194#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500195impl AsRef<FileName> for SourceFile {
196 fn as_ref(&self) -> &FileName {
197 self.path()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500198 }
199}
200
David Tolnay1ebe3972018-01-02 20:14:20 -0800201#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500202impl fmt::Debug for SourceFile {
203 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
204 f.debug_struct("SourceFile")
Nika Layzellb35a9a32017-12-30 14:34:35 -0500205 .field("path", &self.path())
Nika Layzellf8d5f212017-12-11 14:07:02 -0500206 .field("is_real", &self.is_real())
207 .finish()
208 }
209}
210
David Tolnay1ebe3972018-01-02 20:14:20 -0800211#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500212#[derive(Clone, Copy, Debug, PartialEq, Eq)]
213pub struct LineColumn {
214 pub line: usize,
215 pub column: usize,
216}
217
David Tolnay1ebe3972018-01-02 20:14:20 -0800218#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500219thread_local! {
220 static CODEMAP: RefCell<Codemap> = RefCell::new(Codemap {
221 // NOTE: We start with a single dummy file which all call_site() and
222 // def_site() spans reference.
223 files: vec![FileInfo {
224 name: "<unspecified>".to_owned(),
225 span: Span { lo: 0, hi: 0 },
226 lines: vec![0],
227 }],
228 });
229}
230
David Tolnay1ebe3972018-01-02 20:14:20 -0800231#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500232struct FileInfo {
233 name: String,
234 span: Span,
235 lines: Vec<usize>,
236}
237
David Tolnay1ebe3972018-01-02 20:14:20 -0800238#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500239impl FileInfo {
240 fn offset_line_column(&self, offset: usize) -> LineColumn {
David Tolnayb28f38a2018-03-31 22:02:29 +0200241 assert!(self.span_within(Span {
242 lo: offset as u32,
243 hi: offset as u32
244 }));
Nika Layzellf8d5f212017-12-11 14:07:02 -0500245 let offset = offset - self.span.lo as usize;
246 match self.lines.binary_search(&offset) {
247 Ok(found) => LineColumn {
248 line: found + 1,
David Tolnayb28f38a2018-03-31 22:02:29 +0200249 column: 0,
Nika Layzellf8d5f212017-12-11 14:07:02 -0500250 },
251 Err(idx) => LineColumn {
252 line: idx,
David Tolnayb28f38a2018-03-31 22:02:29 +0200253 column: offset - self.lines[idx - 1],
Nika Layzellf8d5f212017-12-11 14:07:02 -0500254 },
255 }
256 }
257
258 fn span_within(&self, span: Span) -> bool {
259 span.lo >= self.span.lo && span.hi <= self.span.hi
260 }
261}
262
263/// Computes the offsets of each line in the given source string.
David Tolnay1ebe3972018-01-02 20:14:20 -0800264#[cfg(procmacro2_semver_exempt)]
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500265fn lines_offsets(s: &str) -> Vec<usize> {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500266 let mut lines = vec![0];
267 let mut prev = 0;
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500268 while let Some(len) = s[prev..].find('\n') {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500269 prev += len + 1;
270 lines.push(prev);
271 }
272 lines
273}
274
David Tolnay1ebe3972018-01-02 20:14:20 -0800275#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500276struct Codemap {
277 files: Vec<FileInfo>,
278}
279
David Tolnay1ebe3972018-01-02 20:14:20 -0800280#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500281impl Codemap {
282 fn next_start_pos(&self) -> u32 {
283 // Add 1 so there's always space between files.
284 //
285 // We'll always have at least 1 file, as we initialize our files list
286 // with a dummy file.
287 self.files.last().unwrap().span.hi + 1
288 }
289
290 fn add_file(&mut self, name: &str, src: &str) -> Span {
Nika Layzella0a7c3d2017-12-30 14:52:39 -0500291 let lines = lines_offsets(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -0500292 let lo = self.next_start_pos();
293 // XXX(nika): Shouild we bother doing a checked cast or checked add here?
David Tolnayb28f38a2018-03-31 22:02:29 +0200294 let span = Span {
295 lo: lo,
296 hi: lo + (src.len() as u32),
297 };
Nika Layzellf8d5f212017-12-11 14:07:02 -0500298
299 self.files.push(FileInfo {
300 name: name.to_owned(),
301 span: span,
302 lines: lines,
303 });
304
305 span
306 }
307
308 fn fileinfo(&self, span: Span) -> &FileInfo {
309 for file in &self.files {
310 if file.span_within(span) {
311 return file;
312 }
313 }
314 panic!("Invalid span with no related FileInfo!");
315 }
316}
317
Nika Layzell99737982018-03-11 18:51:27 -0400318#[derive(Clone, Copy, Debug, PartialEq, Eq)]
David Tolnayddfca052017-12-31 10:41:24 -0500319pub struct Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800320 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500321 lo: u32,
David Tolnay1ebe3972018-01-02 20:14:20 -0800322 #[cfg(procmacro2_semver_exempt)]
David Tolnayddfca052017-12-31 10:41:24 -0500323 hi: u32,
324}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700325
326impl Span {
David Tolnay1ebe3972018-01-02 20:14:20 -0800327 #[cfg(not(procmacro2_semver_exempt))]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700328 pub fn call_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500329 Span {}
330 }
331
David Tolnay1ebe3972018-01-02 20:14:20 -0800332 #[cfg(procmacro2_semver_exempt)]
David Tolnay79105e52017-12-31 11:03:04 -0500333 pub fn call_site() -> Span {
334 Span { lo: 0, hi: 0 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700335 }
Alex Crichtone6085b72017-11-21 07:24:25 -0800336
337 pub fn def_site() -> Span {
David Tolnay79105e52017-12-31 11:03:04 -0500338 Span::call_site()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500339 }
340
David Tolnay4e8e3972018-01-05 18:10:22 -0800341 pub fn resolved_at(&self, _other: Span) -> Span {
342 // Stable spans consist only of line/column information, so
343 // `resolved_at` and `located_at` only select which span the
344 // caller wants line/column information from.
345 *self
346 }
347
348 pub fn located_at(&self, other: Span) -> Span {
349 other
350 }
351
David Tolnay1ebe3972018-01-02 20:14:20 -0800352 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500353 pub fn source_file(&self) -> SourceFile {
354 CODEMAP.with(|cm| {
355 let cm = cm.borrow();
356 let fi = cm.fileinfo(*self);
357 SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500358 name: FileName(fi.name.clone()),
Nika Layzellf8d5f212017-12-11 14:07:02 -0500359 }
360 })
361 }
362
David Tolnay1ebe3972018-01-02 20:14:20 -0800363 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500364 pub fn start(&self) -> LineColumn {
365 CODEMAP.with(|cm| {
366 let cm = cm.borrow();
367 let fi = cm.fileinfo(*self);
368 fi.offset_line_column(self.lo as usize)
369 })
370 }
371
David Tolnay1ebe3972018-01-02 20:14:20 -0800372 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500373 pub fn end(&self) -> LineColumn {
374 CODEMAP.with(|cm| {
375 let cm = cm.borrow();
376 let fi = cm.fileinfo(*self);
377 fi.offset_line_column(self.hi as usize)
378 })
379 }
380
David Tolnay1ebe3972018-01-02 20:14:20 -0800381 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500382 pub fn join(&self, other: Span) -> Option<Span> {
383 CODEMAP.with(|cm| {
384 let cm = cm.borrow();
385 // If `other` is not within the same FileInfo as us, return None.
386 if !cm.fileinfo(*self).span_within(other) {
387 return None;
388 }
389 Some(Span {
390 lo: cmp::min(self.lo, other.lo),
391 hi: cmp::max(self.hi, other.hi),
392 })
393 })
Alex Crichtone6085b72017-11-21 07:24:25 -0800394 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700395}
396
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700397#[derive(Copy, Clone)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700398pub struct Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700399 intern: usize,
Alex Crichtonb2c94622018-04-04 07:36:41 -0700400 span: Span,
David Tolnay041bcd42017-06-03 09:18:04 -0700401}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700402
403thread_local!(static SYMBOLS: RefCell<Interner> = RefCell::new(Interner::new()));
404
David Tolnay10effeb2018-01-06 11:07:49 -0800405impl Term {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700406 pub fn new(string: &str, span: Span) -> Term {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700407 Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700408 intern: SYMBOLS.with(|s| s.borrow_mut().intern(string)),
Alex Crichtonb2c94622018-04-04 07:36:41 -0700409 span,
David Tolnay041bcd42017-06-03 09:18:04 -0700410 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700411 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700412
David Tolnay10effeb2018-01-06 11:07:49 -0800413 pub fn as_str(&self) -> &str {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700414 SYMBOLS.with(|interner| {
415 let interner = interner.borrow();
David Tolnay041bcd42017-06-03 09:18:04 -0700416 let s = interner.get(self.intern);
David Tolnayb28f38a2018-03-31 22:02:29 +0200417 unsafe { &*(s as *const str) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700418 })
419 }
Alex Crichtonb2c94622018-04-04 07:36:41 -0700420
421 pub fn span(&self) -> Span {
422 self.span
423 }
424
425 pub fn set_span(&mut self, span: Span) {
426 self.span = span;
427 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700428}
429
Alex Crichton1a7f7622017-07-05 17:47:15 -0700430impl fmt::Debug for Term {
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700431 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
David Tolnay10effeb2018-01-06 11:07:49 -0800432 f.debug_tuple("Term").field(&self.as_str()).finish()
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700433 }
434}
435
Alex Crichton44bffbc2017-05-19 17:51:59 -0700436struct Interner {
437 string_to_index: HashMap<MyRc, usize>,
438 index_to_string: Vec<Rc<String>>,
439}
440
441#[derive(Hash, Eq, PartialEq)]
442struct MyRc(Rc<String>);
443
444impl Borrow<str> for MyRc {
445 fn borrow(&self) -> &str {
446 &self.0
447 }
448}
449
450impl Interner {
451 fn new() -> Interner {
452 Interner {
453 string_to_index: HashMap::new(),
454 index_to_string: Vec::new(),
455 }
456 }
457
David Tolnayb28f38a2018-03-31 22:02:29 +0200458 fn intern(&mut self, s: &str) -> usize {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700459 if let Some(&idx) = self.string_to_index.get(s) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200460 return idx;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700461 }
462 let s = Rc::new(s.to_string());
463 self.index_to_string.push(s.clone());
David Tolnayb28f38a2018-03-31 22:02:29 +0200464 self.string_to_index
465 .insert(MyRc(s), self.index_to_string.len() - 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700466 self.index_to_string.len() - 1
467 }
468
David Tolnayb28f38a2018-03-31 22:02:29 +0200469 fn get(&self, idx: usize) -> &str {
470 &self.index_to_string[idx]
471 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700472}
473
David Tolnay977f8282017-05-31 17:41:33 -0700474#[derive(Clone, Debug)]
Alex Crichtonb2c94622018-04-04 07:36:41 -0700475pub struct Literal {
476 text: String,
477 span: Span,
478}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700479
Alex Crichton852d53d2017-05-19 19:25:08 -0700480impl Literal {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700481 fn _new(text: String) -> Literal {
482 Literal {
483 text,
484 span: Span::call_site(),
485 }
486 }
487
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700488 pub fn byte_char(byte: u8) -> Literal {
Alex Crichton76a5cc82017-05-23 07:01:44 -0700489 match byte {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700490 0 => Literal::_new(format!("b'\\0'")),
491 b'\"' => Literal::_new(format!("b'\"'")),
Alex Crichton76a5cc82017-05-23 07:01:44 -0700492 n => {
493 let mut escaped = "b'".to_string();
494 escaped.extend(ascii::escape_default(n).map(|c| c as char));
495 escaped.push('\'');
Alex Crichtonb2c94622018-04-04 07:36:41 -0700496 Literal::_new(escaped)
Alex Crichton76a5cc82017-05-23 07:01:44 -0700497 }
498 }
499 }
500
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700501 pub fn byte_string(bytes: &[u8]) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700502 let mut escaped = "b\"".to_string();
503 for b in bytes {
504 match *b {
505 b'\0' => escaped.push_str(r"\0"),
506 b'\t' => escaped.push_str(r"\t"),
507 b'\n' => escaped.push_str(r"\n"),
508 b'\r' => escaped.push_str(r"\r"),
509 b'"' => escaped.push_str("\\\""),
510 b'\\' => escaped.push_str("\\\\"),
David Tolnayb28f38a2018-03-31 22:02:29 +0200511 b'\x20'...b'\x7E' => escaped.push(*b as char),
Alex Crichton852d53d2017-05-19 19:25:08 -0700512 _ => escaped.push_str(&format!("\\x{:02X}", b)),
513 }
514 }
515 escaped.push('"');
Alex Crichtonb2c94622018-04-04 07:36:41 -0700516 Literal::_new(escaped)
Alex Crichton76a5cc82017-05-23 07:01:44 -0700517 }
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700518
David Tolnay114990e2018-01-05 11:17:08 -0800519 pub fn float(n: f64) -> Literal {
520 if !n.is_finite() {
521 panic!("Invalid float literal {}", n);
522 }
523 let mut s = n.to_string();
524 if !s.contains('.') {
525 s += ".0";
526 }
Alex Crichtonb2c94622018-04-04 07:36:41 -0700527 Literal::_new(s)
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700528 }
529
Alex Crichton1a7f7622017-07-05 17:47:15 -0700530 pub fn integer(s: i64) -> Literal {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700531 Literal::_new(s.to_string())
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700532 }
Alex Crichton31316622017-05-26 12:54:47 -0700533
Alex Crichtonb2c94622018-04-04 07:36:41 -0700534 pub fn span(&self) -> Span {
535 self.span
Alex Crichton31316622017-05-26 12:54:47 -0700536 }
537
Alex Crichtonb2c94622018-04-04 07:36:41 -0700538 pub fn set_span(&mut self, span: Span) {
539 self.span = span;
Alex Crichton31316622017-05-26 12:54:47 -0700540 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700541}
542
Alex Crichton44bffbc2017-05-19 17:51:59 -0700543impl fmt::Display for Literal {
544 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700545 self.text.fmt(f)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700546 }
547}
548
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700549macro_rules! ints {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700550 ($($t:ty,)*) => {$(
551 impl From<$t> for Literal {
552 fn from(t: $t) -> Literal {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700553 Literal::_new(format!(concat!("{}", stringify!($t)), t))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700554 }
555 }
556 )*}
557}
558
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700559ints! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700560 u8, u16, u32, u64, usize,
561 i8, i16, i32, i64, isize,
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700562}
563
564macro_rules! floats {
565 ($($t:ty,)*) => {$(
566 impl From<$t> for Literal {
567 fn from(t: $t) -> Literal {
568 assert!(!t.is_nan());
569 assert!(!t.is_infinite());
Alex Crichtonb2c94622018-04-04 07:36:41 -0700570 Literal::_new(format!(concat!("{}", stringify!($t)), t))
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700571 }
572 }
573 )*}
574}
575
576floats! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700577 f32, f64,
578}
579
Alex Crichton44bffbc2017-05-19 17:51:59 -0700580impl<'a> From<&'a str> for Literal {
581 fn from(t: &'a str) -> Literal {
David Tolnayb28f38a2018-03-31 22:02:29 +0200582 let mut s = t.chars()
583 .flat_map(|c| c.escape_default())
584 .collect::<String>();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700585 s.push('"');
586 s.insert(0, '"');
Alex Crichtonb2c94622018-04-04 07:36:41 -0700587 Literal::_new(s)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700588 }
589}
590
591impl From<char> for Literal {
592 fn from(t: char) -> Literal {
Alex Crichtonb2c94622018-04-04 07:36:41 -0700593 Literal::_new(format!("'{}'", t.escape_default().collect::<String>()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700594 }
595}
596
David Tolnay8e976c62017-06-01 12:12:29 -0700597named!(token_stream -> ::TokenStream, map!(
598 many0!(token_tree),
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700599 |trees| ::TokenStream::_new(TokenStream { inner: trees })
David Tolnay8e976c62017-06-01 12:12:29 -0700600));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700601
David Tolnay1ebe3972018-01-02 20:14:20 -0800602#[cfg(not(procmacro2_semver_exempt))]
David Tolnayddfca052017-12-31 10:41:24 -0500603fn token_tree(input: Cursor) -> PResult<TokenTree> {
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700604 token_kind(input)
David Tolnayddfca052017-12-31 10:41:24 -0500605}
606
David Tolnay1ebe3972018-01-02 20:14:20 -0800607#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500608fn token_tree(input: Cursor) -> PResult<TokenTree> {
609 let input = skip_whitespace(input);
610 let lo = input.off;
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700611 let (input, mut token) = token_kind(input)?;
Nika Layzellf8d5f212017-12-11 14:07:02 -0500612 let hi = input.off;
David Tolnayb28f38a2018-03-31 22:02:29 +0200613 token.set_span(::Span::_new(Span { lo: lo, hi: hi }));
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700614 Ok((input, token))
Nika Layzellf8d5f212017-12-11 14:07:02 -0500615}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700616
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700617named!(token_kind -> TokenTree, alt!(
618 map!(group, TokenTree::Group)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700619 |
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700620 map!(literal, TokenTree::Literal) // must be before symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700621 |
Alex Crichton52725f72017-08-28 12:20:58 -0700622 symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700623 |
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700624 map!(op, TokenTree::Op)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700625));
626
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700627named!(group -> Group, alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -0700628 delimited!(
629 punct!("("),
630 token_stream,
631 punct!(")")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700632 ) => { |ts| Group::new(Delimiter::Parenthesis, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700633 |
634 delimited!(
635 punct!("["),
636 token_stream,
637 punct!("]")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700638 ) => { |ts| Group::new(Delimiter::Bracket, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700639 |
640 delimited!(
641 punct!("{"),
642 token_stream,
643 punct!("}")
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700644 ) => { |ts| Group::new(Delimiter::Brace, ts) }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700645));
646
Alex Crichtonaf5bad42018-03-27 14:45:10 -0700647fn symbol(mut input: Cursor) -> PResult<TokenTree> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700648 input = skip_whitespace(input);
649
650 let mut chars = input.char_indices();
David Tolnaya202d502017-06-01 12:26:55 -0700651
652 let lifetime = input.starts_with("'");
653 if lifetime {
654 chars.next();
655 }
656
David Tolnaya13d1422018-03-31 21:27:48 +0200657 let raw = !lifetime && input.starts_with("r#");
658 if raw {
659 chars.next();
660 chars.next();
661 }
662
Alex Crichton44bffbc2017-05-19 17:51:59 -0700663 match chars.next() {
664 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700665 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700666 }
667
David Tolnay214c94c2017-06-01 12:42:56 -0700668 let mut end = input.len();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700669 for (i, ch) in chars {
670 if !UnicodeXID::is_xid_continue(ch) {
David Tolnay214c94c2017-06-01 12:42:56 -0700671 end = i;
672 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700673 }
674 }
675
David Tolnaya13d1422018-03-31 21:27:48 +0200676 let a = &input.rest[..end];
677 if a == "r#_" || lifetime && a != "'static" && KEYWORDS.contains(&&a[1..]) {
David Tolnay214c94c2017-06-01 12:42:56 -0700678 Err(LexError)
David Tolnaya13d1422018-03-31 21:27:48 +0200679 } else if a == "_" {
680 Ok((input.advance(end), Op::new('_', Spacing::Alone).into()))
David Tolnay214c94c2017-06-01 12:42:56 -0700681 } else {
David Tolnayb28f38a2018-03-31 22:02:29 +0200682 Ok((
683 input.advance(end),
684 ::Term::new(a, ::Span::call_site()).into(),
685 ))
David Tolnay214c94c2017-06-01 12:42:56 -0700686 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700687}
688
David Tolnay214c94c2017-06-01 12:42:56 -0700689// From https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/symbol.rs
690static KEYWORDS: &'static [&'static str] = &[
David Tolnayb28f38a2018-03-31 22:02:29 +0200691 "abstract", "alignof", "as", "become", "box", "break", "const", "continue", "crate", "do",
692 "else", "enum", "extern", "false", "final", "fn", "for", "if", "impl", "in", "let", "loop",
693 "macro", "match", "mod", "move", "mut", "offsetof", "override", "priv", "proc", "pub", "pure",
694 "ref", "return", "self", "Self", "sizeof", "static", "struct", "super", "trait", "true",
695 "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while", "yield",
David Tolnay214c94c2017-06-01 12:42:56 -0700696];
697
Nika Layzellf8d5f212017-12-11 14:07:02 -0500698fn literal(input: Cursor) -> PResult<::Literal> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700699 let input_no_ws = skip_whitespace(input);
700
701 match literal_nocapture(input_no_ws) {
David Tolnay1218e122017-06-01 11:13:45 -0700702 Ok((a, ())) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700703 let start = input.len() - input_no_ws.len();
704 let len = input_no_ws.len() - a.len();
705 let end = start + len;
David Tolnayb28f38a2018-03-31 22:02:29 +0200706 Ok((
707 a,
Alex Crichtonb2c94622018-04-04 07:36:41 -0700708 ::Literal::_new(Literal::_new(input.rest[start..end].to_string())),
David Tolnayb28f38a2018-03-31 22:02:29 +0200709 ))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700710 }
David Tolnay1218e122017-06-01 11:13:45 -0700711 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700712 }
713}
714
715named!(literal_nocapture -> (), alt!(
716 string
717 |
718 byte_string
719 |
720 byte
721 |
722 character
723 |
724 float
725 |
726 int
727 |
Alex Crichton44bffbc2017-05-19 17:51:59 -0700728 doc_comment
729));
730
731named!(string -> (), alt!(
732 quoted_string
733 |
734 preceded!(
735 punct!("r"),
736 raw_string
737 ) => { |_| () }
738));
739
740named!(quoted_string -> (), delimited!(
741 punct!("\""),
742 cooked_string,
743 tag!("\"")
744));
745
Nika Layzellf8d5f212017-12-11 14:07:02 -0500746fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700747 let mut chars = input.char_indices().peekable();
748 while let Some((byte_offset, ch)) = chars.next() {
749 match ch {
750 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500751 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700752 }
753 '\r' => {
754 if let Some((_, '\n')) = chars.next() {
755 // ...
756 } else {
757 break;
758 }
759 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200760 '\\' => match chars.next() {
761 Some((_, 'x')) => {
762 if !backslash_x_char(&mut chars) {
763 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700764 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700765 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200766 Some((_, 'n')) | Some((_, 'r')) | Some((_, 't')) | Some((_, '\\'))
767 | Some((_, '\'')) | Some((_, '"')) | 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 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700784 _ch => {}
785 }
786 }
David Tolnay1218e122017-06-01 11:13:45 -0700787 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700788}
789
790named!(byte_string -> (), alt!(
791 delimited!(
792 punct!("b\""),
793 cooked_byte_string,
794 tag!("\"")
795 ) => { |_| () }
796 |
797 preceded!(
798 punct!("br"),
799 raw_string
800 ) => { |_| () }
801));
802
Nika Layzellf8d5f212017-12-11 14:07:02 -0500803fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700804 let mut bytes = input.bytes().enumerate();
805 'outer: while let Some((offset, b)) = bytes.next() {
806 match b {
807 b'"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500808 return Ok((input.advance(offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700809 }
810 b'\r' => {
811 if let Some((_, b'\n')) = bytes.next() {
812 // ...
813 } else {
814 break;
815 }
816 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200817 b'\\' => match bytes.next() {
818 Some((_, b'x')) => {
819 if !backslash_x_byte(&mut bytes) {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700820 break;
821 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700822 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200823 Some((_, b'n')) | Some((_, b'r')) | Some((_, b't')) | Some((_, b'\\'))
824 | Some((_, b'0')) | Some((_, b'\'')) | Some((_, b'"')) => {}
825 Some((newline, b'\n')) | Some((newline, b'\r')) => {
826 let rest = input.advance(newline + 1);
827 for (offset, ch) in rest.char_indices() {
828 if !ch.is_whitespace() {
829 input = rest.advance(offset);
830 bytes = input.bytes().enumerate();
831 continue 'outer;
832 }
833 }
834 break;
835 }
836 _ => break,
837 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700838 b if b < 0x80 => {}
839 _ => break,
840 }
841 }
David Tolnay1218e122017-06-01 11:13:45 -0700842 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700843}
844
Nika Layzellf8d5f212017-12-11 14:07:02 -0500845fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700846 let mut chars = input.char_indices();
847 let mut n = 0;
848 while let Some((byte_offset, ch)) = chars.next() {
849 match ch {
850 '"' => {
851 n = byte_offset;
852 break;
853 }
854 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700855 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700856 }
857 }
858 for (byte_offset, ch) in chars {
859 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500860 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
861 let rest = input.advance(byte_offset + 1 + n);
David Tolnayb28f38a2018-03-31 22:02:29 +0200862 return Ok((rest, ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700863 }
864 '\r' => {}
865 _ => {}
866 }
867 }
David Tolnay1218e122017-06-01 11:13:45 -0700868 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700869}
870
871named!(byte -> (), do_parse!(
872 punct!("b") >>
873 tag!("'") >>
874 cooked_byte >>
875 tag!("'") >>
876 (())
877));
878
Nika Layzellf8d5f212017-12-11 14:07:02 -0500879fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700880 let mut bytes = input.bytes().enumerate();
881 let ok = match bytes.next().map(|(_, b)| b) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200882 Some(b'\\') => match bytes.next().map(|(_, b)| b) {
883 Some(b'x') => backslash_x_byte(&mut bytes),
884 Some(b'n') | Some(b'r') | Some(b't') | Some(b'\\') | Some(b'0') | Some(b'\'')
885 | Some(b'"') => true,
886 _ => false,
887 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700888 b => b.is_some(),
889 };
890 if ok {
891 match bytes.next() {
Alex Crichton8c030332018-01-16 08:07:36 -0800892 Some((offset, _)) => {
893 if input.chars().as_str().is_char_boundary(offset) {
894 Ok((input.advance(offset), ()))
895 } else {
896 Err(LexError)
897 }
898 }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500899 None => Ok((input.advance(input.len()), ())),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700900 }
901 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700902 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700903 }
904}
905
906named!(character -> (), do_parse!(
907 punct!("'") >>
908 cooked_char >>
909 tag!("'") >>
910 (())
911));
912
Nika Layzellf8d5f212017-12-11 14:07:02 -0500913fn cooked_char(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700914 let mut chars = input.char_indices();
915 let ok = match chars.next().map(|(_, ch)| ch) {
David Tolnayb28f38a2018-03-31 22:02:29 +0200916 Some('\\') => match chars.next().map(|(_, ch)| ch) {
917 Some('x') => backslash_x_char(&mut chars),
918 Some('u') => backslash_u(&mut chars),
919 Some('n') | Some('r') | Some('t') | Some('\\') | Some('0') | Some('\'') | Some('"') => {
920 true
Alex Crichton44bffbc2017-05-19 17:51:59 -0700921 }
David Tolnayb28f38a2018-03-31 22:02:29 +0200922 _ => false,
923 },
Alex Crichton44bffbc2017-05-19 17:51:59 -0700924 ch => ch.is_some(),
925 };
926 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500927 match chars.next() {
928 Some((idx, _)) => Ok((input.advance(idx), ())),
929 None => Ok((input.advance(input.len()), ())),
930 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700931 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700932 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700933 }
934}
935
936macro_rules! next_ch {
937 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
938 match $chars.next() {
939 Some((_, ch)) => match ch {
940 $pat $(| $rest)* => ch,
941 _ => return false,
942 },
943 None => return false
944 }
945 };
946}
947
948fn backslash_x_char<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +0200949where
950 I: Iterator<Item = (usize, char)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700951{
952 next_ch!(chars @ '0'...'7');
953 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
954 true
955}
956
957fn backslash_x_byte<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +0200958where
959 I: Iterator<Item = (usize, u8)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700960{
961 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
962 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
963 true
964}
965
966fn backslash_u<I>(chars: &mut I) -> bool
David Tolnayb28f38a2018-03-31 22:02:29 +0200967where
968 I: Iterator<Item = (usize, char)>,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700969{
970 next_ch!(chars @ '{');
971 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
David Tolnay8d109342017-12-25 18:24:45 -0500972 loop {
973 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '_' | '}');
974 if c == '}' {
975 return true;
976 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700977 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700978}
979
Nika Layzellf8d5f212017-12-11 14:07:02 -0500980fn float(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -0700981 let (rest, ()) = float_digits(input)?;
982 for suffix in &["f32", "f64"] {
983 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500984 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -0700985 }
986 }
987 word_break(rest)
988}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700989
Nika Layzellf8d5f212017-12-11 14:07:02 -0500990fn float_digits(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700991 let mut chars = input.chars().peekable();
992 match chars.next() {
993 Some(ch) if ch >= '0' && ch <= '9' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700994 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700995 }
996
997 let mut len = 1;
998 let mut has_dot = false;
999 let mut has_exp = false;
1000 while let Some(&ch) = chars.peek() {
1001 match ch {
1002 '0'...'9' | '_' => {
1003 chars.next();
1004 len += 1;
1005 }
1006 '.' => {
1007 if has_dot {
1008 break;
1009 }
1010 chars.next();
David Tolnayb28f38a2018-03-31 22:02:29 +02001011 if chars
1012 .peek()
1013 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1014 .unwrap_or(false)
1015 {
David Tolnay1218e122017-06-01 11:13:45 -07001016 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001017 }
1018 len += 1;
1019 has_dot = true;
1020 }
1021 'e' | 'E' => {
1022 chars.next();
1023 len += 1;
1024 has_exp = true;
1025 break;
1026 }
1027 _ => break,
1028 }
1029 }
1030
Nika Layzellf8d5f212017-12-11 14:07:02 -05001031 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001032 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001033 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001034 }
1035
1036 if has_exp {
1037 let mut has_exp_value = false;
1038 while let Some(&ch) = chars.peek() {
1039 match ch {
1040 '+' | '-' => {
1041 if has_exp_value {
1042 break;
1043 }
1044 chars.next();
1045 len += 1;
1046 }
1047 '0'...'9' => {
1048 chars.next();
1049 len += 1;
1050 has_exp_value = true;
1051 }
1052 '_' => {
1053 chars.next();
1054 len += 1;
1055 }
1056 _ => break,
1057 }
1058 }
1059 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001060 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001061 }
1062 }
1063
Nika Layzellf8d5f212017-12-11 14:07:02 -05001064 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001065}
1066
Nika Layzellf8d5f212017-12-11 14:07:02 -05001067fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001068 let (rest, ()) = digits(input)?;
1069 for suffix in &[
David Tolnayb28f38a2018-03-31 22:02:29 +02001070 "isize", "i8", "i16", "i32", "i64", "i128", "usize", "u8", "u16", "u32", "u64", "u128"
David Tolnay744a6b82017-06-01 11:34:29 -07001071 ] {
1072 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001073 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001074 }
1075 }
1076 word_break(rest)
1077}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001078
Nika Layzellf8d5f212017-12-11 14:07:02 -05001079fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001080 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001081 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001082 16
1083 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001084 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001085 8
1086 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001087 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001088 2
1089 } else {
1090 10
1091 };
1092
Alex Crichton44bffbc2017-05-19 17:51:59 -07001093 let mut len = 0;
1094 let mut empty = true;
1095 for b in input.bytes() {
1096 let digit = match b {
1097 b'0'...b'9' => (b - b'0') as u64,
1098 b'a'...b'f' => 10 + (b - b'a') as u64,
1099 b'A'...b'F' => 10 + (b - b'A') as u64,
1100 b'_' => {
1101 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001102 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001103 }
1104 len += 1;
1105 continue;
1106 }
1107 _ => break,
1108 };
1109 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001110 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001111 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001112 len += 1;
1113 empty = false;
1114 }
1115 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001116 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001117 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001118 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001119 }
1120}
1121
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001122fn op(input: Cursor) -> PResult<Op> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001123 let input = skip_whitespace(input);
1124 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001125 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001126 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001127 Ok(_) => Spacing::Joint,
1128 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001129 };
Alex Crichtonaf5bad42018-03-27 14:45:10 -07001130 Ok((rest, Op::new(ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001131 }
David Tolnay1218e122017-06-01 11:13:45 -07001132 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001133 }
1134}
1135
Nika Layzellf8d5f212017-12-11 14:07:02 -05001136fn op_char(input: Cursor) -> PResult<char> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001137 let mut chars = input.chars();
1138 let first = match chars.next() {
1139 Some(ch) => ch,
1140 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001141 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001142 }
1143 };
1144 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1145 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001146 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001147 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001148 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001149 }
1150}
1151
Alex Crichton44bffbc2017-05-19 17:51:59 -07001152named!(doc_comment -> (), alt!(
1153 do_parse!(
1154 punct!("//!") >>
Alex Crichtond7904e52018-01-23 11:08:45 -08001155 take_until_newline_or_eof!() >>
Alex Crichton44bffbc2017-05-19 17:51:59 -07001156 (())
1157 )
1158 |
1159 do_parse!(
1160 option!(whitespace) >>
1161 peek!(tag!("/*!")) >>
1162 block_comment >>
1163 (())
1164 )
1165 |
1166 do_parse!(
1167 punct!("///") >>
1168 not!(tag!("/")) >>
Alex Crichtond7904e52018-01-23 11:08:45 -08001169 take_until_newline_or_eof!() >>
Alex Crichton44bffbc2017-05-19 17:51:59 -07001170 (())
1171 )
1172 |
1173 do_parse!(
1174 option!(whitespace) >>
1175 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1176 block_comment >>
1177 (())
1178 )
1179));