diff options
Diffstat (limited to 'crates/mbe/src/parser.rs')
-rw-r--r-- | crates/mbe/src/parser.rs | 68 |
1 files changed, 34 insertions, 34 deletions
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 | } |