1use std::ops::RangeInclusive;
2
3use proc_macro::TokenStream;
4use proc_macro2::Span;
5use quote::quote;
6use recoverable::{recover_enum, recover_struct};
7use syn::{
8 braced, bracketed, parenthesized,
9 parse::{discouraged::Speculative, Parse, ParseStream},
10 parse_macro_input,
11 token::{Brace, Bracket, Paren},
12 Block, DeriveInput, Expr, Ident, LitBool, LitChar, LitStr, Path, Result, Stmt, Token, Type,
13 Visibility,
14};
15
16mod codegen;
17mod display;
18mod recoverable;
19
20mod kw {
21 use syn::custom_keyword;
22
23 custom_keyword!(error);
24 custom_keyword!(context);
25 custom_keyword!(data);
26 custom_keyword!(lookahead_optimization);
27 custom_keyword!(recover);
28}
29
30#[derive(Debug)]
31pub(crate) struct Header {
32 ctx_name: Ident,
33 error_type: Type,
34 data_type: Type,
35 lookahead_optimization: bool,
36 recover: bool,
37}
38
39#[derive(Debug)]
40pub(crate) enum HeaderParam {
41 ContextName(Ident),
42 ErrorType(Type),
43 DataType(Type),
44 LookaheadOptimization(LitBool),
45 Recover(LitBool),
46}
47
48impl Parse for HeaderParam {
49 fn parse(input: ParseStream) -> Result<Self> {
50 if input.parse::<kw::error>().is_ok() {
51 input.parse::<Token![=]>()?;
52 Ok(HeaderParam::ErrorType(input.parse()?))
53 } else if input.parse::<kw::context>().is_ok() {
54 input.parse::<Token![=]>()?;
55 Ok(HeaderParam::ContextName(input.parse()?))
56 } else if input.parse::<kw::data>().is_ok() {
57 input.parse::<Token![=]>()?;
58 Ok(HeaderParam::DataType(input.parse()?))
59 } else if input.parse::<kw::lookahead_optimization>().is_ok() {
60 input.parse::<Token![=]>()?;
61 Ok(HeaderParam::LookaheadOptimization(input.parse()?))
62 } else if input.parse::<kw::recover>().is_ok() {
63 input.parse::<Token![=]>()?;
64 Ok(HeaderParam::Recover(input.parse()?))
65 } else {
66 Err(input.error("expected one of 'error', 'context', 'data', 'lookahead_optimization', or 'recover'"))
67 }
68 }
69}
70
71impl Parse for Header {
72 fn parse(input: ParseStream) -> Result<Self> {
73 let mut ctx_name = Ident::new("__ctx", Span::call_site());
74 let mut error_type = syn::parse(quote! {untwine::ParserError}.into())?;
75 let mut data_type = syn::parse(quote! {()}.into())?;
76 let mut lookahead_optimization = true;
77 let mut recover = false;
78
79 if input.peek(Bracket) {
80 let content;
81 bracketed!(content in input);
82 while !content.is_empty() {
83 let param: HeaderParam = content.parse()?;
84 match param {
85 HeaderParam::ContextName(name) => ctx_name = name,
86 HeaderParam::ErrorType(typ) => error_type = typ,
87 HeaderParam::DataType(typ) => data_type = typ,
88 HeaderParam::LookaheadOptimization(enable) => {
89 lookahead_optimization = enable.value();
90 }
91 HeaderParam::Recover(enable) => recover = enable.value(),
92 }
93 if !content.is_empty() {
94 content.parse::<Token![,]>()?;
95 }
96 }
97 }
98 Ok(Header {
99 ctx_name,
100 error_type,
101 data_type,
102 lookahead_optimization,
103 recover,
104 })
105 }
106}
107
108#[derive(Debug)]
109pub(crate) struct ParserBlock<Stage> {
110 header: Header,
111 parsers: Vec<Stage>,
112}
113
114impl ParserBlock<ParserDef> {
115 fn into_functions(self) -> ParserBlock<ParserFunction> {
116 let functions = self
117 .parsers
118 .into_iter()
119 .flat_map(ParserDef::into_functions)
120 .collect();
121
122 ParserBlock {
123 header: self.header,
124 parsers: functions,
125 }
126 }
127}
128
129impl Parse for ParserBlock<ParserDef> {
130 fn parse(input: ParseStream) -> Result<Self> {
131 let block = ParserBlock {
132 header: input.parse()?,
133 parsers: list(input, false, |i| i.is_empty())?,
134 };
135 Ok(block)
136 }
137}
138
139#[derive(Debug)]
140pub(crate) struct ParserDef {
141 vis: Visibility,
142 name: Ident,
143 patterns: ParserType,
144 return_type: Type,
145}
146
147impl ParserDef {
148 fn into_functions(self) -> Vec<ParserFunction> {
149 match self.patterns {
150 ParserType::Regular(top_level_patterns, block) => vec![ParserFunction {
151 vis: self.vis,
152 error_name: self.name.to_string(),
153 name: self.name,
154 patterns: top_level_patterns,
155 return_type: self.return_type,
156 block,
157 }],
158 ParserType::Match(parser_match) => {
159 parser_match.into_functions(&self.vis, &self.name, &self.return_type)
160 }
161 }
162 }
163}
164
165#[derive(Debug)]
166pub(crate) enum ParserType {
167 Regular(TopLevelPatterns, Block),
168 Match(ParserMatch),
169}
170
171#[derive(Debug)]
172pub(crate) struct ParserMatchArm {
173 patterns: TopLevelPatterns,
174 expr: Expr,
175}
176
177impl Parse for ParserMatchArm {
178 fn parse(input: ParseStream) -> Result<Self> {
179 let patterns = input.parse()?;
180 let _ = input.parse::<Token![=>]>()?;
181 let expr = input.parse()?;
182 Ok(ParserMatchArm { patterns, expr })
183 }
184}
185
186#[derive(Debug)]
187pub(crate) struct ParserMatch {
188 arms: Vec<ParserMatchArm>,
189}
190
191pub(crate) struct ParserFunction {
192 vis: Visibility,
193 name: Ident,
194 error_name: String,
195 patterns: TopLevelPatterns,
196 return_type: Type,
197 block: Block,
198}
199
200impl ParserMatch {
201 fn into_functions(
202 self,
203 vis: &Visibility,
204 parser_name: &Ident,
205 return_type: &Type,
206 ) -> Vec<ParserFunction> {
207 let mut parsers = vec![];
208 let mut names: Vec<Ident> = vec![];
209
210 for (i, arm) in self.arms.into_iter().enumerate() {
211 let name = Ident::new(&format!("__{parser_name}_match_arm_{i}"), Span::call_site());
212 names.push(name.clone());
213
214 let parser = ParserFunction {
215 vis: Visibility::Inherited,
216 error_name: parser_name.to_string(),
217 name,
218 patterns: arm.patterns,
219 return_type: return_type.clone(),
220 block: Block {
221 brace_token: Brace::default(),
222 stmts: vec![Stmt::Expr(arm.expr, None)],
223 },
224 };
225 parsers.push(parser);
226 }
227
228 let choices = names
229 .into_iter()
230 .map(|name| {
231 vec![Pattern {
232 modifier: None,
233 fragment: PatternFragment::ParserRef(name.clone()),
234 }]
235 })
236 .collect();
237
238 let named_rule = ParserFunction {
239 vis: vis.clone(),
240 error_name: parser_name.to_string(),
241 name: parser_name.clone(),
242 patterns: TopLevelPatterns {
243 patterns: vec![LabeledPattern {
244 label: Some(parser_name.clone()),
245 pattern: Pattern {
246 fragment: PatternFragment::Nested(PatternList::Choices(choices)),
247 modifier: None,
248 },
249 }],
250 },
251 return_type: return_type.clone(),
252 block: syn::parse(quote! { { #parser_name } }.into()).unwrap(),
253 };
254 parsers.push(named_rule);
255
256 parsers
257 }
258}
259
260impl Parse for ParserMatch {
261 fn parse(input: ParseStream) -> Result<Self> {
262 input.parse::<Token![match]>()?;
263
264 let block;
265 braced!(block in input);
266
267 let mut arms = vec![];
268
269 if block.is_empty() {
270 return Ok(ParserMatch {
271 arms: vec![syn::parse(
272 quote! { "" => Err(::untwine::error::ParserError::UnexpectedToken.into())? }
273 .into(),
274 )?],
275 });
276 }
277
278 arms.push(block.parse()?);
279 while block.peek(Token![,]) {
280 block.parse::<Token![,]>()?;
281 if !block.is_empty() {
282 arms.push(block.parse()?);
283 }
284 }
285 Ok(ParserMatch { arms })
286 }
287}
288
289fn parse_return_type(input: &ParseStream) -> Result<Type> {
290 if input.parse::<Token![->]>().is_ok() {
291 input.parse()
292 } else {
293 syn::parse::<Type>(quote! {()}.into())
294 }
295}
296
297impl Parse for ParserDef {
298 fn parse(input: ParseStream) -> Result<Self> {
299 let vis = input.parse()?;
300 let name: Ident = input.parse()?;
301 let colon = input
302 .parse::<Token![:]>()
303 .map(|_| true)
304 .or_else(|_| input.parse::<Token![=]>().map(|_| false))?;
305
306 if !colon && input.peek(Token![match]) {
307 let match_stmt: ParserMatch = input.parse()?;
308 let return_type = parse_return_type(&input)?;
309 input.parse::<Token![;]>()?;
310
311 return Ok(ParserDef {
312 vis,
313 name,
314 patterns: ParserType::Match(match_stmt),
315 return_type,
316 });
317 }
318
319 let mut patterns: TopLevelPatterns = input.parse()?;
320 let return_type = parse_return_type(&input)?;
321
322 let block = if colon {
323 input.parse()?
324 } else {
325 input.parse::<Token![;]>()?;
326 if let Some(label) = patterns.patterns.iter().flat_map(|p| p.label.iter()).next() {
327 return Err(syn::Error::new(
328 label.span(),
329 "Cannot use explicit labels here (implicitly captured by = at beginning)",
330 ));
331 }
332
333 let pattern = Pattern {
334 fragment: PatternFragment::Nested(PatternList::List(
335 patterns.patterns.into_iter().map(|p| p.pattern).collect(),
336 )),
337 modifier: None,
338 };
339
340 patterns = TopLevelPatterns {
341 patterns: vec![LabeledPattern {
342 label: Some(name.clone()),
343 pattern,
344 }],
345 };
346
347 syn::parse(quote! {{#name}}.into())?
348 };
349 Ok(ParserDef {
350 vis,
351 name,
352 patterns: ParserType::Regular(patterns, block),
353 return_type,
354 })
355 }
356}
357
358#[derive(Debug, Clone)]
359pub(crate) struct TopLevelPatterns {
360 patterns: Vec<LabeledPattern>,
361}
362
363impl Parse for TopLevelPatterns {
364 fn parse(input: ParseStream) -> Result<Self> {
365 let mut patterns = vec![];
366 while !input.peek(Token![->]) && !input.peek(Token![;]) && !input.peek(Token![=>]) {
367 patterns.push(input.parse()?);
368 }
369 Ok(TopLevelPatterns { patterns })
370 }
371}
372
373#[derive(Debug, Clone)]
374pub(crate) enum PatternFragment {
375 Literal(LitStr),
376 LiteralChar(LitChar),
377 CharRange(CharRange),
378 CharGroup(CharGroup),
379 CharFilter(CharFilter),
380 ParserRef(Ident),
381 Ignore(Box<IgnoredPattern>),
382 Span(PatternList),
383 Nested(PatternList),
384 Annotated(PatternAttribute),
385 AnyChar,
386}
387
388impl Parse for PatternFragment {
389 fn parse(input: ParseStream) -> Result<Self> {
390 if (input.peek(LitChar) && input.peek2(Token![-]) && !input.peek2(Token![->]))
391 || input.peek(Token![^])
392 {
393 input.parse().map(PatternFragment::CharRange)
394 } else if input.peek(LitChar) {
395 input.parse().map(PatternFragment::LiteralChar)
396 } else if input.peek(Bracket) {
397 input.parse().map(PatternFragment::CharGroup)
398 } else if input.peek(Brace) {
399 input.parse().map(PatternFragment::CharFilter)
400 } else if input.peek(LitStr) {
401 input.parse().map(PatternFragment::Literal)
402 } else if input.peek(Paren) {
403 let content;
404 parenthesized!(content in input);
405 content.parse().map(PatternFragment::Nested)
406 } else if input.peek(Token![.]) {
407 input.parse::<Token![.]>()?;
408 Ok(PatternFragment::AnyChar)
409 } else if input.peek(Token![#]) && input.peek2(Bracket) {
410 let fork = input.fork();
411 fork.parse::<Token![#]>()?;
412 let content;
413 bracketed!(content in fork);
414
415 if content.peek(Ident) {
416 Ok(PatternFragment::Annotated(input.parse()?))
417 } else {
418 Ok(PatternFragment::Ignore(Box::new(input.parse()?)))
419 }
420 } else if input.peek(Token![#]) {
421 let ignored: IgnoredPattern = input.parse()?;
422 Ok(PatternFragment::Ignore(Box::new(ignored)))
423 } else if input.peek(Token![<]) {
424 input.parse::<Token![<]>()?;
425 let patterns = input.parse()?;
426 input.parse::<Token![>]>()?;
427 Ok(PatternFragment::Span(patterns))
428 } else if input.peek(Ident) {
429 input.parse().map(PatternFragment::ParserRef)
430 } else {
431 Err(input.error("expected pattern fragment"))
432 }
433 }
434}
435
436#[derive(Debug, Clone)]
437pub(crate) struct Pattern {
438 fragment: PatternFragment,
439 modifier: Option<Modifier>,
440}
441
442impl Parse for Pattern {
443 fn parse(input: ParseStream) -> Result<Self> {
444 Ok(Pattern {
445 fragment: input.parse()?,
446 modifier: optional(input),
447 })
448 }
449}
450
451#[derive(Debug, Clone)]
452pub(crate) struct PatternAttribute {
453 name: Path,
454 args: Vec<Expr>,
455 pattern: Box<Pattern>,
456}
457
458impl Parse for PatternAttribute {
459 fn parse(input: ParseStream) -> Result<Self> {
460 input.parse::<Token![#]>()?;
461 let brackets;
462 bracketed!(brackets in input);
463 let name = brackets.parse()?;
464 let mut args = vec![];
465 if brackets.peek(Paren) {
466 let parens;
467 parenthesized!(parens in brackets);
468 while !parens.is_empty() {
469 args.push(parens.parse()?);
470 if !parens.is_empty() {
471 parens.parse::<Token![,]>()?;
472 }
473 }
474 }
475
476 let pattern = Box::new(input.parse()?);
477
478 Ok(PatternAttribute {
479 name,
480 args,
481 pattern,
482 })
483 }
484}
485
486#[derive(Debug, Clone)]
487pub(crate) struct CharRange {
488 inverted: bool,
489 range: RangeInclusive<char>,
490}
491
492impl Parse for CharRange {
493 fn parse(input: ParseStream) -> Result<Self> {
494 let inverted: Option<Token![^]> = input.parse()?;
495 let begin: LitChar = input.parse()?;
496 input.parse::<Token![-]>()?;
497 let end: LitChar = input.parse()?;
498 Ok(CharRange {
499 inverted: inverted.is_some(),
500 range: begin.value()..=end.value(),
501 })
502 }
503}
504
505#[derive(Debug, Clone)]
506pub(crate) struct CharGroup {
507 inverted: bool,
508 chars: Vec<char>,
509}
510
511impl Parse for CharGroup {
512 fn parse(input: ParseStream) -> Result<Self> {
513 let content;
514 bracketed!(content in input);
515 let inverted: Option<Token![^]> = content.parse()?;
516 let str: LitStr = content.parse()?;
517 if str.value().is_empty() {
518 return Err(syn::Error::new_spanned(
519 str,
520 "Character groups must have at least one character",
521 ));
522 }
523 Ok(CharGroup {
524 inverted: inverted.is_some(),
525 chars: str.value().chars().collect(),
526 })
527 }
528}
529
530#[derive(Debug, Clone)]
531pub(crate) struct CharFilter {
532 expr: Expr,
533}
534
535impl Parse for CharFilter {
536 fn parse(input: ParseStream) -> Result<Self> {
537 let content;
538 braced!(content in input);
539 Ok(CharFilter {
540 expr: content.parse()?,
541 })
542 }
543}
544
545#[derive(Debug, Clone)]
546pub(crate) struct IgnoredPattern {
547 pattern: Pattern,
548}
549
550impl Parse for IgnoredPattern {
551 fn parse(input: ParseStream) -> Result<Self> {
552 input.parse::<Token![#]>()?;
553 let pattern = input.parse()?;
554 Ok(IgnoredPattern { pattern })
555 }
556}
557
558#[derive(Debug, Clone)]
559pub(crate) struct LabeledPattern {
560 label: Option<Ident>,
561 pattern: Pattern,
562}
563
564impl Parse for LabeledPattern {
565 fn parse(input: ParseStream) -> Result<Self> {
566 let mut label = None;
567 if input.peek2(Token![=]) && !input.peek2(Token![=>]) {
568 label = Some(input.parse()?);
569 input.parse::<Token![=]>()?;
570 }
571 let pattern: Pattern = input.parse()?;
572 Ok(LabeledPattern { label, pattern })
573 }
574}
575
576#[derive(Debug, Clone)]
577pub(crate) enum PatternList {
578 List(Vec<Pattern>),
579 Choices(Vec<Vec<Pattern>>),
580}
581
582fn list_terminator(input: ParseStream) -> bool {
583 input.peek(Token![|]) || input.peek(Token![->]) || input.peek(Token![>])
584}
585
586impl Parse for PatternList {
587 fn parse(input: ParseStream) -> Result<Self> {
588 let patterns: Vec<Pattern> = list(input, true, list_terminator)?;
589 if !input.peek(Token![|]) {
590 return Ok(PatternList::List(patterns));
591 }
592 let mut choices: Vec<Vec<Pattern>> = vec![patterns];
593 while input.peek(Token![|]) {
594 input.parse::<Token![|]>()?;
595 choices.push(list(input, true, list_terminator)?);
596 }
597 Ok(PatternList::Choices(choices))
598 }
599}
600
601#[derive(Debug, Clone)]
602pub(crate) enum Modifier {
603 Optional,
604 Repeating,
605 OptionalRepeating,
606 Delimited(PatternFragment),
607 OptionalDelimited(PatternFragment),
608}
609
610impl Parse for Modifier {
611 fn parse(input: ParseStream) -> Result<Self> {
612 if input.parse::<Option<Token![+]>>()?.is_some() {
613 Ok(Modifier::Repeating)
614 } else if input.parse::<Option<Token![?]>>()?.is_some() {
615 Ok(Modifier::Optional)
616 } else if input.parse::<Option<Token![*]>>()?.is_some() {
617 Ok(Modifier::OptionalRepeating)
618 } else if input.parse::<Option<Token![$]>>()?.is_some() {
619 let fragment = input.parse()?;
620 if input.peek(Token![+]) {
621 input.parse::<Token![+]>()?;
622 Ok(Modifier::Delimited(fragment))
623 } else {
624 input.parse::<Token![*]>()?;
625 Ok(Modifier::OptionalDelimited(fragment))
626 }
627 } else {
628 Err(input.error("expected modifier"))
629 }
630 }
631}
632
633fn list<T: Parse>(
634 input: ParseStream,
635 require: bool,
636 terminator: fn(ParseStream) -> bool,
637) -> Result<Vec<T>> {
638 let mut vec = vec![];
639 while (require && vec.is_empty()) || (!input.is_empty() && !terminator(input)) {
640 vec.push(input.parse()?);
641 }
642 Ok(vec)
643}
644
645fn optional<T: Parse>(input: ParseStream) -> Option<T> {
646 let fork = input.fork();
647 match fork.parse() {
648 Ok(val) => {
649 input.advance_to(&fork);
650 Some(val)
651 }
652 Err(_) => None,
653 }
654}
655
656#[proc_macro]
774pub fn parser(input: TokenStream) -> TokenStream {
775 let block: ParserBlock<ParserDef> = parse_macro_input!(input as ParserBlock<ParserDef>);
776
777 match codegen::generate_parser_block(block) {
778 Ok(stream) => stream.into(),
779 Err(err) => err.to_compile_error().into(),
780 }
781}
782
783#[proc_macro_derive(Recoverable, attributes(recover))]
784pub fn recovery(input: TokenStream) -> TokenStream {
785 let derive_input = parse_macro_input!(input as DeriveInput);
786 match derive_input.data {
787 syn::Data::Struct(data) => {
788 recover_struct(&data, &derive_input.ident, &derive_input.generics)
789 }
790 syn::Data::Enum(data) => recover_enum(&data, &derive_input.ident, &derive_input.generics)
791 .unwrap_or_else(|e| e.to_compile_error()),
792 syn::Data::Union(_) => panic!("Cannot derive Recoverable on unions"),
793 }
794 .into()
795}