blob: 56c0dd2a294e42ec7d2ac70d6c9aefc0c8650a5c [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;
Nika Layzella9dbc182017-12-30 14:50:13 -05004#[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -05005use std::cmp;
Alex Crichton44bffbc2017-05-19 17:51:59 -07006use std::collections::HashMap;
7use std::fmt;
8use std::iter;
David Tolnay041bcd42017-06-03 09:18:04 -07009use std::marker::PhantomData;
Alex Crichton44bffbc2017-05-19 17:51:59 -070010use std::ops;
11use std::rc::Rc;
12use std::str::FromStr;
13use std::vec;
14
15use proc_macro;
David Tolnayb1032662017-05-31 15:52:28 -070016use unicode_xid::UnicodeXID;
Nika Layzellf8d5f212017-12-11 14:07:02 -050017use strnom::{Cursor, PResult, skip_whitespace, block_comment, whitespace, word_break};
Alex Crichton44bffbc2017-05-19 17:51:59 -070018
Alex Crichton1a7f7622017-07-05 17:47:15 -070019use {TokenTree, TokenNode, Delimiter, Spacing};
Alex Crichton44bffbc2017-05-19 17:51:59 -070020
David Tolnay977f8282017-05-31 17:41:33 -070021#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -070022pub struct TokenStream {
23 inner: Vec<TokenTree>,
24}
25
26#[derive(Debug)]
27pub struct LexError;
28
29impl TokenStream {
30 pub fn empty() -> TokenStream {
31 TokenStream { inner: Vec::new() }
32 }
33
34 pub fn is_empty(&self) -> bool {
35 self.inner.len() == 0
36 }
37}
38
Nika Layzella9dbc182017-12-30 14:50:13 -050039#[cfg(procmacro2_unstable)]
40fn 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
53#[cfg(not(procmacro2_unstable))]
54fn get_cursor(src: &str) -> Cursor {
55 Cursor {
56 rest: src,
Nika Layzella9dbc182017-12-30 14:50:13 -050057 }
58}
59
Alex Crichton44bffbc2017-05-19 17:51:59 -070060impl FromStr for TokenStream {
61 type Err = LexError;
62
63 fn from_str(src: &str) -> Result<TokenStream, LexError> {
Nika Layzellf8d5f212017-12-11 14:07:02 -050064 // Create a dummy file & add it to the codemap
Nika Layzella9dbc182017-12-30 14:50:13 -050065 let cursor = get_cursor(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -050066
67 match token_stream(cursor) {
David Tolnay1218e122017-06-01 11:13:45 -070068 Ok((input, output)) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -070069 if skip_whitespace(input).len() != 0 {
70 Err(LexError)
71 } else {
David Tolnay8e976c62017-06-01 12:12:29 -070072 Ok(output.0)
Alex Crichton44bffbc2017-05-19 17:51:59 -070073 }
74 }
David Tolnay1218e122017-06-01 11:13:45 -070075 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -070076 }
77 }
78}
79
80impl fmt::Display for TokenStream {
81 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82 let mut joint = false;
83 for (i, tt) in self.inner.iter().enumerate() {
84 if i != 0 && !joint {
85 write!(f, " ")?;
86 }
87 joint = false;
88 match tt.kind {
Alex Crichton1a7f7622017-07-05 17:47:15 -070089 TokenNode::Group(delim, ref stream) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -070090 let (start, end) = match delim {
91 Delimiter::Parenthesis => ("(", ")"),
92 Delimiter::Brace => ("{", "}"),
93 Delimiter::Bracket => ("[", "]"),
94 Delimiter::None => ("", ""),
95 };
Alex Crichton852d53d2017-05-19 19:25:08 -070096 if stream.0.inner.len() == 0 {
97 write!(f, "{} {}", start, end)?
98 } else {
99 write!(f, "{} {} {}", start, stream, end)?
100 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700101 }
Alex Crichton1a7f7622017-07-05 17:47:15 -0700102 TokenNode::Term(ref sym) => write!(f, "{}", sym.as_str())?,
103 TokenNode::Op(ch, ref op) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700104 write!(f, "{}", ch)?;
105 match *op {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700106 Spacing::Alone => {}
107 Spacing::Joint => joint = true,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700108 }
109 }
Alex Crichton1a7f7622017-07-05 17:47:15 -0700110 TokenNode::Literal(ref literal) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700111 write!(f, "{}", literal)?;
112 // handle comments
113 if (literal.0).0.starts_with("/") {
114 write!(f, "\n")?;
115 }
116 }
117 }
118 }
119
120 Ok(())
121 }
122}
123
124impl From<proc_macro::TokenStream> for TokenStream {
125 fn from(inner: proc_macro::TokenStream) -> TokenStream {
126 inner.to_string().parse().expect("compiler token stream parse failed")
127 }
128}
129
130impl From<TokenStream> for proc_macro::TokenStream {
131 fn from(inner: TokenStream) -> proc_macro::TokenStream {
132 inner.to_string().parse().expect("failed to parse to compiler tokens")
133 }
134}
135
136
137impl From<TokenTree> for TokenStream {
138 fn from(tree: TokenTree) -> TokenStream {
139 TokenStream { inner: vec![tree] }
140 }
141}
142
143impl iter::FromIterator<TokenStream> for TokenStream {
144 fn from_iter<I: IntoIterator<Item=TokenStream>>(streams: I) -> Self {
145 let mut v = Vec::new();
146
147 for stream in streams.into_iter() {
148 v.extend(stream.inner);
149 }
150
151 TokenStream { inner: v }
152 }
153}
154
Alex Crichton1a7f7622017-07-05 17:47:15 -0700155pub type TokenTreeIter = vec::IntoIter<TokenTree>;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700156
157impl IntoIterator for TokenStream {
158 type Item = TokenTree;
Alex Crichton1a7f7622017-07-05 17:47:15 -0700159 type IntoIter = TokenTreeIter;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700160
Alex Crichton1a7f7622017-07-05 17:47:15 -0700161 fn into_iter(self) -> TokenTreeIter {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700162 self.inner.into_iter()
163 }
164}
165
Nika Layzella9dbc182017-12-30 14:50:13 -0500166#[cfg(procmacro2_unstable)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500167#[derive(Clone, PartialEq, Eq, Debug)]
168pub struct FileName(String);
169
Nika Layzella9dbc182017-12-30 14:50:13 -0500170#[cfg(procmacro2_unstable)]
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
Nika Layzella9dbc182017-12-30 14:50:13 -0500177#[cfg(procmacro2_unstable)]
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
Nika Layzella9dbc182017-12-30 14:50:13 -0500183#[cfg(procmacro2_unstable)]
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
Nika Layzella9dbc182017-12-30 14:50:13 -0500196#[cfg(procmacro2_unstable)]
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
Nika Layzella9dbc182017-12-30 14:50:13 -0500203#[cfg(procmacro2_unstable)]
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
Nika Layzella9dbc182017-12-30 14:50:13 -0500213#[cfg(procmacro2_unstable)]
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
Nika Layzella9dbc182017-12-30 14:50:13 -0500220#[cfg(procmacro2_unstable)]
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
Nika Layzella9dbc182017-12-30 14:50:13 -0500233#[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500234struct FileInfo {
235 name: String,
236 span: Span,
237 lines: Vec<usize>,
238}
239
Nika Layzella9dbc182017-12-30 14:50:13 -0500240#[cfg(procmacro2_unstable)]
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.
Nika Layzella9dbc182017-12-30 14:50:13 -0500263#[cfg(procmacro2_unstable)]
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
Nika Layzella9dbc182017-12-30 14:50:13 -0500274#[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500275struct Codemap {
276 files: Vec<FileInfo>,
277}
278
Nika Layzella9dbc182017-12-30 14:50:13 -0500279#[cfg(procmacro2_unstable)]
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 {
316 #[cfg(procmacro2_unstable)]
317 lo: u32,
318 #[cfg(procmacro2_unstable)]
319 hi: u32,
320}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700321
322impl Span {
323 pub fn call_site() -> Span {
David Tolnayddfca052017-12-31 10:41:24 -0500324 Span {
325 #[cfg(procmacro2_unstable)]
326 lo: 0,
327 #[cfg(procmacro2_unstable)]
328 hi: 0,
329 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700330 }
Alex Crichtone6085b72017-11-21 07:24:25 -0800331
332 pub fn def_site() -> Span {
David Tolnayddfca052017-12-31 10:41:24 -0500333 Span {
334 #[cfg(procmacro2_unstable)]
335 lo: 0,
336 #[cfg(procmacro2_unstable)]
337 hi: 0,
338 }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500339 }
340
Nika Layzella9dbc182017-12-30 14:50:13 -0500341 #[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500342 pub fn source_file(&self) -> SourceFile {
343 CODEMAP.with(|cm| {
344 let cm = cm.borrow();
345 let fi = cm.fileinfo(*self);
346 SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500347 name: FileName(fi.name.clone()),
Nika Layzellf8d5f212017-12-11 14:07:02 -0500348 }
349 })
350 }
351
Nika Layzella9dbc182017-12-30 14:50:13 -0500352 #[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500353 pub fn start(&self) -> LineColumn {
354 CODEMAP.with(|cm| {
355 let cm = cm.borrow();
356 let fi = cm.fileinfo(*self);
357 fi.offset_line_column(self.lo as usize)
358 })
359 }
360
Nika Layzella9dbc182017-12-30 14:50:13 -0500361 #[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500362 pub fn end(&self) -> LineColumn {
363 CODEMAP.with(|cm| {
364 let cm = cm.borrow();
365 let fi = cm.fileinfo(*self);
366 fi.offset_line_column(self.hi as usize)
367 })
368 }
369
Nika Layzella9dbc182017-12-30 14:50:13 -0500370 #[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500371 pub fn join(&self, other: Span) -> Option<Span> {
372 CODEMAP.with(|cm| {
373 let cm = cm.borrow();
374 // If `other` is not within the same FileInfo as us, return None.
375 if !cm.fileinfo(*self).span_within(other) {
376 return None;
377 }
378 Some(Span {
379 lo: cmp::min(self.lo, other.lo),
380 hi: cmp::max(self.hi, other.hi),
381 })
382 })
Alex Crichtone6085b72017-11-21 07:24:25 -0800383 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700384}
385
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700386#[derive(Copy, Clone)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700387pub struct Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700388 intern: usize,
389 not_send_sync: PhantomData<*const ()>,
390}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700391
392thread_local!(static SYMBOLS: RefCell<Interner> = RefCell::new(Interner::new()));
393
Alex Crichton1a7f7622017-07-05 17:47:15 -0700394impl<'a> From<&'a str> for Term {
395 fn from(string: &'a str) -> Term {
396 Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700397 intern: SYMBOLS.with(|s| s.borrow_mut().intern(string)),
398 not_send_sync: PhantomData,
399 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700400 }
401}
402
Alex Crichton1a7f7622017-07-05 17:47:15 -0700403impl ops::Deref for Term {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700404 type Target = str;
405
406 fn deref(&self) -> &str {
407 SYMBOLS.with(|interner| {
408 let interner = interner.borrow();
David Tolnay041bcd42017-06-03 09:18:04 -0700409 let s = interner.get(self.intern);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700410 unsafe {
411 &*(s as *const str)
412 }
413 })
414 }
415}
416
Alex Crichton1a7f7622017-07-05 17:47:15 -0700417impl fmt::Debug for Term {
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700418 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700419 f.debug_tuple("Term").field(&&**self).finish()
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700420 }
421}
422
Alex Crichton44bffbc2017-05-19 17:51:59 -0700423struct Interner {
424 string_to_index: HashMap<MyRc, usize>,
425 index_to_string: Vec<Rc<String>>,
426}
427
428#[derive(Hash, Eq, PartialEq)]
429struct MyRc(Rc<String>);
430
431impl Borrow<str> for MyRc {
432 fn borrow(&self) -> &str {
433 &self.0
434 }
435}
436
437impl Interner {
438 fn new() -> Interner {
439 Interner {
440 string_to_index: HashMap::new(),
441 index_to_string: Vec::new(),
442 }
443 }
444
445 fn intern(&mut self, s: &str) -> usize {
446 if let Some(&idx) = self.string_to_index.get(s) {
447 return idx
448 }
449 let s = Rc::new(s.to_string());
450 self.index_to_string.push(s.clone());
451 self.string_to_index.insert(MyRc(s), self.index_to_string.len() - 1);
452 self.index_to_string.len() - 1
453 }
454
455 fn get(&self, idx: usize) -> &str {
456 &self.index_to_string[idx]
457 }
458}
459
David Tolnay977f8282017-05-31 17:41:33 -0700460#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700461pub struct Literal(String);
462
Alex Crichton852d53d2017-05-19 19:25:08 -0700463impl Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700464 pub fn byte_char(byte: u8) -> Literal {
Alex Crichton76a5cc82017-05-23 07:01:44 -0700465 match byte {
466 0 => Literal(format!("b'\\0'")),
467 b'\"' => Literal(format!("b'\"'")),
468 n => {
469 let mut escaped = "b'".to_string();
470 escaped.extend(ascii::escape_default(n).map(|c| c as char));
471 escaped.push('\'');
472 Literal(escaped)
473 }
474 }
475 }
476
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700477 pub fn byte_string(bytes: &[u8]) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700478 let mut escaped = "b\"".to_string();
479 for b in bytes {
480 match *b {
481 b'\0' => escaped.push_str(r"\0"),
482 b'\t' => escaped.push_str(r"\t"),
483 b'\n' => escaped.push_str(r"\n"),
484 b'\r' => escaped.push_str(r"\r"),
485 b'"' => escaped.push_str("\\\""),
486 b'\\' => escaped.push_str("\\\\"),
487 b'\x20' ... b'\x7E' => escaped.push(*b as char),
488 _ => escaped.push_str(&format!("\\x{:02X}", b)),
489 }
490 }
491 escaped.push('"');
492 Literal(escaped)
493 }
Alex Crichton76a5cc82017-05-23 07:01:44 -0700494
495 pub fn doccomment(s: &str) -> Literal {
496 Literal(s.to_string())
497 }
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700498
Alex Crichton1a7f7622017-07-05 17:47:15 -0700499 pub fn float(s: f64) -> Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700500 Literal(s.to_string())
501 }
502
Alex Crichton1a7f7622017-07-05 17:47:15 -0700503 pub fn integer(s: i64) -> Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700504 Literal(s.to_string())
505 }
Alex Crichton31316622017-05-26 12:54:47 -0700506
507 pub fn raw_string(s: &str, pounds: usize) -> Literal {
508 let mut ret = format!("r");
509 ret.extend((0..pounds).map(|_| "#"));
510 ret.push('"');
511 ret.push_str(s);
512 ret.push('"');
513 ret.extend((0..pounds).map(|_| "#"));
514 Literal(ret)
515 }
516
517 pub fn raw_byte_string(s: &str, pounds: usize) -> Literal {
Alex Crichton7ed6d282017-05-26 13:42:50 -0700518 let mut ret = format!("br");
Alex Crichton31316622017-05-26 12:54:47 -0700519 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 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700526}
527
Alex Crichton44bffbc2017-05-19 17:51:59 -0700528impl fmt::Display for Literal {
529 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
530 self.0.fmt(f)
531 }
532}
533
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700534macro_rules! ints {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700535 ($($t:ty,)*) => {$(
536 impl From<$t> for Literal {
537 fn from(t: $t) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700538 Literal(format!(concat!("{}", stringify!($t)), t))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700539 }
540 }
541 )*}
542}
543
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700544ints! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700545 u8, u16, u32, u64, usize,
546 i8, i16, i32, i64, isize,
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700547}
548
549macro_rules! floats {
550 ($($t:ty,)*) => {$(
551 impl From<$t> for Literal {
552 fn from(t: $t) -> Literal {
553 assert!(!t.is_nan());
554 assert!(!t.is_infinite());
555 Literal(format!(concat!("{}", stringify!($t)), t))
556 }
557 }
558 )*}
559}
560
561floats! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700562 f32, f64,
563}
564
Alex Crichton44bffbc2017-05-19 17:51:59 -0700565impl<'a> From<&'a str> for Literal {
566 fn from(t: &'a str) -> Literal {
567 let mut s = t.chars().flat_map(|c| c.escape_default()).collect::<String>();
568 s.push('"');
569 s.insert(0, '"');
570 Literal(s)
571 }
572}
573
574impl From<char> for Literal {
575 fn from(t: char) -> Literal {
Alex Crichton2d0cf0b2017-05-26 14:00:16 -0700576 Literal(format!("'{}'", t.escape_default().collect::<String>()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700577 }
578}
579
David Tolnay8e976c62017-06-01 12:12:29 -0700580named!(token_stream -> ::TokenStream, map!(
581 many0!(token_tree),
582 |trees| ::TokenStream(TokenStream { inner: trees })
583));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700584
David Tolnayddfca052017-12-31 10:41:24 -0500585#[cfg(not(procmacro2_unstable))]
586fn token_tree(input: Cursor) -> PResult<TokenTree> {
587 let (input, kind) = token_kind(input)?;
588 Ok((input, TokenTree {
589 span: ::Span(Span {}),
590 kind: kind,
591 }))
592}
593
594#[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500595fn token_tree(input: Cursor) -> PResult<TokenTree> {
596 let input = skip_whitespace(input);
597 let lo = input.off;
598 let (input, kind) = token_kind(input)?;
599 let hi = input.off;
600 Ok((input, TokenTree {
601 span: ::Span(Span {
602 lo: lo,
603 hi: hi,
604 }),
605 kind: kind,
606 }))
607}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700608
Alex Crichton1a7f7622017-07-05 17:47:15 -0700609named!(token_kind -> TokenNode, alt!(
610 map!(delimited, |(d, s)| TokenNode::Group(d, s))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700611 |
Alex Crichton1a7f7622017-07-05 17:47:15 -0700612 map!(literal, TokenNode::Literal) // must be before symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700613 |
Alex Crichton52725f72017-08-28 12:20:58 -0700614 symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700615 |
Alex Crichton1a7f7622017-07-05 17:47:15 -0700616 map!(op, |(op, kind)| TokenNode::Op(op, kind))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700617));
618
David Tolnay8e976c62017-06-01 12:12:29 -0700619named!(delimited -> (Delimiter, ::TokenStream), alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -0700620 delimited!(
621 punct!("("),
622 token_stream,
623 punct!(")")
624 ) => { |ts| (Delimiter::Parenthesis, ts) }
625 |
626 delimited!(
627 punct!("["),
628 token_stream,
629 punct!("]")
630 ) => { |ts| (Delimiter::Bracket, ts) }
631 |
632 delimited!(
633 punct!("{"),
634 token_stream,
635 punct!("}")
636 ) => { |ts| (Delimiter::Brace, ts) }
637));
638
Nika Layzellf8d5f212017-12-11 14:07:02 -0500639fn symbol(mut input: Cursor) -> PResult<TokenNode> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700640 input = skip_whitespace(input);
641
642 let mut chars = input.char_indices();
David Tolnaya202d502017-06-01 12:26:55 -0700643
644 let lifetime = input.starts_with("'");
645 if lifetime {
646 chars.next();
647 }
648
Alex Crichton44bffbc2017-05-19 17:51:59 -0700649 match chars.next() {
650 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700651 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700652 }
653
David Tolnay214c94c2017-06-01 12:42:56 -0700654 let mut end = input.len();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700655 for (i, ch) in chars {
656 if !UnicodeXID::is_xid_continue(ch) {
David Tolnay214c94c2017-06-01 12:42:56 -0700657 end = i;
658 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700659 }
660 }
661
Nika Layzellf8d5f212017-12-11 14:07:02 -0500662 if lifetime && &input.rest[..end] != "'static" && KEYWORDS.contains(&&input.rest[1..end]) {
David Tolnay214c94c2017-06-01 12:42:56 -0700663 Err(LexError)
664 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500665 let a = &input.rest[..end];
Alex Crichton52725f72017-08-28 12:20:58 -0700666 if a == "_" {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500667 Ok((input.advance(end), TokenNode::Op('_', Spacing::Alone)))
Alex Crichton52725f72017-08-28 12:20:58 -0700668 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500669 Ok((input.advance(end), TokenNode::Term(::Term::intern(a))))
Alex Crichton52725f72017-08-28 12:20:58 -0700670 }
David Tolnay214c94c2017-06-01 12:42:56 -0700671 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700672}
673
David Tolnay214c94c2017-06-01 12:42:56 -0700674// From https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/symbol.rs
675static KEYWORDS: &'static [&'static str] = &[
676 "abstract", "alignof", "as", "become", "box", "break", "const", "continue",
677 "crate", "do", "else", "enum", "extern", "false", "final", "fn", "for",
678 "if", "impl", "in", "let", "loop", "macro", "match", "mod", "move", "mut",
679 "offsetof", "override", "priv", "proc", "pub", "pure", "ref", "return",
680 "self", "Self", "sizeof", "static", "struct", "super", "trait", "true",
681 "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while",
682 "yield",
683];
684
Nika Layzellf8d5f212017-12-11 14:07:02 -0500685fn literal(input: Cursor) -> PResult<::Literal> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700686 let input_no_ws = skip_whitespace(input);
687
688 match literal_nocapture(input_no_ws) {
David Tolnay1218e122017-06-01 11:13:45 -0700689 Ok((a, ())) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700690 let start = input.len() - input_no_ws.len();
691 let len = input_no_ws.len() - a.len();
692 let end = start + len;
Nika Layzellf8d5f212017-12-11 14:07:02 -0500693 Ok((a, ::Literal(Literal(input.rest[start..end].to_string()))))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700694 }
David Tolnay1218e122017-06-01 11:13:45 -0700695 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700696 }
697}
698
699named!(literal_nocapture -> (), alt!(
700 string
701 |
702 byte_string
703 |
704 byte
705 |
706 character
707 |
708 float
709 |
710 int
711 |
712 boolean
713 |
714 doc_comment
715));
716
717named!(string -> (), alt!(
718 quoted_string
719 |
720 preceded!(
721 punct!("r"),
722 raw_string
723 ) => { |_| () }
724));
725
726named!(quoted_string -> (), delimited!(
727 punct!("\""),
728 cooked_string,
729 tag!("\"")
730));
731
Nika Layzellf8d5f212017-12-11 14:07:02 -0500732fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700733 let mut chars = input.char_indices().peekable();
734 while let Some((byte_offset, ch)) = chars.next() {
735 match ch {
736 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500737 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700738 }
739 '\r' => {
740 if let Some((_, '\n')) = chars.next() {
741 // ...
742 } else {
743 break;
744 }
745 }
746 '\\' => {
747 match chars.next() {
748 Some((_, 'x')) => {
749 if !backslash_x_char(&mut chars) {
750 break
751 }
752 }
753 Some((_, 'n')) |
754 Some((_, 'r')) |
755 Some((_, 't')) |
756 Some((_, '\\')) |
757 Some((_, '\'')) |
758 Some((_, '"')) |
759 Some((_, '0')) => {}
760 Some((_, 'u')) => {
761 if !backslash_u(&mut chars) {
762 break
763 }
764 }
765 Some((_, '\n')) | Some((_, '\r')) => {
766 while let Some(&(_, ch)) = chars.peek() {
767 if ch.is_whitespace() {
768 chars.next();
769 } else {
770 break;
771 }
772 }
773 }
774 _ => break,
775 }
776 }
777 _ch => {}
778 }
779 }
David Tolnay1218e122017-06-01 11:13:45 -0700780 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700781}
782
783named!(byte_string -> (), alt!(
784 delimited!(
785 punct!("b\""),
786 cooked_byte_string,
787 tag!("\"")
788 ) => { |_| () }
789 |
790 preceded!(
791 punct!("br"),
792 raw_string
793 ) => { |_| () }
794));
795
Nika Layzellf8d5f212017-12-11 14:07:02 -0500796fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700797 let mut bytes = input.bytes().enumerate();
798 'outer: while let Some((offset, b)) = bytes.next() {
799 match b {
800 b'"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500801 return Ok((input.advance(offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700802 }
803 b'\r' => {
804 if let Some((_, b'\n')) = bytes.next() {
805 // ...
806 } else {
807 break;
808 }
809 }
810 b'\\' => {
811 match bytes.next() {
812 Some((_, b'x')) => {
813 if !backslash_x_byte(&mut bytes) {
814 break
815 }
816 }
817 Some((_, b'n')) |
818 Some((_, b'r')) |
819 Some((_, b't')) |
820 Some((_, b'\\')) |
821 Some((_, b'0')) |
822 Some((_, b'\'')) |
823 Some((_, b'"')) => {}
824 Some((newline, b'\n')) |
825 Some((newline, b'\r')) => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500826 let rest = input.advance(newline + 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700827 for (offset, ch) in rest.char_indices() {
828 if !ch.is_whitespace() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500829 input = rest.advance(offset);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700830 bytes = input.bytes().enumerate();
831 continue 'outer;
832 }
833 }
834 break;
835 }
836 _ => break,
837 }
838 }
839 b if b < 0x80 => {}
840 _ => break,
841 }
842 }
David Tolnay1218e122017-06-01 11:13:45 -0700843 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700844}
845
Nika Layzellf8d5f212017-12-11 14:07:02 -0500846fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700847 let mut chars = input.char_indices();
848 let mut n = 0;
849 while let Some((byte_offset, ch)) = chars.next() {
850 match ch {
851 '"' => {
852 n = byte_offset;
853 break;
854 }
855 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700856 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700857 }
858 }
859 for (byte_offset, ch) in chars {
860 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500861 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
862 let rest = input.advance(byte_offset + 1 + n);
David Tolnay1218e122017-06-01 11:13:45 -0700863 return Ok((rest, ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700864 }
865 '\r' => {}
866 _ => {}
867 }
868 }
David Tolnay1218e122017-06-01 11:13:45 -0700869 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700870}
871
872named!(byte -> (), do_parse!(
873 punct!("b") >>
874 tag!("'") >>
875 cooked_byte >>
876 tag!("'") >>
877 (())
878));
879
Nika Layzellf8d5f212017-12-11 14:07:02 -0500880fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700881 let mut bytes = input.bytes().enumerate();
882 let ok = match bytes.next().map(|(_, b)| b) {
883 Some(b'\\') => {
884 match bytes.next().map(|(_, b)| b) {
885 Some(b'x') => backslash_x_byte(&mut bytes),
886 Some(b'n') |
887 Some(b'r') |
888 Some(b't') |
889 Some(b'\\') |
890 Some(b'0') |
891 Some(b'\'') |
892 Some(b'"') => true,
893 _ => false,
894 }
895 }
896 b => b.is_some(),
897 };
898 if ok {
899 match bytes.next() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500900 Some((offset, _)) => Ok((input.advance(offset), ())),
901 None => Ok((input.advance(input.len()), ())),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700902 }
903 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700904 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700905 }
906}
907
908named!(character -> (), do_parse!(
909 punct!("'") >>
910 cooked_char >>
911 tag!("'") >>
912 (())
913));
914
Nika Layzellf8d5f212017-12-11 14:07:02 -0500915fn cooked_char(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700916 let mut chars = input.char_indices();
917 let ok = match chars.next().map(|(_, ch)| ch) {
918 Some('\\') => {
919 match chars.next().map(|(_, ch)| ch) {
920 Some('x') => backslash_x_char(&mut chars),
921 Some('u') => backslash_u(&mut chars),
922 Some('n') |
923 Some('r') |
924 Some('t') |
925 Some('\\') |
926 Some('0') |
927 Some('\'') |
928 Some('"') => true,
929 _ => false,
930 }
931 }
932 ch => ch.is_some(),
933 };
934 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500935 match chars.next() {
936 Some((idx, _)) => Ok((input.advance(idx), ())),
937 None => Ok((input.advance(input.len()), ())),
938 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700939 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700940 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700941 }
942}
943
944macro_rules! next_ch {
945 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
946 match $chars.next() {
947 Some((_, ch)) => match ch {
948 $pat $(| $rest)* => ch,
949 _ => return false,
950 },
951 None => return false
952 }
953 };
954}
955
956fn backslash_x_char<I>(chars: &mut I) -> bool
957 where I: Iterator<Item = (usize, char)>
958{
959 next_ch!(chars @ '0'...'7');
960 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
961 true
962}
963
964fn backslash_x_byte<I>(chars: &mut I) -> bool
965 where I: Iterator<Item = (usize, u8)>
966{
967 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
968 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
969 true
970}
971
972fn backslash_u<I>(chars: &mut I) -> bool
973 where I: Iterator<Item = (usize, char)>
974{
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();
1016 if chars.peek()
1017 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1018 .unwrap_or(false) {
David Tolnay1218e122017-06-01 11:13:45 -07001019 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001020 }
1021 len += 1;
1022 has_dot = true;
1023 }
1024 'e' | 'E' => {
1025 chars.next();
1026 len += 1;
1027 has_exp = true;
1028 break;
1029 }
1030 _ => break,
1031 }
1032 }
1033
Nika Layzellf8d5f212017-12-11 14:07:02 -05001034 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001035 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001036 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001037 }
1038
1039 if has_exp {
1040 let mut has_exp_value = false;
1041 while let Some(&ch) = chars.peek() {
1042 match ch {
1043 '+' | '-' => {
1044 if has_exp_value {
1045 break;
1046 }
1047 chars.next();
1048 len += 1;
1049 }
1050 '0'...'9' => {
1051 chars.next();
1052 len += 1;
1053 has_exp_value = true;
1054 }
1055 '_' => {
1056 chars.next();
1057 len += 1;
1058 }
1059 _ => break,
1060 }
1061 }
1062 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001063 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001064 }
1065 }
1066
Nika Layzellf8d5f212017-12-11 14:07:02 -05001067 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001068}
1069
Nika Layzellf8d5f212017-12-11 14:07:02 -05001070fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001071 let (rest, ()) = digits(input)?;
1072 for suffix in &[
1073 "isize",
1074 "i8",
1075 "i16",
1076 "i32",
1077 "i64",
1078 "i128",
1079 "usize",
1080 "u8",
1081 "u16",
1082 "u32",
1083 "u64",
1084 "u128",
1085 ] {
1086 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001087 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001088 }
1089 }
1090 word_break(rest)
1091}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001092
Nika Layzellf8d5f212017-12-11 14:07:02 -05001093fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001094 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001095 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001096 16
1097 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001098 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001099 8
1100 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001101 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001102 2
1103 } else {
1104 10
1105 };
1106
Alex Crichton44bffbc2017-05-19 17:51:59 -07001107 let mut len = 0;
1108 let mut empty = true;
1109 for b in input.bytes() {
1110 let digit = match b {
1111 b'0'...b'9' => (b - b'0') as u64,
1112 b'a'...b'f' => 10 + (b - b'a') as u64,
1113 b'A'...b'F' => 10 + (b - b'A') as u64,
1114 b'_' => {
1115 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001116 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001117 }
1118 len += 1;
1119 continue;
1120 }
1121 _ => break,
1122 };
1123 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001124 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001125 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001126 len += 1;
1127 empty = false;
1128 }
1129 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001130 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001131 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001132 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001133 }
1134}
1135
1136named!(boolean -> (), alt!(
1137 keyword!("true") => { |_| () }
1138 |
1139 keyword!("false") => { |_| () }
1140));
1141
Nika Layzellf8d5f212017-12-11 14:07:02 -05001142fn op(input: Cursor) -> PResult<(char, Spacing)> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001143 let input = skip_whitespace(input);
1144 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001145 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001146 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001147 Ok(_) => Spacing::Joint,
1148 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001149 };
David Tolnay1218e122017-06-01 11:13:45 -07001150 Ok((rest, (ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001151 }
David Tolnay1218e122017-06-01 11:13:45 -07001152 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001153 }
1154}
1155
Nika Layzellf8d5f212017-12-11 14:07:02 -05001156fn op_char(input: Cursor) -> PResult<char> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001157 let mut chars = input.chars();
1158 let first = match chars.next() {
1159 Some(ch) => ch,
1160 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001161 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001162 }
1163 };
1164 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1165 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001166 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001167 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001168 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001169 }
1170}
1171
Alex Crichton44bffbc2017-05-19 17:51:59 -07001172named!(doc_comment -> (), alt!(
1173 do_parse!(
1174 punct!("//!") >>
1175 take_until!("\n") >>
1176 (())
1177 )
1178 |
1179 do_parse!(
1180 option!(whitespace) >>
1181 peek!(tag!("/*!")) >>
1182 block_comment >>
1183 (())
1184 )
1185 |
1186 do_parse!(
1187 punct!("///") >>
1188 not!(tag!("/")) >>
1189 take_until!("\n") >>
1190 (())
1191 )
1192 |
1193 do_parse!(
1194 option!(whitespace) >>
1195 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1196 block_comment >>
1197 (())
1198 )
1199));