From be03aa5ee79241a6d22a79625e37f2ce5559a345 Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Thu, 31 Jan 2019 15:26:01 +0300
Subject: [PATCH] extract tt cursor

---
 crates/ra_macros/src/lib.rs        |   1 +
 crates/ra_macros/src/mbe.rs        |   2 +-
 crates/ra_macros/src/mbe_parser.rs | 102 ++---------------------------
 crates/ra_macros/src/tt_cursor.rs  |  92 ++++++++++++++++++++++++++
 4 files changed, 101 insertions(+), 96 deletions(-)
 create mode 100644 crates/ra_macros/src/tt_cursor.rs

diff --git a/crates/ra_macros/src/lib.rs b/crates/ra_macros/src/lib.rs
index 9485b1c3db6..e35a056ccf8 100644
--- a/crates/ra_macros/src/lib.rs
+++ b/crates/ra_macros/src/lib.rs
@@ -12,5 +12,6 @@ macro_rules! impl_froms {
 
 pub mod tt;
 pub mod mbe;
+mod tt_cursor;
 mod mbe_parser;
 mod mbe_expander;
diff --git a/crates/ra_macros/src/mbe.rs b/crates/ra_macros/src/mbe.rs
index ec811c5f0bf..6a168a1b5e2 100644
--- a/crates/ra_macros/src/mbe.rs
+++ b/crates/ra_macros/src/mbe.rs
@@ -1,6 +1,6 @@
 use smol_str::SmolStr;
 
-use crate::tt::{self, Delimiter};
+use crate::tt::Delimiter;
 
 pub use crate::{
     mbe_parser::parse,
diff --git a/crates/ra_macros/src/mbe_parser.rs b/crates/ra_macros/src/mbe_parser.rs
index 93c2d40b4a7..024d3a0404a 100644
--- a/crates/ra_macros/src/mbe_parser.rs
+++ b/crates/ra_macros/src/mbe_parser.rs
@@ -1,99 +1,12 @@
 use crate::{tt, mbe};
+use crate::tt_cursor::TtCursor;
 
 /// This module parses a raw `tt::TokenStream` into macro-by-example token
 /// stream. This is a *mostly* identify function, expect for handling of
 /// `$var:tt_kind` and `$(repeat),*` constructs.
 
-struct RulesParser<'a> {
-    subtree: &'a tt::Subtree,
-    pos: usize,
-}
-
-impl<'a> RulesParser<'a> {
-    fn new(subtree: &'a tt::Subtree) -> RulesParser<'a> {
-        RulesParser { subtree, pos: 0 }
-    }
-
-    fn is_eof(&self) -> bool {
-        self.pos == self.subtree.token_trees.len()
-    }
-
-    fn current(&self) -> Option<&'a tt::TokenTree> {
-        self.subtree.token_trees.get(self.pos)
-    }
-
-    fn at_punct(&self) -> Option<&'a tt::Punct> {
-        match self.current() {
-            Some(tt::TokenTree::Leaf(tt::Leaf::Punct(it))) => Some(it),
-            _ => None,
-        }
-    }
-
-    fn at_char(&self, char: char) -> bool {
-        match self.at_punct() {
-            Some(tt::Punct { char: c }) if *c == char => true,
-            _ => false,
-        }
-    }
-
-    fn at_ident(&mut self) -> Option<&'a tt::Ident> {
-        match self.current() {
-            Some(tt::TokenTree::Leaf(tt::Leaf::Ident(i))) => Some(i),
-            _ => None,
-        }
-    }
-
-    fn bump(&mut self) {
-        self.pos += 1;
-    }
-
-    fn eat(&mut self) -> Option<&'a tt::TokenTree> {
-        match self.current() {
-            Some(it) => {
-                self.bump();
-                Some(it)
-            }
-            None => None,
-        }
-    }
-
-    fn eat_subtree(&mut self) -> Option<&'a tt::Subtree> {
-        match self.current()? {
-            tt::TokenTree::Subtree(sub) => {
-                self.bump();
-                Some(sub)
-            }
-            _ => return None,
-        }
-    }
-
-    fn eat_punct(&mut self) -> Option<&'a tt::Punct> {
-        if let Some(it) = self.at_punct() {
-            self.bump();
-            return Some(it);
-        }
-        None
-    }
-
-    fn eat_ident(&mut self) -> Option<&'a tt::Ident> {
-        if let Some(i) = self.at_ident() {
-            self.bump();
-            return Some(i);
-        }
-        None
-    }
-
-    fn expect_char(&mut self, char: char) -> Option<()> {
-        if self.at_char(char) {
-            self.bump();
-            return Some(());
-        }
-        None
-    }
-}
-
 pub fn parse(tt: &tt::Subtree) -> Option<mbe::MacroRules> {
-    let mut parser = RulesParser::new(tt);
+    let mut parser = TtCursor::new(tt);
     let mut rules = Vec::new();
     while !parser.is_eof() {
         rules.push(parse_rule(&mut parser)?)
@@ -101,7 +14,7 @@ pub fn parse(tt: &tt::Subtree) -> Option<mbe::MacroRules> {
     Some(mbe::MacroRules { rules })
 }
 
-fn parse_rule(p: &mut RulesParser) -> Option<mbe::Rule> {
+fn parse_rule(p: &mut TtCursor) -> Option<mbe::Rule> {
     let lhs = parse_subtree(p.eat_subtree()?)?;
     p.expect_char('=')?;
     p.expect_char('>')?;
@@ -111,7 +24,7 @@ fn parse_rule(p: &mut RulesParser) -> Option<mbe::Rule> {
 
 fn parse_subtree(tt: &tt::Subtree) -> Option<mbe::Subtree> {
     let mut token_trees = Vec::new();
-    let mut p = RulesParser::new(tt);
+    let mut p = TtCursor::new(tt);
     while let Some(tt) = p.eat() {
         let child: mbe::TokenTree = match tt {
             tt::TokenTree::Leaf(leaf) => match leaf {
@@ -142,7 +55,7 @@ fn parse_subtree(tt: &tt::Subtree) -> Option<mbe::Subtree> {
     })
 }
 
-fn parse_var(p: &mut RulesParser) -> Option<mbe::Var> {
+fn parse_var(p: &mut TtCursor) -> Option<mbe::Var> {
     let ident = p.eat_ident().unwrap();
     let text = ident.text.clone();
     let kind = if p.at_char(':') {
@@ -150,8 +63,7 @@ fn parse_var(p: &mut RulesParser) -> Option<mbe::Var> {
         if let Some(ident) = p.eat_ident() {
             Some(ident.text.clone())
         } else {
-            // ugly as hell :(
-            p.pos -= 1;
+            p.rev_bump();
             None
         }
     } else {
@@ -160,7 +72,7 @@ fn parse_var(p: &mut RulesParser) -> Option<mbe::Var> {
     Some(mbe::Var { text, kind })
 }
 
-fn parse_repeat(p: &mut RulesParser) -> Option<mbe::Repeat> {
+fn parse_repeat(p: &mut TtCursor) -> Option<mbe::Repeat> {
     let subtree = p.eat_subtree().unwrap();
     let subtree = parse_subtree(subtree)?;
     let sep = p.eat_punct()?;
diff --git a/crates/ra_macros/src/tt_cursor.rs b/crates/ra_macros/src/tt_cursor.rs
new file mode 100644
index 00000000000..380c60b4080
--- /dev/null
+++ b/crates/ra_macros/src/tt_cursor.rs
@@ -0,0 +1,92 @@
+use crate::tt;
+
+pub(crate) struct TtCursor<'a> {
+    subtree: &'a tt::Subtree,
+    pos: usize,
+}
+
+impl<'a> TtCursor<'a> {
+    pub(crate) fn new(subtree: &'a tt::Subtree) -> TtCursor<'a> {
+        TtCursor { subtree, pos: 0 }
+    }
+
+    pub(crate) fn is_eof(&self) -> bool {
+        self.pos == self.subtree.token_trees.len()
+    }
+
+    pub(crate) fn current(&self) -> Option<&'a tt::TokenTree> {
+        self.subtree.token_trees.get(self.pos)
+    }
+
+    pub(crate) fn at_punct(&self) -> Option<&'a tt::Punct> {
+        match self.current() {
+            Some(tt::TokenTree::Leaf(tt::Leaf::Punct(it))) => Some(it),
+            _ => None,
+        }
+    }
+
+    pub(crate) fn at_char(&self, char: char) -> bool {
+        match self.at_punct() {
+            Some(tt::Punct { char: c }) if *c == char => true,
+            _ => false,
+        }
+    }
+
+    pub(crate) fn at_ident(&mut self) -> Option<&'a tt::Ident> {
+        match self.current() {
+            Some(tt::TokenTree::Leaf(tt::Leaf::Ident(i))) => Some(i),
+            _ => None,
+        }
+    }
+
+    pub(crate) fn bump(&mut self) {
+        self.pos += 1;
+    }
+    pub(crate) fn rev_bump(&mut self) {
+        self.pos -= 1;
+    }
+
+    pub(crate) fn eat(&mut self) -> Option<&'a tt::TokenTree> {
+        match self.current() {
+            Some(it) => {
+                self.bump();
+                Some(it)
+            }
+            None => None,
+        }
+    }
+
+    pub(crate) fn eat_subtree(&mut self) -> Option<&'a tt::Subtree> {
+        match self.current()? {
+            tt::TokenTree::Subtree(sub) => {
+                self.bump();
+                Some(sub)
+            }
+            _ => return None,
+        }
+    }
+
+    pub(crate) fn eat_punct(&mut self) -> Option<&'a tt::Punct> {
+        if let Some(it) = self.at_punct() {
+            self.bump();
+            return Some(it);
+        }
+        None
+    }
+
+    pub(crate) fn eat_ident(&mut self) -> Option<&'a tt::Ident> {
+        if let Some(i) = self.at_ident() {
+            self.bump();
+            return Some(i);
+        }
+        None
+    }
+
+    pub(crate) fn expect_char(&mut self, char: char) -> Option<()> {
+        if self.at_char(char) {
+            self.bump();
+            return Some(());
+        }
+        None
+    }
+}