blob: d30e5e033c2b56ad0050ee3ed10adb36c7461d71 [file] [log] [blame]
Alex Crichton44bffbc2017-05-19 17:51:59 -07001extern crate unicode_xid;
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;
6use std::collections::HashMap;
7use std::fmt;
8use std::iter;
9use std::ops;
10use std::rc::Rc;
11use std::str::FromStr;
12use std::vec;
13
14use proc_macro;
15use self::unicode_xid::UnicodeXID;
16use synom::space::{skip_whitespace, block_comment, whitespace};
17use synom::{IResult};
18
19use {TokenTree, TokenKind, Delimiter, OpKind};
20
21#[derive(Clone)]
22pub 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
39impl FromStr for TokenStream {
40 type Err = LexError;
41
42 fn from_str(src: &str) -> Result<TokenStream, LexError> {
43 match token_stream(src) {
44 IResult::Done(input, output) => {
45 if skip_whitespace(input).len() != 0 {
46 Err(LexError)
47 } else {
48 Ok(output)
49 }
50 }
51 IResult::Error => Err(LexError),
52 }
53 }
54}
55
56impl fmt::Display for TokenStream {
57 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
58 let mut joint = false;
59 for (i, tt) in self.inner.iter().enumerate() {
60 if i != 0 && !joint {
61 write!(f, " ")?;
62 }
63 joint = false;
64 match tt.kind {
65 TokenKind::Sequence(delim, ref stream) => {
66 let (start, end) = match delim {
67 Delimiter::Parenthesis => ("(", ")"),
68 Delimiter::Brace => ("{", "}"),
69 Delimiter::Bracket => ("[", "]"),
70 Delimiter::None => ("", ""),
71 };
Alex Crichton852d53d2017-05-19 19:25:08 -070072 if stream.0.inner.len() == 0 {
73 write!(f, "{} {}", start, end)?
74 } else {
75 write!(f, "{} {} {}", start, stream, end)?
76 }
Alex Crichton44bffbc2017-05-19 17:51:59 -070077 }
78 TokenKind::Word(ref sym) => write!(f, "{}", &**sym)?,
79 TokenKind::Op(ch, ref op) => {
80 write!(f, "{}", ch)?;
81 match *op {
82 OpKind::Alone => {}
83 OpKind::Joint => joint = true,
84 }
85 }
86 TokenKind::Literal(ref literal) => {
87 write!(f, "{}", literal)?;
88 // handle comments
89 if (literal.0).0.starts_with("/") {
90 write!(f, "\n")?;
91 }
92 }
93 }
94 }
95
96 Ok(())
97 }
98}
99
100impl From<proc_macro::TokenStream> for TokenStream {
101 fn from(inner: proc_macro::TokenStream) -> TokenStream {
102 inner.to_string().parse().expect("compiler token stream parse failed")
103 }
104}
105
106impl From<TokenStream> for proc_macro::TokenStream {
107 fn from(inner: TokenStream) -> proc_macro::TokenStream {
108 inner.to_string().parse().expect("failed to parse to compiler tokens")
109 }
110}
111
112
113impl From<TokenTree> for TokenStream {
114 fn from(tree: TokenTree) -> TokenStream {
115 TokenStream { inner: vec![tree] }
116 }
117}
118
119impl iter::FromIterator<TokenStream> for TokenStream {
120 fn from_iter<I: IntoIterator<Item=TokenStream>>(streams: I) -> Self {
121 let mut v = Vec::new();
122
123 for stream in streams.into_iter() {
124 v.extend(stream.inner);
125 }
126
127 TokenStream { inner: v }
128 }
129}
130
131pub type TokenIter = vec::IntoIter<TokenTree>;
132
133impl IntoIterator for TokenStream {
134 type Item = TokenTree;
135 type IntoIter = TokenIter;
136
137 fn into_iter(self) -> TokenIter {
138 self.inner.into_iter()
139 }
140}
141
142#[derive(Clone, Copy, Default)]
143pub struct Span;
144
145impl Span {
146 pub fn call_site() -> Span {
147 Span
148 }
149}
150
151#[derive(Copy, Clone)]
152pub struct Symbol(usize);
153
154thread_local!(static SYMBOLS: RefCell<Interner> = RefCell::new(Interner::new()));
155
156impl<'a> From<&'a str> for Symbol {
157 fn from(string: &'a str) -> Symbol {
158 Symbol(SYMBOLS.with(|s| s.borrow_mut().intern(string)))
159 }
160}
161
162impl ops::Deref for Symbol {
163 type Target = str;
164
165 fn deref(&self) -> &str {
166 SYMBOLS.with(|interner| {
167 let interner = interner.borrow();
168 let s = interner.get(self.0);
169 unsafe {
170 &*(s as *const str)
171 }
172 })
173 }
174}
175
176struct Interner {
177 string_to_index: HashMap<MyRc, usize>,
178 index_to_string: Vec<Rc<String>>,
179}
180
181#[derive(Hash, Eq, PartialEq)]
182struct MyRc(Rc<String>);
183
184impl Borrow<str> for MyRc {
185 fn borrow(&self) -> &str {
186 &self.0
187 }
188}
189
190impl Interner {
191 fn new() -> Interner {
192 Interner {
193 string_to_index: HashMap::new(),
194 index_to_string: Vec::new(),
195 }
196 }
197
198 fn intern(&mut self, s: &str) -> usize {
199 if let Some(&idx) = self.string_to_index.get(s) {
200 return idx
201 }
202 let s = Rc::new(s.to_string());
203 self.index_to_string.push(s.clone());
204 self.string_to_index.insert(MyRc(s), self.index_to_string.len() - 1);
205 self.index_to_string.len() - 1
206 }
207
208 fn get(&self, idx: usize) -> &str {
209 &self.index_to_string[idx]
210 }
211}
212
213#[derive(Clone)]
214pub struct Literal(String);
215
Alex Crichton852d53d2017-05-19 19:25:08 -0700216impl Literal {
Alex Crichton76a5cc82017-05-23 07:01:44 -0700217 pub fn bytechar(byte: u8) -> Literal {
218 match byte {
219 0 => Literal(format!("b'\\0'")),
220 b'\"' => Literal(format!("b'\"'")),
221 n => {
222 let mut escaped = "b'".to_string();
223 escaped.extend(ascii::escape_default(n).map(|c| c as char));
224 escaped.push('\'');
225 Literal(escaped)
226 }
227 }
228 }
229
Alex Crichton852d53d2017-05-19 19:25:08 -0700230 pub fn bytestring(bytes: &[u8]) -> Literal {
231 let mut escaped = "b\"".to_string();
232 for b in bytes {
233 match *b {
234 b'\0' => escaped.push_str(r"\0"),
235 b'\t' => escaped.push_str(r"\t"),
236 b'\n' => escaped.push_str(r"\n"),
237 b'\r' => escaped.push_str(r"\r"),
238 b'"' => escaped.push_str("\\\""),
239 b'\\' => escaped.push_str("\\\\"),
240 b'\x20' ... b'\x7E' => escaped.push(*b as char),
241 _ => escaped.push_str(&format!("\\x{:02X}", b)),
242 }
243 }
244 escaped.push('"');
245 Literal(escaped)
246 }
Alex Crichton76a5cc82017-05-23 07:01:44 -0700247
248 pub fn doccomment(s: &str) -> Literal {
249 Literal(s.to_string())
250 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700251}
252
Alex Crichton44bffbc2017-05-19 17:51:59 -0700253impl fmt::Display for Literal {
254 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
255 self.0.fmt(f)
256 }
257}
258
Alex Crichton852d53d2017-05-19 19:25:08 -0700259macro_rules! numbers {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700260 ($($t:ty,)*) => {$(
261 impl From<$t> for Literal {
262 fn from(t: $t) -> Literal {
Alex Crichton852d53d2017-05-19 19:25:08 -0700263 Literal(format!(concat!("{}", stringify!($t)), t))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700264 }
265 }
266 )*}
267}
268
Alex Crichton852d53d2017-05-19 19:25:08 -0700269numbers! {
270 u8, u16, u32, u64, usize,
271 i8, i16, i32, i64, isize,
272 f32, f64,
273}
274
275impl From<bool> for Literal {
276 fn from(t: bool) -> Literal {
277 Literal(t.to_string())
278 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700279}
280
281impl<'a> From<&'a str> for Literal {
282 fn from(t: &'a str) -> Literal {
283 let mut s = t.chars().flat_map(|c| c.escape_default()).collect::<String>();
284 s.push('"');
285 s.insert(0, '"');
286 Literal(s)
287 }
288}
289
290impl From<char> for Literal {
291 fn from(t: char) -> Literal {
292 Literal(format!("'{}'", t.escape_default()))
293 }
294}
295
296named!(token_stream -> TokenStream,
297 map!(token_trees, |s: Vec<TokenTree>| TokenStream { inner: s }));
298
299named!(token_trees -> Vec<TokenTree>, many0!(token_tree));
300
301named!(token_tree -> TokenTree,
302 map!(token_kind, |s: TokenKind| {
303 TokenTree {
304 span: ::Span(Span),
305 kind: s,
306 }
307 }));
308
309named!(token_kind -> TokenKind, alt!(
310 map!(delimited, |(d, s): (Delimiter, TokenStream)| {
311 TokenKind::Sequence(d, ::TokenStream(s))
312 })
313 |
314 map!(symbol, |w| TokenKind::Word(::Symbol(w)))
315 |
316 map!(literal, |l| TokenKind::Literal(::Literal(l)))
317 |
318 map!(op, |(op, kind): (char, OpKind)| {
319 TokenKind::Op(op, kind)
320 })
321));
322
323named!(delimited -> (Delimiter, TokenStream), alt!(
324 delimited!(
325 punct!("("),
326 token_stream,
327 punct!(")")
328 ) => { |ts| (Delimiter::Parenthesis, ts) }
329 |
330 delimited!(
331 punct!("["),
332 token_stream,
333 punct!("]")
334 ) => { |ts| (Delimiter::Bracket, ts) }
335 |
336 delimited!(
337 punct!("{"),
338 token_stream,
339 punct!("}")
340 ) => { |ts| (Delimiter::Brace, ts) }
341));
342
343named!(symbol -> Symbol, alt!(
344 lifetime
345 |
346 map!(word, Symbol::from)
347));
348
349named!(lifetime -> Symbol, preceded!(
350 punct!("'"),
351 alt!(
352 // TODO: can we get rid of this allocation?
353 map!(word, |id| Symbol::from(&format!("'{}", id)[..]))
354 |
355 map!(keyword!("static"), |_| Symbol::from("'static"))
356 )
357));
358
359fn word(mut input: &str) -> IResult<&str, &str> {
360 input = skip_whitespace(input);
361
362 let mut chars = input.char_indices();
363 match chars.next() {
364 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
365 _ => return IResult::Error,
366 }
367
368 for (i, ch) in chars {
369 if !UnicodeXID::is_xid_continue(ch) {
370 return IResult::Done(&input[i..], &input[..i])
371 }
372 }
373
374 IResult::Done("", input)
375}
376
377fn literal(input: &str) -> IResult<&str, Literal> {
378 let input_no_ws = skip_whitespace(input);
379
380 match literal_nocapture(input_no_ws) {
381 IResult::Done(a, ()) => {
382 let start = input.len() - input_no_ws.len();
383 let len = input_no_ws.len() - a.len();
384 let end = start + len;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700385 IResult::Done(a, Literal(input[start..end].to_string()))
386 }
387 IResult::Error => IResult::Error,
388 }
389}
390
391named!(literal_nocapture -> (), alt!(
392 string
393 |
394 byte_string
395 |
396 byte
397 |
398 character
399 |
400 float
401 |
402 int
403 |
404 boolean
405 |
406 doc_comment
407));
408
409named!(string -> (), alt!(
410 quoted_string
411 |
412 preceded!(
413 punct!("r"),
414 raw_string
415 ) => { |_| () }
416));
417
418named!(quoted_string -> (), delimited!(
419 punct!("\""),
420 cooked_string,
421 tag!("\"")
422));
423
424fn cooked_string(input: &str) -> IResult<&str, ()> {
425 let mut chars = input.char_indices().peekable();
426 while let Some((byte_offset, ch)) = chars.next() {
427 match ch {
428 '"' => {
429 return IResult::Done(&input[byte_offset..], ());
430 }
431 '\r' => {
432 if let Some((_, '\n')) = chars.next() {
433 // ...
434 } else {
435 break;
436 }
437 }
438 '\\' => {
439 match chars.next() {
440 Some((_, 'x')) => {
441 if !backslash_x_char(&mut chars) {
442 break
443 }
444 }
445 Some((_, 'n')) |
446 Some((_, 'r')) |
447 Some((_, 't')) |
448 Some((_, '\\')) |
449 Some((_, '\'')) |
450 Some((_, '"')) |
451 Some((_, '0')) => {}
452 Some((_, 'u')) => {
453 if !backslash_u(&mut chars) {
454 break
455 }
456 }
457 Some((_, '\n')) | Some((_, '\r')) => {
458 while let Some(&(_, ch)) = chars.peek() {
459 if ch.is_whitespace() {
460 chars.next();
461 } else {
462 break;
463 }
464 }
465 }
466 _ => break,
467 }
468 }
469 _ch => {}
470 }
471 }
472 IResult::Error
473}
474
475named!(byte_string -> (), alt!(
476 delimited!(
477 punct!("b\""),
478 cooked_byte_string,
479 tag!("\"")
480 ) => { |_| () }
481 |
482 preceded!(
483 punct!("br"),
484 raw_string
485 ) => { |_| () }
486));
487
488fn cooked_byte_string(mut input: &str) -> IResult<&str, ()> {
489 let mut bytes = input.bytes().enumerate();
490 'outer: while let Some((offset, b)) = bytes.next() {
491 match b {
492 b'"' => {
493 return IResult::Done(&input[offset..], ());
494 }
495 b'\r' => {
496 if let Some((_, b'\n')) = bytes.next() {
497 // ...
498 } else {
499 break;
500 }
501 }
502 b'\\' => {
503 match bytes.next() {
504 Some((_, b'x')) => {
505 if !backslash_x_byte(&mut bytes) {
506 break
507 }
508 }
509 Some((_, b'n')) |
510 Some((_, b'r')) |
511 Some((_, b't')) |
512 Some((_, b'\\')) |
513 Some((_, b'0')) |
514 Some((_, b'\'')) |
515 Some((_, b'"')) => {}
516 Some((newline, b'\n')) |
517 Some((newline, b'\r')) => {
518 let rest = &input[newline + 1..];
519 for (offset, ch) in rest.char_indices() {
520 if !ch.is_whitespace() {
521 input = &rest[offset..];
522 bytes = input.bytes().enumerate();
523 continue 'outer;
524 }
525 }
526 break;
527 }
528 _ => break,
529 }
530 }
531 b if b < 0x80 => {}
532 _ => break,
533 }
534 }
535 IResult::Error
536}
537
538fn raw_string(input: &str) -> IResult<&str, ()> {
539 let mut chars = input.char_indices();
540 let mut n = 0;
541 while let Some((byte_offset, ch)) = chars.next() {
542 match ch {
543 '"' => {
544 n = byte_offset;
545 break;
546 }
547 '#' => {}
548 _ => return IResult::Error,
549 }
550 }
551 for (byte_offset, ch) in chars {
552 match ch {
553 '"' if input[byte_offset + 1..].starts_with(&input[..n]) => {
554 let rest = &input[byte_offset + 1 + n..];
555 return IResult::Done(rest, ())
556 }
557 '\r' => {}
558 _ => {}
559 }
560 }
561 IResult::Error
562}
563
564named!(byte -> (), do_parse!(
565 punct!("b") >>
566 tag!("'") >>
567 cooked_byte >>
568 tag!("'") >>
569 (())
570));
571
572fn cooked_byte(input: &str) -> IResult<&str, ()> {
573 let mut bytes = input.bytes().enumerate();
574 let ok = match bytes.next().map(|(_, b)| b) {
575 Some(b'\\') => {
576 match bytes.next().map(|(_, b)| b) {
577 Some(b'x') => backslash_x_byte(&mut bytes),
578 Some(b'n') |
579 Some(b'r') |
580 Some(b't') |
581 Some(b'\\') |
582 Some(b'0') |
583 Some(b'\'') |
584 Some(b'"') => true,
585 _ => false,
586 }
587 }
588 b => b.is_some(),
589 };
590 if ok {
591 match bytes.next() {
592 Some((offset, _)) => IResult::Done(&input[offset..], ()),
593 None => IResult::Done("", ()),
594 }
595 } else {
596 IResult::Error
597 }
598}
599
600named!(character -> (), do_parse!(
601 punct!("'") >>
602 cooked_char >>
603 tag!("'") >>
604 (())
605));
606
607fn cooked_char(input: &str) -> IResult<&str, ()> {
608 let mut chars = input.char_indices();
609 let ok = match chars.next().map(|(_, ch)| ch) {
610 Some('\\') => {
611 match chars.next().map(|(_, ch)| ch) {
612 Some('x') => backslash_x_char(&mut chars),
613 Some('u') => backslash_u(&mut chars),
614 Some('n') |
615 Some('r') |
616 Some('t') |
617 Some('\\') |
618 Some('0') |
619 Some('\'') |
620 Some('"') => true,
621 _ => false,
622 }
623 }
624 ch => ch.is_some(),
625 };
626 if ok {
627 IResult::Done(chars.as_str(), ())
628 } else {
629 IResult::Error
630 }
631}
632
633macro_rules! next_ch {
634 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
635 match $chars.next() {
636 Some((_, ch)) => match ch {
637 $pat $(| $rest)* => ch,
638 _ => return false,
639 },
640 None => return false
641 }
642 };
643}
644
645fn backslash_x_char<I>(chars: &mut I) -> bool
646 where I: Iterator<Item = (usize, char)>
647{
648 next_ch!(chars @ '0'...'7');
649 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
650 true
651}
652
653fn backslash_x_byte<I>(chars: &mut I) -> bool
654 where I: Iterator<Item = (usize, u8)>
655{
656 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
657 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
658 true
659}
660
661fn backslash_u<I>(chars: &mut I) -> bool
662 where I: Iterator<Item = (usize, char)>
663{
664 next_ch!(chars @ '{');
665 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
666 let b = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
667 if b == '}' {
668 return true
669 }
670 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
671 if c == '}' {
672 return true
673 }
674 let d = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
675 if d == '}' {
676 return true
677 }
678 let e = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
679 if e == '}' {
680 return true
681 }
682 let f = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
683 if f == '}' {
684 return true
685 }
686 next_ch!(chars @ '}');
687 true
688}
689
690named!(float -> (), do_parse!(
691 float_string >>
692 alt!(
693 tag!("f32") => { |_| () }
694 |
695 tag!("f64") => { |_| () }
696 |
697 epsilon!()
698 ) >>
699 (())
700));
701
702fn float_string(input: &str) -> IResult<&str, ()> {
703 let mut chars = input.chars().peekable();
704 match chars.next() {
705 Some(ch) if ch >= '0' && ch <= '9' => {}
706 _ => return IResult::Error,
707 }
708
709 let mut len = 1;
710 let mut has_dot = false;
711 let mut has_exp = false;
712 while let Some(&ch) = chars.peek() {
713 match ch {
714 '0'...'9' | '_' => {
715 chars.next();
716 len += 1;
717 }
718 '.' => {
719 if has_dot {
720 break;
721 }
722 chars.next();
723 if chars.peek()
724 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
725 .unwrap_or(false) {
726 return IResult::Error;
727 }
728 len += 1;
729 has_dot = true;
730 }
731 'e' | 'E' => {
732 chars.next();
733 len += 1;
734 has_exp = true;
735 break;
736 }
737 _ => break,
738 }
739 }
740
741 let rest = &input[len..];
742 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
743 return IResult::Error;
744 }
745
746 if has_exp {
747 let mut has_exp_value = false;
748 while let Some(&ch) = chars.peek() {
749 match ch {
750 '+' | '-' => {
751 if has_exp_value {
752 break;
753 }
754 chars.next();
755 len += 1;
756 }
757 '0'...'9' => {
758 chars.next();
759 len += 1;
760 has_exp_value = true;
761 }
762 '_' => {
763 chars.next();
764 len += 1;
765 }
766 _ => break,
767 }
768 }
769 if !has_exp_value {
770 return IResult::Error;
771 }
772 }
773
774 IResult::Done(&input[len..], ())
775}
776
777named!(int -> (), do_parse!(
778 digits >>
779 alt!(
780 tag!("isize") => { |_| () }
781 |
782 tag!("i8") => { |_| () }
783 |
784 tag!("i16") => { |_| () }
785 |
786 tag!("i32") => { |_| () }
787 |
788 tag!("i64") => { |_| () }
789 |
790 tag!("usize") => { |_| () }
791 |
792 tag!("u8") => { |_| () }
793 |
794 tag!("u16") => { |_| () }
795 |
796 tag!("u32") => { |_| () }
797 |
798 tag!("u64") => { |_| () }
799 |
800 epsilon!()
801 ) >>
802 (())
803));
804
805fn digits(mut input: &str) -> IResult<&str, ()> {
806 let base = if input.starts_with("0x") {
807 input = &input[2..];
808 16
809 } else if input.starts_with("0o") {
810 input = &input[2..];
811 8
812 } else if input.starts_with("0b") {
813 input = &input[2..];
814 2
815 } else {
816 10
817 };
818
819 let mut value = 0u64;
820 let mut len = 0;
821 let mut empty = true;
822 for b in input.bytes() {
823 let digit = match b {
824 b'0'...b'9' => (b - b'0') as u64,
825 b'a'...b'f' => 10 + (b - b'a') as u64,
826 b'A'...b'F' => 10 + (b - b'A') as u64,
827 b'_' => {
828 if empty && base == 10 {
829 return IResult::Error;
830 }
831 len += 1;
832 continue;
833 }
834 _ => break,
835 };
836 if digit >= base {
837 return IResult::Error;
838 }
839 value = match value.checked_mul(base) {
840 Some(value) => value,
841 None => return IResult::Error,
842 };
843 value = match value.checked_add(digit) {
844 Some(value) => value,
845 None => return IResult::Error,
846 };
847 len += 1;
848 empty = false;
849 }
850 if empty {
851 IResult::Error
852 } else {
853 IResult::Done(&input[len..], ())
854 }
855}
856
857named!(boolean -> (), alt!(
858 keyword!("true") => { |_| () }
859 |
860 keyword!("false") => { |_| () }
861));
862
863macro_rules! punct1 {
864 ($i:expr, $punct:expr) => {
865 punct1($i, $punct)
866 }
867}
868
869fn punct1<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, char> {
870 let input = skip_whitespace(input);
871 if input.starts_with(token) {
872 IResult::Done(&input[1..], token.chars().next().unwrap())
873 } else {
874 IResult::Error
875 }
876}
877
878named!(op -> (char, OpKind), alt!(
879 keyword!("_") => { |_| ('_', OpKind::Alone) }
880 |
881 punct1!("&&") => { |_| ('&', OpKind::Joint) }
882 |
883 punct1!("||") => { |_| ('|', OpKind::Joint) }
884 |
885 punct1!("->") => { |_| ('-', OpKind::Joint) }
886 |
887 punct1!("<-") => { |_| ('<', OpKind::Joint) }
888 |
889 punct1!("=>") => { |_| ('=', OpKind::Joint) }
890 |
891 punct1!("...") => { |_| ('.', OpKind::Joint) }
892 |
893 punct1!("..") => { |_| ('.', OpKind::Joint) }
894 |
895 punct!(".") => { |_| ('.', OpKind::Alone) }
896 |
Alex Crichton852d53d2017-05-19 19:25:08 -0700897 punct!(",") => { |_| (',', OpKind::Alone) }
898 |
Alex Crichton44bffbc2017-05-19 17:51:59 -0700899 bin_op_eq
900 |
901 bin_op
902 |
903 punct1!("<=") => { |_| ('<', OpKind::Joint) }
904 |
905 punct1!("==") => { |_| ('=', OpKind::Joint) }
906 |
907 punct1!("!=") => { |_| ('!', OpKind::Joint) }
908 |
909 punct1!(">=") => { |_| ('>', OpKind::Joint) }
910 |
911 punct1!("::") => { |_| (':', OpKind::Joint) }
912 |
913 punct!("=") => { |_| ('=', OpKind::Alone) }
914 |
915 punct!("<") => { |_| ('<', OpKind::Alone) }
916 |
917 punct!(">") => { |_| ('>', OpKind::Alone) }
918 |
919 punct!("!") => { |_| ('!', OpKind::Alone) }
920 |
921 punct!("~") => { |_| ('~', OpKind::Alone) }
922 |
923 punct!("@") => { |_| ('@', OpKind::Alone) }
924 |
925 punct!(",") => { |_| (',', OpKind::Alone) }
926 |
927 punct!(";") => { |_| (';', OpKind::Alone) }
928 |
929 punct!(":") => { |_| (':', OpKind::Alone) }
930 |
931 punct!("#") => { |_| ('#', OpKind::Alone) }
932 |
933 punct!("$") => { |_| ('$', OpKind::Alone) }
934 |
935 punct!("?") => { |_| ('?', OpKind::Alone) }
936));
937
938named!(bin_op -> (char, OpKind), alt!(
939 punct!("+") => { |_| ('+', OpKind::Alone) }
940 |
941 punct!("-") => { |_| ('-', OpKind::Alone) }
942 |
943 punct!("*") => { |_| ('*', OpKind::Alone) }
944 |
945 punct!("/") => { |_| ('/', OpKind::Alone) }
946 |
947 punct!("%") => { |_| ('%', OpKind::Alone) }
948 |
949 punct!("^") => { |_| ('^', OpKind::Alone) }
950 |
951 punct!("&") => { |_| ('&', OpKind::Alone) }
952 |
953 punct!("|") => { |_| ('|', OpKind::Alone) }
954 |
955 punct1!("<<") => { |_| ('<', OpKind::Joint) }
956 |
957 punct1!(">>") => { |_| ('>', OpKind::Joint) }
958));
959
960named!(bin_op_eq -> (char, OpKind), alt!(
961 punct1!("+=") => { |_| ('+', OpKind::Joint) }
962 |
963 punct1!("-=") => { |_| ('-', OpKind::Joint) }
964 |
965 punct1!("*=") => { |_| ('*', OpKind::Joint) }
966 |
967 punct1!("/=") => { |_| ('/', OpKind::Joint) }
968 |
969 punct1!("%=") => { |_| ('%', OpKind::Joint) }
970 |
971 punct1!("^=") => { |_| ('^', OpKind::Joint) }
972 |
973 punct1!("&=") => { |_| ('&', OpKind::Joint) }
974 |
975 punct1!("|=") => { |_| ('|', OpKind::Joint) }
976 |
977 punct1!("<<=") => { |_| ('<', OpKind::Joint) }
978 |
979 punct1!(">>=") => { |_| ('>', OpKind::Joint) }
980));
981
982named!(doc_comment -> (), alt!(
983 do_parse!(
984 punct!("//!") >>
985 take_until!("\n") >>
986 (())
987 )
988 |
989 do_parse!(
990 option!(whitespace) >>
991 peek!(tag!("/*!")) >>
992 block_comment >>
993 (())
994 )
995 |
996 do_parse!(
997 punct!("///") >>
998 not!(tag!("/")) >>
999 take_until!("\n") >>
1000 (())
1001 )
1002 |
1003 do_parse!(
1004 option!(whitespace) >>
1005 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1006 block_comment >>
1007 (())
1008 )
1009));
1010
1011#[cfg(test)]
1012mod tests {
1013 use super::*;
1014
1015 #[test]
1016 fn symbols() {
1017 assert_eq!(&*Symbol::from("foo"), "foo");
1018 assert_eq!(&*Symbol::from("bar"), "bar");
1019 }
1020
1021 #[test]
1022 fn literals() {
1023 assert_eq!(Literal::from("foo").to_string(), "\"foo\"");
1024 assert_eq!(Literal::from("\"").to_string(), "\"\\\"\"");
1025 }
1026
1027 #[test]
1028 fn roundtrip() {
1029 fn roundtrip(p: &str) {
1030 println!("parse: {}", p);
1031 let s = p.parse::<TokenStream>().unwrap().to_string();
1032 println!("first: {}", s);
1033 let s2 = s.to_string().parse::<TokenStream>().unwrap().to_string();
1034 assert_eq!(s, s2);
1035 }
1036 roundtrip("a");
1037 roundtrip("<<");
1038 roundtrip("<<=");
1039 roundtrip("
1040 /// a
1041 wut
1042 ");
1043 roundtrip("
1044 1
1045 1.0
1046 1f32
1047 2f64
1048 1usize
1049 4isize
1050 4e10
1051 1_000
1052 1_0i32
1053 8u8
1054 9
1055 0
1056 ");
1057 }
1058}