1#![allow(clippy::derive_partial_eq_without_eq)]
2use std::{
3 error::Error,
4 fmt::{self, Debug, Display, Write as _},
5 hash::Hash,
6 marker::PhantomData,
7 vec,
8};
9
10#[cfg(not(target_arch = "wasm32"))]
12use std::time::{Duration, Instant};
13#[cfg(target_arch = "wasm32")]
14use web_time::{Duration, Instant};
15
16use cactus::Cactus;
17use cfgrammar::{
18 RIdx, Span, TIdx,
19 header::{HeaderError, HeaderErrorKind, Value},
20 span::Location,
21 yacc::YaccGrammar,
22};
23use lrtable::{Action, StIdx, StateTable};
24use num_traits::{AsPrimitive, PrimInt, Unsigned};
25use proc_macro2::TokenStream;
26use quote::quote;
27#[cfg(feature = "serde")]
28use serde::{Deserialize, Serialize};
29
30use crate::{LexError, Lexeme, LexerTypes, NonStreamingLexer, cpctplus};
31
32#[cfg(test)]
33const RECOVERY_TIME_BUDGET: u64 = 60_000; #[cfg(not(test))]
35const RECOVERY_TIME_BUDGET: u64 = 500; #[deprecated(
38 since = "0.14.0",
39 note = "Use the version of `Node` exported from your `lrpar_mod!`"
40)]
41pub type Node<T, S> = _deprecated_moved_::Node<T, S>;
42
43#[doc(hidden)]
44pub mod _deprecated_moved_ {
45 use super::*;
46 #[derive(Debug, Clone, PartialEq)]
48 pub enum Node<LexemeT: Lexeme<StorageT>, StorageT> {
49 Term { lexeme: LexemeT },
51 Nonterm {
53 ridx: RIdx<StorageT>,
54 nodes: Vec<Node<LexemeT, StorageT>>,
55 },
56 }
57}
58
59#[allow(deprecated)]
60impl<LexemeT: Lexeme<StorageT>, StorageT: 'static + PrimInt + Unsigned> Node<LexemeT, StorageT>
61where
62 usize: AsPrimitive<StorageT>,
63{
64 pub fn pp(&self, grm: &YaccGrammar<StorageT>, input: &str) -> String {
66 let mut st = vec![(0, self)]; let mut s = String::new();
68 while let Some((indent, e)) = st.pop() {
69 for _ in 0..indent {
70 s.push(' ');
71 }
72 match *e {
73 Node::Term { lexeme } => {
74 let tidx = TIdx(lexeme.tok_id());
75 let tn = grm.token_name(tidx).unwrap();
76 let lt = &input[lexeme.span().start()..lexeme.span().end()];
77 writeln!(s, "{} {}", tn, lt).ok();
78 }
79 Node::Nonterm { ridx, ref nodes } => {
80 writeln!(s, "{}", grm.rule_name_str(ridx)).ok();
81 for x in nodes.iter().rev() {
82 st.push((indent + 1, x));
83 }
84 }
85 }
86 }
87 s
88 }
89}
90
91type PStack<StorageT> = Vec<StIdx<StorageT>>; type TokenCostFn<'a, StorageT> = &'a (dyn Fn(TIdx<StorageT>) -> u8 + 'a);
93type ActionFn<'a, 'b, 'input, StorageT, LexerTypesT, ActionT, ParamT> = &'a dyn Fn(
94 RIdx<StorageT>,
95 &'b dyn NonStreamingLexer<'input, LexerTypesT>,
96 Span,
97 vec::Drain<AStackType<<LexerTypesT as LexerTypes>::LexemeT, ActionT>>,
98 ParamT,
99) -> ActionT;
100
101#[derive(Debug)]
102pub enum AStackType<LexemeT, ActionT> {
103 ActionType(ActionT),
104 Lexeme(LexemeT),
105}
106
107pub(super) struct Parser<
108 'a,
109 'b: 'a,
110 'input: 'b,
111 StorageT: 'static + Eq + Hash + PrimInt + Unsigned,
112 LexerTypesT: LexerTypes<StorageT = StorageT>,
113 ActionT: 'a,
114 ParamT: Clone,
115> where
116 usize: AsPrimitive<StorageT>,
117{
118 rcvry_kind: RecoveryKind,
119 pub(super) grm: &'a YaccGrammar<StorageT>,
120 pub(super) token_cost: TokenCostFn<'a, StorageT>,
121 pub(super) stable: &'a StateTable<StorageT>,
122 lexer: &'b dyn NonStreamingLexer<'input, LexerTypesT>,
123 pub(super) lexemes: Vec<LexerTypesT::LexemeT>,
126 actions: &'a [ActionFn<'a, 'b, 'input, LexerTypesT::StorageT, LexerTypesT, ActionT, ParamT>],
127 param: ParamT,
128}
129
130impl<
131 'a,
132 'b: 'a,
133 'input: 'b,
134 StorageT: 'static + Debug + Hash + PrimInt + Unsigned,
135 LexerTypesT: LexerTypes<StorageT = StorageT>,
136 Node,
137>
138 Parser<
139 'a,
140 'b,
141 'input,
142 StorageT,
143 LexerTypesT,
144 Node,
145 (
146 &dyn Fn(LexerTypesT::LexemeT) -> Node,
147 &dyn Fn(RIdx<StorageT>, Vec<Node>) -> Node,
148 ),
149 >
150where
151 usize: AsPrimitive<StorageT>,
152{
153 fn parse_map(
154 rcvry_kind: RecoveryKind,
155 grm: &YaccGrammar<StorageT>,
156 token_cost: TokenCostFn<'a, StorageT>,
157 stable: &StateTable<StorageT>,
158 lexer: &'b dyn NonStreamingLexer<'input, LexerTypesT>,
159 lexemes: Vec<LexerTypesT::LexemeT>,
160 fterm: &'a dyn Fn(LexerTypesT::LexemeT) -> Node,
161 fnonterm: &'a dyn Fn(RIdx<StorageT>, Vec<Node>) -> Node,
162 ) -> (Option<Node>, Vec<LexParseError<StorageT, LexerTypesT>>) {
163 for tidx in grm.iter_tidxs() {
164 assert!(token_cost(tidx) > 0);
165 }
166 let mut actions: Vec<
167 ActionFn<
168 'a,
169 'b,
170 'input,
171 StorageT,
172 LexerTypesT,
173 Node,
174 (
175 &'a dyn Fn(LexerTypesT::LexemeT) -> Node,
176 &'a dyn Fn(RIdx<StorageT>, Vec<Node>) -> Node,
177 ),
178 >,
179 > = Vec::new();
180 actions.resize(usize::from(grm.prods_len()), &action_map);
181 let psr = Parser {
182 rcvry_kind,
183 grm,
184 token_cost,
185 stable,
186 lexer,
187 lexemes,
188 actions: actions.as_slice(),
189 param: (fterm, fnonterm),
190 };
191 let mut pstack = vec![stable.start_state()];
192 let mut astack = Vec::new();
193 let mut errors = Vec::new();
194 let mut spans = Vec::new();
195 let accpt = psr.lr(0, &mut pstack, &mut astack, &mut errors, &mut spans);
196 (accpt, errors)
197 }
198}
199
200fn action_map<StorageT, LexerTypesT: LexerTypes, Node>(
201 ridx: RIdx<StorageT>,
202 _lexer: &dyn NonStreamingLexer<LexerTypesT>,
203 _span: Span,
204 astack: vec::Drain<AStackType<LexerTypesT::LexemeT, Node>>,
205 param: (
206 &dyn Fn(LexerTypesT::LexemeT) -> Node,
207 &dyn Fn(RIdx<StorageT>, Vec<Node>) -> Node,
208 ),
209) -> Node
210where
211 usize: AsPrimitive<LexerTypesT::StorageT>,
212 LexerTypesT::LexemeT: Lexeme<StorageT>,
213{
214 let (fterm, fnonterm) = param;
215 let mut nodes = Vec::with_capacity(astack.len());
216 for a in astack {
217 nodes.push(match a {
218 AStackType::ActionType(n) => n,
219 AStackType::Lexeme(lexeme) => fterm(lexeme),
220 });
221 }
222 fnonterm(ridx, nodes)
223}
224
225#[deprecated(
226 since = "0.14.0",
227 note = "Deprecated with `parse_generictree` there is no direct replacement, besides a custom action"
228)]
229#[allow(deprecated)]
230pub fn action_generictree<StorageT, LexerTypesT: LexerTypes>(
234 ridx: RIdx<StorageT>,
235 _lexer: &dyn NonStreamingLexer<LexerTypesT>,
236 _span: Span,
237 astack: vec::Drain<AStackType<LexerTypesT::LexemeT, Node<LexerTypesT::LexemeT, StorageT>>>,
238 _param: (),
239) -> Node<LexerTypesT::LexemeT, StorageT>
240where
241 usize: AsPrimitive<LexerTypesT::StorageT>,
242 LexerTypesT::LexemeT: Lexeme<StorageT>,
243{
244 let mut nodes = Vec::with_capacity(astack.len());
245 for a in astack {
246 nodes.push(match a {
247 AStackType::ActionType(n) => n,
248 AStackType::Lexeme(lexeme) => Node::Term { lexeme },
249 });
250 }
251 Node::Nonterm { ridx, nodes }
252}
253
254impl<
255 'a,
256 'b: 'a,
257 'input: 'b,
258 StorageT: 'static + Debug + Eq + Hash + PrimInt + Unsigned,
259 LexerTypesT: LexerTypes<StorageT = StorageT>,
260 ActionT: 'a,
261 ParamT: Clone,
262> Parser<'a, 'b, 'input, StorageT, LexerTypesT, ActionT, ParamT>
263where
264 usize: AsPrimitive<StorageT>,
265{
266 fn parse_actions(
267 rcvry_kind: RecoveryKind,
268 grm: &'a YaccGrammar<StorageT>,
269 token_cost: TokenCostFn<'a, StorageT>,
270 stable: &'a StateTable<StorageT>,
271 lexer: &'b dyn NonStreamingLexer<'input, LexerTypesT>,
272 lexemes: Vec<LexerTypesT::LexemeT>,
273 actions: &'a [ActionFn<'a, 'b, 'input, StorageT, LexerTypesT, ActionT, ParamT>],
274 param: ParamT,
275 ) -> (Option<ActionT>, Vec<LexParseError<StorageT, LexerTypesT>>) {
276 for tidx in grm.iter_tidxs() {
277 assert!(token_cost(tidx) > 0);
278 }
279 let psr = Parser {
280 rcvry_kind,
281 grm,
282 token_cost,
283 stable,
284 lexer,
285 lexemes,
286 actions,
287 param,
288 };
289 let mut pstack = vec![stable.start_state()];
290 let mut astack = Vec::new();
291 let mut errors = Vec::new();
292 let mut spans = Vec::new();
293 let accpt = psr.lr(0, &mut pstack, &mut astack, &mut errors, &mut spans);
294 (accpt, errors)
295 }
296
297 fn lr(
311 &self,
312 mut laidx: usize,
313 pstack: &mut PStack<StorageT>,
314 astack: &mut Vec<AStackType<LexerTypesT::LexemeT, ActionT>>,
315 errors: &mut Vec<LexParseError<StorageT, LexerTypesT>>,
316 spans: &mut Vec<Span>,
317 ) -> Option<ActionT> {
318 let mut recoverer = None;
319 let mut recovery_budget = Duration::from_millis(RECOVERY_TIME_BUDGET);
320 loop {
321 debug_assert_eq!(astack.len(), spans.len());
322 let stidx = *pstack.last().unwrap();
323 let la_tidx = self.next_tidx(laidx);
324
325 match self.stable.action(stidx, la_tidx) {
326 Action::Reduce(pidx) => {
327 let ridx = self.grm.prod_to_rule(pidx);
328 let pop_idx = pstack.len() - self.grm.prod(pidx).len();
329
330 pstack.drain(pop_idx..);
331 let prior = *pstack.last().unwrap();
332 pstack.push(self.stable.goto(prior, ridx).unwrap());
333
334 let span = if spans.is_empty() {
335 Span::new(0, 0)
336 } else if pop_idx - 1 < spans.len() {
337 Span::new(spans[pop_idx - 1].start(), spans[spans.len() - 1].end())
338 } else {
339 Span::new(spans[spans.len() - 1].start(), spans[spans.len() - 1].end())
340 };
341 spans.truncate(pop_idx - 1);
342 spans.push(span);
343
344 let v = AStackType::ActionType(self.actions[usize::from(pidx)](
345 ridx,
346 self.lexer,
347 span,
348 astack.drain(pop_idx - 1..),
349 self.param.clone(),
350 ));
351 astack.push(v);
352 }
353 Action::Shift(state_id) => {
354 let la_lexeme = self.next_lexeme(laidx);
355 pstack.push(state_id);
356 astack.push(AStackType::Lexeme(la_lexeme));
357
358 spans.push(la_lexeme.span());
359 laidx += 1;
360 }
361 Action::Accept => {
362 debug_assert_eq!(la_tidx, self.grm.eof_token_idx());
363 debug_assert_eq!(astack.len(), 1);
364 match astack.drain(..).next().unwrap() {
365 AStackType::ActionType(v) => return Some(v),
366 _ => unreachable!(),
367 }
368 }
369 Action::Error => {
370 if recoverer.is_none() {
371 recoverer = Some(match self.rcvry_kind {
372 RecoveryKind::CPCTPlus => cpctplus::recoverer(self),
373 RecoveryKind::None => {
374 let la_lexeme = self.next_lexeme(laidx);
375 errors.push(
376 ParseError {
377 stidx,
378 lexeme: la_lexeme,
379 repairs: vec![],
380 }
381 .into(),
382 );
383 return None;
384 }
385 });
386 }
387
388 let before = Instant::now();
389 let finish_by = before + recovery_budget;
390 let (new_laidx, repairs) = recoverer
391 .as_ref()
392 .unwrap()
393 .as_ref()
394 .recover(finish_by, self, laidx, pstack, astack, spans);
395 let after = Instant::now();
396 recovery_budget = recovery_budget
397 .checked_sub(after - before)
398 .unwrap_or_else(|| Duration::new(0, 0));
399 let keep_going = !repairs.is_empty();
400 let la_lexeme = self.next_lexeme(laidx);
401 errors.push(
402 ParseError {
403 stidx,
404 lexeme: la_lexeme,
405 repairs,
406 }
407 .into(),
408 );
409 if !keep_going {
410 return None;
411 }
412 laidx = new_laidx;
413 }
414 }
415 }
416 }
417
418 pub(super) fn lr_upto(
423 &self,
424 lexeme_prefix: Option<LexerTypesT::LexemeT>,
425 mut laidx: usize,
426 end_laidx: usize,
427 pstack: &mut PStack<StorageT>,
428 astack: &mut Option<&mut Vec<AStackType<LexerTypesT::LexemeT, ActionT>>>,
429 spans: &mut Option<&mut Vec<Span>>,
430 ) -> usize {
431 assert!(lexeme_prefix.is_none() || end_laidx == laidx + 1);
432 while laidx != end_laidx && laidx <= self.lexemes.len() {
433 let stidx = *pstack.last().unwrap();
434 let la_tidx = if let Some(l) = lexeme_prefix {
435 TIdx(l.tok_id())
436 } else {
437 self.next_tidx(laidx)
438 };
439
440 match self.stable.action(stidx, la_tidx) {
441 Action::Reduce(pidx) => {
442 let ridx = self.grm.prod_to_rule(pidx);
443 let pop_idx = pstack.len() - self.grm.prod(pidx).len();
444 if let Some(ref mut astack_uw) = *astack {
445 if let Some(ref mut spans_uw) = *spans {
446 let span = if spans_uw.is_empty() {
447 Span::new(0, 0)
448 } else if pop_idx - 1 < spans_uw.len() {
449 Span::new(
450 spans_uw[pop_idx - 1].start(),
451 spans_uw[spans_uw.len() - 1].end(),
452 )
453 } else {
454 Span::new(
455 spans_uw[spans_uw.len() - 1].start(),
456 spans_uw[spans_uw.len() - 1].end(),
457 )
458 };
459 spans_uw.truncate(pop_idx - 1);
460 spans_uw.push(span);
461
462 let v = AStackType::ActionType(self.actions[usize::from(pidx)](
463 ridx,
464 self.lexer,
465 span,
466 astack_uw.drain(pop_idx - 1..),
467 self.param.clone(),
468 ));
469 astack_uw.push(v);
470 } else {
471 unreachable!();
472 }
473 }
474
475 pstack.drain(pop_idx..);
476 let prior = *pstack.last().unwrap();
477 pstack.push(self.stable.goto(prior, ridx).unwrap());
478 }
479 Action::Shift(state_id) => {
480 if let Some(ref mut astack_uw) = *astack
481 && let Some(spans_uw) = spans
482 {
483 let la_lexeme = if let Some(l) = lexeme_prefix {
484 l
485 } else {
486 self.next_lexeme(laidx)
487 };
488 astack_uw.push(AStackType::Lexeme(la_lexeme));
489 spans_uw.push(la_lexeme.span());
490 }
491 pstack.push(state_id);
492 laidx += 1;
493 }
494 Action::Accept => {
495 break;
496 }
497 Action::Error => {
498 break;
499 }
500 }
501 }
502 laidx
503 }
504
505 pub(super) fn next_lexeme(&self, laidx: usize) -> LexerTypesT::LexemeT {
508 let llen = self.lexemes.len();
509 debug_assert!(laidx <= llen);
510 if laidx < llen {
511 self.lexemes[laidx]
512 } else {
513 let last_la_end = if llen == 0 {
515 0
516 } else {
517 debug_assert!(laidx > 0);
518 let last_la = self.lexemes[laidx - 1];
519 last_la.span().end()
520 };
521
522 Lexeme::new_faulty(
523 StorageT::from(u32::from(self.grm.eof_token_idx())).unwrap(),
524 last_la_end,
525 0,
526 )
527 }
528 }
529
530 pub(super) fn next_tidx(&self, laidx: usize) -> TIdx<StorageT> {
533 let ll = self.lexemes.len();
534 debug_assert!(laidx <= ll);
535 if laidx < ll {
536 TIdx(self.lexemes[laidx].tok_id())
537 } else {
538 self.grm.eof_token_idx()
539 }
540 }
541
542 #[allow(deprecated)]
550 pub(super) fn lr_cactus(
551 &self,
552 lexeme_prefix: Option<LexerTypesT::LexemeT>,
553 mut laidx: usize,
554 end_laidx: usize,
555 mut pstack: Cactus<StIdx<StorageT>>,
556 tstack: &mut Option<&mut Vec<Node<LexerTypesT::LexemeT, StorageT>>>,
557 ) -> (usize, Cactus<StIdx<StorageT>>) {
558 assert!(lexeme_prefix.is_none() || end_laidx == laidx + 1);
559 while laidx != end_laidx {
560 let stidx = *pstack.val().unwrap();
561 let la_tidx = if let Some(l) = lexeme_prefix {
562 TIdx(l.tok_id())
563 } else {
564 self.next_tidx(laidx)
565 };
566
567 match self.stable.action(stidx, la_tidx) {
568 Action::Reduce(pidx) => {
569 let ridx = self.grm.prod_to_rule(pidx);
570 let pop_num = self.grm.prod(pidx).len();
571 if let Some(ref mut tstack_uw) = *tstack {
572 let nodes = tstack_uw
573 .drain(pstack.len() - pop_num - 1..)
574 .collect::<Vec<Node<LexerTypesT::LexemeT, StorageT>>>();
575 tstack_uw.push(Node::Nonterm { ridx, nodes });
576 }
577
578 for _ in 0..pop_num {
579 pstack = pstack.parent().unwrap();
580 }
581 let prior = *pstack.val().unwrap();
582 pstack = pstack.child(self.stable.goto(prior, ridx).unwrap());
583 }
584 Action::Shift(state_id) => {
585 if let Some(ref mut tstack_uw) = *tstack {
586 let la_lexeme = if let Some(l) = lexeme_prefix {
587 l
588 } else {
589 self.next_lexeme(laidx)
590 };
591 tstack_uw.push(Node::Term { lexeme: la_lexeme });
592 }
593 pstack = pstack.child(state_id);
594 laidx += 1;
595 }
596 Action::Accept => {
597 debug_assert_eq!(la_tidx, self.grm.eof_token_idx());
598 if let Some(ref tstack_uw) = *tstack {
599 debug_assert_eq!(tstack_uw.len(), 1);
600 }
601 break;
602 }
603 Action::Error => {
604 break;
605 }
606 }
607 }
608 (laidx, pstack)
609 }
610}
611
612pub(super) trait Recoverer<
613 StorageT: 'static + Debug + Hash + PrimInt + Unsigned,
614 LexerTypesT: LexerTypes<StorageT = StorageT>,
615 ActionT,
616 ParamT: Clone,
617> where
618 usize: AsPrimitive<StorageT>,
619{
620 fn recover(
621 &self,
622 finish_by: Instant,
623 parser: &Parser<StorageT, LexerTypesT, ActionT, ParamT>,
624 in_laidx: usize,
625 in_pstack: &mut PStack<StorageT>,
626 astack: &mut Vec<AStackType<LexerTypesT::LexemeT, ActionT>>,
627 spans: &mut Vec<Span>,
628 ) -> (usize, Vec<Vec<ParseRepair<LexerTypesT::LexemeT, StorageT>>>);
629}
630
631#[derive(Clone, Copy, Debug)]
633#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
634#[non_exhaustive]
635pub enum RecoveryKind {
636 CPCTPlus,
639 None,
641}
642
643impl TryFrom<RecoveryKind> for Value<Location> {
644 type Error = cfgrammar::header::HeaderError<Location>;
645 fn try_from(rk: RecoveryKind) -> Result<Value<Location>, Self::Error> {
646 let from_loc = Location::Other("From<RecoveryKind>".to_string());
647 Ok(Value::Namespaced(format!("RecoveryKind::{rk:?}"), from_loc))
648 }
649}
650
651impl TryFrom<&Value<Location>> for RecoveryKind {
652 type Error = cfgrammar::header::HeaderError<Location>;
653 fn try_from(rk: &Value<Location>) -> Result<RecoveryKind, Self::Error> {
654 match rk {
655 Value::Namespaced(rs, loc) => match rs.as_str() {
656 "RecoveryKind::CPCTPlus" | "CPCTPlus" => Ok(RecoveryKind::CPCTPlus),
657 "RecoveryKind::None" | "None" => Ok(RecoveryKind::None),
658 _ => Err(HeaderError {
659 kind: HeaderErrorKind::ConversionError(
660 "RecoveryKind",
661 "Cannot convert to RecoveryKind",
662 ),
663 locations: vec![loc.clone()],
664 }),
665 },
666 value => Err(HeaderError {
667 kind: HeaderErrorKind::ConversionError(
668 "RecoveryKind",
669 "Cannot convert to RecoveryKind",
670 ),
671 locations: vec![value.primary_location().clone()],
672 }),
673 }
674 }
675}
676
677impl quote::ToTokens for RecoveryKind {
678 fn to_tokens(&self, tokens: &mut TokenStream) {
679 tokens.extend(match *self {
680 RecoveryKind::CPCTPlus => quote!(::lrpar::RecoveryKind::CPCTPlus),
681 RecoveryKind::None => quote!(::lrpar::RecoveryKind::None),
682 })
683 }
684}
685
686#[derive(Debug)]
690pub enum LexParseError<
691 StorageT: 'static + Debug + Hash + PrimInt + Unsigned,
692 LexerTypesT: LexerTypes<StorageT = StorageT>,
693> where
694 usize: AsPrimitive<StorageT>,
695{
696 LexError(LexerTypesT::LexErrorT),
697 ParseError(ParseError<LexerTypesT::LexemeT, StorageT>),
698}
699
700impl<StorageT: Debug + Hash + PrimInt + Unsigned, LexerTypesT: LexerTypes<StorageT = StorageT>>
701 LexParseError<StorageT, LexerTypesT>
702where
703 usize: AsPrimitive<StorageT>,
704{
705 pub fn pp<'a>(
722 &self,
723 lexer: &dyn NonStreamingLexer<LexerTypesT>,
724 epp: &dyn Fn(TIdx<StorageT>) -> Option<&'a str>,
725 ) -> String {
726 match self {
727 LexParseError::LexError(e) => {
728 let ((line, col), _) = lexer.line_col(e.span());
729 format!("Lexing error at line {} column {}.", line, col)
730 }
731 LexParseError::ParseError(e) => {
732 let ((line, col), _) = lexer.line_col(e.lexeme().span());
733 let mut out = format!("Parsing error at line {} column {}.", line, col);
734 let repairs_len = e.repairs().len();
735 if repairs_len == 0 {
736 out.push_str(" No repair sequences found.");
737 } else {
738 out.push_str(" Repair sequences found:");
739 for (i, rs) in e.repairs().iter().enumerate() {
740 let padding = ((repairs_len as f64).log10() as usize)
741 - (((i + 1) as f64).log10() as usize)
742 + 1;
743 write!(out, "\n {}{}: ", " ".repeat(padding), i + 1).ok();
744 let mut rs_out = Vec::new();
745
746 let mut i = 0;
749 while i < rs.len() {
750 match rs[i] {
751 ParseRepair::Delete(l) => {
752 let mut j = i + 1;
753 let mut last_end = l.span().end();
754 while j < rs.len() {
755 if let ParseRepair::Delete(next_l) = rs[j]
756 && next_l.span().start() == last_end
757 {
758 last_end = next_l.span().end();
759 j += 1;
760 continue;
761 }
762 break;
763 }
764 let t = &lexer
765 .span_str(Span::new(l.span().start(), last_end))
766 .replace('\n', "\\n");
767 rs_out.push(format!("Delete {}", t));
768 i = j;
769 }
770 ParseRepair::Insert(tidx) => {
771 rs_out.push(format!("Insert {}", epp(tidx).unwrap()));
772 i += 1;
773 }
774 ParseRepair::Shift(l) => {
775 let t = &lexer.span_str(l.span()).replace('\n', "\\n");
776 rs_out.push(format!("Shift {}", t));
777 i += 1;
778 }
779 }
780 }
781
782 out.push_str(&rs_out.join(", "));
783 }
784 }
785 out
786 }
787 }
788 }
789}
790
791impl<
792 StorageT: 'static + Debug + Hash + PrimInt + Unsigned,
793 LexerTypesT: LexerTypes<StorageT = StorageT>,
794> fmt::Display for LexParseError<StorageT, LexerTypesT>
795where
796 usize: AsPrimitive<StorageT>,
797{
798 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
799 match *self {
800 LexParseError::LexError(ref e) => Display::fmt(e, f),
801 LexParseError::ParseError(ref e) => Display::fmt(e, f),
802 }
803 }
804}
805
806impl<
807 StorageT: 'static + Debug + Hash + PrimInt + Unsigned,
808 LexerTypesT: LexerTypes<StorageT = StorageT>,
809> Error for LexParseError<StorageT, LexerTypesT>
810where
811 usize: AsPrimitive<StorageT>,
812{
813}
814
815impl<
816 StorageT: 'static + Debug + Hash + PrimInt + Unsigned,
817 LexerTypesT: LexerTypes<StorageT = StorageT, LexErrorT = T>,
818 T: LexError,
819> From<T> for LexParseError<StorageT, LexerTypesT>
820where
821 usize: AsPrimitive<StorageT>,
822{
823 fn from(err: T) -> LexParseError<StorageT, LexerTypesT> {
824 LexParseError::LexError(err)
825 }
826}
827
828impl<
829 StorageT: 'static + Debug + Hash + PrimInt + Unsigned,
830 LexerTypesT: LexerTypes<StorageT = StorageT>,
831> From<ParseError<LexerTypesT::LexemeT, StorageT>> for LexParseError<StorageT, LexerTypesT>
832where
833 usize: AsPrimitive<StorageT>,
834{
835 fn from(
836 err: ParseError<LexerTypesT::LexemeT, StorageT>,
837 ) -> LexParseError<StorageT, LexerTypesT> {
838 LexParseError::ParseError(err)
839 }
840}
841
842pub struct RTParserBuilder<
844 'a,
845 StorageT: 'static + Eq + Debug + Hash + PrimInt + Unsigned,
846 LexerTypesT: LexerTypes<StorageT = StorageT>,
847> where
848 usize: AsPrimitive<StorageT>,
849{
850 grm: &'a YaccGrammar<StorageT>,
851 stable: &'a StateTable<StorageT>,
852 recoverer: RecoveryKind,
853 term_costs: &'a dyn Fn(TIdx<StorageT>) -> u8,
854 phantom: PhantomData<(StorageT, LexerTypesT)>,
855}
856
857impl<
858 'a,
859 StorageT: 'static + Debug + Hash + PrimInt + Unsigned,
860 LexerTypesT: LexerTypes<StorageT = StorageT>,
861> RTParserBuilder<'a, StorageT, LexerTypesT>
862where
863 usize: AsPrimitive<StorageT>,
864{
865 pub fn new(grm: &'a YaccGrammar<StorageT>, stable: &'a StateTable<StorageT>) -> Self {
867 RTParserBuilder {
868 grm,
869 stable,
870 recoverer: RecoveryKind::CPCTPlus,
871 term_costs: &|_| 1,
872 phantom: PhantomData,
873 }
874 }
875
876 pub fn recoverer(mut self, rk: RecoveryKind) -> Self {
878 self.recoverer = rk;
879 self
880 }
881
882 pub fn term_costs(mut self, f: &'a dyn Fn(TIdx<StorageT>) -> u8) -> Self {
883 self.term_costs = f;
884 self
885 }
886
887 #[deprecated(
888 since = "0.14.0",
889 note = "Use `parse_map` to return a `Node` from your `lrpar_mod!` instead"
890 )]
891 #[allow(deprecated)]
892 pub fn parse_generictree(
895 &self,
896 lexer: &dyn NonStreamingLexer<LexerTypesT>,
897 ) -> (
898 Option<Node<LexerTypesT::LexemeT, StorageT>>,
899 Vec<LexParseError<StorageT, LexerTypesT>>,
900 ) {
901 self.parse_map(lexer, &|lexeme| Node::Term { lexeme }, &|ridx, nodes| {
902 Node::Nonterm { ridx, nodes }
903 })
904 }
905
906 pub fn parse_map<Node>(
909 &self,
910 lexer: &dyn NonStreamingLexer<LexerTypesT>,
911 fterm: &dyn Fn(LexerTypesT::LexemeT) -> Node,
912 fnonterm: &dyn Fn(RIdx<StorageT>, Vec<Node>) -> Node,
913 ) -> (Option<Node>, Vec<LexParseError<StorageT, LexerTypesT>>) {
914 let lexemes = match lexer.iter().collect() {
915 Ok(lexemes) => lexemes,
916 Err(e) => return (None, vec![e.into()]),
917 };
918 Parser::<
919 StorageT,
920 LexerTypesT,
921 Node,
922 (
923 &dyn Fn(LexerTypesT::LexemeT) -> Node,
924 &dyn Fn(RIdx<StorageT>, Vec<Node>) -> Node,
925 ),
926 >::parse_map(
927 self.recoverer,
928 self.grm,
929 self.term_costs,
930 self.stable,
931 lexer,
932 lexemes,
933 fterm,
934 fnonterm,
935 )
936 }
937
938 #[deprecated(since = "0.14.0", note = "Use `parse_map` instead")]
939 pub fn parse_noaction(
942 &self,
943 lexer: &dyn NonStreamingLexer<LexerTypesT>,
944 ) -> Vec<LexParseError<StorageT, LexerTypesT>> {
945 self.parse_map(lexer, &|_| (), &|_, _| ()).1
946 }
947
948 pub fn parse_actions<'b: 'a, 'input: 'b, ActionT: 'a, ParamT: Clone>(
955 &self,
956 lexer: &'b dyn NonStreamingLexer<'input, LexerTypesT>,
957 actions: &'a [ActionFn<'a, 'b, 'input, StorageT, LexerTypesT, ActionT, ParamT>],
958 param: ParamT,
959 ) -> (Option<ActionT>, Vec<LexParseError<StorageT, LexerTypesT>>) {
960 let lexemes = match lexer.iter().collect() {
961 Ok(lexemes) => lexemes,
962 Err(e) => return (None, vec![e.into()]),
963 };
964 Parser::parse_actions(
965 self.recoverer,
966 self.grm,
967 self.term_costs,
968 self.stable,
969 lexer,
970 lexemes,
971 actions,
972 param,
973 )
974 }
975
976 pub fn grammar(&self) -> &YaccGrammar<StorageT> {
977 self.grm
978 }
979}
980
981#[derive(Clone, Debug, Eq, Hash, PartialEq)]
984pub enum ParseRepair<LexemeT: Lexeme<StorageT>, StorageT: Hash> {
985 Insert(TIdx<StorageT>),
987 Delete(LexemeT),
989 Shift(LexemeT),
991}
992
993#[derive(Clone, Debug, PartialEq)]
995pub struct ParseError<LexemeT: Lexeme<StorageT>, StorageT: Hash> {
996 stidx: StIdx<StorageT>,
997 lexeme: LexemeT,
998 repairs: Vec<Vec<ParseRepair<LexemeT, StorageT>>>,
999}
1000
1001impl<LexemeT: Lexeme<StorageT>, StorageT: Debug + Hash> Display for ParseError<LexemeT, StorageT> {
1002 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1003 write!(f, "Parse error at lexeme {:?}", self.lexeme)
1004 }
1005}
1006
1007impl<LexemeT: Lexeme<StorageT>, StorageT: Debug + Hash> Error for ParseError<LexemeT, StorageT> {}
1008
1009impl<LexemeT: Lexeme<StorageT>, StorageT: Hash + PrimInt + Unsigned> ParseError<LexemeT, StorageT> {
1010 pub fn stidx(&self) -> StIdx<StorageT> {
1012 self.stidx
1013 }
1014
1015 pub fn lexeme(&self) -> &LexemeT {
1017 &self.lexeme
1018 }
1019
1020 pub fn repairs(&self) -> &Vec<Vec<ParseRepair<LexemeT, StorageT>>> {
1023 &self.repairs
1024 }
1025}
1026
1027#[cfg(test)]
1028pub(crate) mod test {
1029 use std::collections::HashMap;
1030
1031 use cfgrammar::{
1032 Span,
1033 yacc::{YaccGrammar, YaccKind, YaccOriginalActionKind},
1034 };
1035 use lrtable::{Minimiser, from_yacc};
1036 use num_traits::ToPrimitive;
1037 use regex::Regex;
1038
1039 use super::*;
1040 use crate::{
1041 Lexeme, Lexer,
1042 test_utils::{TestLexError, TestLexeme, TestLexerTypes},
1043 };
1044
1045 #[allow(deprecated)]
1046 pub(crate) fn do_parse<'input>(
1047 rcvry_kind: RecoveryKind,
1048 lexs: &str,
1049 grms: &str,
1050 input: &'input str,
1051 ) -> (
1052 YaccGrammar<u16>,
1053 SmallLexer<'input>,
1054 Result<
1055 Node<TestLexeme, u16>,
1056 (
1057 Option<Node<TestLexeme, u16>>,
1058 Vec<LexParseError<u16, TestLexerTypes>>,
1059 ),
1060 >,
1061 ) {
1062 do_parse_with_costs(rcvry_kind, lexs, grms, input, &HashMap::new())
1063 }
1064
1065 #[allow(deprecated)]
1066 fn do_parse_with_costs<'input>(
1067 rcvry_kind: RecoveryKind,
1068 lexs: &str,
1069 grms: &str,
1070 input: &'input str,
1071 costs: &HashMap<&str, u8>,
1072 ) -> (
1073 YaccGrammar<u16>,
1074 SmallLexer<'input>,
1075 Result<
1076 Node<TestLexeme, u16>,
1077 (
1078 Option<Node<TestLexeme, u16>>,
1079 Vec<LexParseError<u16, TestLexerTypes>>,
1080 ),
1081 >,
1082 ) {
1083 let grm = YaccGrammar::<u16>::new_with_storaget(
1084 YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
1085 grms,
1086 )
1087 .unwrap();
1088 let (_, stable) = from_yacc(&grm, Minimiser::Pager).unwrap();
1089 let rule_ids = grm
1090 .tokens_map()
1091 .iter()
1092 .map(|(&n, &i)| (n.to_owned(), u32::from(i).to_u16().unwrap()))
1093 .collect();
1094 let lexer_rules = small_lexer(lexs, rule_ids);
1095 let lexemes = small_lex(lexer_rules, input);
1096 let lexer = SmallLexer { lexemes, s: input };
1097 let costs_tidx = costs
1098 .iter()
1099 .map(|(k, v)| (grm.token_idx(k).unwrap(), v))
1100 .collect::<HashMap<_, _>>();
1101 let (r, errs) = RTParserBuilder::new(&grm, &stable)
1102 .recoverer(rcvry_kind)
1103 .term_costs(&|tidx| **costs_tidx.get(&tidx).unwrap_or(&&1))
1104 .parse_generictree(&lexer);
1105 if let Some(node) = r {
1106 if errs.is_empty() {
1107 (grm, lexer, Ok(node))
1108 } else {
1109 (grm, lexer, Err((Some(node), errs)))
1110 }
1111 } else {
1112 (grm, lexer, Err((None, errs)))
1113 }
1114 }
1115
1116 fn check_parse_output(lexs: &str, grms: &str, input: &str, expected: &str) {
1117 let (grm, _, pt) = do_parse(RecoveryKind::CPCTPlus, lexs, grms, input);
1118 assert_eq!(expected, pt.unwrap().pp(&grm, input));
1119 }
1120
1121 pub(crate) struct SmallLexer<'input> {
1126 lexemes: Vec<TestLexeme>,
1127 s: &'input str,
1128 }
1129
1130 impl Lexer<TestLexerTypes> for SmallLexer<'_> {
1131 fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = Result<TestLexeme, TestLexError>> + 'a> {
1132 Box::new(self.lexemes.iter().map(|x| Ok(*x)))
1133 }
1134 }
1135
1136 impl<'input> NonStreamingLexer<'input, TestLexerTypes> for SmallLexer<'input> {
1137 fn span_str(&self, span: Span) -> &'input str {
1138 &self.s[span.start()..span.end()]
1139 }
1140
1141 fn span_lines_str(&self, _: Span) -> &'input str {
1142 unreachable!();
1143 }
1144
1145 fn line_col(&self, _: Span) -> ((usize, usize), (usize, usize)) {
1146 unreachable!();
1147 }
1148 }
1149
1150 fn small_lexer(lexs: &str, ids_map: HashMap<String, u16>) -> Vec<(u16, Regex)> {
1151 let mut rules = Vec::new();
1152 for l in lexs.split('\n').map(|x| x.trim()).filter(|x| !x.is_empty()) {
1153 assert!(l.rfind('\'') == Some(l.len() - 1));
1154 let i = l[..l.len() - 1].rfind('\'').unwrap();
1155 let name = &l[i + 1..l.len() - 1];
1156 let re = &l[..i - 1].trim();
1157 rules.push((
1158 ids_map[name],
1159 Regex::new(&format!("\\A(?:{})", re)).unwrap(),
1160 ));
1161 }
1162 rules
1163 }
1164
1165 fn small_lex(rules: Vec<(u16, Regex)>, input: &str) -> Vec<TestLexeme> {
1166 let mut lexemes = vec![];
1167 let mut i = 0;
1168 while i < input.len() {
1169 let mut longest = 0; let mut longest_tok_id = 0; for (tok_id, r) in rules.iter() {
1172 if let Some(m) = r.find(&input[i..]) {
1173 let len = m.end();
1174 if len > longest {
1175 longest = len;
1176 longest_tok_id = *tok_id;
1177 }
1178 }
1179 }
1180 assert!(longest > 0);
1181 lexemes.push(Lexeme::new(longest_tok_id, i, longest));
1182 i += longest;
1183 }
1184 lexemes
1185 }
1186
1187 #[test]
1188 fn simple_parse() {
1189 check_parse_output(
1191 "[a-zA-Z_] 'ID'
1192 \\+ '+'",
1193 "
1194%start E
1195%%
1196E: T '+' E
1197 | T;
1198T: 'ID';
1199",
1200 "a+b",
1201 "E
1202 T
1203 ID a
1204 + +
1205 E
1206 T
1207 ID b
1208",
1209 );
1210 }
1211
1212 #[test]
1213 fn parse_empty_rules() {
1214 let lexs = "[a-zA-Z_] 'ID'";
1215 let grms = "%start S
1216%%
1217S: L;
1218L: 'ID'
1219 | ;
1220";
1221 check_parse_output(
1222 lexs, grms, "", "S
1223 L
1224",
1225 );
1226
1227 check_parse_output(
1228 lexs,
1229 grms,
1230 "x",
1231 "S
1232 L
1233 ID x
1234",
1235 );
1236 }
1237
1238 #[test]
1239 fn recursive_parse() {
1240 let lexs = "\\+ '+'
1241 \\* '*'
1242 [0-9]+ 'INT'";
1243 let grms = "%start Expr
1244%%
1245Expr : Expr '+' Term | Term;
1246Term : Term '*' Factor | Factor;
1247Factor : 'INT';";
1248
1249 check_parse_output(
1250 lexs,
1251 grms,
1252 "2+3*4",
1253 "Expr
1254 Expr
1255 Term
1256 Factor
1257 INT 2
1258 + +
1259 Term
1260 Term
1261 Factor
1262 INT 3
1263 * *
1264 Factor
1265 INT 4
1266",
1267 );
1268 check_parse_output(
1269 lexs,
1270 grms,
1271 "2*3+4",
1272 "Expr
1273 Expr
1274 Term
1275 Term
1276 Factor
1277 INT 2
1278 * *
1279 Factor
1280 INT 3
1281 + +
1282 Term
1283 Factor
1284 INT 4
1285",
1286 );
1287 }
1288
1289 #[test]
1290 fn parse_error() {
1291 let lexs = "\\( '('
1292 \\) ')'
1293 [a-zA-Z_][a-zA-Z_0-9]* 'ID'";
1294 let grms = "%start Call
1295%%
1296Call: 'ID' '(' ')';";
1297
1298 check_parse_output(
1299 lexs,
1300 grms,
1301 "f()",
1302 "Call
1303 ID f
1304 ( (
1305 ) )
1306",
1307 );
1308
1309 let (grm, _, pr) = do_parse(RecoveryKind::CPCTPlus, lexs, grms, "f(");
1310 let (_, errs) = pr.unwrap_err();
1311 assert_eq!(errs.len(), 1);
1312 let err_tok_id = usize::from(grm.eof_token_idx()).to_u16().unwrap();
1313 match &errs[0] {
1314 LexParseError::ParseError(e) => {
1315 assert_eq!(e.lexeme(), &Lexeme::new_faulty(err_tok_id, 2, 0));
1316 assert!(e.lexeme().faulty());
1317 }
1318 _ => unreachable!(),
1319 }
1320
1321 let (grm, _, pr) = do_parse(RecoveryKind::CPCTPlus, lexs, grms, "f(f(");
1322 let (_, errs) = pr.unwrap_err();
1323 assert_eq!(errs.len(), 1);
1324 let err_tok_id = usize::from(grm.token_idx("ID").unwrap()).to_u16().unwrap();
1325 match &errs[0] {
1326 LexParseError::ParseError(e) => {
1327 assert_eq!(e.lexeme(), &Lexeme::new(err_tok_id, 2, 1));
1328 assert!(!e.lexeme().faulty());
1329 }
1330 _ => unreachable!(),
1331 }
1332 }
1333
1334 #[test]
1335 fn test_parse_map() {
1336 #[derive(PartialEq, Debug)]
1337 enum TestParseMap<'a> {
1338 Term(&'a str, &'a str),
1339 NonTerm(&'a str, Vec<TestParseMap<'a>>),
1340 }
1341 let lex_src = r#"[0-9]+ 'INT'
1342\+ '+'
1343\* '*'
1344"#;
1345 let grammar_src = "
1346%grmtools{yacckind: Original(NoAction)}
1347%start Expr
1348%%
1349Expr : Expr '+' Term | Term;
1350Term : Term '*' Factor | Factor;
1351Factor : 'INT';";
1352 let input_src = "2*3+4";
1353 let grm = str::parse::<YaccGrammar<u16>>(grammar_src).unwrap();
1354 let (_, stable) = lrtable::from_yacc(&grm, lrtable::Minimiser::Pager).unwrap();
1355 let rt_parser = RTParserBuilder::new(&grm, &stable);
1356 let rule_ids = grm
1357 .tokens_map()
1358 .iter()
1359 .map(|(&n, &i)| (n.to_owned(), u32::from(i).to_u16().unwrap()))
1360 .collect();
1361 let lexer_rules = small_lexer(lex_src, rule_ids);
1362 let lexemes = small_lex(lexer_rules, input_src);
1363 let lexer = SmallLexer {
1364 lexemes,
1365 s: input_src,
1366 };
1367
1368 let (parse_map, errs) = rt_parser.parse_map(
1369 &lexer,
1370 &|lexeme: TestLexeme| {
1371 let tidx = TIdx(lexeme.tok_id());
1372 let tn = &grm.token_name(tidx).unwrap();
1373 let lt = &input_src[lexeme.span().start()..lexeme.span().end()];
1374 TestParseMap::Term(tn, lt)
1375 },
1376 &|ridx, nodes| {
1377 let rule_name = &grm.rule_name_str(ridx);
1378 TestParseMap::NonTerm(rule_name, nodes)
1379 },
1380 );
1381 assert!(parse_map.is_some() && errs.is_empty());
1382 check_parse_output(
1384 lex_src,
1385 grammar_src,
1386 input_src,
1387 "Expr
1388 Expr
1389 Term
1390 Term
1391 Factor
1392 INT 2
1393 * *
1394 Factor
1395 INT 3
1396 + +
1397 Term
1398 Factor
1399 INT 4
1400",
1401 );
1402
1403 let expected_parse_map = {
1404 use TestParseMap::*;
1405 NonTerm(
1406 "Expr",
1407 vec![
1408 NonTerm(
1409 "Expr",
1410 vec![NonTerm(
1411 "Term",
1412 vec![
1413 NonTerm("Term", vec![NonTerm("Factor", vec![Term("INT", "2")])]),
1414 Term("*", "*"),
1415 NonTerm("Factor", vec![Term("INT", "3")]),
1416 ],
1417 )],
1418 ),
1419 Term("+", "+"),
1420 NonTerm("Term", vec![NonTerm("Factor", vec![Term("INT", "4")])]),
1421 ],
1422 )
1423 };
1424 assert_eq!(parse_map, Some(expected_parse_map));
1425 }
1426}