aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe/src/mbe_parser.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-01-31 18:09:43 +0000
committerAleksey Kladov <[email protected]>2019-01-31 20:23:30 +0000
commit40feacdeb90786b49ea9e0510ba22ff7af79e020 (patch)
tree294162ffb99480a5f150b9718675a954a4ac0f0a /crates/ra_mbe/src/mbe_parser.rs
parentad80a0c551458de7d27a98d182d7f559de04f291 (diff)
split macros across crates
Diffstat (limited to 'crates/ra_mbe/src/mbe_parser.rs')
-rw-r--r--crates/ra_mbe/src/mbe_parser.rs93
1 files changed, 93 insertions, 0 deletions
diff --git a/crates/ra_mbe/src/mbe_parser.rs b/crates/ra_mbe/src/mbe_parser.rs
new file mode 100644
index 000000000..a70ed1d52
--- /dev/null
+++ b/crates/ra_mbe/src/mbe_parser.rs
@@ -0,0 +1,93 @@
1use crate::{self as mbe, tt_cursor::TtCursor};
2
3/// This module parses a raw `tt::TokenStream` into macro-by-example token
4/// stream. This is a *mostly* identify function, expect for handling of
5/// `$var:tt_kind` and `$(repeat),*` constructs.
6
7pub fn parse(tt: &tt::Subtree) -> Option<mbe::MacroRules> {
8 let mut parser = TtCursor::new(tt);
9 let mut rules = Vec::new();
10 while !parser.is_eof() {
11 rules.push(parse_rule(&mut parser)?)
12 }
13 Some(mbe::MacroRules { rules })
14}
15
16fn parse_rule(p: &mut TtCursor) -> Option<mbe::Rule> {
17 let lhs = parse_subtree(p.eat_subtree()?)?;
18 p.expect_char('=')?;
19 p.expect_char('>')?;
20 let rhs = parse_subtree(p.eat_subtree()?)?;
21 Some(mbe::Rule { lhs, rhs })
22}
23
24fn parse_subtree(tt: &tt::Subtree) -> Option<mbe::Subtree> {
25 let mut token_trees = Vec::new();
26 let mut p = TtCursor::new(tt);
27 while let Some(tt) = p.eat() {
28 let child: mbe::TokenTree = match tt {
29 tt::TokenTree::Leaf(leaf) => match leaf {
30 tt::Leaf::Punct(tt::Punct { char: '$', .. }) => {
31 if p.at_ident().is_some() {
32 mbe::Leaf::from(parse_var(&mut p)?).into()
33 } else {
34 parse_repeat(&mut p)?.into()
35 }
36 }
37 tt::Leaf::Punct(punct) => mbe::Leaf::from(*punct).into(),
38 tt::Leaf::Ident(tt::Ident { text }) => {
39 mbe::Leaf::from(mbe::Ident { text: text.clone() }).into()
40 }
41 tt::Leaf::Literal(tt::Literal { text }) => {
42 mbe::Leaf::from(mbe::Literal { text: text.clone() }).into()
43 }
44 },
45 tt::TokenTree::Subtree(subtree) => parse_subtree(&subtree)?.into(),
46 };
47 token_trees.push(child);
48 }
49 Some(mbe::Subtree {
50 token_trees,
51 delimiter: tt.delimiter,
52 })
53}
54
55fn parse_var(p: &mut TtCursor) -> Option<mbe::Var> {
56 let ident = p.eat_ident().unwrap();
57 let text = ident.text.clone();
58 let kind = if p.at_char(':') {
59 p.bump();
60 if let Some(ident) = p.eat_ident() {
61 Some(ident.text.clone())
62 } else {
63 p.rev_bump();
64 None
65 }
66 } else {
67 None
68 };
69 Some(mbe::Var { text, kind })
70}
71
72fn parse_repeat(p: &mut TtCursor) -> Option<mbe::Repeat> {
73 let subtree = p.eat_subtree().unwrap();
74 let subtree = parse_subtree(subtree)?;
75 let sep = p.eat_punct()?;
76 let (separator, rep) = match sep.char {
77 '*' | '+' | '?' => (None, sep.char),
78 char => (Some(char), p.eat_punct()?.char),
79 };
80
81 let kind = match rep {
82 '*' => mbe::RepeatKind::ZeroOrMore,
83 '+' => mbe::RepeatKind::OneOrMore,
84 '?' => mbe::RepeatKind::ZeroOrOne,
85 _ => return None,
86 };
87 p.bump();
88 Some(mbe::Repeat {
89 subtree,
90 kind,
91 separator,
92 })
93}