aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_mbe/src/mbe_expander/transcriber.rs33
1 files changed, 21 insertions, 12 deletions
diff --git a/crates/ra_mbe/src/mbe_expander/transcriber.rs b/crates/ra_mbe/src/mbe_expander/transcriber.rs
index 4b173edd3..7c9bb4d00 100644
--- a/crates/ra_mbe/src/mbe_expander/transcriber.rs
+++ b/crates/ra_mbe/src/mbe_expander/transcriber.rs
@@ -1,4 +1,4 @@
1//! Transcraber takes a template, like `fn $ident() {}`, a set of bindings like 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() {}` 2//! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}`
3 3
4use ra_syntax::SmolStr; 4use ra_syntax::SmolStr;
@@ -53,7 +53,8 @@ impl Bindings {
53pub(super) fn transcribe(template: &tt::Subtree, bindings: &Bindings) -> ExpandResult<tt::Subtree> { 53pub(super) fn transcribe(template: &tt::Subtree, bindings: &Bindings) -> ExpandResult<tt::Subtree> {
54 assert!(template.delimiter == None); 54 assert!(template.delimiter == None);
55 let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() }; 55 let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() };
56 expand_subtree(&mut ctx, template) 56 let mut arena: Vec<tt::TokenTree> = Vec::new();
57 expand_subtree(&mut ctx, template, &mut arena)
57} 58}
58 59
59#[derive(Debug)] 60#[derive(Debug)]
@@ -73,8 +74,13 @@ struct ExpandCtx<'a> {
73 nesting: Vec<NestingState>, 74 nesting: Vec<NestingState>,
74} 75}
75 76
76fn expand_subtree(ctx: &mut ExpandCtx, template: &tt::Subtree) -> ExpandResult<tt::Subtree> { 77fn expand_subtree(
77 let mut buf: Vec<tt::TokenTree> = Vec::new(); 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();
78 let mut err = None; 84 let mut err = None;
79 for op in parse_template(template) { 85 for op in parse_template(template) {
80 let op = match op { 86 let op = match op {
@@ -85,25 +91,27 @@ fn expand_subtree(ctx: &mut ExpandCtx, template: &tt::Subtree) -> ExpandResult<t
85 } 91 }
86 }; 92 };
87 match op { 93 match op {
88 Op::TokenTree(tt @ tt::TokenTree::Leaf(..)) => buf.push(tt.clone()), 94 Op::TokenTree(tt @ tt::TokenTree::Leaf(..)) => arena.push(tt.clone()),
89 Op::TokenTree(tt::TokenTree::Subtree(tt)) => { 95 Op::TokenTree(tt::TokenTree::Subtree(tt)) => {
90 let ExpandResult(tt, e) = expand_subtree(ctx, tt); 96 let ExpandResult(tt, e) = expand_subtree(ctx, tt, arena);
91 err = err.or(e); 97 err = err.or(e);
92 buf.push(tt.into()); 98 arena.push(tt.into());
93 } 99 }
94 Op::Var { name, kind: _ } => { 100 Op::Var { name, kind: _ } => {
95 let ExpandResult(fragment, e) = expand_var(ctx, name); 101 let ExpandResult(fragment, e) = expand_var(ctx, name);
96 err = err.or(e); 102 err = err.or(e);
97 push_fragment(&mut buf, fragment); 103 push_fragment(arena, fragment);
98 } 104 }
99 Op::Repeat { subtree, kind, separator } => { 105 Op::Repeat { subtree, kind, separator } => {
100 let ExpandResult(fragment, e) = expand_repeat(ctx, subtree, kind, separator); 106 let ExpandResult(fragment, e) = expand_repeat(ctx, subtree, kind, separator, arena);
101 err = err.or(e); 107 err = err.or(e);
102 push_fragment(&mut buf, fragment) 108 push_fragment(arena, fragment)
103 } 109 }
104 } 110 }
105 } 111 }
106 ExpandResult(tt::Subtree { delimiter: template.delimiter, token_trees: buf }, err) 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)
107} 115}
108 116
109fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> { 117fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> {
@@ -155,6 +163,7 @@ fn expand_repeat(
155 template: &tt::Subtree, 163 template: &tt::Subtree,
156 kind: RepeatKind, 164 kind: RepeatKind,
157 separator: Option<Separator>, 165 separator: Option<Separator>,
166 arena: &mut Vec<tt::TokenTree>,
158) -> ExpandResult<Fragment> { 167) -> ExpandResult<Fragment> {
159 let mut buf: Vec<tt::TokenTree> = Vec::new(); 168 let mut buf: Vec<tt::TokenTree> = Vec::new();
160 ctx.nesting.push(NestingState { idx: 0, at_end: false, hit: false }); 169 ctx.nesting.push(NestingState { idx: 0, at_end: false, hit: false });
@@ -165,7 +174,7 @@ fn expand_repeat(
165 let mut counter = 0; 174 let mut counter = 0;
166 175
167 loop { 176 loop {
168 let ExpandResult(mut t, e) = expand_subtree(ctx, template); 177 let ExpandResult(mut t, e) = expand_subtree(ctx, template, arena);
169 let nesting_state = ctx.nesting.last_mut().unwrap(); 178 let nesting_state = ctx.nesting.last_mut().unwrap();
170 if nesting_state.at_end || !nesting_state.hit { 179 if nesting_state.at_end || !nesting_state.hit {
171 break; 180 break;