diff options
Diffstat (limited to 'crates/mbe/src/parser.rs')
-rw-r--r-- | crates/mbe/src/parser.rs | 130 |
1 files changed, 104 insertions, 26 deletions
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index f3047972d..8671322e1 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs | |||
@@ -3,15 +3,84 @@ | |||
3 | 3 | ||
4 | use smallvec::SmallVec; | 4 | use smallvec::SmallVec; |
5 | use syntax::SmolStr; | 5 | use syntax::SmolStr; |
6 | use tt::Delimiter; | ||
6 | 7 | ||
7 | use crate::{tt_iter::TtIter, ExpandError, MetaTemplate}; | 8 | use crate::{tt_iter::TtIter, ParseError}; |
9 | |||
10 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
11 | pub(crate) struct MetaTemplate(pub(crate) Vec<Op>); | ||
12 | |||
13 | #[derive(Debug, Clone, Copy)] | ||
14 | pub(crate) enum OpDelimited<'a> { | ||
15 | Op(&'a Op), | ||
16 | Open, | ||
17 | Close, | ||
18 | } | ||
19 | |||
20 | #[derive(Debug, Clone, Copy)] | ||
21 | pub(crate) struct OpDelimitedIter<'a> { | ||
22 | inner: &'a Vec<Op>, | ||
23 | delimited: Option<&'a Delimiter>, | ||
24 | idx: usize, | ||
25 | } | ||
26 | |||
27 | impl<'a> OpDelimitedIter<'a> { | ||
28 | pub(crate) fn is_eof(&self) -> bool { | ||
29 | let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 }; | ||
30 | self.idx >= len | ||
31 | } | ||
32 | |||
33 | pub(crate) fn peek(&self) -> Option<OpDelimited<'a>> { | ||
34 | match self.delimited { | ||
35 | None => self.inner.get(self.idx).map(OpDelimited::Op), | ||
36 | Some(_) => match self.idx { | ||
37 | 0 => Some(OpDelimited::Open), | ||
38 | i if i == self.inner.len() + 1 => Some(OpDelimited::Close), | ||
39 | i => self.inner.get(i - 1).map(OpDelimited::Op), | ||
40 | }, | ||
41 | } | ||
42 | } | ||
43 | |||
44 | pub(crate) fn reset(&self) -> Self { | ||
45 | Self { inner: &self.inner, idx: 0, delimited: self.delimited } | ||
46 | } | ||
47 | } | ||
48 | |||
49 | impl<'a> Iterator for OpDelimitedIter<'a> { | ||
50 | type Item = OpDelimited<'a>; | ||
51 | |||
52 | fn next(&mut self) -> Option<Self::Item> { | ||
53 | let res = self.peek(); | ||
54 | self.idx += 1; | ||
55 | res | ||
56 | } | ||
57 | |||
58 | fn size_hint(&self) -> (usize, Option<usize>) { | ||
59 | let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 }; | ||
60 | let remain = len.checked_sub(self.idx).unwrap_or(0); | ||
61 | (remain, Some(remain)) | ||
62 | } | ||
63 | } | ||
64 | |||
65 | impl<'a> MetaTemplate { | ||
66 | pub(crate) fn iter(&self) -> impl Iterator<Item = &Op> { | ||
67 | self.0.iter() | ||
68 | } | ||
69 | |||
70 | pub(crate) fn iter_delimited( | ||
71 | &'a self, | ||
72 | delimited: Option<&'a Delimiter>, | ||
73 | ) -> OpDelimitedIter<'a> { | ||
74 | OpDelimitedIter { inner: &self.0, idx: 0, delimited } | ||
75 | } | ||
76 | } | ||
8 | 77 | ||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | 78 | #[derive(Clone, Debug, PartialEq, Eq)] |
10 | pub(crate) enum Op { | 79 | pub(crate) enum Op { |
11 | Var { name: SmolStr, kind: Option<SmolStr>, id: tt::TokenId }, | 80 | Var { name: SmolStr, kind: Option<SmolStr>, id: tt::TokenId }, |
12 | Repeat { subtree: MetaTemplate, kind: RepeatKind, separator: Option<Separator> }, | 81 | Repeat { tokens: MetaTemplate, kind: RepeatKind, separator: Option<Separator> }, |
13 | Leaf(tt::Leaf), | 82 | Leaf(tt::Leaf), |
14 | Subtree(MetaTemplate), | 83 | Subtree { tokens: MetaTemplate, delimiter: Option<Delimiter> }, |
15 | } | 84 | } |
16 | 85 | ||
17 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | 86 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
@@ -46,12 +115,22 @@ impl PartialEq for Separator { | |||
46 | } | 115 | } |
47 | } | 116 | } |
48 | 117 | ||
49 | pub(crate) fn parse_template(template: &tt::Subtree) -> Vec<Result<Op, ExpandError>> { | 118 | impl Separator { |
50 | parse_inner(&template, Mode::Template) | 119 | pub(crate) fn tt_count(&self) -> usize { |
120 | match self { | ||
121 | Separator::Literal(_) => 1, | ||
122 | Separator::Ident(_) => 1, | ||
123 | Separator::Puncts(it) => it.len(), | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | |||
128 | pub(crate) fn parse_template(template: &tt::Subtree) -> Result<Vec<Op>, ParseError> { | ||
129 | parse_inner(&template, Mode::Template).into_iter().collect() | ||
51 | } | 130 | } |
52 | 131 | ||
53 | pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Vec<Result<Op, ExpandError>> { | 132 | pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Result<Vec<Op>, ParseError> { |
54 | parse_inner(&pattern, Mode::Pattern) | 133 | parse_inner(&pattern, Mode::Pattern).into_iter().collect() |
55 | } | 134 | } |
56 | 135 | ||
57 | #[derive(Clone, Copy)] | 136 | #[derive(Clone, Copy)] |
@@ -60,7 +139,7 @@ enum Mode { | |||
60 | Template, | 139 | Template, |
61 | } | 140 | } |
62 | 141 | ||
63 | fn parse_inner(tt: &tt::Subtree, mode: Mode) -> Vec<Result<Op, ExpandError>> { | 142 | fn parse_inner(tt: &tt::Subtree, mode: Mode) -> Vec<Result<Op, ParseError>> { |
64 | let mut src = TtIter::new(&tt); | 143 | let mut src = TtIter::new(&tt); |
65 | std::iter::from_fn(move || { | 144 | std::iter::from_fn(move || { |
66 | let first = src.next()?; | 145 | let first = src.next()?; |
@@ -71,7 +150,7 @@ fn parse_inner(tt: &tt::Subtree, mode: Mode) -> Vec<Result<Op, ExpandError>> { | |||
71 | 150 | ||
72 | macro_rules! err { | 151 | macro_rules! err { |
73 | ($($tt:tt)*) => { | 152 | ($($tt:tt)*) => { |
74 | ExpandError::UnexpectedToken | 153 | ParseError::UnexpectedToken(($($tt)*).to_string()) |
75 | }; | 154 | }; |
76 | } | 155 | } |
77 | 156 | ||
@@ -81,7 +160,7 @@ macro_rules! bail { | |||
81 | }; | 160 | }; |
82 | } | 161 | } |
83 | 162 | ||
84 | fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Result<Op, ExpandError> { | 163 | fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Result<Op, ParseError> { |
85 | let res = match first { | 164 | let res = match first { |
86 | tt::TokenTree::Leaf(leaf @ tt::Leaf::Punct(tt::Punct { char: '$', .. })) => { | 165 | tt::TokenTree::Leaf(leaf @ tt::Leaf::Punct(tt::Punct { char: '$', .. })) => { |
87 | // Note that the '$' itself is a valid token inside macro_rules. | 166 | // Note that the '$' itself is a valid token inside macro_rules. |
@@ -92,17 +171,17 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul | |||
92 | match second { | 171 | match second { |
93 | tt::TokenTree::Subtree(subtree) => { | 172 | tt::TokenTree::Subtree(subtree) => { |
94 | let (separator, kind) = parse_repeat(src)?; | 173 | let (separator, kind) = parse_repeat(src)?; |
95 | let delimiter = subtree.delimiter; | 174 | let tokens = parse_inner(&subtree, mode) |
96 | let tokens = parse_inner(&subtree, mode); | 175 | .into_iter() |
97 | let subtree = MetaTemplate { tokens, delimiter }; | 176 | .collect::<Result<Vec<Op>, ParseError>>()?; |
98 | Op::Repeat { subtree, separator, kind } | 177 | Op::Repeat { tokens: MetaTemplate(tokens), separator, kind } |
99 | } | 178 | } |
100 | tt::TokenTree::Leaf(leaf) => match leaf { | 179 | tt::TokenTree::Leaf(leaf) => match leaf { |
101 | tt::Leaf::Punct(punct) => { | 180 | tt::Leaf::Punct(punct) => { |
102 | static UNDERSCORE: SmolStr = SmolStr::new_inline("_"); | 181 | static UNDERSCORE: SmolStr = SmolStr::new_inline("_"); |
103 | 182 | ||
104 | if punct.char != '_' { | 183 | if punct.char != '_' { |
105 | return Err(ExpandError::UnexpectedToken); | 184 | return Err(ParseError::Expected("_".to_string())); |
106 | } | 185 | } |
107 | let name = UNDERSCORE.clone(); | 186 | let name = UNDERSCORE.clone(); |
108 | let kind = eat_fragment_kind(src, mode)?; | 187 | let kind = eat_fragment_kind(src, mode)?; |
@@ -134,16 +213,15 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul | |||
134 | } | 213 | } |
135 | tt::TokenTree::Leaf(tt) => Op::Leaf(tt.clone()), | 214 | tt::TokenTree::Leaf(tt) => Op::Leaf(tt.clone()), |
136 | tt::TokenTree::Subtree(subtree) => { | 215 | tt::TokenTree::Subtree(subtree) => { |
137 | let delimiter = subtree.delimiter; | 216 | let tokens = |
138 | let tokens = parse_inner(&subtree, mode); | 217 | parse_inner(&subtree, mode).into_iter().collect::<Result<Vec<Op>, ParseError>>()?; |
139 | let subtree = MetaTemplate { tokens, delimiter }; | 218 | Op::Subtree { tokens: MetaTemplate(tokens), delimiter: subtree.delimiter } |
140 | Op::Subtree(subtree) | ||
141 | } | 219 | } |
142 | }; | 220 | }; |
143 | Ok(res) | 221 | Ok(res) |
144 | } | 222 | } |
145 | 223 | ||
146 | fn eat_fragment_kind<'a>(src: &mut TtIter<'a>, mode: Mode) -> Result<Option<SmolStr>, ExpandError> { | 224 | fn eat_fragment_kind<'a>(src: &mut TtIter<'a>, mode: Mode) -> Result<Option<SmolStr>, ParseError> { |
147 | if let Mode::Pattern = mode { | 225 | if let Mode::Pattern = mode { |
148 | src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?; | 226 | src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?; |
149 | let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?; | 227 | let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?; |
@@ -156,12 +234,12 @@ fn is_boolean_literal(lit: &tt::Literal) -> bool { | |||
156 | matches!(lit.text.as_str(), "true" | "false") | 234 | matches!(lit.text.as_str(), "true" | "false") |
157 | } | 235 | } |
158 | 236 | ||
159 | fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), ExpandError> { | 237 | fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), ParseError> { |
160 | let mut separator = Separator::Puncts(SmallVec::new()); | 238 | let mut separator = Separator::Puncts(SmallVec::new()); |
161 | for tt in src { | 239 | for tt in src { |
162 | let tt = match tt { | 240 | let tt = match tt { |
163 | tt::TokenTree::Leaf(leaf) => leaf, | 241 | tt::TokenTree::Leaf(leaf) => leaf, |
164 | tt::TokenTree::Subtree(_) => return Err(ExpandError::InvalidRepeat), | 242 | tt::TokenTree::Subtree(_) => return Err(ParseError::InvalidRepeat), |
165 | }; | 243 | }; |
166 | let has_sep = match &separator { | 244 | let has_sep = match &separator { |
167 | Separator::Puncts(puncts) => !puncts.is_empty(), | 245 | Separator::Puncts(puncts) => !puncts.is_empty(), |
@@ -169,7 +247,7 @@ fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), Exp | |||
169 | }; | 247 | }; |
170 | match tt { | 248 | match tt { |
171 | tt::Leaf::Ident(_) | tt::Leaf::Literal(_) if has_sep => { | 249 | tt::Leaf::Ident(_) | tt::Leaf::Literal(_) if has_sep => { |
172 | return Err(ExpandError::InvalidRepeat) | 250 | return Err(ParseError::InvalidRepeat) |
173 | } | 251 | } |
174 | tt::Leaf::Ident(ident) => separator = Separator::Ident(ident.clone()), | 252 | tt::Leaf::Ident(ident) => separator = Separator::Ident(ident.clone()), |
175 | tt::Leaf::Literal(lit) => separator = Separator::Literal(lit.clone()), | 253 | tt::Leaf::Literal(lit) => separator = Separator::Literal(lit.clone()), |
@@ -182,11 +260,11 @@ fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), Exp | |||
182 | match &mut separator { | 260 | match &mut separator { |
183 | Separator::Puncts(puncts) => { | 261 | Separator::Puncts(puncts) => { |
184 | if puncts.len() == 3 { | 262 | if puncts.len() == 3 { |
185 | return Err(ExpandError::InvalidRepeat); | 263 | return Err(ParseError::InvalidRepeat); |
186 | } | 264 | } |
187 | puncts.push(punct.clone()) | 265 | puncts.push(punct.clone()) |
188 | } | 266 | } |
189 | _ => return Err(ExpandError::InvalidRepeat), | 267 | _ => return Err(ParseError::InvalidRepeat), |
190 | } | 268 | } |
191 | continue; | 269 | continue; |
192 | } | 270 | } |
@@ -196,5 +274,5 @@ fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), Exp | |||
196 | } | 274 | } |
197 | } | 275 | } |
198 | } | 276 | } |
199 | Err(ExpandError::InvalidRepeat) | 277 | Err(ParseError::InvalidRepeat) |
200 | } | 278 | } |