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