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