blob: 041130c5d3bd49dea89511adcc4d2fc360f71c92 [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
Nika Layzella9dbc182017-12-30 14:50:13 -050015#[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -050016use memchr;
Alex Crichton44bffbc2017-05-19 17:51:59 -070017use proc_macro;
David Tolnayb1032662017-05-31 15:52:28 -070018use unicode_xid::UnicodeXID;
Nika Layzellf8d5f212017-12-11 14:07:02 -050019use strnom::{Cursor, PResult, skip_whitespace, block_comment, whitespace, word_break};
Alex Crichton44bffbc2017-05-19 17:51:59 -070020
Alex Crichton1a7f7622017-07-05 17:47:15 -070021use {TokenTree, TokenNode, Delimiter, Spacing};
Alex Crichton44bffbc2017-05-19 17:51:59 -070022
David Tolnay977f8282017-05-31 17:41:33 -070023#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -070024pub struct TokenStream {
25 inner: Vec<TokenTree>,
26}
27
28#[derive(Debug)]
29pub struct LexError;
30
31impl TokenStream {
32 pub fn empty() -> TokenStream {
33 TokenStream { inner: Vec::new() }
34 }
35
36 pub fn is_empty(&self) -> bool {
37 self.inner.len() == 0
38 }
39}
40
Nika Layzella9dbc182017-12-30 14:50:13 -050041#[cfg(procmacro2_unstable)]
42fn get_cursor(src: &str) -> Cursor {
43 // Create a dummy file & add it to the codemap
44 CODEMAP.with(|cm| {
45 let mut cm = cm.borrow_mut();
46 let name = format!("<parsed string {}>", cm.files.len());
47 let span = cm.add_file(&name, src);
48 Cursor {
49 rest: src,
50 off: span.lo,
51 }
52 })
53}
54
55#[cfg(not(procmacro2_unstable))]
56fn get_cursor(src: &str) -> Cursor {
57 Cursor {
58 rest: src,
59 off: 0,
60 }
61}
62
Alex Crichton44bffbc2017-05-19 17:51:59 -070063impl FromStr for TokenStream {
64 type Err = LexError;
65
66 fn from_str(src: &str) -> Result<TokenStream, LexError> {
Nika Layzellf8d5f212017-12-11 14:07:02 -050067 // Create a dummy file & add it to the codemap
Nika Layzella9dbc182017-12-30 14:50:13 -050068 let cursor = get_cursor(src);
Nika Layzellf8d5f212017-12-11 14:07:02 -050069
70 match token_stream(cursor) {
David Tolnay1218e122017-06-01 11:13:45 -070071 Ok((input, output)) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -070072 if skip_whitespace(input).len() != 0 {
73 Err(LexError)
74 } else {
David Tolnay8e976c62017-06-01 12:12:29 -070075 Ok(output.0)
Alex Crichton44bffbc2017-05-19 17:51:59 -070076 }
77 }
David Tolnay1218e122017-06-01 11:13:45 -070078 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -070079 }
80 }
81}
82
83impl fmt::Display for TokenStream {
84 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85 let mut joint = false;
86 for (i, tt) in self.inner.iter().enumerate() {
87 if i != 0 && !joint {
88 write!(f, " ")?;
89 }
90 joint = false;
91 match tt.kind {
Alex Crichton1a7f7622017-07-05 17:47:15 -070092 TokenNode::Group(delim, ref stream) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -070093 let (start, end) = match delim {
94 Delimiter::Parenthesis => ("(", ")"),
95 Delimiter::Brace => ("{", "}"),
96 Delimiter::Bracket => ("[", "]"),
97 Delimiter::None => ("", ""),
98 };
Alex Crichton852d53d2017-05-19 19:25:08 -070099 if stream.0.inner.len() == 0 {
100 write!(f, "{} {}", start, end)?
101 } else {
102 write!(f, "{} {} {}", start, stream, end)?
103 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700104 }
Alex Crichton1a7f7622017-07-05 17:47:15 -0700105 TokenNode::Term(ref sym) => write!(f, "{}", sym.as_str())?,
106 TokenNode::Op(ch, ref op) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700107 write!(f, "{}", ch)?;
108 match *op {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700109 Spacing::Alone => {}
110 Spacing::Joint => joint = true,
Alex Crichton44bffbc2017-05-19 17:51:59 -0700111 }
112 }
Alex Crichton1a7f7622017-07-05 17:47:15 -0700113 TokenNode::Literal(ref literal) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700114 write!(f, "{}", literal)?;
115 // handle comments
116 if (literal.0).0.starts_with("/") {
117 write!(f, "\n")?;
118 }
119 }
120 }
121 }
122
123 Ok(())
124 }
125}
126
127impl From<proc_macro::TokenStream> for TokenStream {
128 fn from(inner: proc_macro::TokenStream) -> TokenStream {
129 inner.to_string().parse().expect("compiler token stream parse failed")
130 }
131}
132
133impl From<TokenStream> for proc_macro::TokenStream {
134 fn from(inner: TokenStream) -> proc_macro::TokenStream {
135 inner.to_string().parse().expect("failed to parse to compiler tokens")
136 }
137}
138
139
140impl From<TokenTree> for TokenStream {
141 fn from(tree: TokenTree) -> TokenStream {
142 TokenStream { inner: vec![tree] }
143 }
144}
145
146impl iter::FromIterator<TokenStream> for TokenStream {
147 fn from_iter<I: IntoIterator<Item=TokenStream>>(streams: I) -> Self {
148 let mut v = Vec::new();
149
150 for stream in streams.into_iter() {
151 v.extend(stream.inner);
152 }
153
154 TokenStream { inner: v }
155 }
156}
157
Alex Crichton1a7f7622017-07-05 17:47:15 -0700158pub type TokenTreeIter = vec::IntoIter<TokenTree>;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700159
160impl IntoIterator for TokenStream {
161 type Item = TokenTree;
Alex Crichton1a7f7622017-07-05 17:47:15 -0700162 type IntoIter = TokenTreeIter;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700163
Alex Crichton1a7f7622017-07-05 17:47:15 -0700164 fn into_iter(self) -> TokenTreeIter {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700165 self.inner.into_iter()
166 }
167}
168
Nika Layzella9dbc182017-12-30 14:50:13 -0500169#[cfg(procmacro2_unstable)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500170#[derive(Clone, PartialEq, Eq, Debug)]
171pub struct FileName(String);
172
Nika Layzella9dbc182017-12-30 14:50:13 -0500173#[cfg(procmacro2_unstable)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500174impl fmt::Display for FileName {
175 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
176 self.0.fmt(f)
177 }
178}
179
Nika Layzella9dbc182017-12-30 14:50:13 -0500180#[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500181#[derive(Clone, PartialEq, Eq)]
182pub struct SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500183 name: FileName,
Nika Layzellf8d5f212017-12-11 14:07:02 -0500184}
185
Nika Layzella9dbc182017-12-30 14:50:13 -0500186#[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500187impl SourceFile {
188 /// Get the path to this source file as a string.
Nika Layzellb35a9a32017-12-30 14:34:35 -0500189 pub fn path(&self) -> &FileName {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500190 &self.name
191 }
192
193 pub fn is_real(&self) -> bool {
194 // XXX(nika): Support real files in the future?
195 false
196 }
197}
198
Nika Layzella9dbc182017-12-30 14:50:13 -0500199#[cfg(procmacro2_unstable)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500200impl AsRef<FileName> for SourceFile {
201 fn as_ref(&self) -> &FileName {
202 self.path()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500203 }
204}
205
Nika Layzella9dbc182017-12-30 14:50:13 -0500206#[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500207impl fmt::Debug for SourceFile {
208 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
209 f.debug_struct("SourceFile")
Nika Layzellb35a9a32017-12-30 14:34:35 -0500210 .field("path", &self.path())
Nika Layzellf8d5f212017-12-11 14:07:02 -0500211 .field("is_real", &self.is_real())
212 .finish()
213 }
214}
215
Nika Layzella9dbc182017-12-30 14:50:13 -0500216#[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500217#[derive(Clone, Copy, Debug, PartialEq, Eq)]
218pub struct LineColumn {
219 pub line: usize,
220 pub column: usize,
221}
222
Nika Layzella9dbc182017-12-30 14:50:13 -0500223#[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500224thread_local! {
225 static CODEMAP: RefCell<Codemap> = RefCell::new(Codemap {
226 // NOTE: We start with a single dummy file which all call_site() and
227 // def_site() spans reference.
228 files: vec![FileInfo {
229 name: "<unspecified>".to_owned(),
230 span: Span { lo: 0, hi: 0 },
231 lines: vec![0],
232 }],
233 });
234}
235
Nika Layzella9dbc182017-12-30 14:50:13 -0500236#[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500237struct FileInfo {
238 name: String,
239 span: Span,
240 lines: Vec<usize>,
241}
242
Nika Layzella9dbc182017-12-30 14:50:13 -0500243#[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500244impl FileInfo {
245 fn offset_line_column(&self, offset: usize) -> LineColumn {
246 assert!(self.span_within(Span { lo: offset as u32, hi: offset as u32 }));
247 let offset = offset - self.span.lo as usize;
248 match self.lines.binary_search(&offset) {
249 Ok(found) => LineColumn {
250 line: found + 1,
251 column: 0
252 },
253 Err(idx) => LineColumn {
254 line: idx,
255 column: offset - self.lines[idx - 1]
256 },
257 }
258 }
259
260 fn span_within(&self, span: Span) -> bool {
261 span.lo >= self.span.lo && span.hi <= self.span.hi
262 }
263}
264
265/// Computes the offsets of each line in the given source string.
Nika Layzella9dbc182017-12-30 14:50:13 -0500266#[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500267fn lines_offsets(s: &[u8]) -> Vec<usize> {
268 let mut lines = vec![0];
269 let mut prev = 0;
270 while let Some(len) = memchr::memchr(b'\n', &s[prev..]) {
271 prev += len + 1;
272 lines.push(prev);
273 }
274 lines
275}
276
Nika Layzella9dbc182017-12-30 14:50:13 -0500277#[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500278struct Codemap {
279 files: Vec<FileInfo>,
280}
281
Nika Layzella9dbc182017-12-30 14:50:13 -0500282#[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500283impl Codemap {
284 fn next_start_pos(&self) -> u32 {
285 // Add 1 so there's always space between files.
286 //
287 // We'll always have at least 1 file, as we initialize our files list
288 // with a dummy file.
289 self.files.last().unwrap().span.hi + 1
290 }
291
292 fn add_file(&mut self, name: &str, src: &str) -> Span {
293 let lines = lines_offsets(src.as_bytes());
294 let lo = self.next_start_pos();
295 // XXX(nika): Shouild we bother doing a checked cast or checked add here?
296 let span = Span { lo: lo, hi: lo + (src.len() as u32) };
297
298 self.files.push(FileInfo {
299 name: name.to_owned(),
300 span: span,
301 lines: lines,
302 });
303
304 span
305 }
306
307 fn fileinfo(&self, span: Span) -> &FileInfo {
308 for file in &self.files {
309 if file.span_within(span) {
310 return file;
311 }
312 }
313 panic!("Invalid span with no related FileInfo!");
314 }
315}
316
Alex Crichtone6085b72017-11-21 07:24:25 -0800317#[derive(Clone, Copy, Debug)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500318pub struct Span { lo: u32, hi: u32 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700319
320impl Span {
321 pub fn call_site() -> Span {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500322 Span { lo: 0, hi: 0 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700323 }
Alex Crichtone6085b72017-11-21 07:24:25 -0800324
325 pub fn def_site() -> Span {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500326 Span { lo: 0, hi: 0 }
327 }
328
Nika Layzella9dbc182017-12-30 14:50:13 -0500329 #[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500330 pub fn source_file(&self) -> SourceFile {
331 CODEMAP.with(|cm| {
332 let cm = cm.borrow();
333 let fi = cm.fileinfo(*self);
334 SourceFile {
Nika Layzellb35a9a32017-12-30 14:34:35 -0500335 name: FileName(fi.name.clone()),
Nika Layzellf8d5f212017-12-11 14:07:02 -0500336 }
337 })
338 }
339
Nika Layzella9dbc182017-12-30 14:50:13 -0500340 #[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500341 pub fn start(&self) -> LineColumn {
342 CODEMAP.with(|cm| {
343 let cm = cm.borrow();
344 let fi = cm.fileinfo(*self);
345 fi.offset_line_column(self.lo as usize)
346 })
347 }
348
Nika Layzella9dbc182017-12-30 14:50:13 -0500349 #[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500350 pub fn end(&self) -> LineColumn {
351 CODEMAP.with(|cm| {
352 let cm = cm.borrow();
353 let fi = cm.fileinfo(*self);
354 fi.offset_line_column(self.hi as usize)
355 })
356 }
357
Nika Layzella9dbc182017-12-30 14:50:13 -0500358 #[cfg(procmacro2_unstable)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500359 pub fn join(&self, other: Span) -> Option<Span> {
360 CODEMAP.with(|cm| {
361 let cm = cm.borrow();
362 // If `other` is not within the same FileInfo as us, return None.
363 if !cm.fileinfo(*self).span_within(other) {
364 return None;
365 }
366 Some(Span {
367 lo: cmp::min(self.lo, other.lo),
368 hi: cmp::max(self.hi, other.hi),
369 })
370 })
Alex Crichtone6085b72017-11-21 07:24:25 -0800371 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700372}
373
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700374#[derive(Copy, Clone)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700375pub struct Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700376 intern: usize,
377 not_send_sync: PhantomData<*const ()>,
378}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700379
380thread_local!(static SYMBOLS: RefCell<Interner> = RefCell::new(Interner::new()));
381
Alex Crichton1a7f7622017-07-05 17:47:15 -0700382impl<'a> From<&'a str> for Term {
383 fn from(string: &'a str) -> Term {
384 Term {
David Tolnay041bcd42017-06-03 09:18:04 -0700385 intern: SYMBOLS.with(|s| s.borrow_mut().intern(string)),
386 not_send_sync: PhantomData,
387 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700388 }
389}
390
Alex Crichton1a7f7622017-07-05 17:47:15 -0700391impl ops::Deref for Term {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700392 type Target = str;
393
394 fn deref(&self) -> &str {
395 SYMBOLS.with(|interner| {
396 let interner = interner.borrow();
David Tolnay041bcd42017-06-03 09:18:04 -0700397 let s = interner.get(self.intern);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700398 unsafe {
399 &*(s as *const str)
400 }
401 })
402 }
403}
404
Alex Crichton1a7f7622017-07-05 17:47:15 -0700405impl fmt::Debug for Term {
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700406 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700407 f.debug_tuple("Term").field(&&**self).finish()
David Tolnay8ad3e3e2017-06-03 16:45:00 -0700408 }
409}
410
Alex Crichton44bffbc2017-05-19 17:51:59 -0700411struct Interner {
412 string_to_index: HashMap<MyRc, usize>,
413 index_to_string: Vec<Rc<String>>,
414}
415
416#[derive(Hash, Eq, PartialEq)]
417struct MyRc(Rc<String>);
418
419impl Borrow<str> for MyRc {
420 fn borrow(&self) -> &str {
421 &self.0
422 }
423}
424
425impl Interner {
426 fn new() -> Interner {
427 Interner {
428 string_to_index: HashMap::new(),
429 index_to_string: Vec::new(),
430 }
431 }
432
433 fn intern(&mut self, s: &str) -> usize {
434 if let Some(&idx) = self.string_to_index.get(s) {
435 return idx
436 }
437 let s = Rc::new(s.to_string());
438 self.index_to_string.push(s.clone());
439 self.string_to_index.insert(MyRc(s), self.index_to_string.len() - 1);
440 self.index_to_string.len() - 1
441 }
442
443 fn get(&self, idx: usize) -> &str {
444 &self.index_to_string[idx]
445 }
446}
447
David Tolnay977f8282017-05-31 17:41:33 -0700448#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700449pub struct Literal(String);
450
Alex Crichton852d53d2017-05-19 19:25:08 -0700451impl Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700452 pub fn byte_char(byte: u8) -> Literal {
Alex Crichton76a5cc82017-05-23 07:01:44 -0700453 match byte {
454 0 => Literal(format!("b'\\0'")),
455 b'\"' => Literal(format!("b'\"'")),
456 n => {
457 let mut escaped = "b'".to_string();
458 escaped.extend(ascii::escape_default(n).map(|c| c as char));
459 escaped.push('\'');
460 Literal(escaped)
461 }
462 }
463 }
464
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700465 pub fn byte_string(bytes: &[u8]) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700466 let mut escaped = "b\"".to_string();
467 for b in bytes {
468 match *b {
469 b'\0' => escaped.push_str(r"\0"),
470 b'\t' => escaped.push_str(r"\t"),
471 b'\n' => escaped.push_str(r"\n"),
472 b'\r' => escaped.push_str(r"\r"),
473 b'"' => escaped.push_str("\\\""),
474 b'\\' => escaped.push_str("\\\\"),
475 b'\x20' ... b'\x7E' => escaped.push(*b as char),
476 _ => escaped.push_str(&format!("\\x{:02X}", b)),
477 }
478 }
479 escaped.push('"');
480 Literal(escaped)
481 }
Alex Crichton76a5cc82017-05-23 07:01:44 -0700482
483 pub fn doccomment(s: &str) -> Literal {
484 Literal(s.to_string())
485 }
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700486
Alex Crichton1a7f7622017-07-05 17:47:15 -0700487 pub fn float(s: f64) -> Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700488 Literal(s.to_string())
489 }
490
Alex Crichton1a7f7622017-07-05 17:47:15 -0700491 pub fn integer(s: i64) -> Literal {
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700492 Literal(s.to_string())
493 }
Alex Crichton31316622017-05-26 12:54:47 -0700494
495 pub fn raw_string(s: &str, pounds: usize) -> Literal {
496 let mut ret = format!("r");
497 ret.extend((0..pounds).map(|_| "#"));
498 ret.push('"');
499 ret.push_str(s);
500 ret.push('"');
501 ret.extend((0..pounds).map(|_| "#"));
502 Literal(ret)
503 }
504
505 pub fn raw_byte_string(s: &str, pounds: usize) -> Literal {
Alex Crichton7ed6d282017-05-26 13:42:50 -0700506 let mut ret = format!("br");
Alex Crichton31316622017-05-26 12:54:47 -0700507 ret.extend((0..pounds).map(|_| "#"));
508 ret.push('"');
509 ret.push_str(s);
510 ret.push('"');
511 ret.extend((0..pounds).map(|_| "#"));
512 Literal(ret)
513 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700514}
515
Alex Crichton44bffbc2017-05-19 17:51:59 -0700516impl fmt::Display for Literal {
517 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
518 self.0.fmt(f)
519 }
520}
521
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700522macro_rules! ints {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700523 ($($t:ty,)*) => {$(
524 impl From<$t> for Literal {
525 fn from(t: $t) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700526 Literal(format!(concat!("{}", stringify!($t)), t))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700527 }
528 }
529 )*}
530}
531
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700532ints! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700533 u8, u16, u32, u64, usize,
534 i8, i16, i32, i64, isize,
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700535}
536
537macro_rules! floats {
538 ($($t:ty,)*) => {$(
539 impl From<$t> for Literal {
540 fn from(t: $t) -> Literal {
541 assert!(!t.is_nan());
542 assert!(!t.is_infinite());
543 Literal(format!(concat!("{}", stringify!($t)), t))
544 }
545 }
546 )*}
547}
548
549floats! {
Alex Crichton852d53d2017-05-19 19:25:08 -0700550 f32, f64,
551}
552
Alex Crichton44bffbc2017-05-19 17:51:59 -0700553impl<'a> From<&'a str> for Literal {
554 fn from(t: &'a str) -> Literal {
555 let mut s = t.chars().flat_map(|c| c.escape_default()).collect::<String>();
556 s.push('"');
557 s.insert(0, '"');
558 Literal(s)
559 }
560}
561
562impl From<char> for Literal {
563 fn from(t: char) -> Literal {
Alex Crichton2d0cf0b2017-05-26 14:00:16 -0700564 Literal(format!("'{}'", t.escape_default().collect::<String>()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700565 }
566}
567
David Tolnay8e976c62017-06-01 12:12:29 -0700568named!(token_stream -> ::TokenStream, map!(
569 many0!(token_tree),
570 |trees| ::TokenStream(TokenStream { inner: trees })
571));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700572
Nika Layzellf8d5f212017-12-11 14:07:02 -0500573fn token_tree(input: Cursor) -> PResult<TokenTree> {
574 let input = skip_whitespace(input);
575 let lo = input.off;
576 let (input, kind) = token_kind(input)?;
577 let hi = input.off;
578 Ok((input, TokenTree {
579 span: ::Span(Span {
580 lo: lo,
581 hi: hi,
582 }),
583 kind: kind,
584 }))
585}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700586
Alex Crichton1a7f7622017-07-05 17:47:15 -0700587named!(token_kind -> TokenNode, alt!(
588 map!(delimited, |(d, s)| TokenNode::Group(d, s))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700589 |
Alex Crichton1a7f7622017-07-05 17:47:15 -0700590 map!(literal, TokenNode::Literal) // must be before symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700591 |
Alex Crichton52725f72017-08-28 12:20:58 -0700592 symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700593 |
Alex Crichton1a7f7622017-07-05 17:47:15 -0700594 map!(op, |(op, kind)| TokenNode::Op(op, kind))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700595));
596
David Tolnay8e976c62017-06-01 12:12:29 -0700597named!(delimited -> (Delimiter, ::TokenStream), alt!(
Alex Crichton44bffbc2017-05-19 17:51:59 -0700598 delimited!(
599 punct!("("),
600 token_stream,
601 punct!(")")
602 ) => { |ts| (Delimiter::Parenthesis, ts) }
603 |
604 delimited!(
605 punct!("["),
606 token_stream,
607 punct!("]")
608 ) => { |ts| (Delimiter::Bracket, ts) }
609 |
610 delimited!(
611 punct!("{"),
612 token_stream,
613 punct!("}")
614 ) => { |ts| (Delimiter::Brace, ts) }
615));
616
Nika Layzellf8d5f212017-12-11 14:07:02 -0500617fn symbol(mut input: Cursor) -> PResult<TokenNode> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700618 input = skip_whitespace(input);
619
620 let mut chars = input.char_indices();
David Tolnaya202d502017-06-01 12:26:55 -0700621
622 let lifetime = input.starts_with("'");
623 if lifetime {
624 chars.next();
625 }
626
Alex Crichton44bffbc2017-05-19 17:51:59 -0700627 match chars.next() {
628 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700629 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700630 }
631
David Tolnay214c94c2017-06-01 12:42:56 -0700632 let mut end = input.len();
Alex Crichton44bffbc2017-05-19 17:51:59 -0700633 for (i, ch) in chars {
634 if !UnicodeXID::is_xid_continue(ch) {
David Tolnay214c94c2017-06-01 12:42:56 -0700635 end = i;
636 break;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700637 }
638 }
639
Nika Layzellf8d5f212017-12-11 14:07:02 -0500640 if lifetime && &input.rest[..end] != "'static" && KEYWORDS.contains(&&input.rest[1..end]) {
David Tolnay214c94c2017-06-01 12:42:56 -0700641 Err(LexError)
642 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500643 let a = &input.rest[..end];
Alex Crichton52725f72017-08-28 12:20:58 -0700644 if a == "_" {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500645 Ok((input.advance(end), TokenNode::Op('_', Spacing::Alone)))
Alex Crichton52725f72017-08-28 12:20:58 -0700646 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500647 Ok((input.advance(end), TokenNode::Term(::Term::intern(a))))
Alex Crichton52725f72017-08-28 12:20:58 -0700648 }
David Tolnay214c94c2017-06-01 12:42:56 -0700649 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700650}
651
David Tolnay214c94c2017-06-01 12:42:56 -0700652// From https://github.com/rust-lang/rust/blob/master/src/libsyntax_pos/symbol.rs
653static KEYWORDS: &'static [&'static str] = &[
654 "abstract", "alignof", "as", "become", "box", "break", "const", "continue",
655 "crate", "do", "else", "enum", "extern", "false", "final", "fn", "for",
656 "if", "impl", "in", "let", "loop", "macro", "match", "mod", "move", "mut",
657 "offsetof", "override", "priv", "proc", "pub", "pure", "ref", "return",
658 "self", "Self", "sizeof", "static", "struct", "super", "trait", "true",
659 "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while",
660 "yield",
661];
662
Nika Layzellf8d5f212017-12-11 14:07:02 -0500663fn literal(input: Cursor) -> PResult<::Literal> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700664 let input_no_ws = skip_whitespace(input);
665
666 match literal_nocapture(input_no_ws) {
David Tolnay1218e122017-06-01 11:13:45 -0700667 Ok((a, ())) => {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700668 let start = input.len() - input_no_ws.len();
669 let len = input_no_ws.len() - a.len();
670 let end = start + len;
Nika Layzellf8d5f212017-12-11 14:07:02 -0500671 Ok((a, ::Literal(Literal(input.rest[start..end].to_string()))))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700672 }
David Tolnay1218e122017-06-01 11:13:45 -0700673 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700674 }
675}
676
677named!(literal_nocapture -> (), alt!(
678 string
679 |
680 byte_string
681 |
682 byte
683 |
684 character
685 |
686 float
687 |
688 int
689 |
690 boolean
691 |
692 doc_comment
693));
694
695named!(string -> (), alt!(
696 quoted_string
697 |
698 preceded!(
699 punct!("r"),
700 raw_string
701 ) => { |_| () }
702));
703
704named!(quoted_string -> (), delimited!(
705 punct!("\""),
706 cooked_string,
707 tag!("\"")
708));
709
Nika Layzellf8d5f212017-12-11 14:07:02 -0500710fn cooked_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700711 let mut chars = input.char_indices().peekable();
712 while let Some((byte_offset, ch)) = chars.next() {
713 match ch {
714 '"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500715 return Ok((input.advance(byte_offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700716 }
717 '\r' => {
718 if let Some((_, '\n')) = chars.next() {
719 // ...
720 } else {
721 break;
722 }
723 }
724 '\\' => {
725 match chars.next() {
726 Some((_, 'x')) => {
727 if !backslash_x_char(&mut chars) {
728 break
729 }
730 }
731 Some((_, 'n')) |
732 Some((_, 'r')) |
733 Some((_, 't')) |
734 Some((_, '\\')) |
735 Some((_, '\'')) |
736 Some((_, '"')) |
737 Some((_, '0')) => {}
738 Some((_, 'u')) => {
739 if !backslash_u(&mut chars) {
740 break
741 }
742 }
743 Some((_, '\n')) | Some((_, '\r')) => {
744 while let Some(&(_, ch)) = chars.peek() {
745 if ch.is_whitespace() {
746 chars.next();
747 } else {
748 break;
749 }
750 }
751 }
752 _ => break,
753 }
754 }
755 _ch => {}
756 }
757 }
David Tolnay1218e122017-06-01 11:13:45 -0700758 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700759}
760
761named!(byte_string -> (), alt!(
762 delimited!(
763 punct!("b\""),
764 cooked_byte_string,
765 tag!("\"")
766 ) => { |_| () }
767 |
768 preceded!(
769 punct!("br"),
770 raw_string
771 ) => { |_| () }
772));
773
Nika Layzellf8d5f212017-12-11 14:07:02 -0500774fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700775 let mut bytes = input.bytes().enumerate();
776 'outer: while let Some((offset, b)) = bytes.next() {
777 match b {
778 b'"' => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500779 return Ok((input.advance(offset), ()));
Alex Crichton44bffbc2017-05-19 17:51:59 -0700780 }
781 b'\r' => {
782 if let Some((_, b'\n')) = bytes.next() {
783 // ...
784 } else {
785 break;
786 }
787 }
788 b'\\' => {
789 match bytes.next() {
790 Some((_, b'x')) => {
791 if !backslash_x_byte(&mut bytes) {
792 break
793 }
794 }
795 Some((_, b'n')) |
796 Some((_, b'r')) |
797 Some((_, b't')) |
798 Some((_, b'\\')) |
799 Some((_, b'0')) |
800 Some((_, b'\'')) |
801 Some((_, b'"')) => {}
802 Some((newline, b'\n')) |
803 Some((newline, b'\r')) => {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500804 let rest = input.advance(newline + 1);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700805 for (offset, ch) in rest.char_indices() {
806 if !ch.is_whitespace() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500807 input = rest.advance(offset);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700808 bytes = input.bytes().enumerate();
809 continue 'outer;
810 }
811 }
812 break;
813 }
814 _ => break,
815 }
816 }
817 b if b < 0x80 => {}
818 _ => break,
819 }
820 }
David Tolnay1218e122017-06-01 11:13:45 -0700821 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700822}
823
Nika Layzellf8d5f212017-12-11 14:07:02 -0500824fn raw_string(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700825 let mut chars = input.char_indices();
826 let mut n = 0;
827 while let Some((byte_offset, ch)) = chars.next() {
828 match ch {
829 '"' => {
830 n = byte_offset;
831 break;
832 }
833 '#' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700834 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700835 }
836 }
837 for (byte_offset, ch) in chars {
838 match ch {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500839 '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
840 let rest = input.advance(byte_offset + 1 + n);
David Tolnay1218e122017-06-01 11:13:45 -0700841 return Ok((rest, ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700842 }
843 '\r' => {}
844 _ => {}
845 }
846 }
David Tolnay1218e122017-06-01 11:13:45 -0700847 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700848}
849
850named!(byte -> (), do_parse!(
851 punct!("b") >>
852 tag!("'") >>
853 cooked_byte >>
854 tag!("'") >>
855 (())
856));
857
Nika Layzellf8d5f212017-12-11 14:07:02 -0500858fn cooked_byte(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700859 let mut bytes = input.bytes().enumerate();
860 let ok = match bytes.next().map(|(_, b)| b) {
861 Some(b'\\') => {
862 match bytes.next().map(|(_, b)| b) {
863 Some(b'x') => backslash_x_byte(&mut bytes),
864 Some(b'n') |
865 Some(b'r') |
866 Some(b't') |
867 Some(b'\\') |
868 Some(b'0') |
869 Some(b'\'') |
870 Some(b'"') => true,
871 _ => false,
872 }
873 }
874 b => b.is_some(),
875 };
876 if ok {
877 match bytes.next() {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500878 Some((offset, _)) => Ok((input.advance(offset), ())),
879 None => Ok((input.advance(input.len()), ())),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700880 }
881 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700882 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700883 }
884}
885
886named!(character -> (), do_parse!(
887 punct!("'") >>
888 cooked_char >>
889 tag!("'") >>
890 (())
891));
892
Nika Layzellf8d5f212017-12-11 14:07:02 -0500893fn cooked_char(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700894 let mut chars = input.char_indices();
895 let ok = match chars.next().map(|(_, ch)| ch) {
896 Some('\\') => {
897 match chars.next().map(|(_, ch)| ch) {
898 Some('x') => backslash_x_char(&mut chars),
899 Some('u') => backslash_u(&mut chars),
900 Some('n') |
901 Some('r') |
902 Some('t') |
903 Some('\\') |
904 Some('0') |
905 Some('\'') |
906 Some('"') => true,
907 _ => false,
908 }
909 }
910 ch => ch.is_some(),
911 };
912 if ok {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500913 match chars.next() {
914 Some((idx, _)) => Ok((input.advance(idx), ())),
915 None => Ok((input.advance(input.len()), ())),
916 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700917 } else {
David Tolnay1218e122017-06-01 11:13:45 -0700918 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -0700919 }
920}
921
922macro_rules! next_ch {
923 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
924 match $chars.next() {
925 Some((_, ch)) => match ch {
926 $pat $(| $rest)* => ch,
927 _ => return false,
928 },
929 None => return false
930 }
931 };
932}
933
934fn backslash_x_char<I>(chars: &mut I) -> bool
935 where I: Iterator<Item = (usize, char)>
936{
937 next_ch!(chars @ '0'...'7');
938 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
939 true
940}
941
942fn backslash_x_byte<I>(chars: &mut I) -> bool
943 where I: Iterator<Item = (usize, u8)>
944{
945 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
946 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
947 true
948}
949
950fn backslash_u<I>(chars: &mut I) -> bool
951 where I: Iterator<Item = (usize, char)>
952{
953 next_ch!(chars @ '{');
954 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
955 let b = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
956 if b == '}' {
957 return true
958 }
959 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
960 if c == '}' {
961 return true
962 }
963 let d = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
964 if d == '}' {
965 return true
966 }
967 let e = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
968 if e == '}' {
969 return true
970 }
971 let f = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
972 if f == '}' {
973 return true
974 }
975 next_ch!(chars @ '}');
976 true
977}
978
Nika Layzellf8d5f212017-12-11 14:07:02 -0500979fn float(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -0700980 let (rest, ()) = float_digits(input)?;
981 for suffix in &["f32", "f64"] {
982 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -0500983 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -0700984 }
985 }
986 word_break(rest)
987}
Alex Crichton44bffbc2017-05-19 17:51:59 -0700988
Nika Layzellf8d5f212017-12-11 14:07:02 -0500989fn float_digits(input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700990 let mut chars = input.chars().peekable();
991 match chars.next() {
992 Some(ch) if ch >= '0' && ch <= '9' => {}
David Tolnay1218e122017-06-01 11:13:45 -0700993 _ => return Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700994 }
995
996 let mut len = 1;
997 let mut has_dot = false;
998 let mut has_exp = false;
999 while let Some(&ch) = chars.peek() {
1000 match ch {
1001 '0'...'9' | '_' => {
1002 chars.next();
1003 len += 1;
1004 }
1005 '.' => {
1006 if has_dot {
1007 break;
1008 }
1009 chars.next();
1010 if chars.peek()
1011 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
1012 .unwrap_or(false) {
David Tolnay1218e122017-06-01 11:13:45 -07001013 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001014 }
1015 len += 1;
1016 has_dot = true;
1017 }
1018 'e' | 'E' => {
1019 chars.next();
1020 len += 1;
1021 has_exp = true;
1022 break;
1023 }
1024 _ => break,
1025 }
1026 }
1027
Nika Layzellf8d5f212017-12-11 14:07:02 -05001028 let rest = input.advance(len);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001029 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
David Tolnay1218e122017-06-01 11:13:45 -07001030 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001031 }
1032
1033 if has_exp {
1034 let mut has_exp_value = false;
1035 while let Some(&ch) = chars.peek() {
1036 match ch {
1037 '+' | '-' => {
1038 if has_exp_value {
1039 break;
1040 }
1041 chars.next();
1042 len += 1;
1043 }
1044 '0'...'9' => {
1045 chars.next();
1046 len += 1;
1047 has_exp_value = true;
1048 }
1049 '_' => {
1050 chars.next();
1051 len += 1;
1052 }
1053 _ => break,
1054 }
1055 }
1056 if !has_exp_value {
David Tolnay1218e122017-06-01 11:13:45 -07001057 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001058 }
1059 }
1060
Nika Layzellf8d5f212017-12-11 14:07:02 -05001061 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001062}
1063
Nika Layzellf8d5f212017-12-11 14:07:02 -05001064fn int(input: Cursor) -> PResult<()> {
David Tolnay744a6b82017-06-01 11:34:29 -07001065 let (rest, ()) = digits(input)?;
1066 for suffix in &[
1067 "isize",
1068 "i8",
1069 "i16",
1070 "i32",
1071 "i64",
1072 "i128",
1073 "usize",
1074 "u8",
1075 "u16",
1076 "u32",
1077 "u64",
1078 "u128",
1079 ] {
1080 if rest.starts_with(suffix) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001081 return word_break(rest.advance(suffix.len()));
David Tolnay744a6b82017-06-01 11:34:29 -07001082 }
1083 }
1084 word_break(rest)
1085}
Alex Crichton44bffbc2017-05-19 17:51:59 -07001086
Nika Layzellf8d5f212017-12-11 14:07:02 -05001087fn digits(mut input: Cursor) -> PResult<()> {
Alex Crichton44bffbc2017-05-19 17:51:59 -07001088 let base = if input.starts_with("0x") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001089 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001090 16
1091 } else if input.starts_with("0o") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001092 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001093 8
1094 } else if input.starts_with("0b") {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001095 input = input.advance(2);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001096 2
1097 } else {
1098 10
1099 };
1100
Alex Crichton44bffbc2017-05-19 17:51:59 -07001101 let mut len = 0;
1102 let mut empty = true;
1103 for b in input.bytes() {
1104 let digit = match b {
1105 b'0'...b'9' => (b - b'0') as u64,
1106 b'a'...b'f' => 10 + (b - b'a') as u64,
1107 b'A'...b'F' => 10 + (b - b'A') as u64,
1108 b'_' => {
1109 if empty && base == 10 {
David Tolnay1218e122017-06-01 11:13:45 -07001110 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001111 }
1112 len += 1;
1113 continue;
1114 }
1115 _ => break,
1116 };
1117 if digit >= base {
David Tolnay1218e122017-06-01 11:13:45 -07001118 return Err(LexError);
Alex Crichton44bffbc2017-05-19 17:51:59 -07001119 }
Alex Crichton44bffbc2017-05-19 17:51:59 -07001120 len += 1;
1121 empty = false;
1122 }
1123 if empty {
David Tolnay1218e122017-06-01 11:13:45 -07001124 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001125 } else {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001126 Ok((input.advance(len), ()))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001127 }
1128}
1129
1130named!(boolean -> (), alt!(
1131 keyword!("true") => { |_| () }
1132 |
1133 keyword!("false") => { |_| () }
1134));
1135
Nika Layzellf8d5f212017-12-11 14:07:02 -05001136fn op(input: Cursor) -> PResult<(char, Spacing)> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001137 let input = skip_whitespace(input);
1138 match op_char(input) {
David Tolnay1218e122017-06-01 11:13:45 -07001139 Ok((rest, ch)) => {
David Tolnayea75c5f2017-05-31 23:40:33 -07001140 let kind = match op_char(rest) {
Alex Crichton1a7f7622017-07-05 17:47:15 -07001141 Ok(_) => Spacing::Joint,
1142 Err(LexError) => Spacing::Alone,
David Tolnayea75c5f2017-05-31 23:40:33 -07001143 };
David Tolnay1218e122017-06-01 11:13:45 -07001144 Ok((rest, (ch, kind)))
David Tolnayea75c5f2017-05-31 23:40:33 -07001145 }
David Tolnay1218e122017-06-01 11:13:45 -07001146 Err(LexError) => Err(LexError),
Alex Crichton44bffbc2017-05-19 17:51:59 -07001147 }
1148}
1149
Nika Layzellf8d5f212017-12-11 14:07:02 -05001150fn op_char(input: Cursor) -> PResult<char> {
David Tolnayea75c5f2017-05-31 23:40:33 -07001151 let mut chars = input.chars();
1152 let first = match chars.next() {
1153 Some(ch) => ch,
1154 None => {
David Tolnay1218e122017-06-01 11:13:45 -07001155 return Err(LexError);
David Tolnayea75c5f2017-05-31 23:40:33 -07001156 }
1157 };
1158 let recognized = "~!@#$%^&*-=+|;:,<.>/?";
1159 if recognized.contains(first) {
Nika Layzellf8d5f212017-12-11 14:07:02 -05001160 Ok((input.advance(first.len_utf8()), first))
Alex Crichton44bffbc2017-05-19 17:51:59 -07001161 } else {
David Tolnay1218e122017-06-01 11:13:45 -07001162 Err(LexError)
Alex Crichton44bffbc2017-05-19 17:51:59 -07001163 }
1164}
1165
Alex Crichton44bffbc2017-05-19 17:51:59 -07001166named!(doc_comment -> (), alt!(
1167 do_parse!(
1168 punct!("//!") >>
1169 take_until!("\n") >>
1170 (())
1171 )
1172 |
1173 do_parse!(
1174 option!(whitespace) >>
1175 peek!(tag!("/*!")) >>
1176 block_comment >>
1177 (())
1178 )
1179 |
1180 do_parse!(
1181 punct!("///") >>
1182 not!(tag!("/")) >>
1183 take_until!("\n") >>
1184 (())
1185 )
1186 |
1187 do_parse!(
1188 option!(whitespace) >>
1189 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1190 block_comment >>
1191 (())
1192 )
1193));