1use proc_macro2::Delimiter;
2use proc_macro2::{Group, Ident, Literal, Span, TokenStream, TokenTree};
3use std::collections::{HashMap, HashSet};
4
5use quote::{format_ident, quote, quote_spanned};
6
7pub use self::Expr::*;
8use crate::analysis;
9use crate::ast::*;
10
11pub fn report_error(span: Span, msg: String) -> TokenStream {
12 quote_spanned!(span=>compile_error!(#msg);)
13}
14
15pub fn report_error_expr(span: Span, msg: String) -> TokenStream {
16 quote_spanned!(span=> { compile_error!(#msg); panic!() })
18}
19
20fn group_check_prefix(group: &Group, prefix: char) -> Option<TokenStream> {
22 let mut iter = group.stream().into_iter();
23 match iter.next() {
24 Some(TokenTree::Punct(p)) if p.as_char() == prefix => Some(iter.collect()),
25 _ => None,
26 }
27}
28
29fn extra_args_def(grammar: &Grammar) -> TokenStream {
30 let args: Vec<TokenStream> = grammar
31 .args
32 .iter()
33 .map(|&(ref name, ref tp)| quote!(, #name: #tp))
34 .collect();
35 quote!(#(#args)*)
36}
37
38fn extra_args_call(grammar: &Grammar) -> TokenStream {
39 let args: Vec<TokenStream> = grammar
40 .args
41 .iter()
42 .map(|&(ref name, _)| quote!(, #name))
43 .collect();
44 quote!(#(#args)*)
45}
46
47#[derive(Clone)]
48struct Context<'a> {
49 rules: &'a HashMap<String, &'a Rule>,
50 rules_from_args: HashSet<String>,
51 grammar_lifetime_params: &'a [TokenStream],
52 input_ty: TokenStream,
53 parse_state_ty: TokenStream,
54 extra_args_call: TokenStream,
55 extra_args_def: TokenStream,
56}
57
58pub(crate) fn compile_grammar(grammar: &Grammar) -> TokenStream {
59 let analysis = analysis::check(grammar);
60
61 let grammar_lifetime_params = ty_params_slice(&grammar.lifetime_params);
62
63 let context = &Context {
64 rules: &analysis.rules,
65 rules_from_args: HashSet::new(),
66 grammar_lifetime_params,
67 input_ty: quote!(&'input Input<#(#grammar_lifetime_params),*>),
68 parse_state_ty: quote!(&mut ParseState<'input #(, #grammar_lifetime_params)*>),
69 extra_args_call: extra_args_call(grammar),
70 extra_args_def: extra_args_def(grammar),
71 };
72
73 let mut seen_rule_names = HashSet::new();
74
75 let mut items = vec![];
76 for item in &grammar.items {
77 match item {
78 Item::Use(tt) => items.push(tt.clone()),
79 Item::Rule(rule) => {
80 if !seen_rule_names.insert(rule.name.to_string()) {
81 items.push(report_error(
82 rule.name.span(),
83 format!("duplicate rule `{}`", rule.name),
84 ));
85 continue;
86 }
87
88 if rule.cache.is_some() && !(rule.params.is_empty() && rule.ty_params.is_none()) {
89 items.push(report_error(
90 rule.name.span(),
91 "rules with generics or parameters cannot use #[cache] or #[cache_left_rec]".to_string(),
92 ));
93 continue;
94 }
95
96 if rule.visibility.is_some() {
97 for param in &rule.params {
98 if let RuleParamTy::Rule(..) = ¶m.ty {
99 items.push(report_error(
100 param.name.span(),
101 "parameters on `pub rule` must be Rust types".to_string(),
102 ))
103 }
104 }
105
106 items.push(compile_rule_export(context, rule));
107 } else if rule.no_eof {
108 items.push(report_error(
109 rule.name.span(),
110 "#[no_eof] is only meaningful for `pub rule`".to_string(),
111 ));
112 }
113
114 items.push(compile_rule(context, rule));
115 }
116 }
117 }
118
119 let parse_state = make_parse_state(grammar);
120 let Grammar {
121 name,
122 doc,
123 input_type,
124 visibility,
125 ..
126 } = grammar;
127
128 let mut errors: Vec<TokenStream> = analysis
129 .left_recursion
130 .iter()
131 .map(|rec| report_error(rec.span, rec.msg()))
132 .collect();
133
134 errors.extend(
135 analysis
136 .loop_nullability
137 .iter()
138 .map(|nl| report_error(nl.span, nl.msg())),
139 );
140
141 quote_spanned! { Span::mixed_site() =>
142 #doc
143 #visibility mod #name {
144 #[allow(unused_imports)]
145 use super::*;
146 type Input<#(#grammar_lifetime_params),*> = #input_type;
147 type PositionRepr<#(#grammar_lifetime_params),*> = <Input<#(#grammar_lifetime_params),*> as ::peg::Parse>::PositionRepr;
148
149 #(#errors)*
150 #parse_state
151 #(#items)*
152 }
153 }
154}
155
156fn make_parse_state(grammar: &Grammar) -> TokenStream {
157 let span = Span::mixed_site();
158 let grammar_lifetime_params = ty_params_slice(&grammar.lifetime_params);
159 let mut cache_fields_def: Vec<TokenStream> = Vec::new();
160 let mut cache_fields: Vec<Ident> = Vec::new();
161 for rule in grammar.iter_rules() {
162 if rule.cache.is_some() && rule.params.is_empty() && rule.ty_params.is_none() {
163 let name = format_ident!("{}_cache", rule.name);
164 let ret_ty = rule.ret_type.clone().unwrap_or_else(|| quote!(()));
165 cache_fields_def.push(
166 quote_spanned! { span => #name: ::std::collections::HashMap<usize, ::peg::RuleResult<#ret_ty>> },
167 );
168 cache_fields.push(name);
169 }
170 }
171
172 quote_spanned! { span =>
173 #[allow(unused_parens)]
174 struct ParseState<'input #(, #grammar_lifetime_params)*> {
175 _phantom: ::core::marker::PhantomData<(&'input () #(, &#grammar_lifetime_params ())*)>,
176 #(#cache_fields_def),*
177 }
178
179 impl<'input #(, #grammar_lifetime_params)*> ParseState<'input #(, #grammar_lifetime_params)*> {
180 fn new() -> ParseState<'input #(, #grammar_lifetime_params)*> {
181 ParseState {
182 _phantom: ::core::marker::PhantomData,
183 #(#cache_fields: ::std::collections::HashMap::new()),*
184 }
185 }
186 }
187 }
188}
189
190fn ty_params_slice(ty_params: &Option<Vec<TokenStream>>) -> &[TokenStream] {
191 ty_params.as_ref().map(|x| &x[..]).unwrap_or(&[])
192}
193
194fn rule_params_list(context: &Context, rule: &Rule) -> Vec<TokenStream> {
195 let Context {
196 input_ty,
197 parse_state_ty,
198 ..
199 } = context;
200 let span = rule.span.resolved_at(Span::mixed_site());
201 rule.params.iter().map(|param| {
202 let name = ¶m.name;
203 match ¶m.ty {
204 RuleParamTy::Rust(ty) => quote_spanned!{ span => #name: #ty },
205 RuleParamTy::Rule(ty) => quote_spanned!{ span =>
206 #name: impl Fn(#input_ty, #parse_state_ty, &mut ::peg::error::ErrorState, usize) -> ::peg::RuleResult<#ty>
207 },
208 }
209 }).collect()
210}
211
212fn compile_rule(context: &Context, rule: &Rule) -> TokenStream {
215 let span = rule.span.resolved_at(Span::mixed_site());
216 let name = format_ident!("__parse_{}", rule.name, span = span);
217 let ret_ty = rule.ret_type.clone().unwrap_or_else(|| quote!(()));
218 let ty_params = ty_params_slice(&rule.ty_params);
219 let where_clause = rule.where_clause.as_ref().into_iter();
220
221 let Context {
222 input_ty,
223 parse_state_ty,
224 grammar_lifetime_params,
225 extra_args_def,
226 ..
227 } = context;
228
229 let mut context = context.clone();
230 context
231 .rules_from_args
232 .extend(rule.params.iter().map(|param| param.name.to_string()));
233
234 let body = compile_expr(&context, &rule.expr, rule.ret_type.is_some());
235
236 let wrapped_body = if cfg!(feature = "trace") {
237 let str_rule_name = rule.name.to_string();
238 quote_spanned! { span => {
239 let loc = ::peg::Parse::position_repr(__input, __pos);
240 println!("[PEG_TRACE] Attempting to match rule `{}` at {}", #str_rule_name, loc);
241 let __peg_result: ::peg::RuleResult<#ret_ty> = {#body};
242 match __peg_result {
243 ::peg::RuleResult::Matched(epos, _) => {
244 let eloc = ::peg::Parse::position_repr(__input, epos);
245 println!("[PEG_TRACE] Matched rule `{}` at {} to {}", #str_rule_name, loc, eloc);
246 }
247 ::peg::RuleResult::Failed => {
248 println!("[PEG_TRACE] Failed to match rule `{}` at {}", #str_rule_name, loc);
249 }
250 }
251
252 __peg_result
253 }}
254 } else {
255 body
256 };
257
258 let rule_params = rule_params_list(&context, rule);
259
260 let fn_body = match &rule.cache {
261 None => wrapped_body,
262 Some(cache_type) => {
263 let cache_field = format_ident!("{}_cache", rule.name);
264
265 let cache_trace = if cfg!(feature = "trace") {
266 let str_rule_name = rule.name.to_string();
267 quote_spanned! { span =>
268 let loc = ::peg::Parse::position_repr(__input, __pos);
269 match &entry {
270 &::peg::RuleResult::Matched(..) => println!("[PEG_TRACE] Cached match of rule {} at {}", #str_rule_name, loc),
271 &Failed => println!("[PEG_TRACE] Cached fail of rule {} at {}", #str_rule_name, loc),
272 };
273 }
274 } else {
275 quote!()
276 };
277
278 match cache_type {
279 Cache::Simple => quote_spanned! { span =>
280 if let Some(entry) = __state.#cache_field.get(&__pos) {
281 #cache_trace
282 return entry.clone();
283 }
284
285 let __rule_result = #wrapped_body;
286 __state.#cache_field.insert(__pos, __rule_result.clone());
287 __rule_result
288 },
289 Cache::Recursive =>
290 {
293 quote_spanned! { span =>
294 if let Some(entry) = __state.#cache_field.get(&__pos) {
295 #cache_trace
296 return entry.clone();
297 }
298
299 __state.#cache_field.insert(__pos, ::peg::RuleResult::Failed);
300 let mut __last_result = ::peg::RuleResult::Failed;
301 loop {
302 let __current_result = { #wrapped_body };
303 match __current_result {
304 ::peg::RuleResult::Failed => break,
305 ::peg::RuleResult::Matched(__current_endpos, _) =>
306 match __last_result {
307 ::peg::RuleResult::Matched(__last_endpos, _) if __current_endpos <= __last_endpos => break,
308 _ => {
309 __state.#cache_field.insert(__pos, __current_result.clone());
310 __last_result = __current_result;
311 },
312 }
313 }
314 }
315
316 return __last_result;
317 }
318 }
319 }
320 }
321 };
322
323 quote_spanned! { span =>
324 fn #name<'input #(, #grammar_lifetime_params)* #(, #ty_params)*>(
325 __input: #input_ty,
326 __state: #parse_state_ty,
327 __err_state: &mut ::peg::error::ErrorState,
328 __pos: usize #extra_args_def #(, #rule_params)*,
329 ) -> ::peg::RuleResult<#ret_ty>
330 #(#where_clause)*
331 {
332 #![allow(non_snake_case, unused, clippy::redundant_closure_call)]
333 #fn_body
334 }
335 }
336}
337
338fn compile_rule_export(context: &Context, rule: &Rule) -> TokenStream {
341 let span = rule.span.resolved_at(Span::mixed_site());
342
343 let Rule {
344 doc,
345 name,
346 visibility,
347 ..
348 } = rule;
349 let ret_ty = rule.ret_type.clone().unwrap_or_else(|| quote!(()));
350 let parse_fn = format_ident!("__parse_{}", rule.name, span = name.span());
351 let ty_params = ty_params_slice(&rule.ty_params);
352 let where_clause = rule.where_clause.as_ref().into_iter();
353 let rule_params = rule_params_list(context, rule);
354 let rule_params_call: Vec<TokenStream> = rule
355 .params
356 .iter()
357 .map(|param| {
358 let param_name = ¶m.name;
359 quote!(#param_name)
360 })
361 .collect();
362
363 let Context {
364 input_ty,
365 extra_args_call,
366 extra_args_def,
367 grammar_lifetime_params,
368 ..
369 } = context;
370 let eof_check = if rule.no_eof {
371 quote_spanned! { span => true }
372 } else {
373 quote_spanned! { span => ::peg::Parse::is_eof(__input, __pos) }
374 };
375
376 quote_spanned! { span =>
381 #doc
382 #visibility fn #name<'input #(, #grammar_lifetime_params)* #(, #ty_params)*>(
383 __input: #input_ty #extra_args_def #(, #rule_params)*
384 ) -> ::core::result::Result<
385 #ret_ty,
386 ::peg::error::ParseError<PositionRepr<#(#grammar_lifetime_params),*>>
387 >
388 #(#where_clause)*
389 {
390 #![allow(non_snake_case, unused)]
391
392 let mut __err_state = ::peg::error::ErrorState::new(::peg::Parse::start(__input));
393 let mut __state = ParseState::new();
394 match #parse_fn(__input, &mut __state, &mut __err_state, ::peg::Parse::start(__input) #extra_args_call #(, #rule_params_call)*) {
395 ::peg::RuleResult::Matched(__pos, __value) => {
396 if #eof_check {
397 return Ok(__value)
398 } else {
399 __err_state.mark_failure(__pos, "EOF");
400 }
401 }
402 _ => ()
403 }
404
405 __state = ParseState::new();
406 __err_state.reparse_for_error();
407
408 match #parse_fn(__input, &mut __state, &mut __err_state, ::peg::Parse::start(__input) #extra_args_call #(, #rule_params_call)*) {
409 ::peg::RuleResult::Matched(__pos, __value) => {
410 if #eof_check {
411 panic!("Parser is nondeterministic: succeeded when reparsing for error position");
412 return Ok(__value); } else {
414 __err_state.mark_failure(__pos, "EOF");
415 }
416 }
417 _ => ()
418 }
419
420 Err(__err_state.into_parse_error(__input))
421 }
422 }
423}
424
425fn name_or_ignore(n: Option<&Ident>) -> TokenStream {
426 match n {
427 Some(n) => quote!(#n),
428 None => quote!(_),
429 }
430}
431
432fn ordered_choice(span: Span, mut rs: impl DoubleEndedIterator<Item = TokenStream>) -> TokenStream {
433 rs.next_back().map(|last| rs.rfold(last, |fallback, preferred| {
434 quote_spanned! { span => {
435 let __choice_res = #preferred;
436 match __choice_res {
437 ::peg::RuleResult::Matched(__pos, __value) => ::peg::RuleResult::Matched(__pos, __value),
438 ::peg::RuleResult::Failed => #fallback
439 }
440 }}
441 })).expect("ordered choice must not be empty")
442}
443
444fn labeled_seq(context: &Context, exprs: &[TaggedExpr], inner: TokenStream) -> TokenStream {
445 exprs.iter().rfold(inner, |then, expr| {
446 compile_expr_continuation(context, &expr.expr, expr.name.as_ref(), then)
447 })
448}
449
450fn compile_expr_continuation(
451 context: &Context,
452 e: &SpannedExpr,
453 result_name: Option<&Ident>,
454 continuation: TokenStream,
455) -> TokenStream {
456 let span = e.span.resolved_at(Span::mixed_site());
457
458 let result_pat = name_or_ignore(result_name);
459 match e.expr {
460 LiteralExpr(ref s) => compile_literal_expr(s, continuation),
461
462 PatternExpr(ref pattern) => {
463 let result_name = result_name
464 .cloned()
465 .unwrap_or_else(|| Ident::new("__ch", span));
466 compile_pattern_expr(
467 pattern,
468 result_name,
469 quote_spanned! { span =>
470 { let __pos = __next; { #continuation } }
471 },
472 )
473 }
474
475 _ => {
476 let seq_res = compile_expr(context, e, result_name.is_some());
477 quote_spanned! { span => {
478 let __seq_res = #seq_res;
479 match __seq_res {
480 ::peg::RuleResult::Matched(__pos, #result_pat) => { #continuation }
481 ::peg::RuleResult::Failed => ::peg::RuleResult::Failed,
482 }
483 }}
484 }
485 }
486}
487
488fn compile_literal_expr(s: &Literal, continuation: TokenStream) -> TokenStream {
489 let span = s.span().resolved_at(Span::mixed_site());
490 let escaped_str = s.to_string();
491 quote_spanned! { span =>
492 match ::peg::ParseLiteral::parse_string_literal(__input, __pos, #s) {
493 ::peg::RuleResult::Matched(__pos, __val) => { #continuation }
494 ::peg::RuleResult::Failed => { __err_state.mark_failure(__pos, #escaped_str); ::peg::RuleResult::Failed }
495 }
496 }
497}
498
499fn compile_pattern_expr(
500 pattern_group: &Group,
501 result_name: Ident,
502 success_res: TokenStream,
503) -> TokenStream {
504 let span = pattern_group.span().resolved_at(Span::mixed_site());
505 let pat_str = pattern_group.to_string();
506 let failure_res = quote_spanned! { span => { __err_state.mark_failure(__pos, #pat_str); ::peg::RuleResult::Failed } };
507
508 let (pattern, in_set, not_in_set) =
509 if let Some(pattern) = group_check_prefix(pattern_group, '^') {
510 (pattern, failure_res, success_res)
511 } else {
512 (pattern_group.stream(), success_res, failure_res)
513 };
514
515 let pattern = Group::new(Delimiter::None, pattern);
516
517 quote_spanned! { span =>
518 match ::peg::ParseElem::parse_elem(__input, __pos) {
519 ::peg::RuleResult::Matched(__next, #result_name) => match #result_name {
520 #pattern => #in_set,
521 _ => #not_in_set,
522 }
523 ::peg::RuleResult::Failed => { __err_state.mark_failure(__pos, #pat_str); ::peg::RuleResult::Failed }
524 }
525 }
526}
527
528fn compile_expr(context: &Context, e: &SpannedExpr, result_used: bool) -> TokenStream {
529 let span = e.span.resolved_at(Span::mixed_site());
530
531 match e.expr {
532 LiteralExpr(ref s) => compile_literal_expr(
533 s,
534 quote_spanned! { span =>
535 ::peg::RuleResult::Matched(__pos, __val)
536 },
537 ),
538
539 PatternExpr(ref pattern_group) => {
540 let res_name = Ident::new("__ch", span);
541 let res = if result_used {
542 quote!(#res_name)
543 } else {
544 quote_spanned! { span => () }
545 };
546 compile_pattern_expr(
547 pattern_group,
548 res_name,
549 quote_spanned! { span =>
550 ::peg::RuleResult::Matched(__next, #res)
551 },
552 )
553 }
554
555 RuleExpr(ref rule_name, ref generics, ref rule_args)
556 if context.rules_from_args.contains(&rule_name.to_string()) =>
557 {
558 if !rule_args.is_empty() {
559 return report_error_expr(
560 rule_name.span(),
561 "rule closure does not accept arguments".to_string(),
562 );
563 }
564
565 if generics.is_some() {
566 return report_error_expr(
567 rule_name.span(),
568 "rule closure cannot have generics".to_string()
569 );
570 }
571
572 quote_spanned! { span=> #rule_name(__input, __state, __err_state, __pos) }
573 }
574
575 RuleExpr(ref rule_name, ref generics, ref rule_args) => {
576 let rule_name_str = rule_name.to_string();
577
578 let rule_def = if let Some(rule_def) = context.rules.get(&rule_name_str) {
579 rule_def
580 } else {
581 return report_error_expr(
582 rule_name.span(),
583 format!("undefined rule `{}`", rule_name_str),
584 );
585 };
586
587 if result_used && rule_def.ret_type.is_none() {
588 let msg = format!(
589 "using result of rule `{}`, which does not return a value",
590 rule_name_str
591 );
592 return report_error_expr(rule_name.span(), msg);
593 }
594
595 if rule_def.params.len() != rule_args.len() {
596 return report_error_expr(
597 rule_name.span(),
598 format!(
599 "this rule takes {} parameters but {} parameters were supplied",
600 rule_def.params.len(),
601 rule_args.len()
602 ),
603 );
604 }
605
606 let func = format_ident!("__parse_{}", rule_name, span = rule_name.span());
607 let extra_args_call = &context.extra_args_call;
608
609 let rule_args_call: Vec<TokenStream> = rule_args
610 .iter()
611 .map(|arg| match arg {
612 RuleArg::Peg(e) => {
613 let expr = compile_expr(context, e, true);
614 quote_spanned! { span=> |__input, __state, __err_state, __pos| { #expr } }
615 }
616 RuleArg::Rust(e) => e.clone(),
617 })
618 .collect();
619
620 if result_used {
621 quote_spanned! { span=> #func #generics (__input, __state, __err_state, __pos #extra_args_call #(, #rule_args_call)*) }
622 } else {
623 quote_spanned! { span=>
624 match #func #generics (__input, __state, __err_state, __pos #extra_args_call #(, #rule_args_call)*){
625 ::peg::RuleResult::Matched(pos, _) => ::peg::RuleResult::Matched(pos, ()),
626 ::peg::RuleResult::Failed => ::peg::RuleResult::Failed,
627 }
628 }
629 }
630 }
631
632 MethodExpr(ref method, ref args) => {
633 quote_spanned! { span=> __input.#method(__pos, #args) }
634 }
635
636 CustomExpr(ref code) => {
637 let code = code.stream();
638 quote_spanned! { span=> ::peg::call_custom_closure((#code), __input, __pos) }
639 }
640
641 ChoiceExpr(ref exprs) => ordered_choice(
642 span,
643 exprs
644 .iter()
645 .map(|expr| compile_expr(context, expr, result_used)),
646 ),
647
648 OptionalExpr(ref e) => {
649 let optional_res = compile_expr(context, e, result_used);
650
651 if result_used {
652 quote_spanned! { span=>
653 match #optional_res {
654 ::peg::RuleResult::Matched(__newpos, __value) => { ::peg::RuleResult::Matched(__newpos, Some(__value)) },
655 ::peg::RuleResult::Failed => { ::peg::RuleResult::Matched(__pos, None) },
656 }
657 }
658 } else {
659 quote_spanned! { span=>
660 match #optional_res {
661 ::peg::RuleResult::Matched(__newpos, _) => { ::peg::RuleResult::Matched(__newpos, ()) },
662 ::peg::RuleResult::Failed => { ::peg::RuleResult::Matched(__pos, ()) },
663 }
664 }
665 }
666 }
667
668 Repeat {
669 ref inner,
670 ref bound,
671 ref sep,
672 } => {
673 let inner = compile_expr(context, inner, result_used);
674
675 let (min, max) = match bound {
676 BoundedRepeat::None => (None, None),
677 BoundedRepeat::Plus => (Some(quote!(1)), None),
678 BoundedRepeat::Exact(ref code) => (Some(code.clone()), Some(code.clone())),
679 BoundedRepeat::Both(ref min, ref max) => (min.clone(), max.clone()),
680 };
681
682 let match_sep = if let Some(sep) = sep {
683 let sep_inner = compile_expr(context, sep, false);
684 quote_spanned! { span=>
685 let __pos = if __repeat_value.is_empty() { __pos } else {
686 let __sep_res = #sep_inner;
687 match __sep_res {
688 ::peg::RuleResult::Matched(__newpos, _) => { __newpos },
689 ::peg::RuleResult::Failed => break,
690 }
691 };
692 }
693 } else {
694 quote!()
695 };
696
697 let result = if result_used {
698 quote_spanned! { span=> __repeat_value }
699 } else {
700 quote!(())
701 };
702
703 let (repeat_vec, repeat_step) =
704 if result_used || min.is_some() || max.is_some() || sep.is_some() {
705 (
706 Some(quote_spanned! { span => let mut __repeat_value = vec!(); }),
707 Some(quote_spanned! { span => __repeat_value.push(__value); }),
708 )
709 } else {
710 (None, None)
711 };
712
713 let max_check = max.map(|max| {
714 quote_spanned! { span=> if __repeat_value.len() >= #max { break } }
715 });
716
717 let result_check = if let Some(min) = min {
718 quote_spanned! { span=>
719 if __repeat_value.len() >= #min {
720 ::peg::RuleResult::Matched(__repeat_pos, #result)
721 } else {
722 ::peg::RuleResult::Failed
723 }
724 }
725 } else {
726 quote_spanned! { span=> ::peg::RuleResult::Matched(__repeat_pos, #result) }
727 };
728
729 quote_spanned! { span=> {
730 let mut __repeat_pos = __pos;
731 #repeat_vec
732
733 loop {
734 let __pos = __repeat_pos;
735
736 #match_sep
737 #max_check
738
739 let __step_res = #inner;
740 match __step_res {
741 ::peg::RuleResult::Matched(__newpos, __value) => {
742 __repeat_pos = __newpos;
743 #repeat_step
744 },
745 ::peg::RuleResult::Failed => {
746 break;
747 }
748 }
749 }
750
751 #result_check
752 }}
753 }
754
755 PosAssertExpr(ref e) => {
756 let assert_res = compile_expr(context, e, result_used);
757 quote_spanned! { span=> {
758 __err_state.suppress_fail += 1;
759 let __assert_res = #assert_res;
760 __err_state.suppress_fail -= 1;
761 match __assert_res {
762 ::peg::RuleResult::Matched(_, __value) => ::peg::RuleResult::Matched(__pos, __value),
763 ::peg::RuleResult::Failed => ::peg::RuleResult::Failed,
764 }
765 }}
766 }
767
768 NegAssertExpr(ref e) => {
769 let assert_res = compile_expr(context, e, false);
770 quote_spanned! { span=> {
771 __err_state.suppress_fail += 1;
772 let __assert_res = #assert_res;
773 __err_state.suppress_fail -= 1;
774 match __assert_res {
775 ::peg::RuleResult::Failed => ::peg::RuleResult::Matched(__pos, ()),
776 ::peg::RuleResult::Matched(..) => ::peg::RuleResult::Failed,
777 }
778 }}
779 }
780
781 ActionExpr(ref exprs, ref code) => labeled_seq(context, exprs, {
782 if let Some(code) = code {
783 let code_span = code.span().resolved_at(Span::mixed_site());
784
785 if let Some(body) = group_check_prefix(code, '?') {
787 quote_spanned! {code_span =>
788 match (||{ #body })() {
789 Ok(res) => ::peg::RuleResult::Matched(__pos, res),
790 Err(expected) => {
791 __err_state.mark_failure(__pos, expected);
792 ::peg::RuleResult::Failed
793 },
794 }
795 }
796 } else {
797 quote_spanned! {code_span => ::peg::RuleResult::Matched(__pos, (||#code)()) }
798 }
799 } else {
800 quote_spanned! { span => ::peg::RuleResult::Matched(__pos, ()) }
801 }
802 }),
803 MatchStrExpr(ref expr) => {
804 let inner = compile_expr(context, expr, false);
805 quote_spanned! { span => {
806 let str_start = __pos;
807 match #inner {
808 ::peg::RuleResult::Matched(__newpos, _) => { ::peg::RuleResult::Matched(__newpos, ::peg::ParseSlice::parse_slice(__input, str_start, __newpos)) },
809 ::peg::RuleResult::Failed => ::peg::RuleResult::Failed,
810 }
811 }}
812 }
813 PositionExpr => {
814 quote_spanned! { span => ::peg::RuleResult::Matched(__pos, __pos) }
815 }
816 QuietExpr(ref expr) => {
817 let inner = compile_expr(context, expr, result_used);
818 quote_spanned! { span => {
819 __err_state.suppress_fail += 1;
820 let res = #inner;
821 __err_state.suppress_fail -= 1;
822 res
823 }}
824 }
825 FailExpr(ref expected) => {
826 quote_spanned! { span => { __err_state.mark_failure(__pos, #expected); ::peg::RuleResult::Failed }}
827 }
828
829 PrecedenceExpr { ref levels } => {
830 let mut pre_rules = Vec::new();
831 let mut level_code = Vec::new();
832 let mut span_capture: Option<(TokenStream, TokenStream, TokenStream, &Group)> = None;
833
834 for (prec, level) in levels.iter().enumerate() {
835 let prec = prec as i32;
836
837 let mut post_rules = Vec::new();
838
839 for op in &level.operators {
840 let op_span = op.span.resolved_at(Span::mixed_site());
841
842 if op.elements.is_empty() {
843 return report_error(op_span, "incomplete rule".to_string());
844 }
845
846 let left_arg = &op.elements[0];
847 let l_arg = name_or_ignore(left_arg.name.as_ref());
848
849 let right_arg = &op.elements[op.elements.len() - 1];
850 let r_arg = name_or_ignore(right_arg.name.as_ref());
851
852 let action = &op.action;
853 let action = quote_spanned!(op.action.span()=>(||#action)());
854
855 let action = if let Some((lpos_name, val_name, rpos_name, wrap_action)) =
856 &span_capture
857 {
858 let wrap_action_span = wrap_action.span().resolved_at(Span::mixed_site());
859 quote_spanned!(wrap_action_span => (|#lpos_name, #val_name, #rpos_name|#wrap_action)(__lpos, #action, __pos))
860 } else {
861 action
862 };
863
864 match (&left_arg.expr.expr, &right_arg.expr.expr) {
865 (&PositionExpr, &PositionExpr) if op.elements.len() == 3 => {
866 match &op.elements[1].expr.expr {
868 &MarkerExpr(..) => (),
869 _ => {
870 return report_error(op_span, "span capture rule must be `l:position!() n:@ r:position!()".to_string());
871 }
872 }
873
874 span_capture = Some((
875 name_or_ignore(op.elements[0].name.as_ref()),
876 name_or_ignore(op.elements[1].name.as_ref()),
877 name_or_ignore(op.elements[2].name.as_ref()),
878 &op.action,
879 ));
880 }
881 (&MarkerExpr(la), &MarkerExpr(ra)) if op.elements.len() >= 3 => {
882 let new_prec = match (la, ra) {
884 (true, false) => prec + 1, (false, true) => prec, _ => return report_error(op_span, "precedence rules must use `@` and `(@)` to indicate associativity".to_string())
887 };
888
889 post_rules.push(
890 labeled_seq(context, &op.elements[1..op.elements.len()-1], {
891 quote_spanned!{ op_span =>
892 if let ::peg::RuleResult::Matched(__pos, #r_arg) = __recurse(__pos, #new_prec, __state, __err_state) {
893 let #l_arg = __infix_result;
894 __infix_result = #action;
895 ::peg::RuleResult::Matched(__pos, ())
896 } else { ::peg::RuleResult::Failed }
897 }
898 })
899 );
900 }
901 (&MarkerExpr(_), _) if op.elements.len() >= 2 => {
902 post_rules.push(labeled_seq(
904 context,
905 &op.elements[1..op.elements.len()],
906 {
907 quote_spanned! { op_span =>
908 let #l_arg = __infix_result;
909 __infix_result = #action;
910 ::peg::RuleResult::Matched(__pos, ())
911 }
912 },
913 ));
914 }
915 (_, &MarkerExpr(a)) if op.elements.len() >= 2 => {
916 let new_prec = match a {
918 true => prec,
919 false => prec + 1,
920 };
921 pre_rules.push(
922 labeled_seq(context, &op.elements[..op.elements.len()-1], {
923 quote_spanned!{ op_span =>
924 if let ::peg::RuleResult::Matched(__pos, #r_arg) = __recurse(__pos, #new_prec, __state, __err_state) {
925 ::peg::RuleResult::Matched(__pos, #action)
926 } else { ::peg::RuleResult::Failed }
927 }
928 })
929 );
930 }
931 _ => {
932 pre_rules.push(labeled_seq(context, &op.elements, {
934 quote_spanned! { op_span => ::peg::RuleResult::Matched(__pos, #action) }
935 }));
936 }
937 };
938 }
939
940 if !post_rules.is_empty() {
941 level_code.push(quote_spanned! { span =>
942 if #prec >= __min_prec {
943 #(
944 if let ::peg::RuleResult::Matched(__pos, ()) = #post_rules {
945 return (__infix_result, ::peg::RuleResult::Matched(__pos, ()));
946 }
947 )*
948 }
949 });
950 }
951 }
952
953 let (enter, leave) = if cfg!(feature = "trace") {
954 (
955 quote_spanned! {span => println!("[PEG_TRACE] Entering level {}", min_prec);},
956 quote_spanned! {span => println!("[PEG_TRACE] Leaving level {}", min_prec);},
957 )
958 } else {
959 (quote!(), quote!())
960 };
961
962 quote_spanned! { span => {
966 fn __infix_parse<T, S>(
967 state: &mut S,
968 err_state: &mut ::peg::error::ErrorState,
969 min_prec: i32,
970 lpos: usize,
971 prefix_atom: &dyn Fn(usize, &mut S, &mut ::peg::error::ErrorState, &dyn Fn(usize, i32, &mut S, &mut ::peg::error::ErrorState) -> ::peg::RuleResult<T>) -> ::peg::RuleResult<T>,
972 level_code: &dyn Fn(usize, usize, i32, T, &mut S, &mut ::peg::error::ErrorState, &dyn Fn(usize, i32, &mut S, &mut ::peg::error::ErrorState) -> ::peg::RuleResult<T>) -> (T, ::peg::RuleResult<()>),
973 ) -> ::peg::RuleResult<T> {
974 let initial = {
975 prefix_atom(lpos, state, err_state, &|pos, min_prec, state, err_state| {
976 __infix_parse(state, err_state, min_prec, pos, prefix_atom, level_code)
977 })
978 };
979
980 if let ::peg::RuleResult::Matched(pos, mut infix_result) = initial {
981 #enter
982 let mut repeat_pos = pos;
983 loop {
984 let (val, res) = level_code(
985 repeat_pos,
986 lpos,
987 min_prec,
988 infix_result,
989 state,
990 err_state,
991 &|pos, min_prec, state, err_state| {
992 __infix_parse(state, err_state, min_prec, pos, prefix_atom, level_code)
993 }
994 );
995 infix_result = val;
996
997 if let ::peg::RuleResult::Matched(pos, ()) = res {
998 repeat_pos = pos;
999 continue;
1000 }
1001
1002 break;
1003 }
1004 #leave
1005 ::peg::RuleResult::Matched(repeat_pos, infix_result)
1006 } else {
1007 ::peg::RuleResult::Failed
1008 }
1009 }
1010
1011 __infix_parse(__state, __err_state, 0, __pos,
1012 &|__pos, __state, __err_state, __recurse| {
1013 let __lpos = __pos;
1014 #(
1015 if let ::peg::RuleResult::Matched(__pos, __v) = #pre_rules {
1016 return ::peg::RuleResult::Matched(__pos, __v);
1017 }
1018 )*
1019
1020 ::peg::RuleResult::Failed
1021 },
1022 &|__pos, __lpos, __min_prec, mut __infix_result, __state, __err_state, __recurse| {
1023 #(#level_code)*
1024 (__infix_result, ::peg::RuleResult::Failed)
1025 }
1026 )
1027 }}
1028 }
1029 MarkerExpr { .. } => {
1030 report_error(span, "`@` is only allowed in `precedence!{}`".to_string())
1031 }
1032 }
1033}