1use nom::branch::alt;
52use nom::combinator::map;
53use nom::combinator::opt;
54use nom::error::make_error;
55use nom::error::ErrorKind;
56use nom::multi::many0;
57use nom::Parser;
58use nom::{IResult, Needed};
59use pratt::Affix;
60use pratt::Associativity;
61use pratt::PrattError;
62use pratt::PrattParser;
63use pratt::Precedence;
64use proc_macro2::Group;
65use proc_macro2::Ident;
66use proc_macro2::Literal;
67use proc_macro2::Punct;
68use proc_macro2::Spacing;
69use proc_macro2::Span;
70use proc_macro2::TokenStream;
71use proc_macro2::TokenTree;
72use proc_macro_error2::abort;
73use proc_macro_error2::abort_call_site;
74use proc_macro_error2::proc_macro_error;
75use quote::quote;
76use quote::ToTokens;
77use quote::TokenStreamExt;
78use std::iter::{Cloned, Enumerate};
79use std::ops::Deref;
80use std::slice::Iter;
81use syn::punctuated::Punctuated;
82use syn::Token;
83
84#[proc_macro]
88#[proc_macro_error]
89pub fn rule(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
90 let tokens: TokenStream = tokens.into();
91 let i: Vec<TokenTree> = tokens.into_iter().collect();
92
93 let (i, terminals) = if let Ok((rest, (match_text, _, match_token, _))) =
95 (path, match_punct(','), path, match_punct(',')).parse(Input(&i))
96 {
97 (
98 rest,
99 Some(CustomTerminal {
100 match_text: match_text.1,
101 match_token: match_token.1,
102 }),
103 )
104 } else {
105 (Input(i.as_slice()), None)
106 };
107
108 let terminal = terminals.unwrap_or_else(|| CustomTerminal {
109 match_text: Path {
110 segments: vec![Ident::new("match_text", Span::call_site())],
111 },
112 match_token: Path {
113 segments: vec![Ident::new("match_token", Span::call_site())],
114 },
115 });
116
117 let rule = parse_rule(i.iter().cloned().collect());
118 rule.check_return_type();
119 rule.to_token_stream(&terminal).into()
120}
121
122#[derive(Debug, Clone)]
123struct Path {
124 segments: Vec<Ident>,
125}
126
127#[derive(Debug, Clone)]
128enum Rule {
129 MatchText(Span, Literal),
130 MatchToken(Span, Path),
131 ExternalFunction(Span, Path, Option<Group>),
132 Context(Span, Literal, Box<Rule>),
133 Peek(Span, Box<Rule>),
134 Not(Span, Box<Rule>),
135 Optional(Span, Box<Rule>),
136 Cut(Span, Box<Rule>),
137 Many0(Span, Box<Rule>),
138 Many1(Span, Box<Rule>),
139 Sequence(Span, Vec<Rule>),
140 Choice(Span, Vec<Rule>),
141}
142
143#[derive(Debug, Clone)]
144enum RuleElement {
145 MatchText(Literal),
146 MatchToken(Path),
147 ExternalFunction(Path, Option<Group>),
148 Context(Literal),
149 Peek,
150 Not,
151 Optional,
152 Cut,
153 Many0,
154 Many1,
155 Sequence,
156 Choice,
157 SubRule(Rule),
158}
159
160#[derive(Debug, Clone)]
161struct WithSpan {
162 elem: RuleElement,
163 span: Span,
164}
165
166#[derive(Debug, Clone)]
167enum ReturnType {
168 Option(Box<ReturnType>),
169 Vec(Box<ReturnType>),
170 Unit,
171 Unknown,
172}
173
174struct CustomTerminal {
175 match_text: Path,
176 match_token: Path,
177}
178
179#[derive(Debug, Clone)]
180struct Input<'a>(&'a [TokenTree]);
181
182impl Deref for Input<'_> {
183 type Target = [TokenTree];
184
185 fn deref(&self) -> &Self::Target {
186 self.0
187 }
188}
189
190impl<'a> nom::Input for Input<'a> {
191 type Item = TokenTree;
192 type Iter = Cloned<Iter<'a, TokenTree>>;
193 type IterIndices = Enumerate<Self::Iter>;
194
195 fn input_len(&self) -> usize {
196 self.0.len()
197 }
198
199 fn take(&self, index: usize) -> Self {
200 Input(&self.0[0..index])
201 }
202
203 fn take_from(&self, index: usize) -> Self {
204 Input(&self.0[index..])
205 }
206
207 fn take_split(&self, index: usize) -> (Self, Self) {
208 let (prefix, suffix) = self.0.split_at(index);
209 (Input(suffix), Input(prefix))
210 }
211
212 fn position<P>(&self, predicate: P) -> Option<usize>
213 where
214 P: Fn(Self::Item) -> bool,
215 {
216 self.iter().position(|b| predicate(b.clone()))
217 }
218
219 fn iter_elements(&self) -> Self::Iter {
220 self.0.iter().cloned()
221 }
222
223 fn iter_indices(&self) -> Self::IterIndices {
224 self.iter_elements().enumerate()
225 }
226
227 fn slice_index(&self, count: usize) -> Result<usize, Needed> {
228 if self.len() >= count {
229 Ok(count)
230 } else {
231 Err(Needed::new(count - self.len()))
232 }
233 }
234}
235
236fn match_punct<'a>(punct: char) -> impl FnMut(Input<'a>) -> IResult<Input<'a>, TokenTree> {
237 move |i| match i.first().and_then(|token| match token {
238 TokenTree::Punct(p) if p.as_char() == punct => Some(token.clone()),
239 _ => None,
240 }) {
241 Some(token) => Ok((Input(&i.0[1..]), token)),
242 _ => Err(nom::Err::Error(make_error(i, ErrorKind::Satisfy))),
243 }
244}
245
246fn group(i: Input) -> IResult<Input, Group> {
247 match i.first().and_then(|token| match token {
248 TokenTree::Group(group) => Some(group.clone()),
249 _ => None,
250 }) {
251 Some(group) => Ok((Input(&i.0[1..]), group)),
252 _ => Err(nom::Err::Error(make_error(i, ErrorKind::Satisfy))),
253 }
254}
255
256fn literal(i: Input) -> IResult<Input, Literal> {
257 match i.first().and_then(|token| match token {
258 TokenTree::Literal(lit) => Some(lit.clone()),
259 _ => None,
260 }) {
261 Some(lit) => Ok((Input(&i.0[1..]), lit)),
262 _ => Err(nom::Err::Error(make_error(i, ErrorKind::Satisfy))),
263 }
264}
265
266fn ident(i: Input) -> IResult<Input, Ident> {
267 match i.first().and_then(|token| match token {
268 TokenTree::Ident(ident) => Some(ident.clone()),
269 _ => None,
270 }) {
271 Some(ident) => Ok((Input(&i.0[1..]), ident)),
272 _ => Err(nom::Err::Error(make_error(i, ErrorKind::Satisfy))),
273 }
274}
275
276fn path(i: Input) -> IResult<Input, (Span, Path)> {
277 map(
278 (ident, many0((match_punct(':'), match_punct(':'), ident))),
279 |(head, tail)| {
280 let mut segments = vec![head.clone()];
281 segments.extend(tail.into_iter().map(|(_, _, segment)| segment));
282 let span = segments
283 .iter()
284 .try_fold(head.span(), |span, seg| span.join(seg.span()))
285 .unwrap_or(Span::call_site());
286 (span, Path { segments })
287 },
288 )
289 .parse(i)
290}
291
292fn parse_rule(tokens: TokenStream) -> Rule {
293 let i: Vec<TokenTree> = tokens.into_iter().collect();
294
295 let (i, elems) = many0(parse_rule_element).parse(Input(&i)).unwrap();
296 if !i.is_empty() {
297 let rest: TokenStream = i.iter().cloned().collect();
298 abort!(rest, "unable to parse the following rules: {}", rest);
299 }
300
301 let mut iter = elems.into_iter().peekable();
302 let rule = unwrap_pratt(RuleParser.parse(&mut iter));
303 if iter.peek().is_some() {
304 let rest: Vec<_> = iter.collect();
305 abort!(
306 rest[0].span,
307 "unable to parse the following rules: {:?}",
308 rest
309 );
310 }
311
312 rule
313}
314
315fn parse_rule_element(i: Input) -> IResult<Input, WithSpan> {
316 let function_call = |i| {
317 let (i, hashtag) = match_punct('#')(i)?;
318 let (i, (path_span, fn_path)) = path(i)?;
319 let (i, args) = opt(group).parse(i)?;
320 let span = hashtag.span().join(path_span).unwrap_or(Span::call_site());
321 let span = args
322 .as_ref()
323 .and_then(|args| args.span().join(span))
324 .unwrap_or(span);
325
326 Ok((
327 i,
328 WithSpan {
329 elem: RuleElement::ExternalFunction(fn_path, args),
330 span,
331 },
332 ))
333 };
334 let context = map((match_punct(':'), literal), |(colon, msg)| {
335 let span = colon.span().join(msg.span()).unwrap_or(Span::call_site());
336 WithSpan {
337 elem: RuleElement::Context(msg),
338 span,
339 }
340 });
341 alt((
342 map(match_punct('|'), |token| WithSpan {
343 span: token.span(),
344 elem: RuleElement::Choice,
345 }),
346 map(match_punct('*'), |token| WithSpan {
347 span: token.span(),
348 elem: RuleElement::Many0,
349 }),
350 map(match_punct('+'), |token| WithSpan {
351 span: token.span(),
352 elem: RuleElement::Many1,
353 }),
354 map(match_punct('?'), |token| WithSpan {
355 span: token.span(),
356 elem: RuleElement::Optional,
357 }),
358 map(match_punct('^'), |token| WithSpan {
359 span: token.span(),
360 elem: RuleElement::Cut,
361 }),
362 map(match_punct('&'), |token| WithSpan {
363 span: token.span(),
364 elem: RuleElement::Peek,
365 }),
366 map(match_punct('!'), |token| WithSpan {
367 span: token.span(),
368 elem: RuleElement::Not,
369 }),
370 map(match_punct('~'), |token| WithSpan {
371 span: token.span(),
372 elem: RuleElement::Sequence,
373 }),
374 map(literal, |lit| WithSpan {
375 span: lit.span(),
376 elem: RuleElement::MatchText(lit),
377 }),
378 map(path, |(span, p)| WithSpan {
379 span,
380 elem: RuleElement::MatchToken(p),
381 }),
382 map(group, |group| WithSpan {
383 span: group.span(),
384 elem: RuleElement::SubRule(parse_rule(group.stream())),
385 }),
386 function_call,
387 context,
388 ))
389 .parse(i)
390}
391
392fn unwrap_pratt(res: Result<Rule, PrattError<WithSpan, pratt::NoError>>) -> Rule {
393 match res {
394 Ok(res) => res,
395 Err(PrattError::EmptyInput) => abort_call_site!("expected more tokens for rule"),
396 Err(PrattError::UnexpectedNilfix(input)) => {
397 abort!(input.span, "unable to parse the value")
398 }
399 Err(PrattError::UnexpectedPrefix(input)) => {
400 abort!(input.span, "unable to parse the prefix operator")
401 }
402 Err(PrattError::UnexpectedInfix(input)) => {
403 abort!(input.span, "unable to parse the binary operator")
404 }
405 Err(PrattError::UnexpectedPostfix(input)) => {
406 abort!(input.span, "unable to parse the postfix operator")
407 }
408 Err(PrattError::UserError(_)) => unreachable!(),
409 }
410}
411
412struct RuleParser;
413
414impl<I: Iterator<Item = WithSpan>> PrattParser<I> for RuleParser {
415 type Error = pratt::NoError;
416 type Input = WithSpan;
417 type Output = Rule;
418
419 fn query(&mut self, elem: &WithSpan) -> pratt::Result<Affix> {
420 let affix = match elem.elem {
421 RuleElement::Choice => Affix::Infix(Precedence(1), Associativity::Left),
422 RuleElement::Context(_) => Affix::Postfix(Precedence(2)),
423 RuleElement::Sequence => Affix::Infix(Precedence(3), Associativity::Left),
424 RuleElement::Optional => Affix::Postfix(Precedence(4)),
425 RuleElement::Many1 => Affix::Postfix(Precedence(4)),
426 RuleElement::Many0 => Affix::Postfix(Precedence(4)),
427 RuleElement::Cut => Affix::Prefix(Precedence(5)),
428 RuleElement::Peek => Affix::Prefix(Precedence(5)),
429 RuleElement::Not => Affix::Prefix(Precedence(5)),
430 _ => Affix::Nilfix,
431 };
432 Ok(affix)
433 }
434
435 fn primary(&mut self, elem: WithSpan) -> pratt::Result<Rule> {
436 let rule = match elem.elem {
437 RuleElement::SubRule(rule) => rule,
438 RuleElement::MatchText(text) => Rule::MatchText(elem.span, text),
439 RuleElement::MatchToken(token) => Rule::MatchToken(elem.span, token),
440 RuleElement::ExternalFunction(func, args) => {
441 Rule::ExternalFunction(elem.span, func, args)
442 }
443 _ => unreachable!(),
444 };
445 Ok(rule)
446 }
447
448 fn infix(&mut self, lhs: Rule, elem: WithSpan, rhs: Rule) -> pratt::Result<Rule> {
449 let rule = match elem.elem {
450 RuleElement::Sequence => match lhs {
451 Rule::Sequence(span, mut seq) => {
452 let span = span
453 .join(elem.span)
454 .unwrap_or(Span::call_site())
455 .join(rhs.span())
456 .unwrap_or(Span::call_site());
457 seq.push(rhs);
458 Rule::Sequence(span, seq)
459 }
460 lhs => {
461 let span = lhs.span().join(rhs.span()).unwrap_or(Span::call_site());
462 Rule::Sequence(span, vec![lhs, rhs])
463 }
464 },
465 RuleElement::Choice => match lhs {
466 Rule::Choice(span, mut choices) => {
467 let span = span
468 .join(elem.span)
469 .unwrap_or(Span::call_site())
470 .join(rhs.span())
471 .unwrap_or(Span::call_site());
472 choices.push(rhs);
473 Rule::Choice(span, choices)
474 }
475 lhs => {
476 let span = lhs.span().join(rhs.span()).unwrap_or(Span::call_site());
477 Rule::Choice(span, vec![lhs, rhs])
478 }
479 },
480 _ => unreachable!(),
481 };
482 Ok(rule)
483 }
484
485 fn prefix(&mut self, elem: WithSpan, rhs: Rule) -> pratt::Result<Rule> {
486 let rule = match elem.elem {
487 RuleElement::Cut => {
488 let span = elem.span.join(rhs.span()).unwrap_or(Span::call_site());
489 Rule::Cut(span, Box::new(rhs))
490 }
491 RuleElement::Peek => {
492 let span = elem.span.join(rhs.span()).unwrap_or(Span::call_site());
493 Rule::Peek(span, Box::new(rhs))
494 }
495 RuleElement::Not => {
496 let span = elem.span.join(rhs.span()).unwrap_or(Span::call_site());
497 Rule::Not(span, Box::new(rhs))
498 }
499 _ => unreachable!(),
500 };
501 Ok(rule)
502 }
503
504 fn postfix(&mut self, lhs: Rule, elem: WithSpan) -> pratt::Result<Rule> {
505 let rule = match elem.elem {
506 RuleElement::Optional => {
507 let span = lhs.span().join(elem.span).unwrap_or(Span::call_site());
508 Rule::Optional(span, Box::new(lhs))
509 }
510 RuleElement::Many0 => {
511 let span = lhs.span().join(elem.span).unwrap_or(Span::call_site());
512 Rule::Many0(span, Box::new(lhs))
513 }
514 RuleElement::Many1 => {
515 let span = lhs.span().join(elem.span).unwrap_or(Span::call_site());
516 Rule::Many1(span, Box::new(lhs))
517 }
518 RuleElement::Context(msg) => {
519 let span = lhs.span().join(elem.span).unwrap_or(Span::call_site());
520 Rule::Context(span, msg, Box::new(lhs))
521 }
522 _ => unreachable!(),
523 };
524 Ok(rule)
525 }
526}
527
528impl std::fmt::Display for ReturnType {
529 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
530 match self {
531 ReturnType::Option(ty) => write!(f, "Option<{}>", ty),
532 ReturnType::Vec(ty) => write!(f, "Vec<{}>", ty),
533 ReturnType::Unit => write!(f, "()"),
534 ReturnType::Unknown => write!(f, "_"),
535 }
536 }
537}
538
539impl PartialEq for ReturnType {
540 fn eq(&self, other: &ReturnType) -> bool {
541 match (self, other) {
542 (ReturnType::Option(lhs), ReturnType::Option(rhs)) => lhs == rhs,
543 (ReturnType::Vec(lhs), ReturnType::Vec(rhs)) => lhs == rhs,
544 (ReturnType::Unit, ReturnType::Unit) => true,
545 (ReturnType::Unknown, _) => true,
546 (_, ReturnType::Unknown) => true,
547 _ => false,
548 }
549 }
550}
551
552impl Rule {
553 fn check_return_type(&self) -> ReturnType {
554 match self {
555 Rule::MatchText(_, _) | Rule::MatchToken(_, _) | Rule::ExternalFunction(_, _, _) => {
556 ReturnType::Unknown
557 }
558 Rule::Context(_, _, rule) | Rule::Peek(_, rule) => rule.check_return_type(),
559 Rule::Not(_, _) => ReturnType::Unit,
560 Rule::Optional(_, rule) => ReturnType::Option(Box::new(rule.check_return_type())),
561 Rule::Cut(_, rule) => rule.check_return_type(),
562 Rule::Many0(_, rule) | Rule::Many1(_, rule) => {
563 ReturnType::Vec(Box::new(rule.check_return_type()))
564 }
565 Rule::Sequence(_, rules) => {
566 rules.iter().for_each(|rule| {
567 rule.check_return_type();
568 });
569 ReturnType::Vec(Box::new(ReturnType::Unknown))
570 }
571 Rule::Choice(_, rules) => {
572 for slice in rules.windows(2) {
573 match (slice[0].check_return_type(), slice[1].check_return_type()) {
574 (ReturnType::Option(_), _) => {
575 abort!(
576 slice[0].span(),
577 "optional shouldn't be in a choice because it will shortcut the following branches",
578 )
579 }
580 (a, b) if a != b => abort!(
581 slice[0]
582 .span()
583 .join(slice[1].span())
584 .unwrap_or(Span::call_site()),
585 "type mismatched between {:} and {:}",
586 a,
587 b,
588 ),
589 _ => (),
590 }
591 }
592 ReturnType::Vec(Box::new(rules[0].check_return_type()))
593 }
594 }
595 }
596
597 fn span(&self) -> Span {
598 match self {
599 Rule::MatchText(span, _)
600 | Rule::MatchToken(span, _)
601 | Rule::ExternalFunction(span, _, _)
602 | Rule::Context(span, _, _)
603 | Rule::Peek(span, _)
604 | Rule::Not(span, _)
605 | Rule::Optional(span, _)
606 | Rule::Cut(span, _)
607 | Rule::Many0(span, _)
608 | Rule::Many1(span, _)
609 | Rule::Sequence(span, _)
610 | Rule::Choice(span, _) => *span,
611 }
612 }
613
614 fn to_tokens(&self, terminal: &CustomTerminal, tokens: &mut TokenStream) {
615 let token = match self {
616 Rule::MatchText(_, text) => {
617 let match_text = &terminal.match_text;
618 quote! { #match_text (#text) }
619 }
620 Rule::MatchToken(_, token) => {
621 let match_token = &terminal.match_token;
622 quote! { #match_token (#token) }
623 }
624 Rule::ExternalFunction(_, name, arg) => {
625 quote! { #name #arg }
626 }
627 Rule::Context(_, msg, rule) => {
628 let rule = rule.to_token_stream(terminal);
629 quote! { nom::error::context(#msg, #rule) }
630 }
631 Rule::Peek(_, rule) => {
632 let rule = rule.to_token_stream(terminal);
633 quote! { nom::combinator::peek(#rule) }
634 }
635 Rule::Not(_, rule) => {
636 let rule = rule.to_token_stream(terminal);
637 quote! { nom::combinator::not(#rule) }
638 }
639 Rule::Optional(_, rule) => {
640 let rule = rule.to_token_stream(terminal);
641 quote! { nom::combinator::opt(#rule) }
642 }
643 Rule::Cut(_, rule) => {
644 let rule = rule.to_token_stream(terminal);
645 quote! { nom::combinator::cut(#rule) }
646 }
647 Rule::Many0(_, rule) => {
648 let rule = rule.to_token_stream(terminal);
649 quote! { nom::multi::many0(#rule) }
650 }
651 Rule::Many1(_, rule) => {
652 let rule = rule.to_token_stream(terminal);
653 quote! { nom::multi::many1(#rule) }
654 }
655 Rule::Sequence(_, rules) => {
656 let list: Punctuated<TokenStream, Token![,]> = rules
657 .iter()
658 .map(|rule| rule.to_token_stream(terminal))
659 .collect();
660 quote! { (#list) }
661 }
662 Rule::Choice(_, rules) => {
663 let list: Punctuated<TokenStream, Token![,]> = rules
664 .iter()
665 .map(|rule| rule.to_token_stream(terminal))
666 .collect();
667 quote! { nom::branch::alt((#list)) }
668 }
669 };
670
671 tokens.extend(token);
672 }
673
674 fn to_token_stream(&self, terminal: &CustomTerminal) -> TokenStream {
675 let mut tokens = TokenStream::new();
676 self.to_tokens(terminal, &mut tokens);
677 tokens
678 }
679}
680
681impl ToTokens for Path {
682 fn to_tokens(&self, tokens: &mut TokenStream) {
683 for (i, segment) in self.segments.iter().enumerate() {
684 if i > 0 {
685 tokens.append(Punct::new(':', Spacing::Joint));
687 tokens.append(Punct::new(':', Spacing::Alone));
688 }
689 segment.to_tokens(tokens);
690 }
691 }
692}