aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--crates/ra_hir/src/macros.rs31
-rw-r--r--crates/ra_macros/Cargo.toml1
-rw-r--r--crates/ra_macros/src/mbe.rs7
-rw-r--r--crates/ra_macros/src/mbe_expander.rs145
-rw-r--r--crates/ra_macros/src/mbe_parser.rs2
-rw-r--r--crates/ra_macros/src/tt.rs67
-rw-r--r--crates/ra_macros/src/tt_cursor.rs1
8 files changed, 215 insertions, 40 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b48721622..a9bc80c40 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1022,6 +1022,7 @@ dependencies = [
1022name = "ra_macros" 1022name = "ra_macros"
1023version = "0.1.0" 1023version = "0.1.0"
1024dependencies = [ 1024dependencies = [
1025 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
1025 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1026 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1026 "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1027 "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
1027] 1028]
diff --git a/crates/ra_hir/src/macros.rs b/crates/ra_hir/src/macros.rs
index 7e9aba3f2..059543bf2 100644
--- a/crates/ra_hir/src/macros.rs
+++ b/crates/ra_hir/src/macros.rs
@@ -254,7 +254,7 @@ fn convert_tt(tt: &SyntaxNode) -> Option<tt::Subtree> {
254 254
255#[test] 255#[test]
256fn test_convert_tt() { 256fn test_convert_tt() {
257 let text = r#" 257 let macro_defenition = r#"
258macro_rules! impl_froms { 258macro_rules! impl_froms {
259 ($e:ident: $($v:ident),*) => { 259 ($e:ident: $($v:ident),*) => {
260 $( 260 $(
@@ -267,13 +267,32 @@ macro_rules! impl_froms {
267 } 267 }
268} 268}
269"#; 269"#;
270 let source_file = ast::SourceFile::parse(text); 270
271 let maco_call = source_file 271 let macro_invocation = r#"
272impl_froms!(TokenTree: Leaf, Subtree);
273"#;
274
275 let source_file = ast::SourceFile::parse(macro_defenition);
276 let macro_defenition = source_file
272 .syntax() 277 .syntax()
273 .descendants() 278 .descendants()
274 .find_map(ast::MacroCall::cast) 279 .find_map(ast::MacroCall::cast)
275 .unwrap(); 280 .unwrap();
276 let tt = macro_call_to_tt(maco_call).unwrap(); 281
277 let tt = mbe::parse(&tt); 282 let source_file = ast::SourceFile::parse(macro_invocation);
278 assert!(tt.is_some()); 283 let macro_invocation = source_file
284 .syntax()
285 .descendants()
286 .find_map(ast::MacroCall::cast)
287 .unwrap();
288
289 let defenition_tt = macro_call_to_tt(macro_defenition).unwrap();
290 let invocation_tt = macro_call_to_tt(macro_invocation).unwrap();
291 let mbe = mbe::parse(&defenition_tt).unwrap();
292 let expansion = mbe::exapnd(&mbe, &invocation_tt).unwrap();
293 assert_eq!(
294 expansion.to_string(),
295 "{(impl From < Leaf > for TokenTree {fn from (it : Leaf) - > TokenTree {TokenTree : : Leaf (it)}}) \
296 (impl From < Subtree > for TokenTree {fn from (it : Subtree) - > TokenTree {TokenTree : : Subtree (it)}})}"
297 )
279} 298}
diff --git a/crates/ra_macros/Cargo.toml b/crates/ra_macros/Cargo.toml
index 7d3cb055c..1c9cc9e92 100644
--- a/crates/ra_macros/Cargo.toml
+++ b/crates/ra_macros/Cargo.toml
@@ -7,3 +7,4 @@ authors = ["Aleksey Kladov <[email protected]>"]
7[dependencies] 7[dependencies]
8rustc-hash = "1.0.0" 8rustc-hash = "1.0.0"
9smol_str = "0.1.9" 9smol_str = "0.1.9"
10join_to_string = "0.1.3"
diff --git a/crates/ra_macros/src/mbe.rs b/crates/ra_macros/src/mbe.rs
index 6a168a1b5..ac76d64e4 100644
--- a/crates/ra_macros/src/mbe.rs
+++ b/crates/ra_macros/src/mbe.rs
@@ -1,6 +1,6 @@
1use smol_str::SmolStr; 1use smol_str::SmolStr;
2 2
3use crate::tt::Delimiter; 3pub(crate) use crate::tt::{Delimiter, Punct};
4 4
5pub use crate::{ 5pub use crate::{
6 mbe_parser::parse, 6 mbe_parser::parse,
@@ -61,11 +61,6 @@ pub(crate) struct Literal {
61} 61}
62 62
63#[derive(Debug)] 63#[derive(Debug)]
64pub(crate) struct Punct {
65 pub(crate) char: char,
66}
67
68#[derive(Debug)]
69pub(crate) struct Ident { 64pub(crate) struct Ident {
70 pub(crate) text: SmolStr, 65 pub(crate) text: SmolStr,
71} 66}
diff --git a/crates/ra_macros/src/mbe_expander.rs b/crates/ra_macros/src/mbe_expander.rs
index f55c337da..5d5363261 100644
--- a/crates/ra_macros/src/mbe_expander.rs
+++ b/crates/ra_macros/src/mbe_expander.rs
@@ -1,15 +1,16 @@
1use rustc_hash::FxHashMap; 1use rustc_hash::FxHashMap;
2use smol_str::SmolStr; 2use smol_str::SmolStr;
3 3
4use crate::{mbe, tt}; 4use crate::{mbe, tt, tt_cursor::TtCursor};
5 5
6pub fn exapnd(rules: &mbe::MacroRules, input: &tt::Subtree) -> Option<tt::Subtree> { 6pub fn exapnd(rules: &mbe::MacroRules, input: &tt::Subtree) -> Option<tt::Subtree> {
7 rules.rules.iter().find_map(|it| expand_rule(it, input)) 7 rules.rules.iter().find_map(|it| expand_rule(it, input))
8} 8}
9 9
10fn expand_rule(rule: &mbe::Rule, input: &tt::Subtree) -> Option<tt::Subtree> { 10fn expand_rule(rule: &mbe::Rule, input: &tt::Subtree) -> Option<tt::Subtree> {
11 let bindings = match_lhs(&rule.lhs, input)?; 11 let mut input = TtCursor::new(input);
12 expand_rhs(&rule.rhs, &bindings) 12 let bindings = match_lhs(&rule.lhs, &mut input)?;
13 expand_subtree(&rule.rhs, &bindings, &mut Vec::new())
13} 14}
14 15
15#[derive(Debug, Default)] 16#[derive(Debug, Default)]
@@ -23,25 +24,35 @@ enum Binding {
23 Nested(Vec<Binding>), 24 Nested(Vec<Binding>),
24} 25}
25 26
26/* 27impl Bindings {
27 28 fn get(&self, name: &SmolStr, nesting: &[usize]) -> Option<&tt::TokenTree> {
28macro_rules! impl_froms { 29 let mut b = self.inner.get(name)?;
29 ($e:ident: $($v:ident),*) => { 30 for &idx in nesting.iter() {
30 $( 31 b = match b {
31 impl From<$v> for $e { 32 Binding::Simple(_) => break,
32 fn from(it: $v) -> $e { 33 Binding::Nested(bs) => bs.get(idx)?,
33 $e::$v(it) 34 };
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()));
35 } 45 }
36 )* 46 match self.inner.get_mut(&key) {
47 Some(Binding::Nested(it)) => it.push(value),
48 _ => return None,
49 }
50 }
51 Some(())
37 } 52 }
38} 53}
39 54
40impl_froms! (Foo: Bar, Baz) 55fn match_lhs(pattern: &mbe::Subtree, input: &mut TtCursor) -> Option<Bindings> {
41
42*/
43
44fn match_lhs(pattern: &mbe::Subtree, input: &tt::Subtree) -> Option<Bindings> {
45 let mut res = Bindings::default(); 56 let mut res = Bindings::default();
46 for pat in pattern.token_trees.iter() { 57 for pat in pattern.token_trees.iter() {
47 match pat { 58 match pat {
@@ -49,18 +60,110 @@ fn match_lhs(pattern: &mbe::Subtree, input: &tt::Subtree) -> Option<Bindings> {
49 mbe::Leaf::Var(mbe::Var { text, kind }) => { 60 mbe::Leaf::Var(mbe::Var { text, kind }) => {
50 let kind = kind.clone()?; 61 let kind = kind.clone()?;
51 match kind.as_str() { 62 match kind.as_str() {
52 "ident" => (), 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 }
53 _ => return None, 70 _ => return None,
54 } 71 }
55 } 72 }
73 mbe::Leaf::Punct(punct) => {
74 if input.eat_punct()? != punct {
75 return None;
76 }
77 }
56 _ => return None, 78 _ => return None,
57 }, 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 }
58 _ => {} 92 _ => {}
59 } 93 }
60 } 94 }
61 Some(res) 95 Some(res)
62} 96}
63 97
64fn expand_rhs(template: &mbe::Subtree, bindings: &Bindings) -> Option<tt::Subtree> { 98/*
65 None 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)
66} 169}
diff --git a/crates/ra_macros/src/mbe_parser.rs b/crates/ra_macros/src/mbe_parser.rs
index 024d3a040..279ab2f25 100644
--- a/crates/ra_macros/src/mbe_parser.rs
+++ b/crates/ra_macros/src/mbe_parser.rs
@@ -84,7 +84,7 @@ fn parse_repeat(p: &mut TtCursor) -> Option<mbe::Repeat> {
84 let kind = match rep { 84 let kind = match rep {
85 '*' => mbe::RepeatKind::ZeroOrMore, 85 '*' => mbe::RepeatKind::ZeroOrMore,
86 '+' => mbe::RepeatKind::OneOrMore, 86 '+' => mbe::RepeatKind::OneOrMore,
87 '?' => mbe::RepeatKind::ZeroOrMore, 87 '?' => mbe::RepeatKind::ZeroOrOne,
88 _ => return None, 88 _ => return None,
89 }; 89 };
90 p.bump(); 90 p.bump();
diff --git a/crates/ra_macros/src/tt.rs b/crates/ra_macros/src/tt.rs
index 364eed9e6..56e930f00 100644
--- a/crates/ra_macros/src/tt.rs
+++ b/crates/ra_macros/src/tt.rs
@@ -1,13 +1,16 @@
1use std::fmt;
2
1use smol_str::SmolStr; 3use smol_str::SmolStr;
4use join_to_string::join;
2 5
3#[derive(Debug)] 6#[derive(Debug, Clone)]
4pub enum TokenTree { 7pub enum TokenTree {
5 Leaf(Leaf), 8 Leaf(Leaf),
6 Subtree(Subtree), 9 Subtree(Subtree),
7} 10}
8impl_froms!(TokenTree: Leaf, Subtree); 11impl_froms!(TokenTree: Leaf, Subtree);
9 12
10#[derive(Debug)] 13#[derive(Debug, Clone)]
11pub enum Leaf { 14pub enum Leaf {
12 Literal(Literal), 15 Literal(Literal),
13 Punct(Punct), 16 Punct(Punct),
@@ -15,7 +18,7 @@ pub enum Leaf {
15} 18}
16impl_froms!(Leaf: Literal, Punct, Ident); 19impl_froms!(Leaf: Literal, Punct, Ident);
17 20
18#[derive(Debug)] 21#[derive(Debug, Clone)]
19pub struct Subtree { 22pub struct Subtree {
20 pub delimiter: Delimiter, 23 pub delimiter: Delimiter,
21 pub token_trees: Vec<TokenTree>, 24 pub token_trees: Vec<TokenTree>,
@@ -29,17 +32,69 @@ pub enum Delimiter {
29 None, 32 None,
30} 33}
31 34
32#[derive(Debug)] 35#[derive(Debug, Clone)]
33pub struct Literal { 36pub struct Literal {
34 pub text: SmolStr, 37 pub text: SmolStr,
35} 38}
36 39
37#[derive(Debug)] 40#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct Punct { 41pub struct Punct {
39 pub char: char, 42 pub char: char,
40} 43}
41 44
42#[derive(Debug)] 45#[derive(Debug, Clone)]
43pub struct Ident { 46pub struct Ident {
44 pub text: SmolStr, 47 pub text: SmolStr,
45} 48}
49
50impl fmt::Display for TokenTree {
51 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52 match self {
53 TokenTree::Leaf(it) => fmt::Display::fmt(it, f),
54 TokenTree::Subtree(it) => fmt::Display::fmt(it, f),
55 }
56 }
57}
58
59impl fmt::Display for Subtree {
60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61 let (l, r) = match self.delimiter {
62 Delimiter::Parenthesis => ("(", ")"),
63 Delimiter::Brace => ("{", "}"),
64 Delimiter::Bracket => ("[", "]"),
65 Delimiter::None => ("", ""),
66 };
67 join(self.token_trees.iter())
68 .separator(" ")
69 .surround_with(l, r)
70 .to_fmt(f)
71 }
72}
73
74impl fmt::Display for Leaf {
75 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76 match self {
77 Leaf::Ident(it) => fmt::Display::fmt(it, f),
78 Leaf::Literal(it) => fmt::Display::fmt(it, f),
79 Leaf::Punct(it) => fmt::Display::fmt(it, f),
80 }
81 }
82}
83
84impl fmt::Display for Ident {
85 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86 fmt::Display::fmt(&self.text, f)
87 }
88}
89
90impl fmt::Display for Literal {
91 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92 fmt::Display::fmt(&self.text, f)
93 }
94}
95
96impl fmt::Display for Punct {
97 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98 fmt::Display::fmt(&self.char, f)
99 }
100}
diff --git a/crates/ra_macros/src/tt_cursor.rs b/crates/ra_macros/src/tt_cursor.rs
index 380c60b40..6dc9f400d 100644
--- a/crates/ra_macros/src/tt_cursor.rs
+++ b/crates/ra_macros/src/tt_cursor.rs
@@ -1,5 +1,6 @@
1use crate::tt; 1use crate::tt;
2 2
3#[derive(Clone)]
3pub(crate) struct TtCursor<'a> { 4pub(crate) struct TtCursor<'a> {
4 subtree: &'a tt::Subtree, 5 subtree: &'a tt::Subtree,
5 pos: usize, 6 pos: usize,