diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-12-30 00:39:29 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-12-30 00:39:29 +0000 |
commit | 848e817f603ed12e065bc3057d12e04b481fb5bb (patch) | |
tree | c4dd3ba17b56e25995e2ee14eabac1a4659b41e7 /crates | |
parent | 386c447038166687b9403bec71d5924b8e2d3fbc (diff) | |
parent | 266b14d4b5b44d1491e50c7aa2ed4b85020796e1 (diff) |
Merge #7083
7083: Refactor mbe parsing code r=edwin0cheng a=edwin0cheng
Inspire by #5426 , this PR refactor out the parsing code such that it only parsed on `mbe::Rule`, but not on invocations.
However, it just improve the overall performance unnoticeablely :(
Co-authored-by: Edwin Cheng <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/mbe/src/lib.rs | 46 | ||||
-rw-r--r-- | crates/mbe/src/mbe_expander/matcher.rs | 32 | ||||
-rw-r--r-- | crates/mbe/src/mbe_expander/transcriber.rs | 29 | ||||
-rw-r--r-- | crates/mbe/src/parser.rs | 68 |
4 files changed, 99 insertions, 76 deletions
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index 3ad609a00..7878faaa4 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs | |||
@@ -14,10 +14,10 @@ mod tests; | |||
14 | 14 | ||
15 | use std::fmt; | 15 | use std::fmt; |
16 | 16 | ||
17 | pub use tt::{Delimiter, Punct}; | 17 | pub use tt::{Delimiter, DelimiterKind, Punct}; |
18 | 18 | ||
19 | use crate::{ | 19 | use crate::{ |
20 | parser::{parse_pattern, Op}, | 20 | parser::{parse_pattern, parse_template, Op}, |
21 | tt_iter::TtIter, | 21 | tt_iter::TtIter, |
22 | }; | 22 | }; |
23 | 23 | ||
@@ -78,8 +78,24 @@ pub struct MacroRules { | |||
78 | 78 | ||
79 | #[derive(Clone, Debug, PartialEq, Eq)] | 79 | #[derive(Clone, Debug, PartialEq, Eq)] |
80 | struct Rule { | 80 | struct Rule { |
81 | lhs: tt::Subtree, | 81 | lhs: MetaTemplate, |
82 | rhs: tt::Subtree, | 82 | rhs: MetaTemplate, |
83 | } | ||
84 | |||
85 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
86 | struct MetaTemplate { | ||
87 | delimiter: Option<Delimiter>, | ||
88 | tokens: Vec<Result<Op, ExpandError>>, | ||
89 | } | ||
90 | |||
91 | impl<'a> MetaTemplate { | ||
92 | fn iter(&self) -> impl Iterator<Item = &Result<Op, ExpandError>> { | ||
93 | self.tokens.iter() | ||
94 | } | ||
95 | |||
96 | fn delimiter_kind(&self) -> Option<DelimiterKind> { | ||
97 | self.delimiter.map(|it| it.kind) | ||
98 | } | ||
83 | } | 99 | } |
84 | 100 | ||
85 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | 101 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
@@ -167,7 +183,7 @@ impl MacroRules { | |||
167 | rules.push(rule); | 183 | rules.push(rule); |
168 | if let Err(()) = src.expect_char(';') { | 184 | if let Err(()) = src.expect_char(';') { |
169 | if src.len() > 0 { | 185 | if src.len() > 0 { |
170 | return Err(ParseError::Expected("expected `:`".to_string())); | 186 | return Err(ParseError::Expected("expected `;`".to_string())); |
171 | } | 187 | } |
172 | break; | 188 | break; |
173 | } | 189 | } |
@@ -213,11 +229,15 @@ impl Rule { | |||
213 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))? | 229 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))? |
214 | .clone(); | 230 | .clone(); |
215 | rhs.delimiter = None; | 231 | rhs.delimiter = None; |
232 | |||
233 | let lhs = MetaTemplate { tokens: parse_pattern(&lhs), delimiter: None }; | ||
234 | let rhs = MetaTemplate { tokens: parse_template(&rhs), delimiter: None }; | ||
235 | |||
216 | Ok(crate::Rule { lhs, rhs }) | 236 | Ok(crate::Rule { lhs, rhs }) |
217 | } | 237 | } |
218 | } | 238 | } |
219 | 239 | ||
220 | fn to_parse_error(e: ExpandError) -> ParseError { | 240 | fn to_parse_error(e: &ExpandError) -> ParseError { |
221 | let msg = match e { | 241 | let msg = match e { |
222 | ExpandError::InvalidRepeat => "invalid repeat".to_string(), | 242 | ExpandError::InvalidRepeat => "invalid repeat".to_string(), |
223 | _ => "invalid macro definition".to_string(), | 243 | _ => "invalid macro definition".to_string(), |
@@ -225,22 +245,22 @@ fn to_parse_error(e: ExpandError) -> ParseError { | |||
225 | ParseError::Expected(msg) | 245 | ParseError::Expected(msg) |
226 | } | 246 | } |
227 | 247 | ||
228 | fn validate(pattern: &tt::Subtree) -> Result<(), ParseError> { | 248 | fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> { |
229 | for op in parse_pattern(pattern) { | 249 | for op in pattern.iter() { |
230 | let op = op.map_err(to_parse_error)?; | 250 | let op = op.as_ref().map_err(|e| to_parse_error(&e))?; |
231 | 251 | ||
232 | match op { | 252 | match op { |
233 | Op::TokenTree(tt::TokenTree::Subtree(subtree)) => validate(subtree)?, | 253 | Op::Subtree(subtree) => validate(&subtree)?, |
234 | Op::Repeat { subtree, separator, .. } => { | 254 | Op::Repeat { subtree, separator, .. } => { |
235 | // Checks that no repetition which could match an empty token | 255 | // Checks that no repetition which could match an empty token |
236 | // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558 | 256 | // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558 |
237 | 257 | ||
238 | if separator.is_none() { | 258 | if separator.is_none() { |
239 | if parse_pattern(subtree).all(|child_op| { | 259 | if subtree.iter().all(|child_op| { |
240 | match child_op.map_err(to_parse_error) { | 260 | match child_op.as_ref().map_err(to_parse_error) { |
241 | Ok(Op::Var { kind, .. }) => { | 261 | Ok(Op::Var { kind, .. }) => { |
242 | // vis is optional | 262 | // vis is optional |
243 | if kind.map_or(false, |it| it == "vis") { | 263 | if kind.as_ref().map_or(false, |it| it == "vis") { |
244 | return true; | 264 | return true; |
245 | } | 265 | } |
246 | } | 266 | } |
diff --git a/crates/mbe/src/mbe_expander/matcher.rs b/crates/mbe/src/mbe_expander/matcher.rs index 44722c0f1..ab5f87c48 100644 --- a/crates/mbe/src/mbe_expander/matcher.rs +++ b/crates/mbe/src/mbe_expander/matcher.rs | |||
@@ -2,10 +2,10 @@ | |||
2 | 2 | ||
3 | use crate::{ | 3 | use crate::{ |
4 | mbe_expander::{Binding, Bindings, Fragment}, | 4 | mbe_expander::{Binding, Bindings, Fragment}, |
5 | parser::{parse_pattern, Op, RepeatKind, Separator}, | 5 | parser::{Op, RepeatKind, Separator}, |
6 | subtree_source::SubtreeTokenSource, | 6 | subtree_source::SubtreeTokenSource, |
7 | tt_iter::TtIter, | 7 | tt_iter::TtIter, |
8 | ExpandError, | 8 | ExpandError, MetaTemplate, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use super::ExpandResult; | 11 | use super::ExpandResult; |
@@ -83,7 +83,7 @@ impl Match { | |||
83 | // sense to try using it. Matching errors are added to the `Match`. It might | 83 | // sense to try using it. Matching errors are added to the `Match`. It might |
84 | // make sense to make pattern parsing a separate step? | 84 | // make sense to make pattern parsing a separate step? |
85 | 85 | ||
86 | pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Match, ExpandError> { | 86 | pub(super) fn match_(pattern: &MetaTemplate, src: &tt::Subtree) -> Result<Match, ExpandError> { |
87 | assert!(pattern.delimiter == None); | 87 | assert!(pattern.delimiter == None); |
88 | 88 | ||
89 | let mut res = Match::default(); | 89 | let mut res = Match::default(); |
@@ -101,12 +101,12 @@ pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Match, | |||
101 | 101 | ||
102 | fn match_subtree( | 102 | fn match_subtree( |
103 | res: &mut Match, | 103 | res: &mut Match, |
104 | pattern: &tt::Subtree, | 104 | pattern: &MetaTemplate, |
105 | src: &mut TtIter, | 105 | src: &mut TtIter, |
106 | ) -> Result<(), ExpandError> { | 106 | ) -> Result<(), ExpandError> { |
107 | for op in parse_pattern(pattern) { | 107 | for op in pattern.iter() { |
108 | match op? { | 108 | match op.as_ref().map_err(|err| err.clone())? { |
109 | Op::TokenTree(tt::TokenTree::Leaf(lhs)) => { | 109 | Op::Leaf(lhs) => { |
110 | let rhs = match src.expect_leaf() { | 110 | let rhs = match src.expect_leaf() { |
111 | Ok(l) => l, | 111 | Ok(l) => l, |
112 | Err(()) => { | 112 | Err(()) => { |
@@ -132,7 +132,7 @@ fn match_subtree( | |||
132 | } | 132 | } |
133 | } | 133 | } |
134 | } | 134 | } |
135 | Op::TokenTree(tt::TokenTree::Subtree(lhs)) => { | 135 | Op::Subtree(lhs) => { |
136 | let rhs = match src.expect_subtree() { | 136 | let rhs = match src.expect_subtree() { |
137 | Ok(s) => s, | 137 | Ok(s) => s, |
138 | Err(()) => { | 138 | Err(()) => { |
@@ -172,7 +172,7 @@ fn match_subtree( | |||
172 | } | 172 | } |
173 | } | 173 | } |
174 | Op::Repeat { subtree, kind, separator } => { | 174 | Op::Repeat { subtree, kind, separator } => { |
175 | match_repeat(res, subtree, kind, separator, src)?; | 175 | match_repeat(res, subtree, *kind, separator, src)?; |
176 | } | 176 | } |
177 | } | 177 | } |
178 | } | 178 | } |
@@ -372,9 +372,9 @@ impl<'a> TtIter<'a> { | |||
372 | 372 | ||
373 | pub(super) fn match_repeat( | 373 | pub(super) fn match_repeat( |
374 | res: &mut Match, | 374 | res: &mut Match, |
375 | pattern: &tt::Subtree, | 375 | pattern: &MetaTemplate, |
376 | kind: RepeatKind, | 376 | kind: RepeatKind, |
377 | separator: Option<Separator>, | 377 | separator: &Option<Separator>, |
378 | src: &mut TtIter, | 378 | src: &mut TtIter, |
379 | ) -> Result<(), ExpandError> { | 379 | ) -> Result<(), ExpandError> { |
380 | // Dirty hack to make macro-expansion terminate. | 380 | // Dirty hack to make macro-expansion terminate. |
@@ -489,12 +489,12 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen | |||
489 | result.map(|tt| if kind == "expr" { tt.map(Fragment::Ast) } else { tt.map(Fragment::Tokens) }) | 489 | result.map(|tt| if kind == "expr" { tt.map(Fragment::Ast) } else { tt.map(Fragment::Tokens) }) |
490 | } | 490 | } |
491 | 491 | ||
492 | fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &tt::Subtree) -> Result<(), ExpandError> { | 492 | fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &MetaTemplate) -> Result<(), ExpandError> { |
493 | for op in parse_pattern(pattern) { | 493 | for op in pattern.iter() { |
494 | match op? { | 494 | match op.as_ref().map_err(|e| e.clone())? { |
495 | Op::Var { name, .. } => buf.push(name.clone()), | 495 | Op::Var { name, .. } => buf.push(name.clone()), |
496 | Op::TokenTree(tt::TokenTree::Leaf(_)) => (), | 496 | Op::Leaf(_) => (), |
497 | Op::TokenTree(tt::TokenTree::Subtree(subtree)) => collect_vars(buf, subtree)?, | 497 | Op::Subtree(subtree) => collect_vars(buf, subtree)?, |
498 | Op::Repeat { subtree, .. } => collect_vars(buf, subtree)?, | 498 | Op::Repeat { subtree, .. } => collect_vars(buf, subtree)?, |
499 | } | 499 | } |
500 | } | 500 | } |
diff --git a/crates/mbe/src/mbe_expander/transcriber.rs b/crates/mbe/src/mbe_expander/transcriber.rs index 57592dc92..720531237 100644 --- a/crates/mbe/src/mbe_expander/transcriber.rs +++ b/crates/mbe/src/mbe_expander/transcriber.rs | |||
@@ -6,8 +6,8 @@ use syntax::SmolStr; | |||
6 | use super::ExpandResult; | 6 | use super::ExpandResult; |
7 | use crate::{ | 7 | use crate::{ |
8 | mbe_expander::{Binding, Bindings, Fragment}, | 8 | mbe_expander::{Binding, Bindings, Fragment}, |
9 | parser::{parse_template, Op, RepeatKind, Separator}, | 9 | parser::{Op, RepeatKind, Separator}, |
10 | ExpandError, | 10 | ExpandError, MetaTemplate, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | impl Bindings { | 13 | impl Bindings { |
@@ -50,7 +50,10 @@ impl Bindings { | |||
50 | } | 50 | } |
51 | } | 51 | } |
52 | 52 | ||
53 | pub(super) fn transcribe(template: &tt::Subtree, bindings: &Bindings) -> ExpandResult<tt::Subtree> { | 53 | pub(super) fn transcribe( |
54 | template: &MetaTemplate, | ||
55 | bindings: &Bindings, | ||
56 | ) -> ExpandResult<tt::Subtree> { | ||
54 | assert!(template.delimiter == None); | 57 | assert!(template.delimiter == None); |
55 | let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() }; | 58 | let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() }; |
56 | let mut arena: Vec<tt::TokenTree> = Vec::new(); | 59 | let mut arena: Vec<tt::TokenTree> = Vec::new(); |
@@ -76,35 +79,35 @@ struct ExpandCtx<'a> { | |||
76 | 79 | ||
77 | fn expand_subtree( | 80 | fn expand_subtree( |
78 | ctx: &mut ExpandCtx, | 81 | ctx: &mut ExpandCtx, |
79 | template: &tt::Subtree, | 82 | template: &MetaTemplate, |
80 | arena: &mut Vec<tt::TokenTree>, | 83 | arena: &mut Vec<tt::TokenTree>, |
81 | ) -> ExpandResult<tt::Subtree> { | 84 | ) -> 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 | 85 | // 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(); | 86 | let start_elements = arena.len(); |
84 | let mut err = None; | 87 | let mut err = None; |
85 | for op in parse_template(template) { | 88 | for op in template.iter() { |
86 | let op = match op { | 89 | let op = match op { |
87 | Ok(op) => op, | 90 | Ok(op) => op, |
88 | Err(e) => { | 91 | Err(e) => { |
89 | err = Some(e); | 92 | err = Some(e.clone()); |
90 | break; | 93 | break; |
91 | } | 94 | } |
92 | }; | 95 | }; |
93 | match op { | 96 | match op { |
94 | Op::TokenTree(tt @ tt::TokenTree::Leaf(..)) => arena.push(tt.clone()), | 97 | Op::Leaf(tt) => arena.push(tt.clone().into()), |
95 | Op::TokenTree(tt::TokenTree::Subtree(tt)) => { | 98 | Op::Subtree(tt) => { |
96 | let ExpandResult { value: tt, err: e } = expand_subtree(ctx, tt, arena); | 99 | let ExpandResult { value: tt, err: e } = expand_subtree(ctx, &tt, arena); |
97 | err = err.or(e); | 100 | err = err.or(e); |
98 | arena.push(tt.into()); | 101 | arena.push(tt.into()); |
99 | } | 102 | } |
100 | Op::Var { name, .. } => { | 103 | Op::Var { name, .. } => { |
101 | let ExpandResult { value: fragment, err: e } = expand_var(ctx, name); | 104 | let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name); |
102 | err = err.or(e); | 105 | err = err.or(e); |
103 | push_fragment(arena, fragment); | 106 | push_fragment(arena, fragment); |
104 | } | 107 | } |
105 | Op::Repeat { subtree, kind, separator } => { | 108 | Op::Repeat { subtree, kind, separator } => { |
106 | let ExpandResult { value: fragment, err: e } = | 109 | let ExpandResult { value: fragment, err: e } = |
107 | expand_repeat(ctx, subtree, kind, separator, arena); | 110 | expand_repeat(ctx, subtree, *kind, separator, arena); |
108 | err = err.or(e); | 111 | err = err.or(e); |
109 | push_fragment(arena, fragment) | 112 | push_fragment(arena, fragment) |
110 | } | 113 | } |
@@ -161,9 +164,9 @@ fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> { | |||
161 | 164 | ||
162 | fn expand_repeat( | 165 | fn expand_repeat( |
163 | ctx: &mut ExpandCtx, | 166 | ctx: &mut ExpandCtx, |
164 | template: &tt::Subtree, | 167 | template: &MetaTemplate, |
165 | kind: RepeatKind, | 168 | kind: RepeatKind, |
166 | separator: Option<Separator>, | 169 | separator: &Option<Separator>, |
167 | arena: &mut Vec<tt::TokenTree>, | 170 | arena: &mut Vec<tt::TokenTree>, |
168 | ) -> ExpandResult<Fragment> { | 171 | ) -> ExpandResult<Fragment> { |
169 | let mut buf: Vec<tt::TokenTree> = Vec::new(); | 172 | let mut buf: Vec<tt::TokenTree> = Vec::new(); |
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index d681905f5..2f3ebc831 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs | |||
@@ -4,16 +4,17 @@ | |||
4 | use smallvec::SmallVec; | 4 | use smallvec::SmallVec; |
5 | use syntax::SmolStr; | 5 | use syntax::SmolStr; |
6 | 6 | ||
7 | use crate::{tt_iter::TtIter, ExpandError}; | 7 | use crate::{tt_iter::TtIter, ExpandError, MetaTemplate}; |
8 | 8 | ||
9 | #[derive(Debug)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
10 | pub(crate) enum Op<'a> { | 10 | pub(crate) enum Op { |
11 | Var { name: &'a SmolStr, kind: Option<&'a SmolStr> }, | 11 | Var { name: SmolStr, kind: Option<SmolStr> }, |
12 | Repeat { subtree: &'a tt::Subtree, kind: RepeatKind, separator: Option<Separator> }, | 12 | Repeat { subtree: MetaTemplate, kind: RepeatKind, separator: Option<Separator> }, |
13 | TokenTree(&'a tt::TokenTree), | 13 | Leaf(tt::Leaf), |
14 | Subtree(MetaTemplate), | ||
14 | } | 15 | } |
15 | 16 | ||
16 | #[derive(Clone, Debug, PartialEq, Eq)] | 17 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
17 | pub(crate) enum RepeatKind { | 18 | pub(crate) enum RepeatKind { |
18 | ZeroOrMore, | 19 | ZeroOrMore, |
19 | OneOrMore, | 20 | OneOrMore, |
@@ -45,16 +46,12 @@ impl PartialEq for Separator { | |||
45 | } | 46 | } |
46 | } | 47 | } |
47 | 48 | ||
48 | pub(crate) fn parse_template( | 49 | pub(crate) fn parse_template(template: &tt::Subtree) -> Vec<Result<Op, ExpandError>> { |
49 | template: &tt::Subtree, | 50 | parse_inner(&template, Mode::Template) |
50 | ) -> impl Iterator<Item = Result<Op<'_>, ExpandError>> { | ||
51 | parse_inner(template, Mode::Template) | ||
52 | } | 51 | } |
53 | 52 | ||
54 | pub(crate) fn parse_pattern( | 53 | pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Vec<Result<Op, ExpandError>> { |
55 | pattern: &tt::Subtree, | 54 | parse_inner(&pattern, Mode::Pattern) |
56 | ) -> impl Iterator<Item = Result<Op<'_>, ExpandError>> { | ||
57 | parse_inner(pattern, Mode::Pattern) | ||
58 | } | 55 | } |
59 | 56 | ||
60 | #[derive(Clone, Copy)] | 57 | #[derive(Clone, Copy)] |
@@ -63,12 +60,13 @@ enum Mode { | |||
63 | Template, | 60 | Template, |
64 | } | 61 | } |
65 | 62 | ||
66 | fn parse_inner(src: &tt::Subtree, mode: Mode) -> impl Iterator<Item = Result<Op<'_>, ExpandError>> { | 63 | fn parse_inner(tt: &tt::Subtree, mode: Mode) -> Vec<Result<Op, ExpandError>> { |
67 | let mut src = TtIter::new(src); | 64 | let mut src = TtIter::new(&tt); |
68 | std::iter::from_fn(move || { | 65 | std::iter::from_fn(move || { |
69 | let first = src.next()?; | 66 | let first = src.next()?; |
70 | Some(next_op(first, &mut src, mode)) | 67 | Some(next_op(first, &mut src, mode)) |
71 | }) | 68 | }) |
69 | .collect() | ||
72 | } | 70 | } |
73 | 71 | ||
74 | macro_rules! err { | 72 | macro_rules! err { |
@@ -83,21 +81,20 @@ macro_rules! bail { | |||
83 | }; | 81 | }; |
84 | } | 82 | } |
85 | 83 | ||
86 | fn next_op<'a>( | 84 | fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Result<Op, ExpandError> { |
87 | first: &'a tt::TokenTree, | ||
88 | src: &mut TtIter<'a>, | ||
89 | mode: Mode, | ||
90 | ) -> Result<Op<'a>, ExpandError> { | ||
91 | let res = match first { | 85 | let res = match first { |
92 | tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '$', .. })) => { | 86 | tt::TokenTree::Leaf(leaf @ tt::Leaf::Punct(tt::Punct { char: '$', .. })) => { |
93 | // Note that the '$' itself is a valid token inside macro_rules. | 87 | // Note that the '$' itself is a valid token inside macro_rules. |
94 | let second = match src.next() { | 88 | let second = match src.next() { |
95 | None => return Ok(Op::TokenTree(first)), | 89 | None => return Ok(Op::Leaf(leaf.clone())), |
96 | Some(it) => it, | 90 | Some(it) => it, |
97 | }; | 91 | }; |
98 | match second { | 92 | match second { |
99 | tt::TokenTree::Subtree(subtree) => { | 93 | tt::TokenTree::Subtree(subtree) => { |
100 | let (separator, kind) = parse_repeat(src)?; | 94 | let (separator, kind) = parse_repeat(src)?; |
95 | let delimiter = subtree.delimiter; | ||
96 | let tokens = parse_inner(&subtree, mode); | ||
97 | let subtree = MetaTemplate { tokens, delimiter }; | ||
101 | Op::Repeat { subtree, separator, kind } | 98 | Op::Repeat { subtree, separator, kind } |
102 | } | 99 | } |
103 | tt::TokenTree::Leaf(leaf) => match leaf { | 100 | tt::TokenTree::Leaf(leaf) => match leaf { |
@@ -107,18 +104,18 @@ fn next_op<'a>( | |||
107 | if punct.char != '_' { | 104 | if punct.char != '_' { |
108 | return Err(ExpandError::UnexpectedToken); | 105 | return Err(ExpandError::UnexpectedToken); |
109 | } | 106 | } |
110 | let name = &UNDERSCORE; | 107 | let name = UNDERSCORE.clone(); |
111 | let kind = eat_fragment_kind(src, mode)?; | 108 | let kind = eat_fragment_kind(src, mode)?; |
112 | Op::Var { name, kind } | 109 | Op::Var { name, kind } |
113 | } | 110 | } |
114 | tt::Leaf::Ident(ident) => { | 111 | tt::Leaf::Ident(ident) => { |
115 | let name = &ident.text; | 112 | let name = ident.text.clone(); |
116 | let kind = eat_fragment_kind(src, mode)?; | 113 | let kind = eat_fragment_kind(src, mode)?; |
117 | Op::Var { name, kind } | 114 | Op::Var { name, kind } |
118 | } | 115 | } |
119 | tt::Leaf::Literal(lit) => { | 116 | tt::Leaf::Literal(lit) => { |
120 | if is_boolean_literal(lit) { | 117 | if is_boolean_literal(&lit) { |
121 | let name = &lit.text; | 118 | let name = lit.text.clone(); |
122 | let kind = eat_fragment_kind(src, mode)?; | 119 | let kind = eat_fragment_kind(src, mode)?; |
123 | Op::Var { name, kind } | 120 | Op::Var { name, kind } |
124 | } else { | 121 | } else { |
@@ -128,19 +125,22 @@ fn next_op<'a>( | |||
128 | }, | 125 | }, |
129 | } | 126 | } |
130 | } | 127 | } |
131 | tt => Op::TokenTree(tt), | 128 | tt::TokenTree::Leaf(tt) => Op::Leaf(tt.clone()), |
129 | tt::TokenTree::Subtree(subtree) => { | ||
130 | let delimiter = subtree.delimiter; | ||
131 | let tokens = parse_inner(&subtree, mode); | ||
132 | let subtree = MetaTemplate { tokens, delimiter }; | ||
133 | Op::Subtree(subtree) | ||
134 | } | ||
132 | }; | 135 | }; |
133 | Ok(res) | 136 | Ok(res) |
134 | } | 137 | } |
135 | 138 | ||
136 | fn eat_fragment_kind<'a>( | 139 | fn eat_fragment_kind<'a>(src: &mut TtIter<'a>, mode: Mode) -> Result<Option<SmolStr>, ExpandError> { |
137 | src: &mut TtIter<'a>, | ||
138 | mode: Mode, | ||
139 | ) -> Result<Option<&'a SmolStr>, ExpandError> { | ||
140 | if let Mode::Pattern = mode { | 140 | if let Mode::Pattern = mode { |
141 | src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?; | 141 | src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?; |
142 | let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?; | 142 | let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?; |
143 | return Ok(Some(&ident.text)); | 143 | return Ok(Some(ident.text.clone())); |
144 | }; | 144 | }; |
145 | Ok(None) | 145 | Ok(None) |
146 | } | 146 | } |