aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_mbe')
-rw-r--r--crates/ra_mbe/Cargo.toml10
-rw-r--r--crates/ra_mbe/src/lib.rs88
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs169
-rw-r--r--crates/ra_mbe/src/mbe_parser.rs93
-rw-r--r--crates/ra_mbe/src/tt_cursor.rs91
5 files changed, 451 insertions, 0 deletions
diff --git a/crates/ra_mbe/Cargo.toml b/crates/ra_mbe/Cargo.toml
new file mode 100644
index 000000000..b7f03cd38
--- /dev/null
+++ b/crates/ra_mbe/Cargo.toml
@@ -0,0 +1,10 @@
1[package]
2edition = "2018"
3name = "ra_mbe"
4version = "0.1.0"
5authors = ["Aleksey Kladov <[email protected]>"]
6
7[dependencies]
8tt = { path = "../ra_tt", package = "ra_tt" }
9rustc-hash = "1.0.0"
10smol_str = "0.1.9"
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
new file mode 100644
index 000000000..38bf3431a
--- /dev/null
+++ b/crates/ra_mbe/src/lib.rs
@@ -0,0 +1,88 @@
1macro_rules! impl_froms {
2 ($e:ident: $($v:ident), *) => {
3 $(
4 impl From<$v> for $e {
5 fn from(it: $v) -> $e {
6 $e::$v(it)
7 }
8 }
9 )*
10 }
11}
12
13mod tt_cursor;
14mod mbe_parser;
15mod mbe_expander;
16
17use smol_str::SmolStr;
18
19pub use tt::{Delimiter, Punct};
20
21pub use crate::{
22 mbe_parser::parse,
23 mbe_expander::exapnd,
24};
25
26#[derive(Debug)]
27pub struct MacroRules {
28 pub(crate) rules: Vec<Rule>,
29}
30
31#[derive(Debug)]
32pub(crate) struct Rule {
33 pub(crate) lhs: Subtree,
34 pub(crate) rhs: Subtree,
35}
36
37#[derive(Debug)]
38pub(crate) enum TokenTree {
39 Leaf(Leaf),
40 Subtree(Subtree),
41 Repeat(Repeat),
42}
43impl_froms!(TokenTree: Leaf, Subtree, Repeat);
44
45#[derive(Debug)]
46pub(crate) enum Leaf {
47 Literal(Literal),
48 Punct(Punct),
49 Ident(Ident),
50 Var(Var),
51}
52impl_froms!(Leaf: Literal, Punct, Ident, Var);
53
54#[derive(Debug)]
55pub(crate) struct Subtree {
56 pub(crate) delimiter: Delimiter,
57 pub(crate) token_trees: Vec<TokenTree>,
58}
59
60#[derive(Debug)]
61pub(crate) struct Repeat {
62 pub(crate) subtree: Subtree,
63 pub(crate) kind: RepeatKind,
64 pub(crate) separator: Option<char>,
65}
66
67#[derive(Debug)]
68pub(crate) enum RepeatKind {
69 ZeroOrMore,
70 OneOrMore,
71 ZeroOrOne,
72}
73
74#[derive(Debug)]
75pub(crate) struct Literal {
76 pub(crate) text: SmolStr,
77}
78
79#[derive(Debug)]
80pub(crate) struct Ident {
81 pub(crate) text: SmolStr,
82}
83
84#[derive(Debug)]
85pub(crate) struct Var {
86 pub(crate) text: SmolStr,
87 pub(crate) kind: Option<SmolStr>,
88}
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs
new file mode 100644
index 000000000..92ad26889
--- /dev/null
+++ b/crates/ra_mbe/src/mbe_expander.rs
@@ -0,0 +1,169 @@
1use rustc_hash::FxHashMap;
2use smol_str::SmolStr;
3
4use crate::{self as mbe, tt_cursor::TtCursor};
5
6pub fn exapnd(rules: &mbe::MacroRules, input: &tt::Subtree) -> Option<tt::Subtree> {
7 rules.rules.iter().find_map(|it| expand_rule(it, input))
8}
9
10fn expand_rule(rule: &mbe::Rule, input: &tt::Subtree) -> Option<tt::Subtree> {
11 let mut input = TtCursor::new(input);
12 let bindings = match_lhs(&rule.lhs, &mut input)?;
13 expand_subtree(&rule.rhs, &bindings, &mut Vec::new())
14}
15
16#[derive(Debug, Default)]
17struct Bindings {
18 inner: FxHashMap<SmolStr, Binding>,
19}
20
21#[derive(Debug)]
22enum Binding {
23 Simple(tt::TokenTree),
24 Nested(Vec<Binding>),
25}
26
27impl Bindings {
28 fn get(&self, name: &SmolStr, nesting: &[usize]) -> Option<&tt::TokenTree> {
29 let mut b = self.inner.get(name)?;
30 for &idx in nesting.iter() {
31 b = match b {
32 Binding::Simple(_) => break,
33 Binding::Nested(bs) => bs.get(idx)?,
34 };
35 }
36 match b {
37 Binding::Simple(it) => Some(it),
38 Binding::Nested(_) => None,
39 }
40 }
41 fn push_nested(&mut self, nested: Bindings) -> Option<()> {
42 for (key, value) in nested.inner {
43 if !self.inner.contains_key(&key) {
44 self.inner.insert(key.clone(), Binding::Nested(Vec::new()));
45 }
46 match self.inner.get_mut(&key) {
47 Some(Binding::Nested(it)) => it.push(value),
48 _ => return None,
49 }
50 }
51 Some(())
52 }
53}
54
55fn match_lhs(pattern: &mbe::Subtree, input: &mut TtCursor) -> Option<Bindings> {
56 let mut res = Bindings::default();
57 for pat in pattern.token_trees.iter() {
58 match pat {
59 mbe::TokenTree::Leaf(leaf) => match leaf {
60 mbe::Leaf::Var(mbe::Var { text, kind }) => {
61 let kind = kind.clone()?;
62 match kind.as_str() {
63 "ident" => {
64 let ident = input.eat_ident()?.clone();
65 res.inner.insert(
66 text.clone(),
67 Binding::Simple(tt::Leaf::from(ident).into()),
68 );
69 }
70 _ => return None,
71 }
72 }
73 mbe::Leaf::Punct(punct) => {
74 if input.eat_punct()? != punct {
75 return None;
76 }
77 }
78 _ => return None,
79 },
80 mbe::TokenTree::Repeat(mbe::Repeat {
81 subtree,
82 kind: _,
83 separator,
84 }) => {
85 while let Some(nested) = match_lhs(subtree, input) {
86 res.push_nested(nested)?;
87 if separator.is_some() && !input.is_eof() {
88 input.eat_punct()?;
89 }
90 }
91 }
92 _ => {}
93 }
94 }
95 Some(res)
96}
97
98/*
99
100macro_rules! impl_froms {
101 ($e:ident: $($v:ident),*) => {
102 $(
103 impl From<$v> for $e {
104 fn from(it: $v) -> $e {
105 $e::$v(it)
106 }
107 }
108 )*
109 }
110}
111
112impl_froms! (Foo: Bar, Baz)
113
114*/
115
116fn expand_subtree(
117 template: &mbe::Subtree,
118 bindings: &Bindings,
119 nesting: &mut Vec<usize>,
120) -> Option<tt::Subtree> {
121 let token_trees = template
122 .token_trees
123 .iter()
124 .map(|it| expand_tt(it, bindings, nesting))
125 .collect::<Option<Vec<_>>>()?;
126
127 Some(tt::Subtree {
128 token_trees,
129 delimiter: template.delimiter,
130 })
131}
132
133fn expand_tt(
134 template: &mbe::TokenTree,
135 bindings: &Bindings,
136 nesting: &mut Vec<usize>,
137) -> Option<tt::TokenTree> {
138 let res: tt::TokenTree = match template {
139 mbe::TokenTree::Subtree(subtree) => expand_subtree(subtree, bindings, nesting)?.into(),
140 mbe::TokenTree::Repeat(repeat) => {
141 let mut token_trees = Vec::new();
142 nesting.push(0);
143 while let Some(t) = expand_subtree(&repeat.subtree, bindings, nesting) {
144 let idx = nesting.pop().unwrap();
145 nesting.push(idx + 1);
146 token_trees.push(t.into())
147 }
148 nesting.pop().unwrap();
149 tt::Subtree {
150 token_trees,
151 delimiter: tt::Delimiter::None,
152 }
153 .into()
154 }
155 mbe::TokenTree::Leaf(leaf) => match leaf {
156 mbe::Leaf::Ident(ident) => tt::Leaf::from(tt::Ident {
157 text: ident.text.clone(),
158 })
159 .into(),
160 mbe::Leaf::Punct(punct) => tt::Leaf::from(punct.clone()).into(),
161 mbe::Leaf::Var(v) => bindings.get(&v.text, nesting)?.clone(),
162 mbe::Leaf::Literal(l) => tt::Leaf::from(tt::Literal {
163 text: l.text.clone(),
164 })
165 .into(),
166 },
167 };
168 Some(res)
169}
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}
diff --git a/crates/ra_mbe/src/tt_cursor.rs b/crates/ra_mbe/src/tt_cursor.rs
new file mode 100644
index 000000000..30c8eda67
--- /dev/null
+++ b/crates/ra_mbe/src/tt_cursor.rs
@@ -0,0 +1,91 @@
1#[derive(Clone)]
2pub(crate) struct TtCursor<'a> {
3 subtree: &'a tt::Subtree,
4 pos: usize,
5}
6
7impl<'a> TtCursor<'a> {
8 pub(crate) fn new(subtree: &'a tt::Subtree) -> TtCursor<'a> {
9 TtCursor { subtree, pos: 0 }
10 }
11
12 pub(crate) fn is_eof(&self) -> bool {
13 self.pos == self.subtree.token_trees.len()
14 }
15
16 pub(crate) fn current(&self) -> Option<&'a tt::TokenTree> {
17 self.subtree.token_trees.get(self.pos)
18 }
19
20 pub(crate) fn at_punct(&self) -> Option<&'a tt::Punct> {
21 match self.current() {
22 Some(tt::TokenTree::Leaf(tt::Leaf::Punct(it))) => Some(it),
23 _ => None,
24 }
25 }
26
27 pub(crate) fn at_char(&self, char: char) -> bool {
28 match self.at_punct() {
29 Some(tt::Punct { char: c, .. }) if *c == char => true,
30 _ => false,
31 }
32 }
33
34 pub(crate) fn at_ident(&mut self) -> Option<&'a tt::Ident> {
35 match self.current() {
36 Some(tt::TokenTree::Leaf(tt::Leaf::Ident(i))) => Some(i),
37 _ => None,
38 }
39 }
40
41 pub(crate) fn bump(&mut self) {
42 self.pos += 1;
43 }
44 pub(crate) fn rev_bump(&mut self) {
45 self.pos -= 1;
46 }
47
48 pub(crate) fn eat(&mut self) -> Option<&'a tt::TokenTree> {
49 match self.current() {
50 Some(it) => {
51 self.bump();
52 Some(it)
53 }
54 None => None,
55 }
56 }
57
58 pub(crate) fn eat_subtree(&mut self) -> Option<&'a tt::Subtree> {
59 match self.current()? {
60 tt::TokenTree::Subtree(sub) => {
61 self.bump();
62 Some(sub)
63 }
64 _ => return None,
65 }
66 }
67
68 pub(crate) fn eat_punct(&mut self) -> Option<&'a tt::Punct> {
69 if let Some(it) = self.at_punct() {
70 self.bump();
71 return Some(it);
72 }
73 None
74 }
75
76 pub(crate) fn eat_ident(&mut self) -> Option<&'a tt::Ident> {
77 if let Some(i) = self.at_ident() {
78 self.bump();
79 return Some(i);
80 }
81 None
82 }
83
84 pub(crate) fn expect_char(&mut self, char: char) -> Option<()> {
85 if self.at_char(char) {
86 self.bump();
87 return Some(());
88 }
89 None
90 }
91}