aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe/src/mbe_expander/transcriber.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-08-13 09:08:11 +0100
committerAleksey Kladov <[email protected]>2020-08-13 09:36:04 +0100
commit2f45cfc415626cfae5cba89c88a25fb3225486f7 (patch)
treee04c21d108582a89efd2d3e5a680a0ed35156912 /crates/ra_mbe/src/mbe_expander/transcriber.rs
parentd42ba6397668fe28bd9cd92db829755905469a69 (diff)
Rename ra_mbe -> mbe
Diffstat (limited to 'crates/ra_mbe/src/mbe_expander/transcriber.rs')
-rw-r--r--crates/ra_mbe/src/mbe_expander/transcriber.rs254
1 files changed, 0 insertions, 254 deletions
diff --git a/crates/ra_mbe/src/mbe_expander/transcriber.rs b/crates/ra_mbe/src/mbe_expander/transcriber.rs
deleted file mode 100644
index c9525c5bf..000000000
--- a/crates/ra_mbe/src/mbe_expander/transcriber.rs
+++ /dev/null
@@ -1,254 +0,0 @@
1//! Transcriber takes a template, like `fn $ident() {}`, a set of bindings like
2//! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}`
3
4use syntax::SmolStr;
5
6use super::ExpandResult;
7use crate::{
8 mbe_expander::{Binding, Bindings, Fragment},
9 parser::{parse_template, Op, RepeatKind, Separator},
10 ExpandError,
11};
12
13impl Bindings {
14 fn contains(&self, name: &str) -> bool {
15 self.inner.contains_key(name)
16 }
17
18 fn get(&self, name: &str, nesting: &mut [NestingState]) -> Result<&Fragment, ExpandError> {
19 let mut b = self.inner.get(name).ok_or_else(|| {
20 ExpandError::BindingError(format!("could not find binding `{}`", name))
21 })?;
22 for nesting_state in nesting.iter_mut() {
23 nesting_state.hit = true;
24 b = match b {
25 Binding::Fragment(_) => break,
26 Binding::Nested(bs) => bs.get(nesting_state.idx).ok_or_else(|| {
27 nesting_state.at_end = true;
28 ExpandError::BindingError(format!("could not find nested binding `{}`", name))
29 })?,
30 Binding::Empty => {
31 nesting_state.at_end = true;
32 return Err(ExpandError::BindingError(format!(
33 "could not find empty binding `{}`",
34 name
35 )));
36 }
37 };
38 }
39 match b {
40 Binding::Fragment(it) => Ok(it),
41 Binding::Nested(_) => Err(ExpandError::BindingError(format!(
42 "expected simple binding, found nested binding `{}`",
43 name
44 ))),
45 Binding::Empty => Err(ExpandError::BindingError(format!(
46 "expected simple binding, found empty binding `{}`",
47 name
48 ))),
49 }
50 }
51}
52
53pub(super) fn transcribe(template: &tt::Subtree, bindings: &Bindings) -> ExpandResult<tt::Subtree> {
54 assert!(template.delimiter == None);
55 let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() };
56 let mut arena: Vec<tt::TokenTree> = Vec::new();
57 expand_subtree(&mut ctx, template, &mut arena)
58}
59
60#[derive(Debug)]
61struct NestingState {
62 idx: usize,
63 /// `hit` is currently necessary to tell `expand_repeat` if it should stop
64 /// because there is no variable in use by the current repetition
65 hit: bool,
66 /// `at_end` is currently necessary to tell `expand_repeat` if it should stop
67 /// because there is no more value avaible for the current repetition
68 at_end: bool,
69}
70
71#[derive(Debug)]
72struct ExpandCtx<'a> {
73 bindings: &'a Bindings,
74 nesting: Vec<NestingState>,
75}
76
77fn expand_subtree(
78 ctx: &mut ExpandCtx,
79 template: &tt::Subtree,
80 arena: &mut Vec<tt::TokenTree>,
81) -> ExpandResult<tt::Subtree> {
82 // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation
83 let start_elements = arena.len();
84 let mut err = None;
85 for op in parse_template(template) {
86 let op = match op {
87 Ok(op) => op,
88 Err(e) => {
89 err = Some(e);
90 break;
91 }
92 };
93 match op {
94 Op::TokenTree(tt @ tt::TokenTree::Leaf(..)) => arena.push(tt.clone()),
95 Op::TokenTree(tt::TokenTree::Subtree(tt)) => {
96 let ExpandResult(tt, e) = expand_subtree(ctx, tt, arena);
97 err = err.or(e);
98 arena.push(tt.into());
99 }
100 Op::Var { name, kind: _ } => {
101 let ExpandResult(fragment, e) = expand_var(ctx, name);
102 err = err.or(e);
103 push_fragment(arena, fragment);
104 }
105 Op::Repeat { subtree, kind, separator } => {
106 let ExpandResult(fragment, e) = expand_repeat(ctx, subtree, kind, separator, arena);
107 err = err.or(e);
108 push_fragment(arena, fragment)
109 }
110 }
111 }
112 // drain the elements added in this instance of expand_subtree
113 let tts = arena.drain(start_elements..arena.len()).collect();
114 ExpandResult(tt::Subtree { delimiter: template.delimiter, token_trees: tts }, err)
115}
116
117fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> {
118 if v == "crate" {
119 // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path.
120 let tt =
121 tt::Leaf::from(tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() })
122 .into();
123 ExpandResult::ok(Fragment::Tokens(tt))
124 } else if !ctx.bindings.contains(v) {
125 // Note that it is possible to have a `$var` inside a macro which is not bound.
126 // For example:
127 // ```
128 // macro_rules! foo {
129 // ($a:ident, $b:ident, $c:tt) => {
130 // macro_rules! bar {
131 // ($bi:ident) => {
132 // fn $bi() -> u8 {$c}
133 // }
134 // }
135 // }
136 // ```
137 // We just treat it a normal tokens
138 let tt = tt::Subtree {
139 delimiter: None,
140 token_trees: vec![
141 tt::Leaf::from(tt::Punct {
142 char: '$',
143 spacing: tt::Spacing::Alone,
144 id: tt::TokenId::unspecified(),
145 })
146 .into(),
147 tt::Leaf::from(tt::Ident { text: v.clone(), id: tt::TokenId::unspecified() })
148 .into(),
149 ],
150 }
151 .into();
152 ExpandResult::ok(Fragment::Tokens(tt))
153 } else {
154 ctx.bindings.get(&v, &mut ctx.nesting).map_or_else(
155 |e| ExpandResult(Fragment::Tokens(tt::TokenTree::empty()), Some(e)),
156 |b| ExpandResult::ok(b.clone()),
157 )
158 }
159}
160
161fn expand_repeat(
162 ctx: &mut ExpandCtx,
163 template: &tt::Subtree,
164 kind: RepeatKind,
165 separator: Option<Separator>,
166 arena: &mut Vec<tt::TokenTree>,
167) -> ExpandResult<Fragment> {
168 let mut buf: Vec<tt::TokenTree> = Vec::new();
169 ctx.nesting.push(NestingState { idx: 0, at_end: false, hit: false });
170 // Dirty hack to make macro-expansion terminate.
171 // This should be replaced by a proper macro-by-example implementation
172 let limit = 65536;
173 let mut has_seps = 0;
174 let mut counter = 0;
175
176 loop {
177 let ExpandResult(mut t, e) = expand_subtree(ctx, template, arena);
178 let nesting_state = ctx.nesting.last_mut().unwrap();
179 if nesting_state.at_end || !nesting_state.hit {
180 break;
181 }
182 nesting_state.idx += 1;
183 nesting_state.hit = false;
184
185 counter += 1;
186 if counter == limit {
187 log::warn!(
188 "expand_tt excced in repeat pattern exceed limit => {:#?}\n{:#?}",
189 template,
190 ctx
191 );
192 break;
193 }
194
195 if e.is_some() {
196 continue;
197 }
198
199 t.delimiter = None;
200 push_subtree(&mut buf, t);
201
202 if let Some(ref sep) = separator {
203 match sep {
204 Separator::Ident(ident) => {
205 has_seps = 1;
206 buf.push(tt::Leaf::from(ident.clone()).into());
207 }
208 Separator::Literal(lit) => {
209 has_seps = 1;
210 buf.push(tt::Leaf::from(lit.clone()).into());
211 }
212
213 Separator::Puncts(puncts) => {
214 has_seps = puncts.len();
215 for punct in puncts {
216 buf.push(tt::Leaf::from(*punct).into());
217 }
218 }
219 }
220 }
221
222 if RepeatKind::ZeroOrOne == kind {
223 break;
224 }
225 }
226
227 ctx.nesting.pop().unwrap();
228 for _ in 0..has_seps {
229 buf.pop();
230 }
231
232 // Check if it is a single token subtree without any delimiter
233 // e.g {Delimiter:None> ['>'] /Delimiter:None>}
234 let tt = tt::Subtree { delimiter: None, token_trees: buf }.into();
235
236 if RepeatKind::OneOrMore == kind && counter == 0 {
237 return ExpandResult(Fragment::Tokens(tt), Some(ExpandError::UnexpectedToken));
238 }
239 ExpandResult::ok(Fragment::Tokens(tt))
240}
241
242fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) {
243 match fragment {
244 Fragment::Tokens(tt::TokenTree::Subtree(tt)) => push_subtree(buf, tt),
245 Fragment::Tokens(tt) | Fragment::Ast(tt) => buf.push(tt),
246 }
247}
248
249fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) {
250 match tt.delimiter {
251 None => buf.extend(tt.token_trees),
252 _ => buf.push(tt.into()),
253 }
254}