1pub use crate::parsers::{
71 alt, empty, lines, map, opt, pair, plus, sequence, single_value, star, RuleParser,
72 RuleSetBuilder,
73};
74
75#[macro_export]
111macro_rules! parser {
112 ($($pattern:tt)*) => { $crate::aoc_parse_helper!( $( $pattern )* ) }
113}
114
115#[macro_export]
116#[doc(hidden)]
117macro_rules! aoc_parse_helper {
118 (@seq [ => $mapper:expr ] [ $($stack:tt)* ] [ $($pats:tt ,)* ]) => {
137 $crate::macros::map(
138 $crate::aoc_parse_helper!(@reverse_map [ $($stack)* ] []),
139 | ( $crate::aoc_parse_helper!(@reverse_pats [ $($pats ,)* ] []) ) | $mapper ,
140 )
141 };
142
143 (@seq [ * ? $($tail:tt)* ] [ $($stack:expr ,)* ] [ $($pats:tt ,)* ]) => {
145 core::compile_error!("non-greedy quantifier `*?` is not supported")
146 };
147
148 (@seq [ + ? $($tail:tt)* ] [ $($stack:expr ,)* ] [ $($pats:tt ,)* ]) => {
150 core::compile_error!("non-greedy quantifier `+?` is not supported")
151 };
152
153 (@seq [ * $($tail:tt)* ] [ $top:expr , $($stack:expr ,)* ] [ $($pats:tt ,)* ]) => {
155 $crate::aoc_parse_helper!(@seq [ $($tail)* ] [ $crate::macros::star($top) , $($stack ,)* ] [ $($pats ,)* ])
156 };
157
158 (@seq [ + $($tail:tt)* ] [ $top:expr , $($stack:expr ,)* ] [ $($pats:tt ,)* ]) => {
160 $crate::aoc_parse_helper!(@seq [ $($tail)* ] [ $crate::macros::plus($top) , $($stack ,)* ] [ $($pats ,)* ])
161 };
162
163 (@seq [ ? $($tail:tt)* ] [ $top:expr , $($stack:tt)* ] [ $($pats:tt ,)* ]) => {
165 $crate::aoc_parse_helper!(@seq [ $($tail)* ] [ $crate::macros::opt($top) , $($stack)* ] [ $($pats ,)* ])
166 };
167
168 (@seq [ * $($tail:tt)* ] [ ] [ $($pats:tt ,)* ]) => {
170 core::compile_error!("quantifier `*` has to come after something, not at the start of an expression.")
171 };
172 (@seq [ + $($tail:tt)* ] [ ] [ $($pats:tt ,)* ]) => {
173 core::compile_error!("quantifier `+` has to come after something, not at the start of an expression.")
174 };
175 (@seq [ ? $($tail:tt)* ] [ ] [ $($pats:tt ,)* ]) => {
176 core::compile_error!("quantifier `?` has to come after something, not at the start of an expression.")
177 };
178
179 (@seq [ $label:ident : => $($tail:tt)* ] [ $($stack:expr ,)* ] [ $($pats:tt ,)* ]) => {
181 core::compile_error!(
182 core::concat!("missing pattern after `", core::stringify!($label), ":`")
183 );
184 };
185 (@seq [ $label:ident : ] [ $($stack:expr ,)* ] [ $($pats:tt ,)* ]) => {
186 core::compile_error!(
187 core::concat!("missing pattern after `", core::stringify!($label), ":`")
188 );
189 };
190 (@seq [ $label1:ident : $label2:ident : $( $tail:tt )* ] [ $($stack:expr ,)* ] [ $($pats:tt ,)* ]) => {
191 core::compile_error!(
192 core::concat!(
193 "missing pattern between `", core::stringify!($label1), ":` and `",
194 core::stringify!($label2), ":`"
195 )
196 );
197 };
198
199 (@seq [ $f:ident ( $($args:tt)* ) $($tail:tt)* ] [ $($stack:expr ,)* ] [ $($pats:tt ,)* ]) => {
201 $crate::aoc_parse_helper!(
202 @seq
203 [ $($tail)* ]
204 [
205 $crate::aoc_parse_helper!(@args ( $f ) [ $( $args )* ] [] ())
206 ,
207 $($stack ,)*
208 ]
209 [ _ , $($pats ,)* ]
210 )
211 };
212
213 (@seq [ $label:ident : $f:ident ( $( $args:tt )* ) $( $tail:tt )* ] [ $($stack:expr ,)* ] [ $($pats:tt ,)* ]) => {
215 $crate::aoc_parse_helper!(
216 @seq
217 [ $($tail)* ]
218 [
219 $crate::aoc_parse_helper!(@args ( $f ) [ $( $args )* ] [] ())
220 ,
221 $($stack ,)*
222 ]
223 [ $label , $($pats ,)* ]
224 )
225 };
226
227 (@seq [ $x:literal $($tail:tt)* ] [ $($stack:expr ,)* ] [ $($pats:tt ,)* ]) => {
230 $crate::aoc_parse_helper!(
231 @seq
232 [ $($tail)* ]
233 [
234 $crate::aoc_parse_helper!(@prim $x) ,
235 $($stack ,)*
236 ]
237 [ _, $($pats ,)* ]
238 )
239 };
240
241 (@seq [ $label:ident : $x:tt $($tail:tt)* ] [ $($stack:expr ,)* ] [ $($pats:tt ,)* ]) => {
243 $crate::aoc_parse_helper!(
244 @seq
245 [ $($tail)* ]
246 [
247 $crate::aoc_parse_helper!(@prim $x) ,
248 $($stack ,)*
249 ]
250 [ $label , $($pats ,)* ]
251 )
252 };
253
254 (@seq [ $x:tt $($tail:tt)* ] [ $($stack:expr ,)* ] [ $($pats:tt ,)* ]) => {
256 $crate::aoc_parse_helper!(
257 @seq
258 [ $($tail)* ]
259 [
260 $crate::aoc_parse_helper!(@prim $x) ,
261 $($stack ,)*
262 ]
263 [ _ , $($pats ,)* ]
264 )
265 };
266
267 (@seq [ ] [ $($parts:expr ,)* ] [ $($pats:tt ,)* ]) => {
269 $crate::aoc_parse_helper!(@reverse [ $($parts ,)* ] [])
270 };
271
272 (@seq [ $($tail:tt)* ] [ $($parts:expr ,)* ] [ $($pats:tt ,)* ]) => {
274 core::compile_error!(stringify!(unrecognized syntax @ $($tail)*))
275 };
276
277 (@reverse [ ] [ ]) => {
281 $crate::macros::empty()
282 };
283 (@reverse [ ] [ $out:expr ]) => {
284 $out
285 };
286 (@reverse [ $head:expr , $($tail:expr ,)* ] [ ]) => {
287 $crate::aoc_parse_helper!(@reverse [ $($tail ,)* ] [ $head ])
288 };
289 (@reverse [ $head:expr , $($tail:expr ,)* ] [ $out:expr ]) => {
290 $crate::aoc_parse_helper!(@reverse [ $($tail ,)* ] [ $crate::macros::sequence($head, $out) ])
291 };
292
293 (@reverse_map [] []) => {
299 $crate::macros::empty()
300 };
301 (@reverse_map [] [ $out:expr ]) => {
302 $out
303 };
304 (@reverse_map [ $head:expr , $( $tail:expr , )* ] []) => {
305 $crate::aoc_parse_helper!(@reverse_map [ $( $tail , )* ] [ $head ])
306 };
307 (@reverse_map [ $head:expr , $( $tail:expr , )* ] [ $out:expr ]) => {
308 $crate::aoc_parse_helper!(
309 @reverse_map
310 [ $( $tail , )* ]
311 [ $crate::macros::pair($head, $out) ]
312 )
313 };
314
315 (@reverse_pats [] []) => {
319 ()
320 };
321 (@reverse_pats [] [ $out:pat ]) => {
322 $out
323 };
324 (@reverse_pats [ $head:pat , $( $tail:pat , )* ] []) => {
325 $crate::aoc_parse_helper!(@reverse_pats [ $( $tail , )* ] [ $head ])
326 };
327 (@reverse_pats [ $head:pat , $( $tail:pat , )* ] [ $out:pat ]) => {
328 $crate::aoc_parse_helper!(@reverse_pats [ $( $tail , )* ] [ ($head, $out) ])
329 };
330
331 (@prim $x:ident) => {
335 $x
336 };
337 (@prim $x:literal) => {
338 $x
339 };
340 (@prim ( $($nested:tt)* )) => {
341 $crate::macros::single_value(
342 $crate::aoc_parse_helper!(@seq [ $( $nested )* ] [ ] [ ])
343 )
344 };
345 (@prim { $($nested:tt)* }) => {
346 $crate::aoc_parse_helper!(@list [ $( $nested )* ] [ ] [ ])
347 };
348
349 (@args ( $f:expr ) [ , $($tail:tt)* ] [ $($seq:tt)* ] ( $( $arg:expr , )* )) => {
355 $crate::aoc_parse_helper!(
356 @args
357 ( $f )
358 [ $( $tail )* ]
359 [ ]
360 (
361 $( $arg , )*
362 $crate::aoc_parse_helper!(@seq [ $( $seq )* ] [ ] [ ]) ,
363 )
364 )
365 };
366
367 (@args ( $f:expr ) [ $next:tt $($tail:tt)* ] [ $($seq:tt)* ] ( $( $out:expr , )* )) => {
369 $crate::aoc_parse_helper!(
370 @args
371 ( $f )
372 [ $( $tail )* ]
373 [ $( $seq )* $next ]
374 ( $( $out , )* )
375 )
376 };
377
378 (@args ( $f:expr ) [] [] ( $( $out:expr , )* )) => {
380 $f ( $( $out , )* )
381 };
382
383 (@args ( $f:expr ) [] [ $($seq:tt)+ ] ( $( $out:expr , )* )) => {
385 $crate::aoc_parse_helper!(@args ( $f ) [,] [ $($seq)+ ] ( $( $out , )* ))
386 };
387
388 (@list [ , $($tail:tt)* ] [ $($seq:tt)* ] [ ]) => {
394 $crate::aoc_parse_helper!(
395 @list
396 [ $( $tail )* ]
397 [ ]
398 [ $crate::aoc_parse_helper!(@seq [ $( $seq )* ] [ ] [ ]) ]
399 )
400 };
401
402 (@list [ , $($tail:tt)* ] [ $($seq:tt)* ] [ $out:expr ]) => {
404 $crate::aoc_parse_helper!(
405 @list
406 [ $( $tail )* ]
407 [ ]
408 [ $crate::macros::alt($out, $crate::aoc_parse_helper!(@seq [ $( $seq )* ] [ ] [ ])) ]
409 )
410 };
411
412 (@list [ $next:tt $($tail:tt)* ] [ $($seq:tt)* ] [ $($out:expr)? ]) => {
414 $crate::aoc_parse_helper!(
415 @list
416 [ $( $tail )* ]
417 [ $( $seq )* $next ]
418 [ $( $out )? ]
419 )
420 };
421
422 (@list [ ] [ ] [ ]) => {
425 ::core::compile_error("no arms in alternation")
426 };
427
428 (@list [ ] [ ] [ $out:expr ]) => {
430 $out
431 };
432
433 (@list [ ] [ $($seq:tt)+ ] [ $( $out:expr )? ]) => {
435 $crate::aoc_parse_helper!(@list [,] [ $($seq)+ ] [ $( $out )? ])
436 };
437
438 (@rules [] ( $( $pattern:tt )* )) => {
444 $crate::parser!(@seq [ $( $pattern )* ] [] [])
445 };
446
447 (@rules
448 [ $( [ rule $name:ident : $output_ty:ty = $( $rule_pat:tt )* ] )+ ]
449 ( $( $pattern:tt )* )
450 ) => {
451 {
452 let mut builder = $crate::macros::RuleSetBuilder::new();
453 $(
454 let $name : $crate::macros::RuleParser<$output_ty> = builder.new_rule();
455 )*
456 $(
457 builder.assign_parser_for_rule(
458 &$name,
459 $crate::parser!(@seq [ $( $rule_pat )* ] [] [])
460 );
461 )*
462 builder.build($crate::parser!(@seq [ $( $pattern )* ] [] []))
463 }
464 };
465
466 (@split_rules [ rule $( $tail:tt )* ] [] [ $( $out:tt )* ]) => {
471 $crate::aoc_parse_helper!(
472 @split_rules
473 [ $( $tail )* ]
474 [ rule ]
475 [ $( $out )* ]
476 )
477 };
478
479 (@split_rules [ $( $tail:tt )+ ] [] [ $( $out:tt )* ]) => {
480 $crate::aoc_parse_helper!(
481 @rules
482 [ $( $out )* ]
483 ( $( $tail )+ )
484 )
485 };
486
487 (@split_rules [ ; $( $tail:tt )* ] [ $( $rule:tt )* ] [ $( $out:tt )* ]) => {
488 $crate::aoc_parse_helper!(
489 @split_rules
490 [ $( $tail )* ]
491 []
492 [ $( $out )* [ $( $rule )* ] ]
493 )
494 };
495
496 (@split_rules [ rule $( $tail:tt )* ] [ $( $rule:tt )+ ] [ $( $out:tt )* ]) => {
497 ::core::compile_error!(stringify!(missing semicolon before: rule $($tail)*))
498 };
499
500 (@split_rules [ $other:tt $( $tail:tt )* ] [ $( $rule:tt )* ] [ $( $out:tt )* ]) => {
501 $crate::aoc_parse_helper!(
502 @split_rules
503 [ $( $tail )* ]
504 [ $( $rule )* $other ]
505 [ $( $out )* ]
506 )
507 };
508
509 (@split_rules [] [] [ $( $out:tt )* ]) => {
510 ::core::compile_error!("missing final pattern (at the end of a rule set, specify which rule is the starting point for parsing)")
511 };
512
513 (@ $($tail:tt)*) => {
515 ::core::compile_error!(stringify!(unrecognized syntax @ $($tail)*))
516 };
517
518 ( $( $tail:tt )* ) => {
520 $crate::macros::single_value(
521 $crate::aoc_parse_helper!(@split_rules [ $($tail)* ] [ ] [ ])
522 )
523 };
524}