1use crate::builtins::run_builtin_action_with_info;
4use crate::context::{Context, ContextSeed, InstanceInfo};
5use crate::error::TabnasError;
6use crate::lexer::{compile_number_exclude, Lexer, RelexCheckpoint};
7use crate::options::Options;
8use crate::rule::{
9 resolved_action_order, resolved_alt_action_order, ActionBinding, AltActionBinding, AltMatch,
10 AltSpec, CompareOp, Condition, Rule, RuleDone, RuleDoneAlt, RuleName, RuleSnapshot, RuleSpec,
11 RuleState, StateAction,
12};
13use crate::token::{Tin, Token, TIN_AA, TIN_BD, TIN_ZZ};
14use crate::value::Value;
15use crate::{
16 Action, AltAction, ContextAction, LexSubscriber, ParseGuard, RuleDoneSubscriber,
17 RuleSubscriber, TokenSubscriber,
18};
19use indexmap::IndexMap;
20use std::borrow::Cow;
21use std::collections::{BTreeSet, HashMap};
22use std::panic::{catch_unwind, AssertUnwindSafe};
23use std::rc::Rc;
24use std::sync::Arc;
25
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct Continuations {
28 pub tins: Vec<Tin>,
29 pub tokens: Vec<String>,
30}
31
32#[derive(Debug, Clone)]
33pub struct ParseRecovery {
34 pub value: Option<Value>,
35 pub errors: Vec<TabnasError>,
36 pub fatal: Option<TabnasError>,
37}
38
39#[derive(Default)]
40struct ContinuationCapture {
41 at_end: BTreeSet<Tin>,
42 have_end: bool,
43 failure: Vec<Tin>,
44}
45
46struct ParseMode<'a> {
47 continuation: Option<&'a mut ContinuationCapture>,
48 recovering: bool,
49 errors: &'a mut Vec<TabnasError>,
50 partial: Option<Value>,
51}
52
53struct RelexUndo {
54 position: usize,
55 token: Token,
56 checkpoint: RelexCheckpoint,
57 tokens: Vec<Token>,
58}
59
60#[derive(Clone, Copy)]
61struct ParseSite<'a> {
62 source: &'a str,
63 stack: &'a [Rule],
64 alts: &'a [AltSpec],
65}
66
67pub struct Parser {
68 pub options: Arc<Options>,
72 ignore_tins: Vec<Tin>,
73 exclude_regex: Option<Arc<regex::Regex>>,
84 exclude_pattern: Option<String>,
85 rules: IndexMap<String, Arc<RuleSpec>>,
97 prepared_include: String,
107 prepared_exclude: String,
108 expected_tins: Vec<ExpectedTins>,
114 names: Vec<RuleName>,
126 prepared: Vec<PreparedRule>,
135 pub actions: HashMap<String, Action>,
136 pub context_actions: HashMap<String, ContextAction>,
137 pub matched_actions: HashMap<String, AltAction>,
138 pub state_actions: HashMap<String, StateAction>,
139 pub token_subscribers: Vec<TokenSubscriber>,
140 pub lex_subscribers: Vec<LexSubscriber>,
141 pub rule_subscribers: Vec<RuleSubscriber>,
142 pub rule_done_subscribers: Vec<RuleDoneSubscriber>,
143 pub parse_guards: Vec<ParseGuard>,
144 pub instance: InstanceInfo,
145}
146
147struct PreparedRule {
163 name: RuleName,
169 spec: Arc<RuleSpec>,
170 open: Vec<PreparedAlt>,
171 close: Vec<PreparedAlt>,
172 open_first: AltIndex,
176 close_first: AltIndex,
177 bo: Vec<ActionBinding>,
184 ao: Vec<ActionBinding>,
185 bc: Vec<ActionBinding>,
186 ac: Vec<ActionBinding>,
187}
188
189impl PreparedRule {
190 fn first(&self, is_open: bool) -> &AltIndex {
192 if is_open {
193 &self.open_first
194 } else {
195 &self.close_first
196 }
197 }
198
199 fn alt(&self, is_open: bool, idx: usize) -> Option<&PreparedAlt> {
200 if is_open {
201 self.open.get(idx)
202 } else {
203 self.close.get(idx)
204 }
205 }
206
207 fn before(&self, is_open: bool) -> &[ActionBinding] {
209 if is_open {
210 &self.bo
211 } else {
212 &self.bc
213 }
214 }
215
216 fn after(&self, is_open: bool) -> &[ActionBinding] {
218 if is_open {
219 &self.ao
220 } else {
221 &self.ac
222 }
223 }
224}
225
226struct PreparedAlt {
229 p: PreparedRoute,
230 r: PreparedRoute,
231 actions: Vec<AltActionBinding>,
233 observed: bool,
251 named: bool,
252 groups: bool,
261 group_tags: Vec<String>,
269}
270
271enum PreparedRoute {
272 ByName,
278 Static {
279 slot: usize,
280 name: RuleName,
281 spec: Arc<RuleSpec>,
282 },
283}
284
285impl PreparedRoute {
286 fn resolved(&self, name: &str) -> Option<(usize, RuleName, &Arc<RuleSpec>)> {
297 match self {
298 PreparedRoute::Static {
299 slot,
300 name: prepared,
301 spec,
302 } if prepared.as_str() == name => Some((*slot, prepared.clone(), spec)),
303 _ => None,
304 }
305 }
306}
307
308pub(crate) fn resolved_slot(alt: &AltSpec, slot: usize, options: &Options) -> Option<Vec<Tin>> {
325 let names = alt.s_names.get(slot)?;
326 if names.is_empty() || alt.s.get(slot) != alt.s_bound.get(slot) {
327 return None;
328 }
329 let mut tins = Vec::with_capacity(names.len());
330 for name in names {
331 if let Some(set) = options.token_set.get(name.trim_start_matches('#')) {
332 tins.extend(set.iter().copied());
333 } else {
334 tins.push(options.token(name)?);
335 }
336 }
337 Some(tins)
338}
339
340fn resolve_slot_names(spec: &mut RuleSpec, options: &Options) {
343 for alt in spec.open.iter_mut().chain(spec.close.iter_mut()) {
344 for slot in 0..alt.s.len() {
345 if let Some(tins) = resolved_slot(alt, slot, options) {
346 alt.s[slot] = tins;
347 }
348 }
349 }
350}
351
352#[derive(Debug, Default)]
366struct AltIndex {
367 by_tin: HashMap<Tin, Vec<usize>>,
368 wild: Vec<usize>,
369}
370
371const NO_ALTS: &[usize] = &[];
372
373impl AltIndex {
374 fn of(alts: &[AltSpec]) -> Self {
375 let mut by_tin: HashMap<Tin, Vec<usize>> = HashMap::new();
376 let mut wild = Vec::new();
377 for (idx, alt) in alts.iter().enumerate() {
378 match alt.s.first() {
379 Some(slot) if !slot.is_empty() && !slot.contains(&TIN_AA) => {
380 for tin in slot {
381 let list = by_tin.entry(*tin).or_default();
382 if list.last() != Some(&idx) {
385 list.push(idx);
386 }
387 }
388 }
389 _ => wild.push(idx),
390 }
391 }
392 AltIndex { by_tin, wild }
393 }
394
395 fn named(&self, tin: Tin) -> &[usize] {
398 self.by_tin.get(&tin).map_or(NO_ALTS, Vec::as_slice)
399 }
400}
401
402#[derive(Debug, Default)]
403struct ExpectedTins {
404 open: Vec<Vec<Tin>>,
405 close: Vec<Vec<Tin>>,
406}
407
408impl ExpectedTins {
409 fn of(spec: &RuleSpec, options: &Options) -> Self {
427 Self {
428 open: Self::by_slot(&spec.open, options),
429 close: Self::by_slot(&spec.close, options),
430 }
431 }
432
433 fn by_slot(alts: &[AltSpec], options: &Options) -> Vec<Vec<Tin>> {
434 let alts: Vec<&AltSpec> = alts
435 .iter()
436 .filter(|alt| groups_enabled(alt, options))
437 .collect();
438 let slots = alts.iter().map(|alt| alt.s.len()).max().unwrap_or(0);
439 (0..slots)
440 .map(|slot| Self::collate(alts.iter().copied(), slot))
441 .collect()
442 }
443
444 fn live(alts: &[AltSpec], options: &Options, slot: usize) -> Vec<Tin> {
447 Self::collate(alts.iter().filter(|alt| groups_enabled(alt, options)), slot)
448 }
449
450 fn collate<'a>(alts: impl Iterator<Item = &'a AltSpec>, slot: usize) -> Vec<Tin> {
451 let mut expected = BTreeSet::new();
452 for alt in alts {
453 if let Some(tins) = alt.s.get(slot) {
454 expected.extend(tins.iter().copied());
455 }
456 }
457 expected.into_iter().collect()
458 }
459
460 fn at(&self, is_open: bool, slot: usize) -> &[Tin] {
461 let slots = if is_open { &self.open } else { &self.close };
462 slots.get(slot).map(Vec::as_slice).unwrap_or_default()
463 }
464}
465
466impl Parser {
467 pub fn new(options: Options) -> Self {
468 let mut options = options;
469 options.sort_for_lexing();
470 Self::from_shared(Arc::new(options))
471 }
472
473 pub fn from_shared(options: Arc<Options>) -> Self {
476 Parser {
477 ignore_tins: options.ignore_tins(),
478 exclude_regex: compile_number_exclude(&options),
479 exclude_pattern: options.number.exclude.clone(),
480 options,
481 rules: IndexMap::new(),
482 prepared_include: String::new(),
483 prepared_exclude: String::new(),
484 expected_tins: Vec::new(),
485 names: Vec::new(),
486 prepared: Vec::new(),
487 actions: HashMap::new(),
488 context_actions: HashMap::new(),
489 matched_actions: HashMap::new(),
490 state_actions: HashMap::new(),
491 token_subscribers: Vec::new(),
492 lex_subscribers: Vec::new(),
493 rule_subscribers: Vec::new(),
494 rule_done_subscribers: Vec::new(),
495 parse_guards: Vec::new(),
496 instance: InstanceInfo::default(),
497 }
498 }
499
500 pub fn rules(&self) -> &IndexMap<String, Arc<RuleSpec>> {
505 &self.rules
506 }
507
508 pub fn add_rule(&mut self, spec: RuleSpec) {
509 let mut spec = spec;
515 resolve_slot_names(&mut spec, &self.options);
516 if self.options.rule.include != self.prepared_include
521 || self.options.rule.exclude != self.prepared_exclude
522 {
523 for (row, installed) in self.expected_tins.iter_mut().zip(self.rules.values()) {
524 *row = ExpectedTins::of(installed, &self.options);
525 }
526 }
527 let expected = ExpectedTins::of(&spec, &self.options);
528 let shared = RuleName::from(spec.name.as_str());
529 let (index, _) = self.rules.insert_full(spec.name.clone(), Arc::new(spec));
530 match self.names.get_mut(index) {
537 Some(existing) => *existing = shared,
538 None => self.names.push(shared),
539 }
540 match self.expected_tins.get_mut(index) {
541 Some(existing) => *existing = expected,
542 None => self.expected_tins.push(expected),
543 }
544 self.rebuild_prepared();
545 }
546
547 fn rebuild_prepared(&mut self) {
559 let mut prepared = Vec::with_capacity(self.rules.len());
560 for (index, spec) in self.rules.values().enumerate() {
561 prepared.push(PreparedRule {
562 name: self.names[index].clone(),
563 spec: Arc::clone(spec),
564 open: Self::prepared_alts(&spec.open, &self.rules, &self.names, &self.options),
565 close: Self::prepared_alts(&spec.close, &self.rules, &self.names, &self.options),
566 open_first: AltIndex::of(&spec.open),
567 close_first: AltIndex::of(&spec.close),
568 bo: resolved_action_order(
569 &spec.bo,
570 &spec.bo_fns,
571 &spec.bo_state_fns,
572 &spec.bo_order,
573 ),
574 ao: resolved_action_order(
575 &spec.ao,
576 &spec.ao_fns,
577 &spec.ao_state_fns,
578 &spec.ao_order,
579 ),
580 bc: resolved_action_order(
581 &spec.bc,
582 &spec.bc_fns,
583 &spec.bc_state_fns,
584 &spec.bc_order,
585 ),
586 ac: resolved_action_order(
587 &spec.ac,
588 &spec.ac_fns,
589 &spec.ac_state_fns,
590 &spec.ac_order,
591 ),
592 });
593 }
594 self.prepared = prepared;
595 self.prepared_include.clone_from(&self.options.rule.include);
596 self.prepared_exclude.clone_from(&self.options.rule.exclude);
597 }
598
599 fn prepared_alts(
600 alts: &[AltSpec],
601 rules: &IndexMap<String, Arc<RuleSpec>>,
602 names: &[RuleName],
603 options: &Options,
604 ) -> Vec<PreparedAlt> {
605 alts.iter()
606 .map(|alt| {
607 let actions = resolved_alt_action_order(
612 &alt.a,
613 &alt.action_fns,
614 &alt.matched_action_fns,
615 &alt.action_order,
616 );
617 let observed = alt.c_match.is_some()
618 || alt.c_lex_match.is_some()
619 || alt.e_match.is_some()
620 || alt.p_match.is_some()
621 || alt.r_match.is_some()
622 || alt.b_match.is_some()
623 || alt.h_match.is_some()
624 || actions
625 .iter()
626 .any(|binding| matches!(binding, AltActionBinding::Matched(_)));
627 let named = actions
628 .iter()
629 .any(|binding| matches!(binding, AltActionBinding::Named(_)));
630 PreparedAlt {
631 p: Self::prepared_route(alt.p.as_deref(), rules, names),
632 r: Self::prepared_route(alt.r.as_deref(), rules, names),
633 actions,
634 observed,
635 named,
636 groups: groups_enabled(alt, options),
637 group_tags: listed(&alt.g).map(str::to_owned).collect(),
638 }
639 })
640 .collect()
641 }
642
643 fn prepared_route(
644 route: Option<&str>,
645 rules: &IndexMap<String, Arc<RuleSpec>>,
646 names: &[RuleName],
647 ) -> PreparedRoute {
648 let Some(route) = route.filter(|route| !route.is_empty()) else {
651 return PreparedRoute::ByName;
652 };
653 match rules.get_full(route) {
654 Some((slot, _, spec)) => PreparedRoute::Static {
655 slot,
656 name: names[slot].clone(),
657 spec: Arc::clone(spec),
658 },
659 None => PreparedRoute::ByName,
660 }
661 }
662
663 fn installed(&self, name: &str) -> Option<(usize, RuleName, &Arc<RuleSpec>)> {
674 let (index, _, spec) = self.rules.get_full(name)?;
675 Some((index, self.names[index].clone(), spec))
676 }
677
678 pub fn add_action(&mut self, name: String, action: Action) {
679 self.actions.insert(name, action);
680 }
681
682 pub fn add_context_action(&mut self, name: String, action: ContextAction) {
683 self.context_actions.insert(name, action);
684 }
685
686 pub fn add_matched_action(&mut self, name: String, action: AltAction) {
687 self.matched_actions.insert(name, action);
688 }
689
690 pub fn add_state_action(&mut self, name: String, action: StateAction) {
691 self.state_actions.insert(name, action);
692 }
693
694 pub fn add_token_subscriber(&mut self, subscriber: TokenSubscriber) {
695 self.token_subscribers.push(subscriber);
696 }
697
698 pub fn add_lex_subscriber(&mut self, subscriber: LexSubscriber) {
699 self.lex_subscribers.push(subscriber);
700 }
701
702 pub fn add_rule_subscriber(&mut self, subscriber: RuleSubscriber) {
703 self.rule_subscribers.push(subscriber);
704 }
705
706 pub fn add_parse_guard(&mut self, guard: ParseGuard) {
707 self.parse_guards.push(guard);
708 }
709
710 pub fn add_rule_done_subscriber(&mut self, subscriber: RuleDoneSubscriber) {
711 self.rule_done_subscribers.push(subscriber);
712 }
713
714 pub fn set_instance_info(&mut self, instance: InstanceInfo) {
715 self.instance = instance;
716 }
717
718 fn run_action(
719 &self,
720 name: &str,
721 rule: &mut Rule,
722 context: &mut Context,
723 ) -> Result<(), TabnasError> {
724 self.run_action_with_config(name, rule, context, None)
725 }
726
727 fn run_after_actions(
728 &self,
729 spec: &RuleSpec,
730 prepared: Option<&PreparedRule>,
731 is_open: bool,
732 rule: &mut Rule,
733 context: &mut Context,
734 site: ParseSite<'_>,
735 ) -> Result<(), TabnasError> {
736 if (is_open && !rule.ao) || (!is_open && !rule.ac) {
737 return Ok(());
738 }
739 let by_spec;
746 let bindings: &[ActionBinding] = match prepared {
747 Some(prepared) => prepared.after(is_open),
748 None => {
749 let (actions, callbacks, states, order) = if is_open {
750 (&spec.ao, &spec.ao_fns, &spec.ao_state_fns, &spec.ao_order)
751 } else {
752 (&spec.ac, &spec.ac_fns, &spec.ac_state_fns, &spec.ac_order)
753 };
754 by_spec = resolved_action_order(actions, callbacks, states, order);
755 &by_spec
756 }
757 };
758 if bindings.is_empty() {
759 return Ok(());
760 }
761 let next = rule.next_rule.clone();
762 let mut output = None;
763 for binding in bindings {
764 output = match binding {
765 ActionBinding::Named(action) => {
766 if let Some(callback) = self.state_actions.get(action) {
767 self.run_state_callback(
768 "named lifecycle after action",
769 callback,
770 rule,
771 context,
772 next.as_deref(),
773 output,
774 )
775 .map_err(|error| {
776 self.attach_action_error(
777 error,
778 site.source,
779 rule,
780 site.stack,
781 site.alts,
782 )
783 })?
784 } else {
785 self.run_action(action, rule, context).map_err(|error| {
786 self.attach_action_error(
787 error,
788 site.source,
789 rule,
790 site.stack,
791 site.alts,
792 )
793 })?;
794 None
795 }
796 }
797 ActionBinding::Callback(callback) => {
798 self.run_context_callback("lifecycle after action", callback, rule, context)
799 .map_err(|error| {
800 self.attach_action_error(
801 error,
802 site.source,
803 rule,
804 site.stack,
805 site.alts,
806 )
807 })?;
808 None
809 }
810 ActionBinding::State(callback) => self
811 .run_state_callback(
812 "lifecycle after action",
813 callback,
814 rule,
815 context,
816 next.as_deref(),
817 output,
818 )
819 .map_err(|error| {
820 self.attach_action_error(error, site.source, rule, site.stack, site.alts)
821 })?,
822 };
823 output = self.check_lifecycle_output(output, rule, site)?;
824 }
825 Ok(())
826 }
827
828 fn run_context_callback(
829 &self,
830 label: &str,
831 callback: &ContextAction,
832 rule: &mut Rule,
833 context: &mut Context,
834 ) -> Result<(), TabnasError> {
835 context.set_rule(rule);
836 match catch_unwind(AssertUnwindSafe(|| callback(rule, context))) {
837 Ok(result) => result.map_err(|action_error| {
838 let token = match rule.state {
839 RuleState::Open => rule.o0().or_else(|| rule.c0()),
840 RuleState::Close => rule.c0().or_else(|| rule.o0()),
841 };
842 let mut error = TabnasError::new(
843 action_error.code,
844 token.map_or("", |value| value.src.as_str()),
845 "",
846 token.map_or(0, |value| value.site.pos),
847 token.map_or(1, |value| value.site.ri),
848 token.map_or(1, |value| value.site.ci),
849 );
850 error.detail = action_error.detail;
851 error
852 }),
853 Err(payload) => Err(self.action_panic(payload, label, rule)),
854 }
855 }
856
857 fn run_state_callback(
858 &self,
859 label: &str,
860 callback: &StateAction,
861 rule: &mut Rule,
862 context: &mut Context,
863 next: Option<&RuleSnapshot>,
864 out: Option<Token>,
865 ) -> Result<Option<Token>, TabnasError> {
866 context.set_rule(rule);
867 match catch_unwind(AssertUnwindSafe(|| callback(rule, context, next, out))) {
868 Ok(result) => result.map_err(|action_error| {
869 let token = match rule.state {
870 RuleState::Open => rule.o0().or_else(|| rule.c0()),
871 RuleState::Close => rule.c0().or_else(|| rule.o0()),
872 };
873 let mut error = TabnasError::new(
874 action_error.code,
875 token.map_or("", |value| value.src.as_str()),
876 "",
877 token.map_or(0, |value| value.site.pos),
878 token.map_or(1, |value| value.site.ri),
879 token.map_or(1, |value| value.site.ci),
880 );
881 error.detail = action_error.detail;
882 error
883 }),
884 Err(payload) => Err(self.action_panic(payload, label, rule)),
885 }
886 }
887
888 fn check_lifecycle_output(
889 &self,
890 output: Option<Token>,
891 rule: &Rule,
892 site: ParseSite<'_>,
893 ) -> Result<Option<Token>, TabnasError> {
894 let Some(token) = output.as_ref().filter(|token| !token.err.is_empty()) else {
895 return Ok(output);
896 };
897 Err(self.raised_token_error(token, rule, site))
898 }
899
900 fn raised_token_error(&self, token: &Token, rule: &Rule, site: ParseSite<'_>) -> TabnasError {
901 let error = TabnasError::new(
902 raised_error_code(token),
903 token.src.clone(),
904 site.source,
905 token.site.pos,
906 token.site.ri,
907 token.site.ci,
908 );
909 self.attach_error(error, rule, site.stack, site.alts, Some(token))
910 }
911
912 fn attach_action_error(
913 &self,
914 mut error: TabnasError,
915 src: &str,
916 rule: &Rule,
917 stack: &[Rule],
918 alts: &[AltSpec],
919 ) -> TabnasError {
920 error.full_source = src.into();
921 let token = match rule.state {
922 RuleState::Open => rule.o0().or_else(|| rule.c0()),
923 RuleState::Close => rule.c0().or_else(|| rule.o0()),
924 };
925 self.attach_error(error, rule, stack, alts, token)
926 }
927
928 fn run_action_with_config(
929 &self,
930 name: &str,
931 rule: &mut Rule,
932 context: &mut Context,
933 config: Option<&Value>,
934 ) -> Result<(), TabnasError> {
935 context.set_rule(rule);
936 match catch_unwind(AssertUnwindSafe(|| {
937 run_builtin_action_with_info(name, rule, context, config, &self.options.info)
938 })) {
939 Ok(true) => return Ok(()),
940 Ok(false) => {}
941 Err(payload) => return Err(self.action_panic(payload, name, rule)),
942 }
943 if let Some(action) = self.actions.get(name) {
944 return match catch_unwind(AssertUnwindSafe(|| action(rule))) {
945 Ok(()) => Ok(()),
946 Err(payload) => Err(self.action_panic(payload, name, rule)),
947 };
948 }
949 if let Some(action) = self.context_actions.get(name) {
950 return self.run_context_callback(name, action, rule, context);
951 }
952 let token = match rule.state {
953 RuleState::Open => rule.o0().or_else(|| rule.c0()),
954 RuleState::Close => rule.c0().or_else(|| rule.o0()),
955 };
956 let mut error = TabnasError::new(
957 "unknown",
958 name,
959 "",
960 token.map_or(0, |value| value.site.pos),
961 token.map_or(1, |value| value.site.ri),
962 token.map_or(1, |value| value.site.ci),
963 );
964 error.detail = format!("unknown action: {name}");
965 Err(error)
966 }
967
968 fn action_panic(
969 &self,
970 payload: Box<dyn std::any::Any + Send>,
971 name: &str,
972 rule: &Rule,
973 ) -> TabnasError {
974 let token = match rule.state {
975 RuleState::Open => rule.o0().or_else(|| rule.c0()),
976 RuleState::Close => rule.c0().or_else(|| rule.o0()),
977 };
978 TabnasError::from_panic(
979 payload,
980 &format!("action {name}"),
981 "",
982 token.map_or(0, |value| value.site.pos),
983 token.map_or(1, |value| value.site.ri),
984 token.map_or(1, |value| value.site.ci),
985 &self.options,
986 )
987 }
988
989 fn attach_error(
990 &self,
991 mut error: TabnasError,
992 rule: &Rule,
993 stack: &[Rule],
994 alts: &[AltSpec],
995 token: Option<&Token>,
996 ) -> TabnasError {
997 let mut rule_stack: Vec<String> = stack.iter().map(|item| item.name.to_string()).collect();
998 rule_stack.push(rule.name.to_string());
999 let expected = alts
1000 .iter()
1001 .filter_map(|alt| alt.s.first())
1002 .flat_map(|tins| tins.iter().copied())
1003 .map(|tin| self.options.token_name(tin))
1004 .collect();
1005 error.attach_context(
1006 &rule.name,
1007 if rule.state == RuleState::Open {
1008 "o"
1009 } else {
1010 "c"
1011 },
1012 rule_stack,
1013 token,
1014 expected,
1015 );
1016 self.decorate_error(&mut error);
1017 error
1018 }
1019
1020 fn decorate_error(&self, error: &mut TabnasError) {
1021 error.apply_options(&self.options);
1022 error.plugins = self.instance.plugins.clone();
1023 }
1024
1025 fn catch_callback<T>(
1026 &self,
1027 api: &str,
1028 src: &str,
1029 callback: impl FnOnce() -> T,
1030 ) -> Result<T, TabnasError> {
1031 catch_unwind(AssertUnwindSafe(callback))
1032 .map_err(|payload| TabnasError::from_panic(payload, api, src, 0, 1, 1, &self.options))
1033 }
1034
1035 fn cancelled(&self, src: &str, context: &Context, rule: &Rule, stack: &[Rule]) -> TabnasError {
1038 let token = context.t.first();
1039 let pnt = token
1040 .map(|token| {
1041 (
1042 token.src.as_str(),
1043 token.site.pos,
1044 token.site.ri,
1045 token.site.ci,
1046 )
1047 })
1048 .unwrap_or(("", 0, 1, 1));
1049 let error = TabnasError::new("cancel", pnt.0, src, pnt.1, pnt.2, pnt.3);
1050 self.attach_active_error(error, rule, stack, token)
1051 }
1052
1053 fn attach_active_error(
1054 &self,
1055 mut error: TabnasError,
1056 rule: &Rule,
1057 stack: &[Rule],
1058 token: Option<&Token>,
1059 ) -> TabnasError {
1060 if let Some(spec) = self.rules.get(&*rule.name) {
1061 let alts = if rule.state == RuleState::Open {
1062 &spec.open
1063 } else {
1064 &spec.close
1065 };
1066 self.attach_error(error, rule, stack, alts, token)
1067 } else {
1068 self.decorate_error(&mut error);
1069 error
1070 }
1071 }
1072
1073 fn phase_token(rule: &Rule) -> Option<&Token> {
1074 match rule.state {
1075 RuleState::Open => rule.o0().or_else(|| rule.c0()),
1076 RuleState::Close => rule.c0().or_else(|| rule.o0()),
1077 }
1078 }
1079
1080 fn ancestors_for<'a>(rule: &Rule, stack: &'a [Rule]) -> &'a [Rule] {
1081 if stack.last().is_some_and(|ancestor| ancestor.i == rule.i) {
1082 &stack[..stack.len() - 1]
1083 } else {
1084 stack
1085 }
1086 }
1087
1088 fn rule_done_copy(&self, rule: &Rule) -> Option<Rule> {
1097 (!self.rule_done_subscribers.is_empty()).then(|| rule.clone())
1098 }
1099
1100 fn notify_rule_done(
1101 &self,
1102 rule: &Rule,
1103 context: &Context,
1104 state: RuleState,
1105 alt: Option<RuleDoneAlt>,
1106 src: &str,
1107 stack: &[Rule],
1108 ) -> Result<(), TabnasError> {
1109 if self.rule_done_subscribers.is_empty() {
1110 return Ok(());
1111 }
1112 let done = RuleDone {
1113 state,
1114 alt,
1115 forced: false,
1116 };
1117 let mut site_rule = rule.clone();
1118 site_rule.state = state;
1119 for subscriber in &self.rule_done_subscribers {
1120 let result = self.catch_callback("ruleDone subscriber", src, || {
1121 subscriber(rule, context, &done)
1122 });
1123 result.map_err(|error| {
1124 self.attach_active_error(
1125 error,
1126 &site_rule,
1127 Self::ancestors_for(&site_rule, stack),
1128 Self::phase_token(&site_rule),
1129 )
1130 })?;
1131 }
1132 Ok(())
1133 }
1134
1135 fn notify_forced_close(
1136 &self,
1137 rule: &Rule,
1138 context: &Context,
1139 src: &str,
1140 stack: &[Rule],
1141 ) -> Result<(), TabnasError> {
1142 if self.rule_done_subscribers.is_empty() {
1143 return Ok(());
1144 }
1145 let done = RuleDone {
1146 state: RuleState::Close,
1147 alt: None,
1148 forced: true,
1149 };
1150 let mut site_rule = rule.clone();
1151 site_rule.state = RuleState::Close;
1152 for subscriber in &self.rule_done_subscribers {
1153 let result = self.catch_callback("ruleDone subscriber", src, || {
1154 subscriber(rule, context, &done)
1155 });
1156 result.map_err(|error| {
1157 self.attach_active_error(
1158 error,
1159 &site_rule,
1160 Self::ancestors_for(&site_rule, stack),
1161 Self::phase_token(&site_rule),
1162 )
1163 })?;
1164 }
1165 Ok(())
1166 }
1167
1168 fn attempt_recover(
1169 &self,
1170 mut error: TabnasError,
1171 current_rule: &mut Rule,
1172 stack: &mut Vec<Rule>,
1173 context: &mut Context,
1174 lexer: &mut Lexer,
1175 mode: &mut ParseMode<'_>,
1176 ) -> Result<bool, TabnasError> {
1177 let src = error.full_source.clone();
1178 let recover = &self.options.parse.recover;
1179 if mode.errors.len() >= recover.max_recoveries {
1180 return Ok(false);
1181 }
1182
1183 let suppressed = context
1184 .recover_at
1185 .is_some_and(|at| context.v_abs.saturating_sub(at) < recover.suppress);
1186 let no_progress = context.recover_at == Some(context.v_abs);
1187 let last_si = context.recover_si;
1188 context.recover_at = Some(context.v_abs);
1189
1190 let sync = compute_sync_tins(current_rule, stack, &self.rules, &self.options);
1191 let mut pending: std::collections::VecDeque<Token> = std::mem::take(&mut context.t).into();
1192 let mut skipped = 0usize;
1193
1194 let candidate = loop {
1195 let next = if let Some(token) = pending.pop_front() {
1196 Some(token)
1197 } else {
1198 loop {
1199 let next_raw = self.catch_callback("lexer callback", &src, || {
1200 lexer.next_raw_for_rule(current_rule, context)
1201 });
1202 let next_raw = next_raw.map_err(|error| {
1203 self.attach_active_error(
1204 error,
1205 current_rule,
1206 stack,
1207 Self::phase_token(current_rule),
1208 )
1209 })?;
1210 match next_raw {
1211 Ok(mut token) => {
1212 for subscriber in &self.lex_subscribers {
1213 let result = self.catch_callback("lex subscriber", &src, || {
1214 subscriber(&mut token, current_rule, context)
1215 });
1216 result.map_err(|error| {
1217 self.attach_active_error(
1218 error,
1219 current_rule,
1220 stack,
1221 Some(&token),
1222 )
1223 })?;
1224 }
1225 if self.ignore_tins.contains(&token.tin) {
1226 continue;
1227 }
1228 for subscriber in &self.token_subscribers {
1229 let result = self.catch_callback("token subscriber", &src, || {
1230 subscriber(&token)
1231 });
1232 result.map_err(|error| {
1233 self.attach_active_error(
1234 error,
1235 current_rule,
1236 stack,
1237 Some(&token),
1238 )
1239 })?;
1240 }
1241 break Some(token);
1242 }
1243 Err(lex_error) => {
1244 let mut token = error_token(&lex_error);
1245 for subscriber in &self.lex_subscribers {
1246 let result = self.catch_callback("lex subscriber", &src, || {
1247 subscriber(&mut token, current_rule, context)
1248 });
1249 result.map_err(|error| {
1250 self.attach_active_error(
1251 error,
1252 current_rule,
1253 stack,
1254 Some(&token),
1255 )
1256 })?;
1257 }
1258 lexer.recover_after_error(mid_construct(&lex_error.code));
1259 if skipped >= recover.max_skip {
1260 break None;
1261 }
1262 skipped += 1;
1263 }
1264 }
1265 }
1266 };
1267 let Some(token) = next else {
1268 return Ok(false);
1269 };
1270 if token.tin == TIN_ZZ
1271 || (sync.contains(&token.tin)
1272 && !(no_progress && last_si.is_some_and(|si| token.site.pos <= si)))
1273 {
1274 break token;
1275 }
1276 if skipped >= recover.max_skip {
1277 return Ok(false);
1278 }
1279 skipped += 1;
1280 };
1281
1282 if candidate.tin == TIN_ZZ
1283 && no_progress
1284 && last_si.is_some_and(|si| candidate.site.pos <= si)
1285 {
1286 return Ok(false);
1287 }
1288 context.recover_si = Some(candidate.site.pos);
1289 error.recovered = Some(crate::RecoveredAt {
1290 skipped,
1291 sync: Some(candidate.tin),
1292 bad: false,
1293 });
1294 if !suppressed {
1295 mode.errors.push(error.clone());
1296 context.errs.push(error);
1297 }
1298
1299 context.t.push(candidate.clone());
1300 context.t.extend(pending);
1301 context.bad_to = None;
1302 context.bad_error = None;
1303
1304 if !recover.pop_until_valid {
1305 if let Some(parent) = stack.pop() {
1311 *current_rule = parent;
1312 return Ok(true);
1313 }
1314 return Ok(false);
1315 }
1316
1317 if accepts_close(current_rule, candidate.tin, &self.rules, &self.options) {
1318 if current_rule.state == RuleState::Open {
1319 current_rule.state = RuleState::Close;
1320 } else {
1321 current_rule.skip_befores = true;
1322 }
1323 return Ok(true);
1324 }
1325
1326 self.notify_forced_close(current_rule, context, &src, stack)?;
1327 while let Some(mut parent) = stack.pop() {
1328 parent.accept_child(current_rule);
1329 if accepts_close(&parent, candidate.tin, &self.rules, &self.options) {
1330 *current_rule = parent;
1331 return Ok(true);
1332 }
1333 self.notify_forced_close(&parent, context, &src, stack)?;
1334 *current_rule = parent;
1335 }
1336 Ok(false)
1337 }
1338
1339 #[allow(clippy::too_many_arguments)]
1340 fn recover_error_pass(
1341 &self,
1342 error: TabnasError,
1343 state: RuleState,
1344 mut alt: Option<RuleDoneAlt>,
1345 fallback_error_token: bool,
1346 src: &str,
1347 current_rule: &mut Rule,
1348 stack: &mut Vec<Rule>,
1349 context: &mut Context,
1350 lexer: &mut Lexer,
1351 mode: &mut ParseMode<'_>,
1352 ) -> Result<(), TabnasError> {
1353 let event_rule = current_rule.clone();
1358 let recovered = mode.recovering
1359 && self.attempt_recover(error.clone(), current_rule, stack, context, lexer, mode)?;
1360 if !recovered && fallback_error_token {
1361 if let Some(alt) = alt.as_mut().filter(|alt| alt.err.is_none()) {
1362 let tin = self.options.token(&error.token.name).unwrap_or(TIN_BD);
1363 let mut token = Token::new(
1364 error.token.name.clone(),
1365 tin,
1366 Value::Undefined,
1367 error.token.src.clone(),
1368 crate::Point {
1369 len: error.len,
1370 site: crate::Site {
1371 si: error.pos,
1372 pos: error.pos,
1373 ri: error.row,
1374 ci: error.col,
1375 },
1376 },
1377 );
1378 token.bad(&error.code);
1379 alt.err = Some(token);
1380 }
1381 }
1382 self.notify_rule_done(&event_rule, context, state, alt, src, stack)?;
1383 if recovered {
1384 Ok(())
1385 } else {
1386 Err(error)
1387 }
1388 }
1389
1390 #[allow(clippy::too_many_arguments)]
1391 fn recover_after_actions(
1392 &self,
1393 result: Result<(), TabnasError>,
1394 state: RuleState,
1395 alt: Option<RuleDoneAlt>,
1396 src: &str,
1397 current_rule: &mut Rule,
1398 stack: &mut Vec<Rule>,
1399 context: &mut Context,
1400 lexer: &mut Lexer,
1401 mode: &mut ParseMode<'_>,
1402 ) -> Result<bool, TabnasError> {
1403 let Err(error) = result else {
1404 return Ok(false);
1405 };
1406 self.recover_error_pass(
1407 error,
1408 state,
1409 alt,
1410 true,
1411 src,
1412 current_rule,
1413 stack,
1414 context,
1415 lexer,
1416 mode,
1417 )?;
1418 Ok(true)
1419 }
1420
1421 pub fn parse(&self, src: &str) -> Result<Value, TabnasError> {
1422 self.parse_with_meta(src, Value::Undefined)
1423 }
1424
1425 pub fn parse_with_meta(&self, src: &str, meta: Value) -> Result<Value, TabnasError> {
1426 self.parse_with_owner(src, meta, None, None)
1427 }
1428
1429 pub(crate) fn parse_for(
1430 &self,
1431 owner: &crate::Tabnas,
1432 src: &str,
1433 meta: Value,
1434 ) -> Result<Value, TabnasError> {
1435 self.parse_with_owner(src, meta, Some(owner), None)
1436 }
1437
1438 pub(crate) fn parse_for_with_context(
1439 &self,
1440 owner: &crate::Tabnas,
1441 src: &str,
1442 meta: Value,
1443 parent: &ContextSeed,
1444 ) -> Result<Value, TabnasError> {
1445 self.parse_with_owner(src, meta, Some(owner), Some(parent))
1446 }
1447
1448 fn parse_with_owner(
1449 &self,
1450 src: &str,
1451 meta: Value,
1452 owner: Option<&crate::Tabnas>,
1453 parent: Option<&ContextSeed>,
1454 ) -> Result<Value, TabnasError> {
1455 match catch_unwind(AssertUnwindSafe(|| {
1456 self.parse_uncaught(src, meta, owner, parent)
1457 })) {
1458 Ok(result) => result,
1459 Err(payload) => {
1460 let mut error =
1461 TabnasError::from_panic(payload, "Parser::parse", src, 0, 1, 1, &self.options);
1462 self.decorate_error(&mut error);
1463 Err(error)
1464 }
1465 }
1466 }
1467
1468 fn parse_uncaught(
1469 &self,
1470 src: &str,
1471 meta: Value,
1472 owner: Option<&crate::Tabnas>,
1473 parent: Option<&ContextSeed>,
1474 ) -> Result<Value, TabnasError> {
1475 if let Some(result) = self.run_parser_start(src, &meta, owner, parent) {
1476 return result.map_err(|mut error| {
1477 self.decorate_error(&mut error);
1478 error
1479 });
1480 }
1481 let mut errors = Vec::new();
1482 let recovering = self.options.parse.recover.enabled;
1483 let mut mode = ParseMode {
1484 continuation: None,
1485 recovering,
1486 errors: &mut errors,
1487 partial: None,
1488 };
1489 let result = self
1490 .parse_inner(src, meta, owner, parent, &mut mode)
1491 .map_err(|mut error| {
1492 self.decorate_error(&mut error);
1493 error
1494 });
1495 match result {
1496 Err(_) if recovering => Ok(mode.partial.unwrap_or(Value::Undefined)),
1497 other => other,
1498 }
1499 }
1500
1501 pub fn parse_recover(&self, src: &str) -> ParseRecovery {
1502 self.parse_recover_with_meta(src, Value::Undefined)
1503 }
1504
1505 pub fn parse_recover_with_meta(&self, src: &str, meta: Value) -> ParseRecovery {
1506 self.parse_recover_with_owner(src, meta, None, None)
1507 }
1508
1509 pub(crate) fn parse_recover_for(
1510 &self,
1511 owner: &crate::Tabnas,
1512 src: &str,
1513 meta: Value,
1514 ) -> ParseRecovery {
1515 self.parse_recover_with_owner(src, meta, Some(owner), None)
1516 }
1517
1518 pub(crate) fn parse_recover_for_with_context(
1519 &self,
1520 owner: &crate::Tabnas,
1521 src: &str,
1522 meta: Value,
1523 parent: &ContextSeed,
1524 ) -> ParseRecovery {
1525 self.parse_recover_with_owner(src, meta, Some(owner), Some(parent))
1526 }
1527
1528 fn parse_recover_with_owner(
1529 &self,
1530 src: &str,
1531 meta: Value,
1532 owner: Option<&crate::Tabnas>,
1533 parent: Option<&ContextSeed>,
1534 ) -> ParseRecovery {
1535 match catch_unwind(AssertUnwindSafe(|| {
1536 self.parse_recover_uncaught(src, meta, owner, parent)
1537 })) {
1538 Ok(result) => result,
1539 Err(payload) => {
1540 let mut error = TabnasError::from_panic(
1541 payload,
1542 "Parser::parse_recover",
1543 src,
1544 0,
1545 1,
1546 1,
1547 &self.options,
1548 );
1549 self.decorate_error(&mut error);
1550 ParseRecovery {
1551 value: None,
1552 errors: Vec::new(),
1553 fatal: Some(error),
1554 }
1555 }
1556 }
1557 }
1558
1559 fn parse_recover_uncaught(
1560 &self,
1561 src: &str,
1562 meta: Value,
1563 owner: Option<&crate::Tabnas>,
1564 parent: Option<&ContextSeed>,
1565 ) -> ParseRecovery {
1566 if let Some(result) = self.run_parser_start(src, &meta, owner, parent) {
1567 return match result {
1568 Ok(value) => ParseRecovery {
1569 value: Some(value),
1570 errors: Vec::new(),
1571 fatal: None,
1572 },
1573 Err(mut error) => {
1574 self.decorate_error(&mut error);
1575 ParseRecovery {
1576 value: None,
1577 errors: Vec::new(),
1578 fatal: Some(error),
1579 }
1580 }
1581 };
1582 }
1583 let mut errors = Vec::new();
1584 let recovering = self.options.parse.recover.enabled;
1585 let (result, partial) = {
1586 let mut mode = ParseMode {
1587 continuation: None,
1588 recovering,
1589 errors: &mut errors,
1590 partial: None,
1591 };
1592 let result = self
1593 .parse_inner(src, meta, owner, parent, &mut mode)
1594 .map_err(|mut error| {
1595 self.decorate_error(&mut error);
1596 error
1597 });
1598 (result, mode.partial)
1599 };
1600 for error in &mut errors {
1601 self.decorate_error(error);
1602 }
1603 match result {
1604 Ok(value) => ParseRecovery {
1605 value: Some(value),
1606 errors,
1607 fatal: None,
1608 },
1609 Err(error) => {
1610 if errors.last() != Some(&error) {
1611 errors.push(error.clone());
1612 }
1613 ParseRecovery {
1614 value: recovering.then_some(partial).flatten(),
1615 errors,
1616 fatal: (!recovering).then_some(error),
1617 }
1618 }
1619 }
1620 }
1621
1622 fn run_parser_start(
1623 &self,
1624 src: &str,
1625 meta: &Value,
1626 owner: Option<&crate::Tabnas>,
1627 parent: Option<&ContextSeed>,
1628 ) -> Option<Result<Value, TabnasError>> {
1629 let result = if let Some(start) = self.options.parser.start_with_context.as_ref() {
1630 let Some(owner) = owner else {
1631 let mut error = TabnasError::new("internal", "", src, 0, 1, 1);
1632 error.detail =
1633 "parser.start requires an owning Tabnas instance; call Tabnas::parse".into();
1634 self.decorate_error(&mut error);
1635 return Some(Err(error));
1636 };
1637 catch_unwind(AssertUnwindSafe(|| start(src, owner, meta, parent)))
1638 } else if let Some(start) = self.options.parser.start_with_instance.as_ref() {
1639 let Some(owner) = owner else {
1640 let mut error = TabnasError::new("internal", "", src, 0, 1, 1);
1641 error.detail =
1642 "parser.start requires an owning Tabnas instance; call Tabnas::parse".into();
1643 self.decorate_error(&mut error);
1644 return Some(Err(error));
1645 };
1646 catch_unwind(AssertUnwindSafe(|| start(src, owner, meta)))
1647 } else {
1648 let start = self.options.parser.start.as_ref()?;
1649 catch_unwind(AssertUnwindSafe(|| start(src)))
1650 };
1651 Some(match result {
1652 Ok(result) => result.map_err(|error| *error),
1653 Err(payload) => Err(TabnasError::from_panic(
1654 payload,
1655 "parser.start",
1656 src,
1657 0,
1658 1,
1659 1,
1660 &self.options,
1661 )),
1662 })
1663 }
1664
1665 pub fn continuations(&self, src: &str) -> Continuations {
1669 self.continuations_with_owner(src, None)
1670 }
1671
1672 pub(crate) fn continuations_for(&self, owner: &crate::Tabnas, src: &str) -> Continuations {
1673 self.continuations_with_owner(src, Some(owner))
1674 }
1675
1676 fn continuations_with_owner(&self, src: &str, owner: Option<&crate::Tabnas>) -> Continuations {
1677 catch_unwind(AssertUnwindSafe(|| self.continuations_uncaught(src, owner)))
1678 .unwrap_or_else(|_| self.start_continuations())
1679 }
1680
1681 fn continuations_uncaught(&self, src: &str, owner: Option<&crate::Tabnas>) -> Continuations {
1682 let mut capture = ContinuationCapture::default();
1683 let mut errors = Vec::new();
1684 let result = {
1685 let mut mode = ParseMode {
1686 continuation: Some(&mut capture),
1687 recovering: false,
1688 errors: &mut errors,
1689 partial: None,
1690 };
1691 self.parse_inner(src, Value::Undefined, owner, None, &mut mode)
1692 };
1693 let mut tins = if result.is_ok() {
1694 if capture.have_end {
1695 capture.at_end.insert(TIN_ZZ);
1696 capture.at_end.into_iter().collect()
1697 } else {
1698 self.start_openers()
1699 }
1700 } else if capture.failure.is_empty() {
1701 self.start_openers()
1702 } else {
1703 capture.failure
1704 };
1705 tins.sort_unstable();
1706 tins.dedup();
1707 let tokens = tins
1708 .iter()
1709 .map(|tin| self.options.token_name(*tin))
1710 .collect();
1711 Continuations { tins, tokens }
1712 }
1713
1714 fn start_continuations(&self) -> Continuations {
1715 let tins = self.start_openers();
1716 let tokens = tins
1717 .iter()
1718 .map(|tin| self.options.token_name(*tin))
1719 .collect();
1720 Continuations { tins, tokens }
1721 }
1722
1723 fn start_openers(&self) -> Vec<Tin> {
1724 let start = self.rules.get(&self.options.rule.start);
1725 let mut out = BTreeSet::new();
1726 if let Some(spec) = start {
1727 for alt in &spec.open {
1728 if groups_enabled(alt, &self.options) {
1729 if let Some(slot) = alt.s.first() {
1730 out.extend(completion_tins(slot));
1731 }
1732 }
1733 }
1734 }
1735 out.into_iter().collect()
1736 }
1737
1738 fn expected_match_tins(&self, rule: &Rule, slot: usize) -> Cow<'_, [Tin]> {
1763 if self.options.match_tokens.is_empty() {
1764 return Cow::Borrowed(&[]);
1765 }
1766 let index = match self.names.get(rule.slot) {
1774 Some(installed) if *installed == rule.name => rule.slot,
1775 _ => match self.rules.get_index_of(&*rule.name) {
1776 Some(index) => index,
1777 None => return Cow::Borrowed(&[]),
1778 },
1779 };
1780 let is_open = rule.state == RuleState::Open;
1781 if self.options.rule.include == self.prepared_include
1782 && self.options.rule.exclude == self.prepared_exclude
1783 {
1784 return Cow::Borrowed(self.expected_tins[index].at(is_open, slot));
1785 }
1786 let installed = &self.rules[index];
1787 let alts = if is_open {
1788 &installed.open
1789 } else {
1790 &installed.close
1791 };
1792 Cow::Owned(ExpectedTins::live(alts, &self.options, slot))
1793 }
1794
1795 fn ensure_lookahead(
1796 &self,
1797 lexer: &mut Lexer,
1798 context: &mut Context,
1799 rule: &mut Rule,
1800 count: usize,
1801 mode: &mut ParseMode<'_>,
1802 site: ParseSite<'_>,
1803 ) -> Result<(), TabnasError> {
1804 while context.t.len() < count {
1805 if context.t.last().is_some_and(|token| token.tin == TIN_ZZ) {
1806 break;
1807 }
1808 let expected_match_tins = self.expected_match_tins(rule, context.t.len());
1809 let token = loop {
1810 let next = match context.next_replay() {
1811 Some(token) => Ok(token),
1812 None => {
1813 let result = self.catch_callback("lexer callback", site.source, || {
1814 lexer.next_rule_token(&expected_match_tins, rule, context)
1815 });
1816 result.map_err(|error| {
1817 self.attach_active_error(
1818 error,
1819 rule,
1820 site.stack,
1821 Self::phase_token(rule),
1822 )
1823 })?
1824 }
1825 };
1826 let mut token = match next {
1827 Ok(token) => token,
1828 Err(error) => {
1829 let recovery_error = self
1830 .rules
1831 .get(&*rule.name)
1832 .map(|spec| {
1833 let alts = if rule.state == RuleState::Open {
1834 &spec.open
1835 } else {
1836 &spec.close
1837 };
1838 self.attach_error((*error).clone(), rule, site.stack, alts, None)
1839 })
1840 .unwrap_or_else(|| (*error).clone());
1841 if self.options.lex.relex {
1842 let mut token = error_token(&recovery_error);
1843 for subscriber in &self.lex_subscribers {
1844 let result =
1845 self.catch_callback("lex subscriber", site.source, || {
1846 subscriber(&mut token, rule, context)
1847 });
1848 result.map_err(|error| {
1849 self.attach_active_error(error, rule, site.stack, Some(&token))
1850 })?;
1851 }
1852 break token;
1853 }
1854 if mode.recovering
1855 && absorb_lex_error(
1856 &recovery_error,
1857 context,
1858 &self.options,
1859 mode.errors,
1860 )
1861 {
1862 let mut token = error_token(&recovery_error);
1863 for subscriber in &self.lex_subscribers {
1864 let result =
1865 self.catch_callback("lex subscriber", site.source, || {
1866 subscriber(&mut token, rule, context)
1867 });
1868 result.map_err(|error| {
1869 self.attach_active_error(error, rule, site.stack, Some(&token))
1870 })?;
1871 }
1872 lexer.recover_after_error(mid_construct(&recovery_error.code));
1873 continue;
1874 }
1875 if let Some(capture) = mode.continuation.as_deref_mut() {
1876 capture.failure = continuation_tins(
1877 context,
1878 rule,
1879 site.stack,
1880 &self.rules,
1881 &self.options,
1882 context.t.len(),
1883 None,
1884 );
1885 }
1886 return Err(*error);
1889 }
1890 };
1891 for subscriber in &self.lex_subscribers {
1892 let result = self.catch_callback("lex subscriber", site.source, || {
1893 subscriber(&mut token, rule, context)
1894 });
1895 result.map_err(|error| {
1896 self.attach_active_error(error, rule, site.stack, Some(&token))
1897 })?;
1898 }
1899 if token.tin == TIN_ZZ {
1900 if let Some(capture) = mode.continuation.as_deref_mut() {
1901 capture.have_end = true;
1902 capture.at_end.extend(continuation_tins(
1903 context,
1904 rule,
1905 site.stack,
1906 &self.rules,
1907 &self.options,
1908 context.t.len(),
1909 None,
1910 ));
1911 }
1912 }
1913 if !self.ignore_tins.contains(&token.tin) {
1914 break token;
1915 }
1916 };
1917 for subscriber in &self.token_subscribers {
1918 let result =
1919 self.catch_callback("token subscriber", site.source, || subscriber(&token));
1920 result.map_err(|error| {
1921 self.attach_active_error(error, rule, site.stack, Some(&token))
1922 })?;
1923 }
1924 let is_end = token.tin == TIN_ZZ;
1925 context.t.push(token);
1926 if is_end {
1927 break;
1928 }
1929 }
1930 Ok(())
1931 }
1932
1933 fn parse_inner(
1934 &self,
1935 src: &str,
1936 meta: Value,
1937 owner: Option<&crate::Tabnas>,
1938 parent: Option<&ContextSeed>,
1939 mode: &mut ParseMode<'_>,
1940 ) -> Result<Value, TabnasError> {
1941 let input_meta = meta.clone();
1942 let mut context = Context::new(
1943 self.options.rewind.history,
1944 src,
1945 meta,
1946 Arc::clone(&self.options),
1947 self.instance.clone(),
1948 );
1949 if let Some(parent) = parent {
1950 context.apply_seed(parent);
1951 }
1952 for prepare in &self.options.parse.prepare {
1953 let outcome = self.catch_callback("parse.prepare", src, || {
1954 prepare.run(owner, &mut context, &input_meta)
1955 })?;
1956 if let Err(detail) = outcome {
1957 let mut error = TabnasError::new("internal", "", src, 0, 1, 1);
1958 error.detail = detail.into();
1959 return Err(error);
1960 }
1961 }
1962 for prepare in self.options.parse.named_prepare.values() {
1963 let outcome = self.catch_callback("parse.prepare", src, || {
1964 prepare.run(owner, &mut context, &input_meta)
1965 })?;
1966 if let Err(detail) = outcome {
1967 let mut error = TabnasError::new("internal", "", src, 0, 1, 1);
1968 error.detail = detail.into();
1969 return Err(error);
1970 }
1971 }
1972
1973 if src.is_empty() {
1974 return if self.options.lex.empty {
1975 Ok(self.options.lex.empty_result.clone())
1976 } else {
1977 Err(TabnasError::new("unexpected", "", src, 0, 1, 1))
1978 };
1979 }
1980
1981 let exclude_regex = if self.exclude_pattern == self.options.number.exclude {
1984 self.exclude_regex.clone()
1985 } else {
1986 compile_number_exclude(&self.options)
1987 };
1988 let mut lexer = Lexer::with_shared(src, Arc::clone(&self.options), exclude_regex);
1989
1990 let start_name = self.options.rule.start.as_str();
1993 let Some((start_slot, start_shared, start_spec)) = self.installed(start_name) else {
1994 return Ok(Value::Undefined);
1995 };
1996
1997 let mut current_rule = Rule::new(start_shared.clone(), Value::Undefined);
1998 current_rule.bind_spec(start_spec, start_shared, start_slot);
1999 current_rule.i = 0;
2000 let root_node = current_rule.node.clone();
2001 context.set_root(root_node.clone());
2002 let mut stack: Vec<Rule> = Vec::new();
2003 let park_child_nodes = self.options.parse.recover.pop_until_valid;
2008 let mut next_rule_id = 1;
2009 #[allow(unused_assignments)]
2010 let mut final_value = None;
2011
2012 let mut iterations = 0usize;
2013 let maxmul = if self.options.rule.maxmul == 0 {
2014 3
2015 } else {
2016 self.options.rule.maxmul
2017 };
2018 let max_iterations = self
2019 .rules
2020 .len()
2021 .saturating_mul(src.encode_utf16().count())
2022 .saturating_mul(4)
2023 .saturating_mul(maxmul)
2024 .max(100);
2025 let budget = &self.options.parse.budget;
2026
2027 let mut matched = AltMatch::default();
2035
2036 'parse: loop {
2037 context.set_active(¤t_rule, &stack);
2038 update_partial(mode, &root_node, ¤t_rule, &stack);
2039 iterations += 1;
2040 if iterations > max_iterations {
2041 let pnt = context
2042 .t
2043 .first()
2044 .map(|t| (t.site.pos, t.site.ri, t.site.ci))
2045 .unwrap_or((0, 1, 1));
2046 return Err(TabnasError::new("unexpected", "", src, pnt.0, pnt.1, pnt.2));
2047 }
2048 context.iteration = iterations - 1;
2049 if context.iteration > 0 {
2052 for guard in &self.parse_guards {
2053 let result = self.catch_callback("parse guard", src, || guard(&context));
2054 let keep_going = result.map_err(|error| {
2055 self.attach_active_error(
2056 error,
2057 ¤t_rule,
2058 &stack,
2059 Self::phase_token(¤t_rule).or_else(|| context.t.first()),
2060 )
2061 })?;
2062 if !keep_going {
2063 return Err(self.cancelled(src, &context, ¤t_rule, &stack));
2064 }
2065 }
2066 }
2067 if budget.check_every_n > 0
2068 && context.iteration > 0
2069 && context.iteration % budget.check_every_n == 0
2070 {
2071 if let Some(check) = &budget.on_check {
2072 let result =
2073 self.catch_callback("parse.budget.onCheck", src, || check(&context));
2074 let keep_going = result.map_err(|error| {
2075 self.attach_active_error(
2076 error,
2077 ¤t_rule,
2078 &stack,
2079 Self::phase_token(¤t_rule).or_else(|| context.t.first()),
2080 )
2081 })?;
2082 if !keep_going {
2083 return Err(self.cancelled(src, &context, ¤t_rule, &stack));
2084 }
2085 }
2086 }
2087
2088 let by_name;
2104 let (prepared, spec) = match self.prepared.get(current_rule.slot).filter(|prepared| {
2105 Arc::ptr_eq(&prepared.spec, ¤t_rule.spec)
2106 && prepared.name == current_rule.name
2107 }) {
2108 Some(prepared) => (Some(prepared), &prepared.spec),
2109 None => {
2110 by_name = if current_rule.spec.name == *current_rule.name {
2111 Arc::clone(¤t_rule.spec)
2112 } else {
2113 match self.rules.get(&*current_rule.name) {
2114 Some(s) => s.clone(),
2115 None => {
2116 let pnt = context
2117 .t
2118 .first()
2119 .map(|t| (t.site.pos, t.site.ri, t.site.ci))
2120 .unwrap_or((0, 1, 1));
2121 return Err(TabnasError::new(
2122 "unknown_rule",
2123 &*current_rule.name,
2124 src,
2125 pnt.0,
2126 pnt.1,
2127 pnt.2,
2128 ));
2129 }
2130 }
2131 };
2132 (None, &by_name)
2133 }
2134 };
2135
2136 let is_open = current_rule.state == RuleState::Open;
2137 let alts = if is_open { &spec.open } else { &spec.close };
2138
2139 for subscriber in &self.rule_subscribers {
2140 let result = self.catch_callback("rule subscriber", src, || {
2141 subscriber(&mut current_rule, &mut context)
2142 });
2143 result.map_err(|error| {
2144 self.attach_error(
2145 error,
2146 ¤t_rule,
2147 &stack,
2148 alts,
2149 Self::phase_token(¤t_rule).or_else(|| context.t.first()),
2150 )
2151 })?;
2152 }
2153 update_partial(mode, &root_node, ¤t_rule, &stack);
2154
2155 let skip_befores = current_rule.skip_befores;
2158 current_rule.skip_befores = false;
2159 let before_enabled = if is_open {
2160 current_rule.bo
2161 } else {
2162 current_rule.bc
2163 };
2164 let by_spec;
2169 let before_bindings: &[ActionBinding] = if skip_befores || !before_enabled {
2170 &[]
2171 } else {
2172 match prepared {
2173 Some(prepared) => prepared.before(is_open),
2174 None => {
2175 let (actions, callbacks, states, order) = if is_open {
2176 (&spec.bo, &spec.bo_fns, &spec.bo_state_fns, &spec.bo_order)
2177 } else {
2178 (&spec.bc, &spec.bc_fns, &spec.bc_state_fns, &spec.bc_order)
2179 };
2180 by_spec = resolved_action_order(actions, callbacks, states, order);
2181 &by_spec
2182 }
2183 }
2184 };
2185 if !before_bindings.is_empty() {
2186 let label = if is_open {
2187 "before-open action"
2188 } else {
2189 "before-close action"
2190 };
2191 let next = is_open.then(|| current_rule.snapshot());
2192 let site = ParseSite {
2193 source: src,
2194 stack: &stack,
2195 alts,
2196 };
2197 let mut output = None;
2198 let mut lifecycle_error = None;
2199 for binding in before_bindings {
2200 output = match binding {
2201 ActionBinding::Named(action) => {
2202 if let Some(callback) = self.state_actions.get(action) {
2203 self.run_state_callback(
2204 label,
2205 callback,
2206 &mut current_rule,
2207 &mut context,
2208 next.as_deref(),
2209 output,
2210 )
2211 .map_err(|error| {
2212 self.attach_action_error(
2213 error,
2214 src,
2215 ¤t_rule,
2216 &stack,
2217 alts,
2218 )
2219 })?
2220 } else {
2221 self.run_action(action, &mut current_rule, &mut context)
2222 .map_err(|error| {
2223 self.attach_action_error(
2224 error,
2225 src,
2226 ¤t_rule,
2227 &stack,
2228 alts,
2229 )
2230 })?;
2231 None
2232 }
2233 }
2234 ActionBinding::Callback(callback) => {
2235 self.run_context_callback(
2236 label,
2237 callback,
2238 &mut current_rule,
2239 &mut context,
2240 )
2241 .map_err(|error| {
2242 self.attach_action_error(error, src, ¤t_rule, &stack, alts)
2243 })?;
2244 None
2245 }
2246 ActionBinding::State(callback) => self
2247 .run_state_callback(
2248 label,
2249 callback,
2250 &mut current_rule,
2251 &mut context,
2252 next.as_deref(),
2253 output,
2254 )
2255 .map_err(|error| {
2256 self.attach_action_error(error, src, ¤t_rule, &stack, alts)
2257 })?,
2258 };
2259 match self.check_lifecycle_output(output, ¤t_rule, site) {
2260 Ok(next_output) => output = next_output,
2261 Err(error) => {
2262 lifecycle_error = Some(error);
2263 break;
2264 }
2265 }
2266 }
2267 if let Some(error) = lifecycle_error {
2268 update_partial(mode, &root_node, ¤t_rule, &stack);
2269 self.recover_error_pass(
2270 error,
2271 if is_open {
2272 RuleState::Open
2273 } else {
2274 RuleState::Close
2275 },
2276 None,
2277 false,
2278 src,
2279 &mut current_rule,
2280 &mut stack,
2281 &mut context,
2282 &mut lexer,
2283 mode,
2284 )?;
2285 continue 'parse;
2286 }
2287 }
2288 update_partial(mode, &root_node, ¤t_rule, &stack);
2289
2290 let mut matched_alt_idx: Option<usize> = None;
2292 let mut matched_count = 0;
2293 matched.reset();
2296 let mut record_written = false;
2302 let mut matched_tokens: Option<Rc<Vec<Token>>> = None;
2305
2306 let groups_prepared = self.options.rule.include == self.prepared_include
2312 && self.options.rule.exclude == self.prepared_exclude;
2313
2314 let first_index = if self.options.lex.relex {
2323 None
2324 } else {
2325 prepared.map(|prepared| prepared.first(is_open))
2326 };
2327 let mut lists: Option<(&[usize], &[usize])> = None;
2331 let mut key_tin = TIN_BD;
2332 let (mut ni, mut wi) = (0, 0);
2333 let mut next_idx = 0;
2334 loop {
2335 if lists.is_none() {
2336 if let (Some(index), Some(t0)) = (first_index, context.t.first()) {
2337 if t0.tin != TIN_BD {
2338 key_tin = t0.tin;
2339 let named = index.named(key_tin);
2340 let wild = index.wild.as_slice();
2341 (ni, wi) = (0, 0);
2342 while ni < named.len() && named[ni] < next_idx {
2343 ni += 1;
2344 }
2345 while wi < wild.len() && wild[wi] < next_idx {
2346 wi += 1;
2347 }
2348 lists = Some((named, wild));
2349 }
2350 }
2351 }
2352 let idx = match lists {
2353 Some((named, wild)) => {
2354 let n = named.get(ni).copied().unwrap_or(alts.len());
2355 let w = wild.get(wi).copied().unwrap_or(alts.len());
2356 if alts.len() <= n && alts.len() <= w {
2357 break;
2359 }
2360 if n < w {
2361 ni += 1;
2362 n
2363 } else {
2364 wi += 1;
2365 w
2366 }
2367 }
2368 None => {
2369 if alts.len() <= next_idx {
2370 break;
2371 }
2372 next_idx += 1;
2373 next_idx - 1
2374 }
2375 };
2376 let alt = &alts[idx];
2377 let enabled = match prepared
2378 .filter(|_| groups_prepared)
2379 .and_then(|prepared| prepared.alt(is_open, idx))
2380 {
2381 Some(prepared_alt) => prepared_alt.groups,
2382 None => groups_enabled(alt, &self.options),
2383 };
2384 if !enabled {
2385 continue;
2386 }
2387 let s_len = alt.s.len();
2388 let mut alt_matches = true;
2389 if record_written {
2390 matched.reset();
2391 record_written = false;
2392 }
2393 let mut relex_undo: Option<RelexUndo> = None;
2394 for (pos, pos_tins) in alt.s.iter().enumerate() {
2395 if let Err(error) = self.ensure_lookahead(
2396 &mut lexer,
2397 &mut context,
2398 &mut current_rule,
2399 pos + 1,
2400 mode,
2401 ParseSite {
2402 source: src,
2403 stack: &stack,
2404 alts,
2405 },
2406 ) {
2407 return Err(self.attach_error(error, ¤t_rule, &stack, alts, None));
2408 }
2409 let Some(token) = context.t.get(pos).cloned() else {
2410 alt_matches = false;
2411 break;
2412 };
2413 if !slot_matches(pos_tins, token.tin) {
2414 let recut = if self.options.lex.relex
2415 && !token.src.is_empty()
2416 && !pos_tins.is_empty()
2417 {
2418 let result = self.catch_callback("lexer relex callback", src, || {
2419 lexer.relex(&token, pos_tins, &mut current_rule, &mut context)
2420 });
2421 result.map_err(|error| {
2422 self.attach_error(error, ¤t_rule, &stack, alts, Some(&token))
2423 })?
2424 } else {
2425 None
2426 };
2427 let Some((mut recut, checkpoint)) = recut else {
2428 alt_matches = false;
2429 break;
2430 };
2431 for subscriber in &self.lex_subscribers {
2432 let result = self.catch_callback("lex subscriber", src, || {
2433 subscriber(&mut recut, &mut current_rule, &mut context)
2434 });
2435 result.map_err(|error| {
2436 self.attach_error(error, ¤t_rule, &stack, alts, Some(&recut))
2437 })?;
2438 }
2439 if !pos_tins.contains(&recut.tin) {
2440 lexer.unrelex(checkpoint, &mut context);
2441 alt_matches = false;
2442 break;
2443 }
2444 if relex_undo.is_none() {
2445 relex_undo = Some(RelexUndo {
2446 position: pos,
2447 token,
2448 checkpoint,
2449 tokens: context.t.clone(),
2450 });
2451 }
2452 context.t[pos] = recut;
2453 context.t.truncate(pos + 1);
2454 }
2455 }
2456
2457 if alt_matches {
2458 let tokens: Rc<Vec<Token>> =
2459 Rc::new(context.t.iter().take(s_len).cloned().collect());
2460 if alt.c_ref.is_some() || !alt.c.is_empty() {
2468 let mut candidate = current_rule.clone();
2469 if is_open {
2470 candidate.o = Rc::clone(&tokens);
2471 } else {
2472 candidate.c = Rc::clone(&tokens);
2473 }
2474 if !builtin_condition_matches(alt.c_ref.as_deref(), &candidate)
2475 || !conditions_match(&alt.c, &candidate, &stack)
2476 {
2477 alt_matches = false;
2478 }
2479 }
2480 if alt_matches {
2481 if is_open {
2482 current_rule.o = Rc::clone(&tokens);
2483 } else {
2484 current_rule.c = Rc::clone(&tokens);
2485 }
2486 if let Some(condition) = &alt.c_fn {
2487 context.set_rule(¤t_rule);
2488 let result = self.catch_callback("alternate condition", src, || {
2489 condition(&mut current_rule, &mut context)
2490 });
2491 alt_matches = result.map_err(|error| {
2492 self.attach_error(
2493 error,
2494 ¤t_rule,
2495 &stack,
2496 alts,
2497 Self::phase_token(¤t_rule),
2498 )
2499 })?;
2500 }
2501 if alt_matches {
2502 if let Some(condition) = &alt.c_match {
2503 context.set_rule(¤t_rule);
2504 record_written = true;
2505 let result =
2506 self.catch_callback("matched alternate condition", src, || {
2507 condition(&mut current_rule, &mut context, &mut matched)
2508 });
2509 alt_matches = result.map_err(|error| {
2510 self.attach_error(
2511 error,
2512 ¤t_rule,
2513 &stack,
2514 alts,
2515 Self::phase_token(¤t_rule),
2516 )
2517 })?;
2518 }
2519 }
2520 if alt_matches {
2521 if let Some(condition) = &alt.c_lex_match {
2522 context.set_rule(¤t_rule);
2523 record_written = true;
2524 let result = self.catch_callback(
2525 "matched alternate lexer condition",
2526 src,
2527 || {
2528 condition(
2529 &mut current_rule,
2530 &mut context,
2531 &mut matched,
2532 &mut lexer,
2533 )
2534 },
2535 );
2536 alt_matches = result.map_err(|error| {
2537 self.attach_error(
2538 error,
2539 ¤t_rule,
2540 &stack,
2541 alts,
2542 Self::phase_token(¤t_rule),
2543 )
2544 })?;
2545 }
2546 }
2547 if alt_matches {
2548 if let Some(condition) = &alt.c_lex {
2549 context.set_rule(¤t_rule);
2550 let result =
2551 self.catch_callback("alternate lexer condition", src, || {
2552 condition(&mut current_rule, &mut context, &mut lexer)
2553 });
2554 alt_matches = result.map_err(|error| {
2555 self.attach_error(
2556 error,
2557 ¤t_rule,
2558 &stack,
2559 alts,
2560 Self::phase_token(¤t_rule),
2561 )
2562 })?;
2563 }
2564 }
2565 }
2566 if alt_matches {
2567 matched_alt_idx = Some(idx);
2568 matched_count = s_len;
2569 if alt.c_fn.is_none() && alt.c_match.is_none() {
2579 matched_tokens = Some(Rc::clone(&tokens));
2580 }
2581 break;
2582 }
2583 }
2584 if let Some(undo) = relex_undo {
2585 lexer.unrelex(undo.checkpoint, &mut context);
2586 context.t = undo.tokens;
2587 for subscriber in &self.lex_subscribers {
2588 let mut restored = undo.token.clone();
2589 let result = self.catch_callback("lex subscriber", src, || {
2590 subscriber(&mut restored, &mut current_rule, &mut context)
2591 });
2592 result.map_err(|error| {
2593 self.attach_error(error, ¤t_rule, &stack, alts, Some(&restored))
2594 })?;
2595 }
2596 debug_assert_eq!(context.t.get(undo.position), Some(&undo.token));
2597 }
2598 if lists.is_some() && context.t.first().map(|t0| t0.tin) != Some(key_tin) {
2604 lists = None;
2605 next_idx = idx + 1;
2606 }
2607 }
2608
2609 if let Some(idx) = matched_alt_idx {
2610 let matched_tokens = matched_tokens.unwrap_or_else(|| {
2612 Rc::new(context.t.iter().take(matched_count).cloned().collect())
2613 });
2614 if is_open {
2615 current_rule.o = matched_tokens;
2616 } else {
2617 current_rule.c = matched_tokens;
2618 }
2619
2620 let rewritten: AltSpec;
2631 let alt: &AltSpec = if let Some(modifier) = alts[idx].h.clone() {
2632 context.set_rule(¤t_rule);
2633 let source = alts[idx].clone();
2634 let result = self.catch_callback("alternate modifier", src, || {
2635 modifier(source, &mut current_rule, &mut context)
2636 });
2637 rewritten = result.map_err(|error| {
2638 self.attach_error(
2639 error,
2640 ¤t_rule,
2641 &stack,
2642 alts,
2643 Self::phase_token(¤t_rule),
2644 )
2645 })?;
2646 &rewritten
2647 } else {
2648 &alts[idx]
2649 };
2650
2651 matched.h = alt.h_match.clone();
2652 if !alt.n.is_empty() {
2653 matched.n = alt.n.clone();
2654 }
2655 if !alt.u.is_empty() {
2656 matched.u = alt.u.clone();
2657 }
2658 if !alt.k.is_empty() {
2659 matched.k = alt.k.clone();
2660 }
2661 let prepared_alt = if alts[idx].h.is_some() {
2667 None
2668 } else {
2669 prepared.and_then(|prepared| prepared.alt(is_open, idx))
2670 };
2671 match prepared_alt {
2672 Some(prepared_alt) => matched.g.clone_from(&prepared_alt.group_tags),
2676 None if !alt.g.is_empty() => {
2677 matched.g = listed(&alt.g).map(str::to_owned).collect();
2678 }
2679 None => {}
2680 }
2681 let prepared_alt = prepared_alt.filter(|prepared_alt| {
2691 !prepared_alt.observed
2692 && (!prepared_alt.named || self.matched_actions.is_empty())
2693 });
2694 if prepared_alt.is_none() {
2695 let actions = resolved_alt_action_order(
2696 &alt.a,
2697 &alt.action_fns,
2698 &alt.matched_action_fns,
2699 &alt.action_order,
2700 );
2701 if !actions.is_empty() {
2702 matched.actions = actions;
2703 }
2704 }
2705 if !alt.action_configs.is_empty() {
2706 matched.action_configs = alt.action_configs.clone();
2707 }
2708
2709 if let Some(route) = &alt.p_fn {
2710 context.set_rule(¤t_rule);
2711 matched.p = self
2712 .catch_callback("alternate push", src, || {
2713 route(&mut current_rule, &mut context)
2714 })
2715 .map_err(|error| {
2716 self.attach_error(
2717 error,
2718 ¤t_rule,
2719 &stack,
2720 alts,
2721 Self::phase_token(¤t_rule),
2722 )
2723 })?
2724 .filter(|name| !name.is_empty());
2725 }
2726 if let Some(route) = &alt.p_match {
2727 context.set_rule(¤t_rule);
2728 matched.p = self
2729 .catch_callback("matched alternate push", src, || {
2730 route(&mut current_rule, &mut context, &mut matched)
2731 })
2732 .map_err(|error| {
2733 self.attach_error(
2734 error,
2735 ¤t_rule,
2736 &stack,
2737 alts,
2738 Self::phase_token(¤t_rule),
2739 )
2740 })?
2741 .filter(|name| !name.is_empty());
2742 } else if alt.p_fn.is_none() {
2743 if let Some(route) = alt.p.clone() {
2744 matched.p = (!route.is_empty()).then_some(route);
2745 }
2746 }
2747 if let Some(route) = &alt.r_fn {
2748 context.set_rule(¤t_rule);
2749 matched.r = self
2750 .catch_callback("alternate replace", src, || {
2751 route(&mut current_rule, &mut context)
2752 })
2753 .map_err(|error| {
2754 self.attach_error(
2755 error,
2756 ¤t_rule,
2757 &stack,
2758 alts,
2759 Self::phase_token(¤t_rule),
2760 )
2761 })?
2762 .filter(|name| !name.is_empty());
2763 }
2764 if let Some(route) = &alt.r_match {
2765 context.set_rule(¤t_rule);
2766 matched.r = self
2767 .catch_callback("matched alternate replace", src, || {
2768 route(&mut current_rule, &mut context, &mut matched)
2769 })
2770 .map_err(|error| {
2771 self.attach_error(
2772 error,
2773 ¤t_rule,
2774 &stack,
2775 alts,
2776 Self::phase_token(¤t_rule),
2777 )
2778 })?
2779 .filter(|name| !name.is_empty());
2780 } else if alt.r_fn.is_none() {
2781 if let Some(route) = alt.r.clone() {
2782 matched.r = (!route.is_empty()).then_some(route);
2783 }
2784 }
2785 if let Some(backtrack) = &alt.b_fn {
2786 context.set_rule(¤t_rule);
2787 matched.b = self
2788 .catch_callback("alternate backtrack", src, || {
2789 backtrack(&mut current_rule, &mut context)
2790 })
2791 .map_err(|error| {
2792 self.attach_error(
2793 error,
2794 ¤t_rule,
2795 &stack,
2796 alts,
2797 Self::phase_token(¤t_rule),
2798 )
2799 })?;
2800 }
2801 if let Some(backtrack) = &alt.b_match {
2802 context.set_rule(¤t_rule);
2803 matched.b = self
2804 .catch_callback("matched alternate backtrack", src, || {
2805 backtrack(&mut current_rule, &mut context, &mut matched)
2806 })
2807 .map_err(|error| {
2808 self.attach_error(
2809 error,
2810 ¤t_rule,
2811 &stack,
2812 alts,
2813 Self::phase_token(¤t_rule),
2814 )
2815 })?;
2816 } else if alt.b_fn.is_none() && alt.b != 0 {
2817 matched.b = alt.b;
2818 }
2819
2820 if let Some(modifier) = alt.h_match.clone() {
2821 context.set_rule(¤t_rule);
2822 let next = is_open.then(|| current_rule.snapshot());
2823 matched = self
2824 .catch_callback("matched alternate modifier", src, || {
2825 modifier(
2826 std::mem::take(&mut matched),
2827 &mut current_rule,
2828 &mut context,
2829 next.as_deref(),
2830 )
2831 })
2832 .map_err(|error| {
2833 self.attach_error(
2834 error,
2835 ¤t_rule,
2836 &stack,
2837 alts,
2838 Self::phase_token(¤t_rule),
2839 )
2840 })?;
2841 }
2842
2843 if let Some(error_hook) = alt.e.clone() {
2850 context.set_rule(¤t_rule);
2851 let result = self.catch_callback("alternate error", src, || {
2852 error_hook(&mut current_rule, &mut context)
2853 });
2854 matched.e = result
2855 .map_err(|error| {
2856 self.attach_error(
2857 error,
2858 ¤t_rule,
2859 &stack,
2860 alts,
2861 Self::phase_token(¤t_rule),
2862 )
2863 })?
2864 .map(Box::new);
2865 }
2866 if let Some(error_hook) = alt.e_match.clone() {
2867 context.set_rule(¤t_rule);
2868 let result = self.catch_callback("matched alternate error", src, || {
2869 error_hook(&mut current_rule, &mut context, &mut matched)
2870 });
2871 matched.e = result
2872 .map_err(|error| {
2873 self.attach_error(
2874 error,
2875 ¤t_rule,
2876 &stack,
2877 alts,
2878 Self::phase_token(¤t_rule),
2879 )
2880 })?
2881 .map(Box::new);
2882 }
2883 if let Some(token) = matched.e.clone() {
2886 let code = raised_error_code(&token);
2887 let error = TabnasError::new(
2888 code,
2889 token.src.clone(),
2890 src,
2891 token.site.pos,
2892 token.site.ri,
2893 token.site.ci,
2894 );
2895 let done_alt = (!self.rule_done_subscribers.is_empty()).then(|| RuleDoneAlt {
2896 b: matched.b,
2897 g: matched.g.clone(),
2898 p: matched.p.clone().unwrap_or_default(),
2899 r: matched.r.clone().unwrap_or_default(),
2900 err: Some((*token).clone()),
2901 });
2902 let error = self.attach_error(error, ¤t_rule, &stack, alts, Some(&token));
2903 self.recover_error_pass(
2904 error,
2905 if is_open {
2906 RuleState::Open
2907 } else {
2908 RuleState::Close
2909 },
2910 done_alt,
2911 false,
2912 src,
2913 &mut current_rule,
2914 &mut stack,
2915 &mut context,
2916 &mut lexer,
2917 mode,
2918 )?;
2919 continue;
2920 }
2921
2922 for (k, v) in &matched.n {
2924 if *v == 0 {
2925 current_rule.n_mut().insert(k.clone(), 0);
2926 } else {
2927 *current_rule.n_mut().entry(k.clone()).or_insert(0) += *v;
2928 }
2929 }
2930
2931 for (k, v) in &matched.u {
2933 current_rule.u_mut().insert(k.clone(), v.clone());
2934 }
2935
2936 for (k, v) in &matched.k {
2938 current_rule.k_mut().insert(k.clone(), v.clone());
2939 }
2940
2941 let backtrack = matched.b;
2942 let consumed = matched_count.saturating_sub(backtrack);
2943 context.record_consumed(consumed);
2944
2945 let mut matched_action_error = None;
2949 let mut matched_action_token = None;
2950 let published;
2956 let bindings: &[AltActionBinding] = match prepared_alt {
2957 Some(prepared_alt) => &prepared_alt.actions,
2958 None => {
2959 published = matched.actions.clone();
2960 &published
2961 }
2962 };
2963 for binding in bindings {
2964 let act_name = match binding {
2965 AltActionBinding::Context(callback) => {
2966 self.run_context_callback(
2967 "alternate action",
2968 callback,
2969 &mut current_rule,
2970 &mut context,
2971 )
2972 .map_err(|error| {
2973 self.attach_action_error(error, src, ¤t_rule, &stack, alts)
2974 })?;
2975 continue;
2976 }
2977 AltActionBinding::Matched(callback) => {
2978 context.set_rule(¤t_rule);
2979 let result = self
2980 .catch_callback("matched alternate action", src, || {
2981 callback(&mut current_rule, &mut context, &mut matched)
2982 })
2983 .map_err(|error| {
2984 self.attach_action_error(
2985 error,
2986 src,
2987 ¤t_rule,
2988 &stack,
2989 alts,
2990 )
2991 })?;
2992 let token = result.map_err(|action_error| {
2993 self.attach_action_error(
2994 action_error.into(),
2995 src,
2996 ¤t_rule,
2997 &stack,
2998 alts,
2999 )
3000 })?;
3001 if let Some(token) = token.filter(|token| !token.err.is_empty()) {
3002 matched_action_error = Some(self.raised_token_error(
3003 &token,
3004 ¤t_rule,
3005 ParseSite {
3006 source: src,
3007 stack: &stack,
3008 alts,
3009 },
3010 ));
3011 matched_action_token = Some(token);
3012 break;
3013 }
3014 continue;
3015 }
3016 AltActionBinding::Named(name) => name,
3017 };
3018 if let Some(callback) = self.matched_actions.get(act_name) {
3019 context.set_rule(¤t_rule);
3020 let result = self
3021 .catch_callback("named matched alternate action", src, || {
3022 callback(&mut current_rule, &mut context, &mut matched)
3023 })
3024 .map_err(|error| {
3025 self.attach_action_error(error, src, ¤t_rule, &stack, alts)
3026 })?;
3027 let token = result.map_err(|action_error| {
3028 self.attach_action_error(
3029 action_error.into(),
3030 src,
3031 ¤t_rule,
3032 &stack,
3033 alts,
3034 )
3035 })?;
3036 if let Some(token) = token.filter(|token| !token.err.is_empty()) {
3037 matched_action_error = Some(self.raised_token_error(
3038 &token,
3039 ¤t_rule,
3040 ParseSite {
3041 source: src,
3042 stack: &stack,
3043 alts,
3044 },
3045 ));
3046 matched_action_token = Some(token);
3047 break;
3048 }
3049 continue;
3050 }
3051 match act_name.as_str() {
3052 "@probeInit$" => {
3053 current_rule
3054 .k_mut()
3055 .insert("pd_phase".into(), Value::Number(0.0));
3056 let mark = Value::Number(context.mark() as f64);
3057 current_rule.k_mut().insert("pd_mark".into(), mark);
3058 }
3059 "@probeDecide$" => {
3060 let mark = current_rule.k.get("pd_mark").and_then(|value| {
3061 if let Value::Number(mark) = value {
3062 usize::try_from(*mark as u64).ok()
3063 } else {
3064 None
3065 }
3066 });
3067 let Some(mark) = mark.filter(|mark| *mark <= context.v_abs) else {
3068 let mut error = TabnasError::new("internal", "", src, 0, 1, 1);
3069 error.detail =
3070 "@probeDecide$: phase-0 @probeInit$ did not record a valid mark"
3071 .into();
3072 return Err(error);
3073 };
3074 if let Err(error) = self.ensure_lookahead(
3075 &mut lexer,
3076 &mut context,
3077 &mut current_rule,
3078 1,
3079 mode,
3080 ParseSite {
3081 source: src,
3082 stack: &stack,
3083 alts,
3084 },
3085 ) {
3086 return Err(self.attach_error(
3087 error,
3088 ¤t_rule,
3089 &stack,
3090 alts,
3091 None,
3092 ));
3093 }
3094 let disambiguator =
3095 current_rule.k.get("pd_d").and_then(|value| match value {
3096 Value::String(name) => Some(name.as_str()),
3097 _ => None,
3098 });
3099 let phase = if context
3100 .t
3101 .first()
3102 .is_some_and(|token| Some(token.name.as_str()) == disambiguator)
3103 {
3104 1.0
3105 } else {
3106 2.0
3107 };
3108 context.rewind(mark)?;
3109 current_rule
3110 .k_mut()
3111 .insert("pd_phase".into(), Value::Number(phase));
3112 }
3113 _ => self
3114 .run_action_with_config(
3115 act_name,
3116 &mut current_rule,
3117 &mut context,
3118 matched.action_configs.get(act_name),
3119 )
3120 .map_err(|error| {
3121 self.attach_action_error(error, src, ¤t_rule, &stack, alts)
3122 })?,
3123 }
3124 }
3125 if let Some(error) = matched_action_error {
3126 let recovered_alt = Some(RuleDoneAlt {
3127 b: matched.b,
3128 g: matched.g.clone(),
3129 p: matched.p.clone().unwrap_or_default(),
3130 r: matched.r.clone().unwrap_or_default(),
3131 err: None,
3132 });
3133 self.recover_error_pass(
3134 error,
3135 if is_open {
3136 RuleState::Open
3137 } else {
3138 RuleState::Close
3139 },
3140 recovered_alt,
3141 matched_action_token.is_some(),
3142 src,
3143 &mut current_rule,
3144 &mut stack,
3145 &mut context,
3146 &mut lexer,
3147 mode,
3148 )?;
3149 update_partial(mode, &root_node, ¤t_rule, &stack);
3150 continue 'parse;
3151 }
3152 update_partial(mode, &root_node, ¤t_rule, &stack);
3153
3154 let push_name = matched.p.take();
3162 let replace_name = matched.r.take();
3163 let done_alt = (!self.rule_done_subscribers.is_empty()).then(|| RuleDoneAlt {
3168 b: matched.b,
3169 g: matched.g.clone(),
3170 p: push_name.clone().unwrap_or_default(),
3171 r: replace_name.clone().unwrap_or_default(),
3172 err: None,
3173 });
3174
3175 let mut route = match push_name.as_deref().or(replace_name.as_deref()) {
3194 Some(name) => match prepared
3195 .and_then(|prepared| prepared.alt(is_open, idx))
3196 .map(|alt| if push_name.is_some() { &alt.p } else { &alt.r })
3197 .and_then(|route| route.resolved(name))
3198 .or_else(|| self.installed(name))
3199 {
3200 Some(resolved) => Some(resolved),
3201 None => {
3202 let mut token = Self::phase_token(¤t_rule)
3203 .cloned()
3204 .or_else(|| context.t.first().cloned())
3205 .unwrap_or_else(Token::no_token);
3206 token.bad("unknown_rule");
3207 token
3208 .use_data_mut()
3209 .insert("rulename".into(), Value::String(name.to_string()));
3210 let error = self.raised_token_error(
3211 &token,
3212 ¤t_rule,
3213 ParseSite {
3214 source: src,
3215 stack: &stack,
3216 alts,
3217 },
3218 );
3219 self.recover_error_pass(
3220 error,
3221 if is_open {
3222 RuleState::Open
3223 } else {
3224 RuleState::Close
3225 },
3226 done_alt,
3227 false,
3228 src,
3229 &mut current_rule,
3230 &mut stack,
3231 &mut context,
3232 &mut lexer,
3233 mode,
3234 )?;
3235 update_partial(mode, &root_node, ¤t_rule, &stack);
3236 continue 'parse;
3237 }
3238 },
3239 None => None,
3240 };
3241
3242 let completed_rule: Option<Rule>;
3246 let mut completed_value = None;
3247 if push_name.is_some() {
3248 let (push_slot, push_shared, push_spec) =
3249 route.take().expect("a push route was resolved above");
3250 let mut child = Rule::bound(
3251 push_shared.clone(),
3252 current_rule.node.clone(),
3253 Some(push_spec),
3254 push_slot,
3255 );
3256 child.i = next_rule_id;
3257 next_rule_id += 1;
3258 child.d = stack.len() + 1;
3259 child.parent_node = Some(current_rule.node.clone());
3260 child.n = Rc::clone(¤t_rule.n);
3261 child.k = Rc::clone(¤t_rule.k);
3262 child.parent_rule = Some(bounded_history(
3263 current_rule.snapshot(),
3264 self.options.rule.history,
3265 Link::PusherBefore,
3266 ));
3267 current_rule.next_rule_name = Some(push_shared);
3268 current_rule.child_rule = Some(child.snapshot());
3269 current_rule.next_rule = current_rule.child_rule.clone();
3270 current_rule.note_child_push(&child);
3271 let after = self.run_after_actions(
3272 spec,
3273 prepared,
3274 is_open,
3275 &mut current_rule,
3276 &mut context,
3277 ParseSite {
3278 source: src,
3279 stack: &stack,
3280 alts,
3281 },
3282 );
3283 update_partial(mode, &root_node, ¤t_rule, &stack);
3284 if self.recover_after_actions(
3285 after,
3286 if is_open {
3287 RuleState::Open
3288 } else {
3289 RuleState::Close
3290 },
3291 done_alt.clone(),
3292 src,
3293 &mut current_rule,
3294 &mut stack,
3295 &mut context,
3296 &mut lexer,
3297 mode,
3298 )? {
3299 continue 'parse;
3300 }
3301 if is_open {
3302 current_rule.state = RuleState::Close;
3303 }
3304 child.parent_rule = Some(bounded_history(
3305 current_rule.snapshot(),
3306 self.options.rule.history,
3307 Link::Parent,
3308 ));
3309 completed_rule = self.rule_done_copy(¤t_rule);
3310 if park_child_nodes {
3319 current_rule.park_child_node();
3320 }
3321 stack.push(current_rule);
3322 current_rule = child;
3323 } else if replace_name.is_some() {
3324 let (replace_slot, replace_shared, replace_spec) =
3325 route.take().expect("a replace route was resolved above");
3326 let mut next = Rule::bound(
3327 replace_shared.clone(),
3328 current_rule.node.clone(),
3329 Some(replace_spec),
3330 replace_slot,
3331 );
3332 next.i = next_rule_id;
3333 next_rule_id += 1;
3334 next.d = current_rule.d;
3335 next.parent_node = current_rule.parent_node.clone();
3336 next.parent_rule = current_rule.parent_rule.clone();
3337 next.n = Rc::clone(¤t_rule.n);
3338 next.k = Rc::clone(¤t_rule.k);
3339 current_rule.next_rule_name = Some(replace_shared);
3340 current_rule.next_rule = Some(next.snapshot());
3341 let after = self.run_after_actions(
3342 spec,
3343 prepared,
3344 is_open,
3345 &mut current_rule,
3346 &mut context,
3347 ParseSite {
3348 source: src,
3349 stack: &stack,
3350 alts,
3351 },
3352 );
3353 update_partial(mode, &root_node, ¤t_rule, &stack);
3354 if self.recover_after_actions(
3355 after,
3356 if is_open {
3357 RuleState::Open
3358 } else {
3359 RuleState::Close
3360 },
3361 done_alt.clone(),
3362 src,
3363 &mut current_rule,
3364 &mut stack,
3365 &mut context,
3366 &mut lexer,
3367 mode,
3368 )? {
3369 continue 'parse;
3370 }
3371 if is_open {
3372 current_rule.state = RuleState::Close;
3373 }
3374 next.prev_rule = Some(bounded_history(
3375 current_rule.snapshot(),
3376 self.options.rule.history,
3377 Link::Prev,
3378 ));
3379 if let Some(parent) = stack.last_mut() {
3386 parent.freeze_child(¤t_rule);
3387 }
3388 completed_rule = Some(current_rule);
3392 current_rule = next;
3393 } else if is_open {
3394 current_rule.next_rule_name = Some(current_rule.name.clone());
3395 current_rule.next_rule = Some(current_rule.snapshot());
3396 let after = self.run_after_actions(
3397 spec,
3398 prepared,
3399 true,
3400 &mut current_rule,
3401 &mut context,
3402 ParseSite {
3403 source: src,
3404 stack: &stack,
3405 alts,
3406 },
3407 );
3408 update_partial(mode, &root_node, ¤t_rule, &stack);
3409 if self.recover_after_actions(
3410 after,
3411 RuleState::Open,
3412 done_alt.clone(),
3413 src,
3414 &mut current_rule,
3415 &mut stack,
3416 &mut context,
3417 &mut lexer,
3418 mode,
3419 )? {
3420 continue 'parse;
3421 }
3422 current_rule.state = RuleState::Close;
3423 completed_rule = self.rule_done_copy(¤t_rule);
3424 } else {
3425 current_rule.next_rule_name = stack.last().map(|rule| rule.name.clone());
3427 current_rule.next_rule = stack.last().map(Rule::snapshot);
3428 let after = self.run_after_actions(
3429 spec,
3430 prepared,
3431 false,
3432 &mut current_rule,
3433 &mut context,
3434 ParseSite {
3435 source: src,
3436 stack: &stack,
3437 alts,
3438 },
3439 );
3440 update_partial(mode, &root_node, ¤t_rule, &stack);
3441 if self.recover_after_actions(
3442 after,
3443 RuleState::Close,
3444 done_alt.clone(),
3445 src,
3446 &mut current_rule,
3447 &mut stack,
3448 &mut context,
3449 &mut lexer,
3450 mode,
3451 )? {
3452 continue 'parse;
3453 }
3454 let parent = stack.pop();
3455 completed_rule = self.rule_done_copy(¤t_rule);
3456 if let Some(mut parent) = parent {
3457 parent.accept_child(¤t_rule);
3458 current_rule = parent;
3459 } else {
3460 completed_value = Some(current_rule.node.borrow().clone());
3462 }
3463 }
3464 if let Some(completed_rule) = &completed_rule {
3465 self.notify_rule_done(
3466 completed_rule,
3467 &context,
3468 if is_open {
3469 RuleState::Open
3470 } else {
3471 RuleState::Close
3472 },
3473 done_alt,
3474 src,
3475 &stack,
3476 )?;
3477 }
3478 if let Some(value) = completed_value {
3479 final_value = Some(value);
3480 break;
3481 }
3482 update_partial(mode, &root_node, ¤t_rule, &stack);
3483 } else if alts.is_empty() {
3484 let completed_rule: Option<Rule>;
3487 let mut completed_value = None;
3488 if is_open {
3489 current_rule.next_rule_name = Some(current_rule.name.clone());
3490 current_rule.next_rule = Some(current_rule.snapshot());
3491 let after = self.run_after_actions(
3492 spec,
3493 prepared,
3494 true,
3495 &mut current_rule,
3496 &mut context,
3497 ParseSite {
3498 source: src,
3499 stack: &stack,
3500 alts,
3501 },
3502 );
3503 update_partial(mode, &root_node, ¤t_rule, &stack);
3504 if self.recover_after_actions(
3505 after,
3506 RuleState::Open,
3507 None,
3508 src,
3509 &mut current_rule,
3510 &mut stack,
3511 &mut context,
3512 &mut lexer,
3513 mode,
3514 )? {
3515 continue 'parse;
3516 }
3517 current_rule.state = RuleState::Close;
3518 completed_rule = self.rule_done_copy(¤t_rule);
3519 } else {
3520 current_rule.next_rule_name = stack.last().map(|rule| rule.name.clone());
3521 current_rule.next_rule = stack.last().map(Rule::snapshot);
3522 let after = self.run_after_actions(
3523 spec,
3524 prepared,
3525 false,
3526 &mut current_rule,
3527 &mut context,
3528 ParseSite {
3529 source: src,
3530 stack: &stack,
3531 alts,
3532 },
3533 );
3534 update_partial(mode, &root_node, ¤t_rule, &stack);
3535 if self.recover_after_actions(
3536 after,
3537 RuleState::Close,
3538 None,
3539 src,
3540 &mut current_rule,
3541 &mut stack,
3542 &mut context,
3543 &mut lexer,
3544 mode,
3545 )? {
3546 continue 'parse;
3547 }
3548 let parent = stack.pop();
3549 completed_rule = self.rule_done_copy(¤t_rule);
3550 if let Some(mut parent) = parent {
3551 parent.accept_child(¤t_rule);
3552 current_rule = parent;
3553 } else {
3554 completed_value = Some(current_rule.node.borrow().clone());
3555 }
3556 }
3557 if let Some(completed_rule) = &completed_rule {
3558 self.notify_rule_done(
3559 completed_rule,
3560 &context,
3561 if is_open {
3562 RuleState::Open
3563 } else {
3564 RuleState::Close
3565 },
3566 None,
3567 src,
3568 &stack,
3569 )?;
3570 }
3571 if let Some(value) = completed_value {
3572 final_value = Some(value);
3573 break;
3574 }
3575 update_partial(mode, &root_node, ¤t_rule, &stack);
3576 } else {
3577 if is_open {
3579 if let Err(error) = self.ensure_lookahead(
3580 &mut lexer,
3581 &mut context,
3582 &mut current_rule,
3583 1,
3584 mode,
3585 ParseSite {
3586 source: src,
3587 stack: &stack,
3588 alts,
3589 },
3590 ) {
3591 return Err(self.attach_error(error, ¤t_rule, &stack, alts, None));
3592 }
3593 if let Some(capture) = mode.continuation.as_deref_mut() {
3594 let base = failed_alt_tins(&context, alts, &self.options);
3595 capture.failure = continuation_tins(
3596 &context,
3597 ¤t_rule,
3598 &stack,
3599 &self.rules,
3600 &self.options,
3601 0,
3602 Some(&base),
3603 );
3604 }
3605 let t0 = context.t.first().cloned();
3606 let (src_token, si, ri, ci) = if let Some(t) = t0.as_ref() {
3607 (t.src.to_string(), t.site.pos, t.site.ri, t.site.ci)
3608 } else {
3609 (String::new(), src.len(), 1, 1)
3610 };
3611 let code = t0.as_ref().map_or("unexpected", deferred_error_code);
3612 let error = TabnasError::new(code, src_token, src, si, ri, ci);
3613 let done_alt = (!alts.is_empty() && !self.rule_done_subscribers.is_empty())
3614 .then(|| RuleDoneAlt {
3615 b: 0,
3616 g: Vec::new(),
3617 p: String::new(),
3618 r: String::new(),
3619 err: t0.clone(),
3620 });
3621 let error = self.attach_error(error, ¤t_rule, &stack, alts, t0.as_ref());
3622 self.recover_error_pass(
3623 error,
3624 RuleState::Open,
3625 done_alt,
3626 false,
3627 src,
3628 &mut current_rule,
3629 &mut stack,
3630 &mut context,
3631 &mut lexer,
3632 mode,
3633 )?;
3634 continue;
3635 } else {
3636 if let Err(error) = self.ensure_lookahead(
3637 &mut lexer,
3638 &mut context,
3639 &mut current_rule,
3640 1,
3641 mode,
3642 ParseSite {
3643 source: src,
3644 stack: &stack,
3645 alts,
3646 },
3647 ) {
3648 return Err(self.attach_error(error, ¤t_rule, &stack, alts, None));
3649 }
3650 if let Some(capture) = mode.continuation.as_deref_mut() {
3651 let base = failed_alt_tins(&context, alts, &self.options);
3652 capture.failure = continuation_tins(
3653 &context,
3654 ¤t_rule,
3655 &stack,
3656 &self.rules,
3657 &self.options,
3658 0,
3659 Some(&base),
3660 );
3661 }
3662 let token = context.t.first().cloned();
3663 let (source, pos, row, col) = token.as_ref().map_or_else(
3664 || (String::new(), src.chars().count(), 1, 1),
3665 |value| {
3666 (
3667 value.src.to_string(),
3668 value.site.pos,
3669 value.site.ri,
3670 value.site.ci,
3671 )
3672 },
3673 );
3674 let code = token.as_ref().map_or("unexpected", deferred_error_code);
3675 let error = TabnasError::new(code, source, src, pos, row, col);
3676 let done_alt = Some(RuleDoneAlt {
3677 b: 0,
3678 g: Vec::new(),
3679 p: String::new(),
3680 r: String::new(),
3681 err: token.clone(),
3682 });
3683 let error =
3684 self.attach_error(error, ¤t_rule, &stack, alts, token.as_ref());
3685 self.recover_error_pass(
3686 error,
3687 RuleState::Close,
3688 done_alt,
3689 false,
3690 src,
3691 &mut current_rule,
3692 &mut stack,
3693 &mut context,
3694 &mut lexer,
3695 mode,
3696 )?;
3697 continue;
3698 }
3699 }
3700 }
3701
3702 let res = final_value.unwrap_or(Value::Null).unwrap_undefined();
3703 if mode.recovering {
3704 mode.partial = Some(res.clone());
3705 }
3706
3707 if let Err(error) = self.ensure_lookahead(
3710 &mut lexer,
3711 &mut context,
3712 &mut current_rule,
3713 1,
3714 mode,
3715 ParseSite {
3716 source: src,
3717 stack: &stack,
3718 alts: &[],
3719 },
3720 ) {
3721 let error = self.attach_error(error, ¤t_rule, &stack, &[], None);
3722 if mode.recovering {
3723 if mode.errors.last() != Some(&error) {
3724 mode.errors.push(error.clone());
3725 context.errs.push(error);
3726 }
3727 return Ok(res);
3728 }
3729 return Err(error);
3730 }
3731 if let Some(t0) = context.t.first() {
3732 if t0.tin != TIN_ZZ {
3733 let code = if t0.tin == TIN_BD && !t0.why.is_empty() {
3734 t0.why.as_str()
3735 } else {
3736 "unexpected"
3737 };
3738 let error =
3739 TabnasError::new(code, &*t0.src, src, t0.site.pos, t0.site.ri, t0.site.ci);
3740 let error = self.attach_error(
3741 error,
3742 ¤t_rule,
3743 &stack,
3744 &[AltSpec {
3745 s: vec![vec![TIN_ZZ]],
3746 ..Default::default()
3747 }],
3748 Some(t0),
3749 );
3750 if mode.recovering {
3751 if mode.errors.last() != Some(&error) {
3752 mode.errors.push(error.clone());
3753 context.errs.push(error);
3754 }
3755 return Ok(res);
3756 }
3757 return Err(error);
3758 }
3759 }
3760 if self
3761 .options
3762 .result
3763 .fail
3764 .iter()
3765 .any(|failed| failed.deep_equal(&res))
3766 {
3767 let token = context.t.first();
3768 let error = token.map_or_else(
3769 || TabnasError::new("unexpected", "", src, 0, 1, 1),
3770 |token| {
3771 TabnasError::new(
3772 "unexpected",
3773 &*token.src,
3774 src,
3775 token.site.pos,
3776 token.site.ri,
3777 token.site.ci,
3778 )
3779 },
3780 );
3781 if mode.recovering {
3782 mode.errors.push(error.clone());
3783 context.errs.push(error);
3784 return Ok(res);
3785 }
3786 return Err(error);
3787 }
3788 Ok(res)
3789 }
3790}
3791
3792#[inline]
3800fn update_partial(
3801 mode: &mut ParseMode<'_>,
3802 root_node: &std::rc::Rc<std::cell::RefCell<Value>>,
3803 current_rule: &Rule,
3804 stack: &[Rule],
3805) {
3806 if mode.recovering {
3807 mode.partial = best_partial_value(root_node, current_rule, stack);
3808 }
3809}
3810
3811#[inline(never)]
3812fn best_partial_value(
3813 root_node: &std::rc::Rc<std::cell::RefCell<Value>>,
3814 current_rule: &Rule,
3815 stack: &[Rule],
3816) -> Option<Value> {
3817 let usable = |value: Value| (!matches!(value, Value::Undefined | Value::Null)).then_some(value);
3818
3819 usable(root_node.borrow().clone())
3820 .or_else(|| {
3821 stack
3822 .iter()
3823 .find_map(|rule| usable(rule.node.borrow().clone()))
3824 })
3825 .or_else(|| usable(current_rule.node.borrow().clone()))
3826 .map(Value::unwrap_undefined)
3827}
3828
3829fn error_token(error: &TabnasError) -> Token {
3830 let byte_position = error
3831 .full_source
3832 .char_indices()
3833 .nth(error.pos)
3834 .map_or(error.full_source.len(), |(index, _)| index);
3835 let mut token = Token::new(
3836 "#BD",
3837 TIN_BD,
3838 Value::Undefined,
3839 error.src.clone(),
3840 crate::Point {
3841 len: error.len,
3842 site: crate::Site {
3843 si: byte_position,
3844 pos: error.pos,
3845 ri: error.row,
3846 ci: error.col,
3847 },
3848 },
3849 );
3850 token.err = crate::TokenCode::from(error.code.as_str());
3851 token.why = token.err.clone();
3852 token
3853}
3854
3855fn deferred_error_code(token: &Token) -> &str {
3856 if token.tin != TIN_BD {
3857 "unexpected"
3858 } else if !token.why.is_empty() {
3859 &token.why
3860 } else if !token.err.is_empty() {
3861 &token.err
3862 } else {
3863 "unexpected"
3864 }
3865}
3866
3867fn raised_error_code(token: &Token) -> &str {
3868 if !token.err.is_empty() {
3869 &token.err
3870 } else if !token.why.is_empty() {
3871 &token.why
3872 } else {
3873 "unexpected"
3874 }
3875}
3876
3877fn mid_construct(code: &str) -> bool {
3878 matches!(code, "unprintable" | "invalid_unicode" | "invalid_ascii")
3879}
3880
3881fn absorb_lex_error(
3882 error: &TabnasError,
3883 context: &mut Context,
3884 options: &Options,
3885 errors: &mut Vec<TabnasError>,
3886) -> bool {
3887 let recover = &options.parse.recover;
3888 if errors.len() >= recover.max_recoveries {
3889 return false;
3890 }
3891
3892 let end = error.pos.saturating_add(error.len.max(1));
3893 if context.bad_to.is_some_and(|bad_to| error.pos <= bad_to) {
3894 if let Some(index) = context.bad_error {
3895 if let Some(previous) = errors.get_mut(index) {
3896 let recovered = previous.recovered.get_or_insert(crate::RecoveredAt {
3897 skipped: 0,
3898 sync: None,
3899 bad: true,
3900 });
3901 recovered.skipped = recovered.skipped.saturating_add(1);
3902 let skipped = recovered.skipped;
3903 if recover.max_skip < skipped {
3904 return false;
3905 }
3906 if let Some(context_previous) = context.errs.get_mut(index) {
3907 *context_previous = previous.clone();
3908 }
3909 context.bad_to = Some(end.max(context.bad_to.unwrap_or_default()));
3910 return true;
3911 }
3912 }
3913 }
3914
3915 let suppressed = context
3916 .recover_at
3917 .is_some_and(|at| context.v_abs.saturating_sub(at) < recover.suppress);
3918 if suppressed {
3919 context.bad_error = None;
3920 context.bad_to = Some(end);
3921 return true;
3922 }
3923
3924 let mut recorded = error.clone();
3925 recorded.recovered = Some(crate::RecoveredAt {
3926 skipped: 1,
3927 sync: None,
3928 bad: true,
3929 });
3930 errors.push(recorded.clone());
3931 context.errs.push(recorded);
3932 context.bad_error = Some(errors.len() - 1);
3933 context.bad_to = Some(end);
3934 context.recover_at = Some(context.v_abs);
3935 true
3936}
3937
3938fn slot_matches(slot: &[Tin], tin: Tin) -> bool {
3939 tin != TIN_BD && (slot.is_empty() || slot.contains(&tin) || slot.contains(&TIN_AA))
3940}
3941
3942fn alt_match_depth(alt: &AltSpec, context: &Context) -> usize {
3943 let mut depth = 0;
3944 while depth < alt.s.len() {
3945 let Some(token) = context.t.get(depth) else {
3946 break;
3947 };
3948 if !slot_matches(&alt.s[depth], token.tin) {
3949 break;
3950 }
3951 depth += 1;
3952 }
3953 depth
3954}
3955
3956fn completion_tins(slot: &[Tin]) -> impl Iterator<Item = Tin> + '_ {
3957 slot.iter()
3958 .copied()
3959 .chain(slot.is_empty().then_some(TIN_AA))
3960}
3961
3962fn failed_alt_tins(context: &Context, alts: &[AltSpec], options: &Options) -> Vec<Tin> {
3963 let mut out = BTreeSet::new();
3964 for alt in alts {
3965 if !groups_enabled(alt, options) {
3966 continue;
3967 }
3968 let depth = alt_match_depth(alt, context);
3969 if let Some(slot) = alt.s.get(depth) {
3970 out.extend(completion_tins(slot));
3971 }
3972 }
3973 out.into_iter().collect()
3974}
3975
3976fn lead_tins(alts: &[AltSpec], options: &Options, out: &mut BTreeSet<Tin>) {
3977 for alt in alts {
3978 if !groups_enabled(alt, options) {
3979 continue;
3980 }
3981 if let Some(slot) = alt.s.first() {
3982 out.extend(completion_tins(slot));
3983 }
3984 }
3985}
3986
3987fn has_empty_close(spec: &RuleSpec, options: &Options) -> bool {
3988 spec.close
3989 .iter()
3990 .any(|alt| groups_enabled(alt, options) && alt.s.is_empty())
3991}
3992
3993fn alt_has_sync_group(alt: &AltSpec, sync_groups: &[String]) -> bool {
3994 alt.g
3995 .split(',')
3996 .map(str::trim)
3997 .any(|tag| sync_groups.iter().any(|wanted| wanted == tag))
3998}
3999
4000fn add_close_tins(
4001 rule: &Rule,
4002 rules: &IndexMap<String, Arc<RuleSpec>>,
4003 options: &Options,
4004 tagged_only: bool,
4005 out: &mut BTreeSet<Tin>,
4006) {
4007 let Some(spec) = rules.get(&*rule.name) else {
4008 return;
4009 };
4010 for alt in &spec.close {
4011 if !groups_enabled(alt, options)
4012 || (tagged_only && !alt_has_sync_group(alt, &options.parse.recover.sync_groups))
4013 {
4014 continue;
4015 }
4016 if let Some(slot) = alt.s.first() {
4017 out.extend(completion_tins(slot));
4018 }
4019 }
4020}
4021
4022fn compute_sync_tins(
4023 rule: &Rule,
4024 stack: &[Rule],
4025 rules: &IndexMap<String, Arc<RuleSpec>>,
4026 options: &Options,
4027) -> BTreeSet<Tin> {
4028 let mut out = BTreeSet::new();
4029 add_close_tins(rule, rules, options, true, &mut out);
4030 for parent in stack.iter().rev() {
4031 add_close_tins(parent, rules, options, true, &mut out);
4032 }
4033 if out.is_empty() {
4034 add_close_tins(rule, rules, options, false, &mut out);
4035 for parent in stack.iter().rev() {
4036 add_close_tins(parent, rules, options, false, &mut out);
4037 }
4038 }
4039 for name in &options.parse.recover.sync_tokens {
4040 if let Some(tin) = options.token(name) {
4041 out.insert(tin);
4042 }
4043 if let Some(tins) = options.token_set.get(name.trim_start_matches('#')) {
4044 out.extend(tins.iter().copied());
4045 }
4046 }
4047 out
4048}
4049
4050fn accepts_close(
4051 rule: &Rule,
4052 tin: Tin,
4053 rules: &IndexMap<String, Arc<RuleSpec>>,
4054 options: &Options,
4055) -> bool {
4056 rules.get(&*rule.name).is_some_and(|spec| {
4057 spec.close.iter().any(|alt| {
4058 groups_enabled(alt, options)
4059 && (alt.s.is_empty() || alt.s.first().is_some_and(|slot| slot_matches(slot, tin)))
4060 })
4061 })
4062}
4063
4064fn add_openers(
4065 name: &str,
4066 rules: &IndexMap<String, Arc<RuleSpec>>,
4067 options: &Options,
4068 opened: &mut BTreeSet<String>,
4069 out: &mut BTreeSet<Tin>,
4070) {
4071 if name.is_empty() || !opened.insert(name.to_owned()) {
4072 return;
4073 }
4074 let Some(spec) = rules.get(name) else {
4075 return;
4076 };
4077 lead_tins(&spec.open, options, out);
4078 for alt in &spec.open {
4079 if !groups_enabled(alt, options) || !alt.s.is_empty() {
4080 continue;
4081 }
4082 if let Some(push) = alt.p.as_deref() {
4083 add_openers(push, rules, options, opened, out);
4084 }
4085 if let Some(replace) = alt.r.as_deref() {
4086 add_openers(replace, rules, options, opened, out);
4087 }
4088 }
4089}
4090
4091fn continuation_tins(
4092 context: &Context,
4093 rule: &Rule,
4094 stack: &[Rule],
4095 rules: &IndexMap<String, Arc<RuleSpec>>,
4096 options: &Options,
4097 query_pos: usize,
4098 failed: Option<&[Tin]>,
4099) -> Vec<Tin> {
4100 let Some(spec) = rules.get(&*rule.name) else {
4101 return Vec::new();
4102 };
4103 let state_alts = if rule.state == RuleState::Open {
4104 &spec.open
4105 } else {
4106 &spec.close
4107 };
4108 let mut out = BTreeSet::new();
4109
4110 if let Some(failed) = failed.filter(|tins| !tins.is_empty()) {
4111 out.extend(failed.iter().copied());
4112 } else {
4113 for alt in state_alts {
4114 if !groups_enabled(alt, options) {
4115 continue;
4116 }
4117 let depth = alt_match_depth(alt, context);
4118 if depth == query_pos {
4119 if let Some(slot) = alt.s.get(depth) {
4120 out.extend(completion_tins(slot));
4121 }
4122 }
4123 }
4124 }
4125
4126 let mut close_rule = rule;
4129 let mut parent_index = stack.len();
4130 while let Some(close_spec) = rules.get(&*close_rule.name) {
4131 if !has_empty_close(close_spec, options) || parent_index == 0 {
4132 break;
4133 }
4134 parent_index -= 1;
4135 let parent = &stack[parent_index];
4136 if let Some(parent_spec) = rules.get(&*parent.name) {
4137 lead_tins(&parent_spec.close, options, &mut out);
4138 }
4139 close_rule = parent;
4140 }
4141
4142 let mut opened = BTreeSet::new();
4145 for alt in state_alts {
4146 if !groups_enabled(alt, options) || alt_match_depth(alt, context) != alt.s.len() {
4147 continue;
4148 }
4149 if alt.b_fn.is_some() {
4152 continue;
4153 }
4154 if alt.s.len().checked_sub(alt.b) != Some(query_pos) {
4155 continue;
4156 }
4157 if let Some(push) = alt.p.as_deref() {
4158 add_openers(push, rules, options, &mut opened, &mut out);
4159 }
4160 if let Some(replace) = alt.r.as_deref() {
4161 add_openers(replace, rules, options, &mut opened, &mut out);
4162 }
4163 }
4164
4165 out.into_iter().collect()
4166}
4167
4168fn listed(list: &str) -> impl Iterator<Item = &str> {
4174 list.split(',')
4175 .map(str::trim)
4176 .filter(|entry| !entry.is_empty())
4177}
4178
4179pub(crate) fn groups_enabled(alt: &AltSpec, options: &Options) -> bool {
4180 let include = options.rule.include.as_str();
4185 let exclude = options.rule.exclude.as_str();
4186 if include.is_empty() && exclude.is_empty() {
4187 return true;
4188 }
4189 let declares = |wanted: &str| listed(&alt.g).any(|group| group == wanted);
4196 let included = listed(include).next().is_none() || listed(include).any(&declares);
4197 included && !listed(exclude).any(&declares)
4198}
4199
4200fn builtin_condition_matches(reference: Option<&str>, rule: &Rule) -> bool {
4201 let phase = match rule.k.get("pd_phase") {
4202 Some(Value::Number(value)) => *value as i32,
4203 _ => 0,
4204 };
4205 match reference {
4206 None => true,
4207 Some("@probePhase0$") => phase == 0,
4208 Some("@probePhase1$") => phase == 1,
4209 Some("@probePhase2$") => phase == 2,
4210 Some(_) => false,
4211 }
4212}
4213
4214fn conditions_match(conditions: &[Condition], rule: &Rule, ancestors: &[Rule]) -> bool {
4215 conditions.iter().all(|condition| {
4216 let resolved = resolve_condition_path(rule, ancestors, &condition.path);
4217 if condition.op == CompareOp::Exist {
4218 let exists = condition_exists(rule, ancestors, &condition.path);
4219 let wanted = matches!(condition.value, Value::Bool(true));
4220 return exists == wanted;
4221 }
4222 let Some(actual) = resolved else {
4223 return !matches!(condition.op, CompareOp::Eq);
4224 };
4225 match condition.op {
4226 CompareOp::Eq => actual.deep_equal(&condition.value),
4227 CompareOp::Ne => !actual.deep_equal(&condition.value),
4228 CompareOp::Lt => ordered(&actual, &condition.value).is_none_or(|value| value < 0),
4229 CompareOp::Lte => ordered(&actual, &condition.value).is_none_or(|value| value <= 0),
4230 CompareOp::Gt => ordered(&actual, &condition.value).is_none_or(|value| value > 0),
4231 CompareOp::Gte => ordered(&actual, &condition.value).is_none_or(|value| value >= 0),
4232 CompareOp::Exist => unreachable!("handled above"),
4233 }
4234 })
4235}
4236
4237fn ordered(left: &Value, right: &Value) -> Option<i8> {
4238 match (left, right) {
4239 (Value::Number(left), Value::Number(right)) => Some(if left < right {
4240 -1
4241 } else if left > right {
4242 1
4243 } else {
4244 0
4245 }),
4246 (Value::String(left), Value::String(right)) => Some(match left.cmp(right) {
4247 std::cmp::Ordering::Less => -1,
4248 std::cmp::Ordering::Equal => 0,
4249 std::cmp::Ordering::Greater => 1,
4250 }),
4251 _ => None,
4252 }
4253}
4254
4255fn condition_exists(rule: &Rule, ancestors: &[Rule], path: &[String]) -> bool {
4256 if path.first().map(String::as_str) == Some("n") && path.len() == 2 {
4257 rule.n.contains_key(&path[1])
4258 } else if path.first().map(String::as_str) == Some("parent") {
4259 ancestors
4260 .split_last()
4261 .is_some_and(|(parent, parent_ancestors)| {
4262 condition_exists(parent, parent_ancestors, &path[1..])
4263 })
4264 } else if path.first().map(String::as_str) == Some("child") {
4265 rule.child_rule
4266 .as_deref()
4267 .is_some_and(|child| snapshot_condition_exists(child, &path[1..]))
4268 } else if path.first().map(String::as_str) == Some("prev") {
4269 rule.prev_rule
4270 .as_deref()
4271 .is_some_and(|prev| snapshot_condition_exists(prev, &path[1..]))
4272 } else if path.first().map(String::as_str) == Some("next") {
4273 if let Some(next) = rule.next_rule.as_deref() {
4274 snapshot_condition_exists(next, &path[1..])
4275 } else if rule.next_rule_name.as_deref() == Some(&*rule.name) {
4276 condition_exists(rule, ancestors, &path[1..])
4277 } else {
4278 false
4279 }
4280 } else {
4281 resolve_condition_path(rule, ancestors, path).is_some()
4282 }
4283}
4284
4285fn resolve_condition_path(rule: &Rule, ancestors: &[Rule], path: &[String]) -> Option<Value> {
4286 let root = path.first()?.as_str();
4287 let rest = &path[1..];
4288 match root {
4289 "n" if rest.len() == 1 => Some(Value::Number(*rule.n.get(&rest[0]).unwrap_or(&0) as f64)),
4290 "u" => map_path(&rule.u, rest),
4291 "k" => map_path(&rule.k, rest),
4292 "d" if rest.is_empty() => Some(Value::Number(rule.d as f64)),
4293 "i" if rest.is_empty() => Some(Value::Number(rule.i as f64)),
4294 "name" if rest.is_empty() => Some(Value::String(rule.name.to_string())),
4295 "state" if rest.is_empty() => Some(Value::String(
4296 match rule.state {
4297 RuleState::Open => "o",
4298 RuleState::Close => "c",
4299 }
4300 .into(),
4301 )),
4302 "node" => value_path(rule.node.borrow().clone(), rest),
4303 "need" if rest.is_empty() => Some(Value::Number(rule.need as f64)),
4304 "oN" if rest.is_empty() => Some(Value::Number(rule.o.len() as f64)),
4305 "cN" if rest.is_empty() => Some(Value::Number(rule.c.len() as f64)),
4306 "o" => token_list_path(&rule.o, rest),
4307 "c" => token_list_path(&rule.c, rest),
4308 "o0" => token_path(rule.o.first(), rest),
4309 "o1" => token_path(rule.o.get(1), rest),
4310 "c0" => token_path(rule.c.first(), rest),
4311 "c1" => token_path(rule.c.get(1), rest),
4312 "parent" => {
4313 let (parent, parent_ancestors) = ancestors.split_last()?;
4314 resolve_condition_path(parent, parent_ancestors, rest)
4315 }
4316 "child" => resolve_snapshot_path(rule.child_rule.as_deref()?, rest),
4317 "prev" => resolve_snapshot_path(rule.prev_rule.as_deref()?, rest),
4318 "next" => {
4319 if let Some(next) = rule.next_rule.as_deref() {
4320 resolve_snapshot_path(next, rest)
4321 } else if rule.next_rule_name.as_deref() == Some(&*rule.name) {
4322 resolve_condition_path(rule, ancestors, rest)
4323 } else {
4324 None
4325 }
4326 }
4327 "spec" if rest == ["name"] => Some(Value::String(rule.name.to_string())),
4328 _ => None,
4329 }
4330}
4331
4332#[derive(Clone, Copy, PartialEq, Eq)]
4334enum Link {
4335 Parent,
4338 PusherBefore,
4342 Prev,
4344}
4345
4346fn bounded_history(
4375 snapshot: Rc<RuleSnapshot>,
4376 history: Option<usize>,
4377 link: Link,
4378) -> Rc<RuleSnapshot> {
4379 let Some(history) = crate::options::effective_rule_history(history) else {
4380 return snapshot;
4381 };
4382 let mut links: Vec<&Rc<RuleSnapshot>> = Vec::with_capacity(history);
4388 let mut current = Some(&snapshot);
4389 while let Some(snapshot) = current {
4390 if links.len() == history {
4391 break;
4392 }
4393 links.push(snapshot);
4394 current = snapshot.prev_rule.as_ref();
4395 }
4396 let mut prev: Option<Rc<RuleSnapshot>> = None;
4397 for (depth, original) in links.into_iter().enumerate().rev() {
4399 let mut copy = (**original).clone();
4400 if depth != 0 || link != Link::Parent {
4401 copy.child_rule = None;
4402 copy.next_rule = None;
4403 copy.next_rule_name = None;
4404 }
4405 copy.prev_rule = prev.take();
4406 prev = Some(Rc::new(copy));
4407 }
4408 prev.expect("at least the snapshot itself is copied")
4409}
4410
4411fn snapshot_condition_exists(rule: &RuleSnapshot, path: &[String]) -> bool {
4412 if path.first().map(String::as_str) == Some("n") && path.len() == 2 {
4413 rule.n.contains_key(&path[1])
4414 } else if path.first().map(String::as_str) == Some("parent") {
4415 rule.parent_rule
4416 .as_deref()
4417 .is_some_and(|parent| snapshot_condition_exists(parent, &path[1..]))
4418 } else if path.first().map(String::as_str) == Some("child") {
4419 rule.child_rule
4420 .as_deref()
4421 .is_some_and(|child| snapshot_condition_exists(child, &path[1..]))
4422 } else if path.first().map(String::as_str) == Some("prev") {
4423 rule.prev_rule
4424 .as_deref()
4425 .is_some_and(|prev| snapshot_condition_exists(prev, &path[1..]))
4426 } else if path.first().map(String::as_str) == Some("next") {
4427 if let Some(next) = rule.next_rule.as_deref() {
4428 snapshot_condition_exists(next, &path[1..])
4429 } else if rule.next_rule_name.as_deref() == Some(&*rule.name) {
4430 snapshot_condition_exists(rule, &path[1..])
4431 } else {
4432 false
4433 }
4434 } else {
4435 resolve_snapshot_path(rule, path).is_some()
4436 }
4437}
4438
4439fn resolve_snapshot_path(rule: &RuleSnapshot, path: &[String]) -> Option<Value> {
4440 let root = path.first()?.as_str();
4441 let rest = &path[1..];
4442 match root {
4443 "n" if rest.len() == 1 => Some(Value::Number(*rule.n.get(&rest[0]).unwrap_or(&0) as f64)),
4444 "u" => map_path(&rule.u, rest),
4445 "k" => map_path(&rule.k, rest),
4446 "d" if rest.is_empty() => Some(Value::Number(rule.d as f64)),
4447 "i" if rest.is_empty() => Some(Value::Number(rule.i as f64)),
4448 "name" if rest.is_empty() => Some(Value::String(rule.name.to_string())),
4449 "state" if rest.is_empty() => Some(Value::String(
4450 match rule.state {
4451 RuleState::Open => "o",
4452 RuleState::Close => "c",
4453 }
4454 .into(),
4455 )),
4456 "node" => value_path(rule.node.borrow().clone(), rest),
4457 "need" if rest.is_empty() => Some(Value::Number(rule.need as f64)),
4458 "oN" if rest.is_empty() => Some(Value::Number(rule.o.len() as f64)),
4459 "cN" if rest.is_empty() => Some(Value::Number(rule.c.len() as f64)),
4460 "o" => token_list_path(&rule.o, rest),
4461 "c" => token_list_path(&rule.c, rest),
4462 "o0" => token_path(rule.o.first(), rest),
4463 "o1" => token_path(rule.o.get(1), rest),
4464 "c0" => token_path(rule.c.first(), rest),
4465 "c1" => token_path(rule.c.get(1), rest),
4466 "parent" => resolve_snapshot_path(rule.parent_rule.as_deref()?, rest),
4467 "child" => resolve_snapshot_path(rule.child_rule.as_deref()?, rest),
4468 "prev" => resolve_snapshot_path(rule.prev_rule.as_deref()?, rest),
4469 "next" => {
4470 if let Some(next) = rule.next_rule.as_deref() {
4471 resolve_snapshot_path(next, rest)
4472 } else if rule.next_rule_name.as_deref() == Some(&*rule.name) {
4473 resolve_snapshot_path(rule, rest)
4474 } else {
4475 None
4476 }
4477 }
4478 "spec" if rest == ["name"] => Some(Value::String(rule.name.to_string())),
4479 _ => None,
4480 }
4481}
4482
4483fn map_path(map: &HashMap<String, Value>, path: &[String]) -> Option<Value> {
4484 let (name, rest) = path.split_first()?;
4485 value_path(map.get(name)?.clone(), rest)
4486}
4487
4488fn value_path(mut value: Value, path: &[String]) -> Option<Value> {
4489 for part in path {
4490 value = match value {
4491 Value::Object(map) => map.get(part)?.clone(),
4492 Value::Array(items) => items.get(part.parse::<usize>().ok()?)?.clone(),
4493 _ => return None,
4494 };
4495 }
4496 Some(value)
4497}
4498
4499fn token_list_path(tokens: &[Token], path: &[String]) -> Option<Value> {
4500 let (index, rest) = path.split_first()?;
4501 token_path(tokens.get(index.parse::<usize>().ok()?), rest)
4502}
4503
4504fn token_path(token: Option<&Token>, path: &[String]) -> Option<Value> {
4505 let token = token?;
4506 if path.is_empty() {
4507 let mut value = IndexMap::new();
4508 value.insert("tin".into(), Value::Number(token.tin as f64));
4509 value.insert("name".into(), Value::String(token.name.to_string()));
4510 value.insert("src".into(), Value::String(token.src.to_string()));
4511 value.insert("val".into(), token.val.clone());
4512 value.insert("why".into(), Value::String(token.why.to_string()));
4513 return Some(Value::object(value));
4514 }
4515 let (field, rest) = path.split_first()?;
4516 let value = match field.as_str() {
4517 "tin" => Value::Number(token.tin as f64),
4518 "name" => Value::String(token.name.to_string()),
4519 "src" => Value::String(token.src.to_string()),
4520 "val" => token.val.clone(),
4521 "why" => Value::String(token.why.to_string()),
4522 _ => return None,
4523 };
4524 value_path(value, rest)
4525}
4526
4527#[cfg(test)]
4528mod tests {
4529 use super::*;
4530
4531 #[test]
4541 fn replacing_a_rule_replaces_the_tables_derived_from_it() {
4542 let mut parser = Parser::new(crate::Options::default());
4543
4544 let mut first = RuleSpec::new("val");
4545 first.bo.push("@enter".into());
4546 first.open.push(AltSpec {
4547 s: vec![vec![crate::TIN_NR]],
4548 a: vec!["@act".into()],
4549 ..Default::default()
4550 });
4551 parser.add_rule(first);
4552 let slot = parser
4553 .rules()
4554 .get_index_of("val")
4555 .expect("the rule was just installed");
4556 assert_eq!(parser.expected_tins[slot].at(true, 0), [crate::TIN_NR]);
4557 assert_eq!(&*parser.names[slot], "val");
4558 assert_eq!(parser.prepared[slot].before(true).len(), 1);
4559 assert_eq!(parser.prepared[slot].open[0].actions.len(), 1);
4560
4561 let mut second = RuleSpec::new("val");
4562 second.open.push(AltSpec {
4563 s: vec![vec![crate::TIN_ST]],
4564 ..Default::default()
4565 });
4566 parser.add_rule(second);
4567
4568 assert_eq!(parser.rules().len(), 1, "a replacement, not an addition");
4569 assert_eq!(
4570 parser.expected_tins[slot].at(true, 0),
4571 [crate::TIN_ST],
4572 "lookahead would still expect the replaced rule's tokens"
4573 );
4574 assert_eq!(parser.names.len(), 1, "one rule, one shared name");
4579 assert_eq!(parser.rules().get_index_of("val"), Some(slot));
4580 assert_eq!(&*parser.names[slot], "val");
4581 assert_eq!(parser.prepared.len(), 1);
4587 assert_eq!(&*parser.prepared[slot].name, "val");
4588 assert!(Arc::ptr_eq(
4589 &parser.prepared[slot].spec,
4590 &parser.rules()["val"]
4591 ));
4592 assert!(parser.prepared[slot].before(true).is_empty());
4597 assert!(parser.prepared[slot].open[0].actions.is_empty());
4598 assert!(!parser.prepared[slot].open[0].named);
4599 }
4600
4601 #[test]
4609 fn expected_match_tins_follows_the_rule_name_when_the_slot_goes_stale() {
4610 fn rule_named(name: &str, tin: Tin) -> RuleSpec {
4611 let mut spec = RuleSpec::new(name);
4612 spec.open.push(AltSpec {
4613 s: vec![vec![tin]],
4614 ..Default::default()
4615 });
4616 spec
4617 }
4618
4619 let mut options = crate::Options::default();
4620 let tin = options.register_token("#QQ");
4621 options.match_tokens.insert(
4622 "#QQ".into(),
4623 crate::options::MatchToken {
4624 name: "#QQ".into(),
4625 tin,
4626 matcher: crate::options::MatchTokenMatcher::Regex(regex::Regex::new("^q").unwrap()),
4627 eager: false,
4628 },
4629 );
4630 let mut parser = Parser::new(options);
4631 parser.add_rule(rule_named("val", crate::TIN_NR));
4632 parser.add_rule(rule_named("other", crate::TIN_ST));
4633
4634 let val_slot = parser.rules().get_index_of("val").expect("installed");
4635 let other_slot = parser.rules().get_index_of("other").expect("installed");
4636 assert_ne!(val_slot, other_slot);
4637
4638 let mut rule = Rule::new("val", Value::Undefined);
4641 rule.bind_spec(
4642 &parser.rules()["val"],
4643 parser.names[val_slot].clone(),
4644 val_slot,
4645 );
4646 assert_eq!(&*parser.expected_match_tins(&rule, 0), [crate::TIN_NR]);
4647
4648 rule.name = parser.names[other_slot].clone();
4653 assert_eq!(
4654 &*parser.expected_match_tins(&rule, 0),
4655 [crate::TIN_ST],
4656 "the rule is called `other` now, so `other`'s row answers"
4657 );
4658
4659 rule.name = parser.names[val_slot].clone();
4663 rule.spec = Arc::clone(&parser.rules()["other"]);
4664 assert_eq!(
4665 &*parser.expected_match_tins(&rule, 0),
4666 [crate::TIN_NR],
4667 "still called `val`, so still gated by `val`'s row"
4668 );
4669
4670 let ghost = Rule::new("ghost", Value::Undefined);
4673 assert_eq!(
4674 &*parser.expected_match_tins(&ghost, 0),
4675 &[] as &[Tin],
4676 "an uninstalled name has no row, not another rule's"
4677 );
4678 }
4679
4680 #[test]
4688 fn expected_match_tins_is_empty_until_a_match_token_exists() {
4689 fn val_rule() -> RuleSpec {
4690 let mut spec = RuleSpec::new("val");
4691 spec.open.push(AltSpec {
4692 s: vec![vec![crate::TIN_NR]],
4693 ..Default::default()
4694 });
4695 spec
4696 }
4697 let rule = Rule::new("val", Value::Undefined);
4698
4699 let mut without = Parser::new(crate::Options::default());
4700 without.add_rule(val_rule());
4701 assert!(without.options.match_tokens.is_empty());
4702 assert_eq!(without.expected_tins[0].at(true, 0), [crate::TIN_NR]);
4703 assert_eq!(
4704 &*without.expected_match_tins(&rule, 0),
4705 &[] as &[Tin],
4706 "no custom matcher: nothing to gate, so nothing to look up"
4707 );
4708
4709 let mut options = crate::Options::default();
4710 let tin = options.register_token("#QQ");
4711 options.match_tokens.insert(
4712 "#QQ".into(),
4713 crate::options::MatchToken {
4714 name: "#QQ".into(),
4715 tin,
4716 matcher: crate::options::MatchTokenMatcher::Regex(regex::Regex::new("^q").unwrap()),
4717 eager: false,
4718 },
4719 );
4720 let mut with = Parser::new(options);
4721 with.add_rule(val_rule());
4722 assert_eq!(
4723 &*with.expected_match_tins(&rule, 0),
4724 [crate::TIN_NR],
4725 "a custom matcher is present, so the slot's tins gate it"
4726 );
4727 assert_eq!(
4728 &*with.expected_match_tins(&rule, 1),
4729 &[] as &[Tin],
4730 "a slot the rule never fills expects nothing"
4731 );
4732 }
4733}