diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-09-17 13:53:01 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-09-17 13:53:01 +0100 |
commit | 9421d2a953516b392ae35446bc4f2206dd993c84 (patch) | |
tree | e6c7b46cabe1f10f7da28f3db209df2260045fa8 /crates/ra_mbe/src/lib.rs | |
parent | 8eb2697b7d2a98c952b3acd1711829a13e13cab1 (diff) | |
parent | 4551182f94fe81c314f79ddf8916a5520cfd03b0 (diff) |
Merge #1858
1858: use usual token tree for macro expansions r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_mbe/src/lib.rs')
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 157 |
1 files changed, 61 insertions, 96 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index f07f000ff..41720df79 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -3,30 +3,19 @@ | |||
3 | /// interface, although it contains some code to bridge `SyntaxNode`s and | 3 | /// interface, although it contains some code to bridge `SyntaxNode`s and |
4 | /// `TokenTree`s as well! | 4 | /// `TokenTree`s as well! |
5 | 5 | ||
6 | macro_rules! impl_froms { | 6 | mod parser; |
7 | ($e:ident: $($v:ident), *) => { | ||
8 | $( | ||
9 | impl From<$v> for $e { | ||
10 | fn from(it: $v) -> $e { | ||
11 | $e::$v(it) | ||
12 | } | ||
13 | } | ||
14 | )* | ||
15 | } | ||
16 | } | ||
17 | |||
18 | mod mbe_parser; | ||
19 | mod mbe_expander; | 7 | mod mbe_expander; |
20 | mod syntax_bridge; | 8 | mod syntax_bridge; |
21 | mod tt_cursor; | 9 | mod tt_iter; |
22 | mod subtree_source; | 10 | mod subtree_source; |
23 | mod subtree_parser; | ||
24 | |||
25 | use ra_syntax::SmolStr; | ||
26 | use smallvec::SmallVec; | ||
27 | 11 | ||
28 | pub use tt::{Delimiter, Punct}; | 12 | pub use tt::{Delimiter, Punct}; |
29 | 13 | ||
14 | use crate::{ | ||
15 | parser::{parse_pattern, Op}, | ||
16 | tt_iter::TtIter, | ||
17 | }; | ||
18 | |||
30 | #[derive(Debug, PartialEq, Eq)] | 19 | #[derive(Debug, PartialEq, Eq)] |
31 | pub enum ParseError { | 20 | pub enum ParseError { |
32 | Expected(String), | 21 | Expected(String), |
@@ -38,6 +27,7 @@ pub enum ExpandError { | |||
38 | UnexpectedToken, | 27 | UnexpectedToken, |
39 | BindingError(String), | 28 | BindingError(String), |
40 | ConversionError, | 29 | ConversionError, |
30 | InvalidRepeat, | ||
41 | } | 31 | } |
42 | 32 | ||
43 | pub use crate::syntax_bridge::{ | 33 | pub use crate::syntax_bridge::{ |
@@ -54,97 +44,72 @@ pub struct MacroRules { | |||
54 | pub(crate) rules: Vec<Rule>, | 44 | pub(crate) rules: Vec<Rule>, |
55 | } | 45 | } |
56 | 46 | ||
47 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
48 | pub(crate) struct Rule { | ||
49 | pub(crate) lhs: tt::Subtree, | ||
50 | pub(crate) rhs: tt::Subtree, | ||
51 | } | ||
52 | |||
57 | impl MacroRules { | 53 | impl MacroRules { |
58 | pub fn parse(tt: &tt::Subtree) -> Result<MacroRules, ParseError> { | 54 | pub fn parse(tt: &tt::Subtree) -> Result<MacroRules, ParseError> { |
59 | mbe_parser::parse(tt) | 55 | let mut src = TtIter::new(tt); |
56 | let mut rules = Vec::new(); | ||
57 | while src.len() > 0 { | ||
58 | let rule = Rule::parse(&mut src)?; | ||
59 | rules.push(rule); | ||
60 | if let Err(()) = src.expect_char(';') { | ||
61 | if src.len() > 0 { | ||
62 | return Err(ParseError::Expected("expected `:`".to_string())); | ||
63 | } | ||
64 | break; | ||
65 | } | ||
66 | } | ||
67 | Ok(MacroRules { rules }) | ||
60 | } | 68 | } |
61 | pub fn expand(&self, tt: &tt::Subtree) -> Result<tt::Subtree, ExpandError> { | 69 | pub fn expand(&self, tt: &tt::Subtree) -> Result<tt::Subtree, ExpandError> { |
62 | mbe_expander::expand(self, tt) | 70 | mbe_expander::expand(self, tt) |
63 | } | 71 | } |
64 | } | 72 | } |
65 | 73 | ||
66 | #[derive(Clone, Debug, PartialEq, Eq)] | 74 | impl Rule { |
67 | pub(crate) struct Rule { | 75 | fn parse(src: &mut TtIter) -> Result<Rule, ParseError> { |
68 | pub(crate) lhs: Subtree, | 76 | let mut lhs = src |
69 | pub(crate) rhs: Subtree, | 77 | .expect_subtree() |
70 | } | 78 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))? |
71 | 79 | .clone(); | |
72 | #[derive(Clone, Debug, PartialEq, Eq)] | 80 | validate(&lhs)?; |
73 | pub(crate) enum TokenTree { | 81 | lhs.delimiter = tt::Delimiter::None; |
74 | Leaf(Leaf), | 82 | src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?; |
75 | Subtree(Subtree), | 83 | src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?; |
76 | Repeat(Repeat), | 84 | let mut rhs = src |
77 | } | 85 | .expect_subtree() |
78 | impl_froms!(TokenTree: Leaf, Subtree, Repeat); | 86 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))? |
79 | 87 | .clone(); | |
80 | #[derive(Clone, Debug, PartialEq, Eq)] | 88 | rhs.delimiter = tt::Delimiter::None; |
81 | pub(crate) enum Leaf { | 89 | Ok(crate::Rule { lhs, rhs }) |
82 | Literal(Literal), | 90 | } |
83 | Punct(Punct), | ||
84 | Ident(Ident), | ||
85 | Var(Var), | ||
86 | } | ||
87 | impl_froms!(Leaf: Literal, Punct, Ident, Var); | ||
88 | |||
89 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
90 | pub(crate) struct Subtree { | ||
91 | pub(crate) delimiter: Delimiter, | ||
92 | pub(crate) token_trees: Vec<TokenTree>, | ||
93 | } | ||
94 | |||
95 | #[derive(Clone, Debug, Eq)] | ||
96 | pub(crate) enum Separator { | ||
97 | Literal(tt::Literal), | ||
98 | Ident(tt::Ident), | ||
99 | Puncts(SmallVec<[tt::Punct; 3]>), | ||
100 | } | 91 | } |
101 | 92 | ||
102 | // Note that when we compare a Separator, we just care about its textual value. | 93 | fn validate(pattern: &tt::Subtree) -> Result<(), ParseError> { |
103 | impl PartialEq for crate::Separator { | 94 | for op in parse_pattern(pattern) { |
104 | fn eq(&self, other: &crate::Separator) -> bool { | 95 | let op = match op { |
105 | use crate::Separator::*; | 96 | Ok(it) => it, |
106 | 97 | Err(e) => { | |
107 | match (self, other) { | 98 | let msg = match e { |
108 | (Ident(ref a), Ident(ref b)) => a.text == b.text, | 99 | ExpandError::InvalidRepeat => "invalid repeat".to_string(), |
109 | (Literal(ref a), Literal(ref b)) => a.text == b.text, | 100 | _ => "invalid macro definition".to_string(), |
110 | (Puncts(ref a), Puncts(ref b)) if a.len() == b.len() => { | 101 | }; |
111 | let a_iter = a.iter().map(|a| a.char); | 102 | return Err(ParseError::Expected(msg)); |
112 | let b_iter = b.iter().map(|b| b.char); | 103 | } |
113 | a_iter.eq(b_iter) | 104 | }; |
105 | match op { | ||
106 | Op::TokenTree(tt::TokenTree::Subtree(subtree)) | Op::Repeat { subtree, .. } => { | ||
107 | validate(subtree)? | ||
114 | } | 108 | } |
115 | _ => false, | 109 | _ => (), |
116 | } | 110 | } |
117 | } | 111 | } |
118 | } | 112 | Ok(()) |
119 | |||
120 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
121 | pub(crate) struct Repeat { | ||
122 | pub(crate) subtree: Subtree, | ||
123 | pub(crate) kind: RepeatKind, | ||
124 | pub(crate) separator: Option<Separator>, | ||
125 | } | ||
126 | |||
127 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
128 | pub(crate) enum RepeatKind { | ||
129 | ZeroOrMore, | ||
130 | OneOrMore, | ||
131 | ZeroOrOne, | ||
132 | } | ||
133 | |||
134 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
135 | pub(crate) struct Literal { | ||
136 | pub(crate) text: SmolStr, | ||
137 | } | ||
138 | |||
139 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
140 | pub(crate) struct Ident { | ||
141 | pub(crate) text: SmolStr, | ||
142 | } | ||
143 | |||
144 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
145 | pub(crate) struct Var { | ||
146 | pub(crate) text: SmolStr, | ||
147 | pub(crate) kind: Option<SmolStr>, | ||
148 | } | 113 | } |
149 | 114 | ||
150 | #[cfg(test)] | 115 | #[cfg(test)] |