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