blob: ebff2e9ce25ea6f0d10fc34fae7f6c87bcd3c63b [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
Alex Crichton44bffbc2017-05-19 17:51:59 -0700275impl<'a> From<&'a str> for Literal {
276 fn from(t: &'a str) -> Literal {
277 let mut s = t.chars().flat_map(|c| c.escape_default()).collect::<String>();
278 s.push('"');
279 s.insert(0, '"');
280 Literal(s)
281 }
282}
283
284impl From<char> for Literal {
285 fn from(t: char) -> Literal {
286 Literal(format!("'{}'", t.escape_default()))
287 }
288}
289
290named!(token_stream -> TokenStream,
291 map!(token_trees, |s: Vec<TokenTree>| TokenStream { inner: s }));
292
293named!(token_trees -> Vec<TokenTree>, many0!(token_tree));
294
295named!(token_tree -> TokenTree,
296 map!(token_kind, |s: TokenKind| {
297 TokenTree {
298 span: ::Span(Span),
299 kind: s,
300 }
301 }));
302
303named!(token_kind -> TokenKind, alt!(
304 map!(delimited, |(d, s): (Delimiter, TokenStream)| {
305 TokenKind::Sequence(d, ::TokenStream(s))
306 })
307 |
Michael Layzellbad58012017-05-24 20:42:52 -0400308 map!(literal, |l| TokenKind::Literal(::Literal(l))) // must be before symbol
Alex Crichton44bffbc2017-05-19 17:51:59 -0700309 |
Michael Layzellbad58012017-05-24 20:42:52 -0400310 map!(symbol, |w| TokenKind::Word(::Symbol(w)))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700311 |
312 map!(op, |(op, kind): (char, OpKind)| {
313 TokenKind::Op(op, kind)
314 })
315));
316
317named!(delimited -> (Delimiter, TokenStream), alt!(
318 delimited!(
319 punct!("("),
320 token_stream,
321 punct!(")")
322 ) => { |ts| (Delimiter::Parenthesis, ts) }
323 |
324 delimited!(
325 punct!("["),
326 token_stream,
327 punct!("]")
328 ) => { |ts| (Delimiter::Bracket, ts) }
329 |
330 delimited!(
331 punct!("{"),
332 token_stream,
333 punct!("}")
334 ) => { |ts| (Delimiter::Brace, ts) }
335));
336
337named!(symbol -> Symbol, alt!(
338 lifetime
339 |
340 map!(word, Symbol::from)
341));
342
343named!(lifetime -> Symbol, preceded!(
344 punct!("'"),
345 alt!(
346 // TODO: can we get rid of this allocation?
347 map!(word, |id| Symbol::from(&format!("'{}", id)[..]))
348 |
349 map!(keyword!("static"), |_| Symbol::from("'static"))
350 )
351));
352
353fn word(mut input: &str) -> IResult<&str, &str> {
354 input = skip_whitespace(input);
355
356 let mut chars = input.char_indices();
357 match chars.next() {
358 Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
359 _ => return IResult::Error,
360 }
361
362 for (i, ch) in chars {
363 if !UnicodeXID::is_xid_continue(ch) {
364 return IResult::Done(&input[i..], &input[..i])
365 }
366 }
367
368 IResult::Done("", input)
369}
370
371fn literal(input: &str) -> IResult<&str, Literal> {
372 let input_no_ws = skip_whitespace(input);
373
374 match literal_nocapture(input_no_ws) {
375 IResult::Done(a, ()) => {
376 let start = input.len() - input_no_ws.len();
377 let len = input_no_ws.len() - a.len();
378 let end = start + len;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700379 IResult::Done(a, Literal(input[start..end].to_string()))
380 }
381 IResult::Error => IResult::Error,
382 }
383}
384
385named!(literal_nocapture -> (), alt!(
386 string
387 |
388 byte_string
389 |
390 byte
391 |
392 character
393 |
394 float
395 |
396 int
397 |
398 boolean
399 |
400 doc_comment
401));
402
403named!(string -> (), alt!(
404 quoted_string
405 |
406 preceded!(
407 punct!("r"),
408 raw_string
409 ) => { |_| () }
410));
411
412named!(quoted_string -> (), delimited!(
413 punct!("\""),
414 cooked_string,
415 tag!("\"")
416));
417
418fn cooked_string(input: &str) -> IResult<&str, ()> {
419 let mut chars = input.char_indices().peekable();
420 while let Some((byte_offset, ch)) = chars.next() {
421 match ch {
422 '"' => {
423 return IResult::Done(&input[byte_offset..], ());
424 }
425 '\r' => {
426 if let Some((_, '\n')) = chars.next() {
427 // ...
428 } else {
429 break;
430 }
431 }
432 '\\' => {
433 match chars.next() {
434 Some((_, 'x')) => {
435 if !backslash_x_char(&mut chars) {
436 break
437 }
438 }
439 Some((_, 'n')) |
440 Some((_, 'r')) |
441 Some((_, 't')) |
442 Some((_, '\\')) |
443 Some((_, '\'')) |
444 Some((_, '"')) |
445 Some((_, '0')) => {}
446 Some((_, 'u')) => {
447 if !backslash_u(&mut chars) {
448 break
449 }
450 }
451 Some((_, '\n')) | Some((_, '\r')) => {
452 while let Some(&(_, ch)) = chars.peek() {
453 if ch.is_whitespace() {
454 chars.next();
455 } else {
456 break;
457 }
458 }
459 }
460 _ => break,
461 }
462 }
463 _ch => {}
464 }
465 }
466 IResult::Error
467}
468
469named!(byte_string -> (), alt!(
470 delimited!(
471 punct!("b\""),
472 cooked_byte_string,
473 tag!("\"")
474 ) => { |_| () }
475 |
476 preceded!(
477 punct!("br"),
478 raw_string
479 ) => { |_| () }
480));
481
482fn cooked_byte_string(mut input: &str) -> IResult<&str, ()> {
483 let mut bytes = input.bytes().enumerate();
484 'outer: while let Some((offset, b)) = bytes.next() {
485 match b {
486 b'"' => {
487 return IResult::Done(&input[offset..], ());
488 }
489 b'\r' => {
490 if let Some((_, b'\n')) = bytes.next() {
491 // ...
492 } else {
493 break;
494 }
495 }
496 b'\\' => {
497 match bytes.next() {
498 Some((_, b'x')) => {
499 if !backslash_x_byte(&mut bytes) {
500 break
501 }
502 }
503 Some((_, b'n')) |
504 Some((_, b'r')) |
505 Some((_, b't')) |
506 Some((_, b'\\')) |
507 Some((_, b'0')) |
508 Some((_, b'\'')) |
509 Some((_, b'"')) => {}
510 Some((newline, b'\n')) |
511 Some((newline, b'\r')) => {
512 let rest = &input[newline + 1..];
513 for (offset, ch) in rest.char_indices() {
514 if !ch.is_whitespace() {
515 input = &rest[offset..];
516 bytes = input.bytes().enumerate();
517 continue 'outer;
518 }
519 }
520 break;
521 }
522 _ => break,
523 }
524 }
525 b if b < 0x80 => {}
526 _ => break,
527 }
528 }
529 IResult::Error
530}
531
532fn raw_string(input: &str) -> IResult<&str, ()> {
533 let mut chars = input.char_indices();
534 let mut n = 0;
535 while let Some((byte_offset, ch)) = chars.next() {
536 match ch {
537 '"' => {
538 n = byte_offset;
539 break;
540 }
541 '#' => {}
542 _ => return IResult::Error,
543 }
544 }
545 for (byte_offset, ch) in chars {
546 match ch {
547 '"' if input[byte_offset + 1..].starts_with(&input[..n]) => {
548 let rest = &input[byte_offset + 1 + n..];
549 return IResult::Done(rest, ())
550 }
551 '\r' => {}
552 _ => {}
553 }
554 }
555 IResult::Error
556}
557
558named!(byte -> (), do_parse!(
559 punct!("b") >>
560 tag!("'") >>
561 cooked_byte >>
562 tag!("'") >>
563 (())
564));
565
566fn cooked_byte(input: &str) -> IResult<&str, ()> {
567 let mut bytes = input.bytes().enumerate();
568 let ok = match bytes.next().map(|(_, b)| b) {
569 Some(b'\\') => {
570 match bytes.next().map(|(_, b)| b) {
571 Some(b'x') => backslash_x_byte(&mut bytes),
572 Some(b'n') |
573 Some(b'r') |
574 Some(b't') |
575 Some(b'\\') |
576 Some(b'0') |
577 Some(b'\'') |
578 Some(b'"') => true,
579 _ => false,
580 }
581 }
582 b => b.is_some(),
583 };
584 if ok {
585 match bytes.next() {
586 Some((offset, _)) => IResult::Done(&input[offset..], ()),
587 None => IResult::Done("", ()),
588 }
589 } else {
590 IResult::Error
591 }
592}
593
594named!(character -> (), do_parse!(
595 punct!("'") >>
596 cooked_char >>
597 tag!("'") >>
598 (())
599));
600
601fn cooked_char(input: &str) -> IResult<&str, ()> {
602 let mut chars = input.char_indices();
603 let ok = match chars.next().map(|(_, ch)| ch) {
604 Some('\\') => {
605 match chars.next().map(|(_, ch)| ch) {
606 Some('x') => backslash_x_char(&mut chars),
607 Some('u') => backslash_u(&mut chars),
608 Some('n') |
609 Some('r') |
610 Some('t') |
611 Some('\\') |
612 Some('0') |
613 Some('\'') |
614 Some('"') => true,
615 _ => false,
616 }
617 }
618 ch => ch.is_some(),
619 };
620 if ok {
621 IResult::Done(chars.as_str(), ())
622 } else {
623 IResult::Error
624 }
625}
626
627macro_rules! next_ch {
628 ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
629 match $chars.next() {
630 Some((_, ch)) => match ch {
631 $pat $(| $rest)* => ch,
632 _ => return false,
633 },
634 None => return false
635 }
636 };
637}
638
639fn backslash_x_char<I>(chars: &mut I) -> bool
640 where I: Iterator<Item = (usize, char)>
641{
642 next_ch!(chars @ '0'...'7');
643 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
644 true
645}
646
647fn backslash_x_byte<I>(chars: &mut I) -> bool
648 where I: Iterator<Item = (usize, u8)>
649{
650 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
651 next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
652 true
653}
654
655fn backslash_u<I>(chars: &mut I) -> bool
656 where I: Iterator<Item = (usize, char)>
657{
658 next_ch!(chars @ '{');
659 next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
660 let b = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
661 if b == '}' {
662 return true
663 }
664 let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
665 if c == '}' {
666 return true
667 }
668 let d = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
669 if d == '}' {
670 return true
671 }
672 let e = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
673 if e == '}' {
674 return true
675 }
676 let f = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
677 if f == '}' {
678 return true
679 }
680 next_ch!(chars @ '}');
681 true
682}
683
684named!(float -> (), do_parse!(
685 float_string >>
686 alt!(
687 tag!("f32") => { |_| () }
688 |
689 tag!("f64") => { |_| () }
690 |
691 epsilon!()
692 ) >>
693 (())
694));
695
696fn float_string(input: &str) -> IResult<&str, ()> {
697 let mut chars = input.chars().peekable();
698 match chars.next() {
699 Some(ch) if ch >= '0' && ch <= '9' => {}
700 _ => return IResult::Error,
701 }
702
703 let mut len = 1;
704 let mut has_dot = false;
705 let mut has_exp = false;
706 while let Some(&ch) = chars.peek() {
707 match ch {
708 '0'...'9' | '_' => {
709 chars.next();
710 len += 1;
711 }
712 '.' => {
713 if has_dot {
714 break;
715 }
716 chars.next();
717 if chars.peek()
718 .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
719 .unwrap_or(false) {
720 return IResult::Error;
721 }
722 len += 1;
723 has_dot = true;
724 }
725 'e' | 'E' => {
726 chars.next();
727 len += 1;
728 has_exp = true;
729 break;
730 }
731 _ => break,
732 }
733 }
734
735 let rest = &input[len..];
736 if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
737 return IResult::Error;
738 }
739
740 if has_exp {
741 let mut has_exp_value = false;
742 while let Some(&ch) = chars.peek() {
743 match ch {
744 '+' | '-' => {
745 if has_exp_value {
746 break;
747 }
748 chars.next();
749 len += 1;
750 }
751 '0'...'9' => {
752 chars.next();
753 len += 1;
754 has_exp_value = true;
755 }
756 '_' => {
757 chars.next();
758 len += 1;
759 }
760 _ => break,
761 }
762 }
763 if !has_exp_value {
764 return IResult::Error;
765 }
766 }
767
768 IResult::Done(&input[len..], ())
769}
770
771named!(int -> (), do_parse!(
772 digits >>
773 alt!(
774 tag!("isize") => { |_| () }
775 |
776 tag!("i8") => { |_| () }
777 |
778 tag!("i16") => { |_| () }
779 |
780 tag!("i32") => { |_| () }
781 |
782 tag!("i64") => { |_| () }
783 |
784 tag!("usize") => { |_| () }
785 |
786 tag!("u8") => { |_| () }
787 |
788 tag!("u16") => { |_| () }
789 |
790 tag!("u32") => { |_| () }
791 |
792 tag!("u64") => { |_| () }
793 |
794 epsilon!()
795 ) >>
796 (())
797));
798
799fn digits(mut input: &str) -> IResult<&str, ()> {
800 let base = if input.starts_with("0x") {
801 input = &input[2..];
802 16
803 } else if input.starts_with("0o") {
804 input = &input[2..];
805 8
806 } else if input.starts_with("0b") {
807 input = &input[2..];
808 2
809 } else {
810 10
811 };
812
813 let mut value = 0u64;
814 let mut len = 0;
815 let mut empty = true;
816 for b in input.bytes() {
817 let digit = match b {
818 b'0'...b'9' => (b - b'0') as u64,
819 b'a'...b'f' => 10 + (b - b'a') as u64,
820 b'A'...b'F' => 10 + (b - b'A') as u64,
821 b'_' => {
822 if empty && base == 10 {
823 return IResult::Error;
824 }
825 len += 1;
826 continue;
827 }
828 _ => break,
829 };
830 if digit >= base {
831 return IResult::Error;
832 }
833 value = match value.checked_mul(base) {
834 Some(value) => value,
835 None => return IResult::Error,
836 };
837 value = match value.checked_add(digit) {
838 Some(value) => value,
839 None => return IResult::Error,
840 };
841 len += 1;
842 empty = false;
843 }
844 if empty {
845 IResult::Error
846 } else {
847 IResult::Done(&input[len..], ())
848 }
849}
850
851named!(boolean -> (), alt!(
852 keyword!("true") => { |_| () }
853 |
854 keyword!("false") => { |_| () }
855));
856
857macro_rules! punct1 {
858 ($i:expr, $punct:expr) => {
859 punct1($i, $punct)
860 }
861}
862
863fn punct1<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, char> {
864 let input = skip_whitespace(input);
865 if input.starts_with(token) {
866 IResult::Done(&input[1..], token.chars().next().unwrap())
867 } else {
868 IResult::Error
869 }
870}
871
872named!(op -> (char, OpKind), alt!(
873 keyword!("_") => { |_| ('_', OpKind::Alone) }
874 |
875 punct1!("&&") => { |_| ('&', OpKind::Joint) }
876 |
877 punct1!("||") => { |_| ('|', OpKind::Joint) }
878 |
879 punct1!("->") => { |_| ('-', OpKind::Joint) }
880 |
881 punct1!("<-") => { |_| ('<', OpKind::Joint) }
882 |
883 punct1!("=>") => { |_| ('=', OpKind::Joint) }
884 |
885 punct1!("...") => { |_| ('.', OpKind::Joint) }
886 |
887 punct1!("..") => { |_| ('.', OpKind::Joint) }
888 |
889 punct!(".") => { |_| ('.', OpKind::Alone) }
890 |
Alex Crichton852d53d2017-05-19 19:25:08 -0700891 punct!(",") => { |_| (',', OpKind::Alone) }
892 |
Alex Crichton44bffbc2017-05-19 17:51:59 -0700893 bin_op_eq
894 |
895 bin_op
896 |
897 punct1!("<=") => { |_| ('<', OpKind::Joint) }
898 |
899 punct1!("==") => { |_| ('=', OpKind::Joint) }
900 |
901 punct1!("!=") => { |_| ('!', OpKind::Joint) }
902 |
903 punct1!(">=") => { |_| ('>', OpKind::Joint) }
904 |
905 punct1!("::") => { |_| (':', OpKind::Joint) }
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 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
932named!(bin_op -> (char, OpKind), alt!(
933 punct!("+") => { |_| ('+', OpKind::Alone) }
934 |
935 punct!("-") => { |_| ('-', OpKind::Alone) }
936 |
937 punct!("*") => { |_| ('*', OpKind::Alone) }
938 |
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 punct1!("<<") => { |_| ('<', OpKind::Joint) }
950 |
951 punct1!(">>") => { |_| ('>', OpKind::Joint) }
952));
953
954named!(bin_op_eq -> (char, OpKind), alt!(
955 punct1!("+=") => { |_| ('+', OpKind::Joint) }
956 |
957 punct1!("-=") => { |_| ('-', OpKind::Joint) }
958 |
959 punct1!("*=") => { |_| ('*', OpKind::Joint) }
960 |
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
976named!(doc_comment -> (), alt!(
977 do_parse!(
978 punct!("//!") >>
979 take_until!("\n") >>
980 (())
981 )
982 |
983 do_parse!(
984 option!(whitespace) >>
985 peek!(tag!("/*!")) >>
986 block_comment >>
987 (())
988 )
989 |
990 do_parse!(
991 punct!("///") >>
992 not!(tag!("/")) >>
993 take_until!("\n") >>
994 (())
995 )
996 |
997 do_parse!(
998 option!(whitespace) >>
999 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1000 block_comment >>
1001 (())
1002 )
1003));
1004
1005#[cfg(test)]
1006mod tests {
1007 use super::*;
1008
1009 #[test]
1010 fn symbols() {
1011 assert_eq!(&*Symbol::from("foo"), "foo");
1012 assert_eq!(&*Symbol::from("bar"), "bar");
1013 }
1014
1015 #[test]
1016 fn literals() {
1017 assert_eq!(Literal::from("foo").to_string(), "\"foo\"");
1018 assert_eq!(Literal::from("\"").to_string(), "\"\\\"\"");
1019 }
1020
1021 #[test]
1022 fn roundtrip() {
1023 fn roundtrip(p: &str) {
1024 println!("parse: {}", p);
1025 let s = p.parse::<TokenStream>().unwrap().to_string();
1026 println!("first: {}", s);
1027 let s2 = s.to_string().parse::<TokenStream>().unwrap().to_string();
1028 assert_eq!(s, s2);
1029 }
1030 roundtrip("a");
1031 roundtrip("<<");
1032 roundtrip("<<=");
1033 roundtrip("
1034 /// a
1035 wut
1036 ");
1037 roundtrip("
1038 1
1039 1.0
1040 1f32
1041 2f64
1042 1usize
1043 4isize
1044 4e10
1045 1_000
1046 1_0i32
1047 8u8
1048 9
1049 0
1050 ");
1051 }
1052}