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::cell::RefCell;
22use std::collections::{BTreeSet, HashMap};
23use std::panic::{catch_unwind, AssertUnwindSafe};
24use std::rc::Rc;
25use std::sync::Arc;
26
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct Continuations {
29 pub tins: Vec<Tin>,
30 pub tokens: Vec<String>,
31}
32
33#[derive(Debug, Clone)]
34pub struct ParseRecovery {
35 pub value: Option<Value>,
36 pub errors: Vec<TabnasError>,
37 pub fatal: Option<TabnasError>,
38}
39
40#[derive(Default)]
41struct ContinuationCapture {
42 at_end: BTreeSet<Tin>,
43 have_end: bool,
44 failure: Vec<Tin>,
45}
46
47struct ParseMode<'a> {
48 continuation: Option<&'a mut ContinuationCapture>,
49 recovering: bool,
50 errors: &'a mut Vec<TabnasError>,
51 partial: Option<PartialValue>,
52 gave_up: bool,
61}
62
63enum PartialValue {
72 Node(Rc<RefCell<Value>>),
73 Complete(Value),
74}
75
76impl PartialValue {
77 fn into_value(self) -> Option<Value> {
78 match self {
79 Self::Complete(value) => Some(value),
80 Self::Node(node) => {
81 let value = node.borrow().clone();
82 (!matches!(value, Value::Undefined | Value::Null)).then(|| value.unwrap_undefined())
83 }
84 }
85 }
86}
87
88struct RelexUndo {
89 position: usize,
90 token: Token,
91 checkpoint: RelexCheckpoint,
92 tokens: Vec<Token>,
93}
94
95#[derive(Clone, Copy, PartialEq, Eq)]
98enum Fetch {
99 Rule,
103 Trailing,
107}
108
109#[derive(Clone, Copy)]
110struct ParseSite<'a> {
111 source: &'a str,
112 stack: &'a [Rule],
113 alts: &'a [AltSpec],
114}
115
116pub struct Parser {
117 pub options: Arc<Options>,
121 ignore_tins: Vec<Tin>,
122 exclude_regex: Option<Arc<regex::Regex>>,
133 exclude_pattern: Option<String>,
134 rules: IndexMap<String, Arc<RuleSpec>>,
146 prepared_include: String,
156 prepared_exclude: String,
157 expected_tins: Vec<ExpectedTins>,
163 names: Vec<RuleName>,
175 prepared: Vec<PreparedRule>,
184 pub actions: HashMap<String, Action>,
185 pub context_actions: HashMap<String, ContextAction>,
186 pub matched_actions: HashMap<String, AltAction>,
187 pub state_actions: HashMap<String, StateAction>,
188 pub token_subscribers: Vec<TokenSubscriber>,
189 pub lex_subscribers: Vec<LexSubscriber>,
190 pub rule_subscribers: Vec<RuleSubscriber>,
191 pub rule_done_subscribers: Vec<RuleDoneSubscriber>,
192 pub parse_guards: Vec<ParseGuard>,
193 pub instance: InstanceInfo,
194}
195
196struct PreparedRule {
212 name: RuleName,
218 spec: Arc<RuleSpec>,
219 open: Vec<PreparedAlt>,
220 close: Vec<PreparedAlt>,
221 open_first: AltIndex,
225 close_first: AltIndex,
226 bo: Vec<ActionBinding>,
233 ao: Vec<ActionBinding>,
234 bc: Vec<ActionBinding>,
235 ac: Vec<ActionBinding>,
236}
237
238impl PreparedRule {
239 fn first(&self, is_open: bool) -> &AltIndex {
241 if is_open {
242 &self.open_first
243 } else {
244 &self.close_first
245 }
246 }
247
248 fn alt(&self, is_open: bool, idx: usize) -> Option<&PreparedAlt> {
249 if is_open {
250 self.open.get(idx)
251 } else {
252 self.close.get(idx)
253 }
254 }
255
256 fn before(&self, is_open: bool) -> &[ActionBinding] {
258 if is_open {
259 &self.bo
260 } else {
261 &self.bc
262 }
263 }
264
265 fn after(&self, is_open: bool) -> &[ActionBinding] {
267 if is_open {
268 &self.ao
269 } else {
270 &self.ac
271 }
272 }
273}
274
275struct PreparedAlt {
278 p: PreparedRoute,
279 r: PreparedRoute,
280 actions: Vec<AltActionBinding>,
282 observed: bool,
300 named: bool,
301 groups: bool,
310 group_tags: Vec<String>,
318}
319
320enum PreparedRoute {
321 ByName,
327 Static {
328 slot: usize,
329 name: RuleName,
330 spec: Arc<RuleSpec>,
331 },
332}
333
334impl PreparedRoute {
335 fn resolved(&self, name: &str) -> Option<(usize, RuleName, &Arc<RuleSpec>)> {
346 match self {
347 PreparedRoute::Static {
348 slot,
349 name: prepared,
350 spec,
351 } if prepared.as_str() == name => Some((*slot, prepared.clone(), spec)),
352 _ => None,
353 }
354 }
355}
356
357pub(crate) fn resolved_slot(alt: &AltSpec, slot: usize, options: &Options) -> Option<Vec<Tin>> {
374 let names = alt.s_names.get(slot)?;
375 if names.is_empty() || alt.s.get(slot) != alt.s_bound.get(slot) {
376 return None;
377 }
378 let mut tins = Vec::with_capacity(names.len());
379 for name in names {
380 if let Some(set) = options.token_set.get(name.trim_start_matches('#')) {
381 tins.extend(set.iter().copied());
382 } else {
383 tins.push(options.token(name)?);
384 }
385 }
386 Some(tins)
387}
388
389fn resolve_slot_names(spec: &mut RuleSpec, options: &Options) {
392 for alt in spec.open.iter_mut().chain(spec.close.iter_mut()) {
393 for slot in 0..alt.s.len() {
394 if let Some(tins) = resolved_slot(alt, slot, options) {
395 alt.s[slot] = tins;
396 }
397 }
398 }
399}
400
401#[derive(Debug, Default)]
415struct AltIndex {
416 by_tin: HashMap<Tin, Vec<usize>>,
417 wild: Vec<usize>,
418}
419
420const NO_ALTS: &[usize] = &[];
421
422impl AltIndex {
423 fn of(alts: &[AltSpec]) -> Self {
424 let mut by_tin: HashMap<Tin, Vec<usize>> = HashMap::new();
425 let mut wild = Vec::new();
426 for (idx, alt) in alts.iter().enumerate() {
427 match alt.s.first() {
428 Some(slot) if !slot.is_empty() && !slot.contains(&TIN_AA) => {
429 for tin in slot {
430 let list = by_tin.entry(*tin).or_default();
431 if list.last() != Some(&idx) {
434 list.push(idx);
435 }
436 }
437 }
438 _ => wild.push(idx),
439 }
440 }
441 AltIndex { by_tin, wild }
442 }
443
444 fn named(&self, tin: Tin) -> &[usize] {
447 self.by_tin.get(&tin).map_or(NO_ALTS, Vec::as_slice)
448 }
449}
450
451#[derive(Debug, Default)]
452struct ExpectedTins {
453 open: Vec<Vec<Tin>>,
454 close: Vec<Vec<Tin>>,
455}
456
457impl ExpectedTins {
458 fn of(spec: &RuleSpec, options: &Options) -> Self {
476 Self {
477 open: Self::by_slot(&spec.open, options),
478 close: Self::by_slot(&spec.close, options),
479 }
480 }
481
482 fn by_slot(alts: &[AltSpec], options: &Options) -> Vec<Vec<Tin>> {
483 let alts: Vec<&AltSpec> = alts
484 .iter()
485 .filter(|alt| groups_enabled(alt, options))
486 .collect();
487 let slots = alts.iter().map(|alt| alt.s.len()).max().unwrap_or(0);
488 (0..slots)
489 .map(|slot| Self::collate(alts.iter().copied(), slot))
490 .collect()
491 }
492
493 fn live(alts: &[AltSpec], options: &Options, slot: usize) -> Vec<Tin> {
496 Self::collate(alts.iter().filter(|alt| groups_enabled(alt, options)), slot)
497 }
498
499 fn collate<'a>(alts: impl Iterator<Item = &'a AltSpec>, slot: usize) -> Vec<Tin> {
500 let mut expected = BTreeSet::new();
501 for alt in alts {
502 if let Some(tins) = alt.s.get(slot) {
503 expected.extend(tins.iter().copied());
504 }
505 }
506 expected.into_iter().collect()
507 }
508
509 fn at(&self, is_open: bool, slot: usize) -> &[Tin] {
510 let slots = if is_open { &self.open } else { &self.close };
511 slots.get(slot).map(Vec::as_slice).unwrap_or_default()
512 }
513}
514
515impl Parser {
516 pub fn new(options: Options) -> Self {
517 let mut options = options;
518 options.sort_for_lexing();
519 Self::from_shared(Arc::new(options))
520 }
521
522 pub fn from_shared(options: Arc<Options>) -> Self {
525 if let Err(error) = options.validate_comment_definitions() {
526 panic!("invalid options: {error}");
527 }
528 Parser {
529 ignore_tins: options.ignore_tins(),
530 exclude_regex: compile_number_exclude(&options),
531 exclude_pattern: options.number.exclude.clone(),
532 options,
533 rules: IndexMap::new(),
534 prepared_include: String::new(),
535 prepared_exclude: String::new(),
536 expected_tins: Vec::new(),
537 names: Vec::new(),
538 prepared: Vec::new(),
539 actions: HashMap::new(),
540 context_actions: HashMap::new(),
541 matched_actions: HashMap::new(),
542 state_actions: HashMap::new(),
543 token_subscribers: Vec::new(),
544 lex_subscribers: Vec::new(),
545 rule_subscribers: Vec::new(),
546 rule_done_subscribers: Vec::new(),
547 parse_guards: Vec::new(),
548 instance: InstanceInfo::default(),
549 }
550 }
551
552 pub fn rules(&self) -> &IndexMap<String, Arc<RuleSpec>> {
557 &self.rules
558 }
559
560 pub fn add_rule(&mut self, spec: RuleSpec) {
561 let mut spec = spec;
567 resolve_slot_names(&mut spec, &self.options);
568 if self.options.rule.include != self.prepared_include
573 || self.options.rule.exclude != self.prepared_exclude
574 {
575 for (row, installed) in self.expected_tins.iter_mut().zip(self.rules.values()) {
576 *row = ExpectedTins::of(installed, &self.options);
577 }
578 }
579 let expected = ExpectedTins::of(&spec, &self.options);
580 let shared = RuleName::from(spec.name.as_str());
581 let (index, _) = self.rules.insert_full(spec.name.clone(), Arc::new(spec));
582 match self.names.get_mut(index) {
589 Some(existing) => *existing = shared,
590 None => self.names.push(shared),
591 }
592 match self.expected_tins.get_mut(index) {
593 Some(existing) => *existing = expected,
594 None => self.expected_tins.push(expected),
595 }
596 self.rebuild_prepared();
597 }
598
599 fn rebuild_prepared(&mut self) {
611 let mut prepared = Vec::with_capacity(self.rules.len());
612 for (index, spec) in self.rules.values().enumerate() {
613 prepared.push(PreparedRule {
614 name: self.names[index].clone(),
615 spec: Arc::clone(spec),
616 open: Self::prepared_alts(&spec.open, &self.rules, &self.names, &self.options),
617 close: Self::prepared_alts(&spec.close, &self.rules, &self.names, &self.options),
618 open_first: AltIndex::of(&spec.open),
619 close_first: AltIndex::of(&spec.close),
620 bo: resolved_action_order(
621 &spec.bo,
622 &spec.bo_fns,
623 &spec.bo_state_fns,
624 &spec.bo_order,
625 ),
626 ao: resolved_action_order(
627 &spec.ao,
628 &spec.ao_fns,
629 &spec.ao_state_fns,
630 &spec.ao_order,
631 ),
632 bc: resolved_action_order(
633 &spec.bc,
634 &spec.bc_fns,
635 &spec.bc_state_fns,
636 &spec.bc_order,
637 ),
638 ac: resolved_action_order(
639 &spec.ac,
640 &spec.ac_fns,
641 &spec.ac_state_fns,
642 &spec.ac_order,
643 ),
644 });
645 }
646 self.prepared = prepared;
647 self.prepared_include.clone_from(&self.options.rule.include);
648 self.prepared_exclude.clone_from(&self.options.rule.exclude);
649 }
650
651 fn prepared_alts(
652 alts: &[AltSpec],
653 rules: &IndexMap<String, Arc<RuleSpec>>,
654 names: &[RuleName],
655 options: &Options,
656 ) -> Vec<PreparedAlt> {
657 alts.iter()
658 .map(|alt| {
659 let actions = resolved_alt_action_order(
664 &alt.a,
665 &alt.action_fns,
666 &alt.matched_action_fns,
667 &alt.action_order,
668 );
669 let observed = alt.c_match.is_some()
670 || alt.c_lex_match.is_some()
671 || alt.e_match.is_some()
672 || alt.p_match.is_some()
673 || alt.r_match.is_some()
674 || alt.b_match.is_some()
675 || alt.h_match.is_some()
676 || actions
677 .iter()
678 .any(|binding| matches!(binding, AltActionBinding::Matched(_)));
679 let named = actions
680 .iter()
681 .any(|binding| matches!(binding, AltActionBinding::Named(_)));
682 PreparedAlt {
683 p: Self::prepared_route(alt.p.as_deref(), rules, names),
684 r: Self::prepared_route(alt.r.as_deref(), rules, names),
685 actions,
686 observed,
687 named,
688 groups: groups_enabled(alt, options),
689 group_tags: listed(&alt.g).map(str::to_owned).collect(),
690 }
691 })
692 .collect()
693 }
694
695 fn prepared_route(
696 route: Option<&str>,
697 rules: &IndexMap<String, Arc<RuleSpec>>,
698 names: &[RuleName],
699 ) -> PreparedRoute {
700 let Some(route) = route.filter(|route| !route.is_empty()) else {
703 return PreparedRoute::ByName;
704 };
705 match rules.get_full(route) {
706 Some((slot, _, spec)) => PreparedRoute::Static {
707 slot,
708 name: names[slot].clone(),
709 spec: Arc::clone(spec),
710 },
711 None => PreparedRoute::ByName,
712 }
713 }
714
715 fn installed(&self, name: &str) -> Option<(usize, RuleName, &Arc<RuleSpec>)> {
726 let (index, _, spec) = self.rules.get_full(name)?;
727 Some((index, self.names[index].clone(), spec))
728 }
729
730 pub fn add_action(&mut self, name: String, action: Action) {
731 self.actions.insert(name, action);
732 }
733
734 pub fn add_context_action(&mut self, name: String, action: ContextAction) {
735 self.context_actions.insert(name, action);
736 }
737
738 pub fn add_matched_action(&mut self, name: String, action: AltAction) {
739 self.matched_actions.insert(name, action);
740 }
741
742 pub fn add_state_action(&mut self, name: String, action: StateAction) {
743 self.state_actions.insert(name, action);
744 }
745
746 pub fn add_token_subscriber(&mut self, subscriber: TokenSubscriber) {
747 self.token_subscribers.push(subscriber);
748 }
749
750 pub fn add_lex_subscriber(&mut self, subscriber: LexSubscriber) {
751 self.lex_subscribers.push(subscriber);
752 }
753
754 pub fn add_rule_subscriber(&mut self, subscriber: RuleSubscriber) {
755 self.rule_subscribers.push(subscriber);
756 }
757
758 pub fn add_parse_guard(&mut self, guard: ParseGuard) {
759 self.parse_guards.push(guard);
760 }
761
762 pub fn add_rule_done_subscriber(&mut self, subscriber: RuleDoneSubscriber) {
763 self.rule_done_subscribers.push(subscriber);
764 }
765
766 pub fn set_instance_info(&mut self, instance: InstanceInfo) {
767 self.instance = instance;
768 }
769
770 fn run_action(
771 &self,
772 name: &str,
773 rule: &mut Rule,
774 context: &mut Context,
775 ) -> Result<(), TabnasError> {
776 self.run_action_with_config(name, rule, context, None)
777 }
778
779 fn run_after_actions(
780 &self,
781 spec: &RuleSpec,
782 prepared: Option<&PreparedRule>,
783 is_open: bool,
784 rule: &mut Rule,
785 context: &mut Context,
786 site: ParseSite<'_>,
787 ) -> Result<(), TabnasError> {
788 if (is_open && !rule.ao) || (!is_open && !rule.ac) {
789 return Ok(());
790 }
791 let by_spec;
798 let bindings: &[ActionBinding] = match prepared {
799 Some(prepared) => prepared.after(is_open),
800 None => {
801 let (actions, callbacks, states, order) = if is_open {
802 (&spec.ao, &spec.ao_fns, &spec.ao_state_fns, &spec.ao_order)
803 } else {
804 (&spec.ac, &spec.ac_fns, &spec.ac_state_fns, &spec.ac_order)
805 };
806 by_spec = resolved_action_order(actions, callbacks, states, order);
807 &by_spec
808 }
809 };
810 if bindings.is_empty() {
811 return Ok(());
812 }
813 let next = rule.next_rule.clone();
814 let mut output = None;
815 for binding in bindings {
816 output = match binding {
817 ActionBinding::Named(action) => {
818 if let Some(callback) = self.state_actions.get(action) {
819 self.run_state_callback(
820 "named lifecycle after action",
821 callback,
822 rule,
823 context,
824 next.as_deref(),
825 output,
826 )
827 .map_err(|error| {
828 self.attach_action_error(
829 error,
830 site.source,
831 rule,
832 site.stack,
833 site.alts,
834 )
835 })?
836 } else {
837 self.run_action(action, rule, context).map_err(|error| {
838 self.attach_action_error(
839 error,
840 site.source,
841 rule,
842 site.stack,
843 site.alts,
844 )
845 })?;
846 None
847 }
848 }
849 ActionBinding::Callback(callback) => {
850 self.run_context_callback("lifecycle after action", callback, rule, context)
851 .map_err(|error| {
852 self.attach_action_error(
853 error,
854 site.source,
855 rule,
856 site.stack,
857 site.alts,
858 )
859 })?;
860 None
861 }
862 ActionBinding::State(callback) => self
863 .run_state_callback(
864 "lifecycle after action",
865 callback,
866 rule,
867 context,
868 next.as_deref(),
869 output,
870 )
871 .map_err(|error| {
872 self.attach_action_error(error, site.source, rule, site.stack, site.alts)
873 })?,
874 };
875 output = self.check_lifecycle_output(output, rule, site)?;
876 }
877 Ok(())
878 }
879
880 fn run_context_callback(
881 &self,
882 label: &str,
883 callback: &ContextAction,
884 rule: &mut Rule,
885 context: &mut Context,
886 ) -> Result<(), TabnasError> {
887 context.set_rule(rule);
888 match catch_unwind(AssertUnwindSafe(|| callback(rule, context))) {
889 Ok(result) => result.map_err(|action_error| {
890 let token = match rule.state {
891 RuleState::Open => rule.o0().or_else(|| rule.c0()),
892 RuleState::Close => rule.c0().or_else(|| rule.o0()),
893 };
894 let mut error = TabnasError::new(
895 action_error.code,
896 token.map_or("", |value| value.src.as_str()),
897 "",
898 token.map_or(0, |value| value.site.pos),
899 token.map_or(1, |value| value.site.ri),
900 token.map_or(1, |value| value.site.ci),
901 );
902 error.detail = action_error.detail;
903 error
904 }),
905 Err(payload) => Err(self.action_panic(payload, label, rule)),
906 }
907 }
908
909 fn run_state_callback(
910 &self,
911 label: &str,
912 callback: &StateAction,
913 rule: &mut Rule,
914 context: &mut Context,
915 next: Option<&RuleSnapshot>,
916 out: Option<Token>,
917 ) -> Result<Option<Token>, TabnasError> {
918 context.set_rule(rule);
919 match catch_unwind(AssertUnwindSafe(|| callback(rule, context, next, out))) {
920 Ok(result) => result.map_err(|action_error| {
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 let mut error = TabnasError::new(
926 action_error.code,
927 token.map_or("", |value| value.src.as_str()),
928 "",
929 token.map_or(0, |value| value.site.pos),
930 token.map_or(1, |value| value.site.ri),
931 token.map_or(1, |value| value.site.ci),
932 );
933 error.detail = action_error.detail;
934 error
935 }),
936 Err(payload) => Err(self.action_panic(payload, label, rule)),
937 }
938 }
939
940 fn check_lifecycle_output(
941 &self,
942 output: Option<Token>,
943 rule: &Rule,
944 site: ParseSite<'_>,
945 ) -> Result<Option<Token>, TabnasError> {
946 let Some(token) = output.as_ref().filter(|token| !token.err.is_empty()) else {
947 return Ok(output);
948 };
949 Err(self.raised_token_error(token, rule, site))
950 }
951
952 fn raised_token_error(&self, token: &Token, rule: &Rule, site: ParseSite<'_>) -> TabnasError {
953 let error = TabnasError::new(
954 raised_error_code(token),
955 token.src.clone(),
956 site.source,
957 token.site.pos,
958 token.site.ri,
959 token.site.ci,
960 );
961 self.attach_error(error, rule, site.stack, site.alts, Some(token))
962 }
963
964 fn attach_action_error(
965 &self,
966 mut error: TabnasError,
967 src: &str,
968 rule: &Rule,
969 stack: &[Rule],
970 alts: &[AltSpec],
971 ) -> TabnasError {
972 error.full_source = src.into();
973 let token = match rule.state {
974 RuleState::Open => rule.o0().or_else(|| rule.c0()),
975 RuleState::Close => rule.c0().or_else(|| rule.o0()),
976 };
977 self.attach_error(error, rule, stack, alts, token)
978 }
979
980 fn run_action_with_config(
981 &self,
982 name: &str,
983 rule: &mut Rule,
984 context: &mut Context,
985 config: Option<&Value>,
986 ) -> Result<(), TabnasError> {
987 context.set_rule(rule);
988 match catch_unwind(AssertUnwindSafe(|| {
989 run_builtin_action_with_info(name, rule, context, config, &self.options.info)
990 })) {
991 Ok(true) => return Ok(()),
992 Ok(false) => {}
993 Err(payload) => return Err(self.action_panic(payload, name, rule)),
994 }
995 if let Some(action) = self.actions.get(name) {
996 return match catch_unwind(AssertUnwindSafe(|| action(rule))) {
997 Ok(()) => Ok(()),
998 Err(payload) => Err(self.action_panic(payload, name, rule)),
999 };
1000 }
1001 if let Some(action) = self.context_actions.get(name) {
1002 return self.run_context_callback(name, action, rule, context);
1003 }
1004 let token = match rule.state {
1005 RuleState::Open => rule.o0().or_else(|| rule.c0()),
1006 RuleState::Close => rule.c0().or_else(|| rule.o0()),
1007 };
1008 let mut error = TabnasError::new(
1009 "unknown",
1010 name,
1011 "",
1012 token.map_or(0, |value| value.site.pos),
1013 token.map_or(1, |value| value.site.ri),
1014 token.map_or(1, |value| value.site.ci),
1015 );
1016 error.detail = format!("unknown action: {name}");
1017 Err(error)
1018 }
1019
1020 fn action_panic(
1021 &self,
1022 payload: Box<dyn std::any::Any + Send>,
1023 name: &str,
1024 rule: &Rule,
1025 ) -> TabnasError {
1026 let token = match rule.state {
1027 RuleState::Open => rule.o0().or_else(|| rule.c0()),
1028 RuleState::Close => rule.c0().or_else(|| rule.o0()),
1029 };
1030 TabnasError::from_panic(
1031 payload,
1032 &format!("action {name}"),
1033 "",
1034 token.map_or(0, |value| value.site.pos),
1035 token.map_or(1, |value| value.site.ri),
1036 token.map_or(1, |value| value.site.ci),
1037 &self.options,
1038 )
1039 }
1040
1041 fn attach_error(
1042 &self,
1043 mut error: TabnasError,
1044 rule: &Rule,
1045 stack: &[Rule],
1046 alts: &[AltSpec],
1047 token: Option<&Token>,
1048 ) -> TabnasError {
1049 let mut rule_stack: Vec<String> = stack.iter().map(|item| item.name.to_string()).collect();
1050 rule_stack.push(rule.name.to_string());
1051 let expected = alts
1052 .iter()
1053 .filter_map(|alt| alt.s.first())
1054 .flat_map(|tins| tins.iter().copied())
1055 .map(|tin| self.options.token_name(tin))
1056 .collect();
1057 error.attach_context(
1058 &rule.name,
1059 if rule.state == RuleState::Open {
1060 "o"
1061 } else {
1062 "c"
1063 },
1064 rule_stack,
1065 token,
1066 expected,
1067 );
1068 self.decorate_error(&mut error);
1069 error
1070 }
1071
1072 fn decorate_error(&self, error: &mut TabnasError) {
1073 error.apply_options(&self.options);
1074 error.plugins = self.instance.plugins.clone();
1075 }
1076
1077 fn catch_callback<T>(
1078 &self,
1079 api: &str,
1080 src: &str,
1081 callback: impl FnOnce() -> T,
1082 ) -> Result<T, TabnasError> {
1083 catch_unwind(AssertUnwindSafe(callback))
1084 .map_err(|payload| TabnasError::from_panic(payload, api, src, 0, 1, 1, &self.options))
1085 }
1086
1087 fn cancelled(&self, src: &str, context: &Context, rule: &Rule, stack: &[Rule]) -> TabnasError {
1090 let token = context.t.first();
1091 let pnt = token
1092 .map(|token| {
1093 (
1094 token.src.as_str(),
1095 token.site.pos,
1096 token.site.ri,
1097 token.site.ci,
1098 )
1099 })
1100 .unwrap_or(("", 0, 1, 1));
1101 let error = TabnasError::new("cancel", pnt.0, src, pnt.1, pnt.2, pnt.3);
1102 self.attach_active_error(error, rule, stack, token)
1103 }
1104
1105 fn attach_active_error(
1106 &self,
1107 mut error: TabnasError,
1108 rule: &Rule,
1109 stack: &[Rule],
1110 token: Option<&Token>,
1111 ) -> TabnasError {
1112 if let Some(spec) = self.rules.get(&*rule.name) {
1113 let alts = if rule.state == RuleState::Open {
1114 &spec.open
1115 } else {
1116 &spec.close
1117 };
1118 self.attach_error(error, rule, stack, alts, token)
1119 } else {
1120 self.decorate_error(&mut error);
1121 error
1122 }
1123 }
1124
1125 fn phase_token(rule: &Rule) -> Option<&Token> {
1126 match rule.state {
1127 RuleState::Open => rule.o0().or_else(|| rule.c0()),
1128 RuleState::Close => rule.c0().or_else(|| rule.o0()),
1129 }
1130 }
1131
1132 fn ancestors_for<'a>(rule: &Rule, stack: &'a [Rule]) -> &'a [Rule] {
1133 if stack.last().is_some_and(|ancestor| ancestor.i == rule.i) {
1134 &stack[..stack.len() - 1]
1135 } else {
1136 stack
1137 }
1138 }
1139
1140 fn rule_done_copy(&self, rule: &Rule) -> Option<Rule> {
1149 (!self.rule_done_subscribers.is_empty()).then(|| rule.clone())
1150 }
1151
1152 fn notify_rule_done(
1153 &self,
1154 rule: &Rule,
1155 context: &Context,
1156 state: RuleState,
1157 alt: Option<RuleDoneAlt>,
1158 src: &str,
1159 stack: &[Rule],
1160 ) -> Result<(), TabnasError> {
1161 if self.rule_done_subscribers.is_empty() {
1162 return Ok(());
1163 }
1164 let done = RuleDone {
1165 state,
1166 alt,
1167 forced: false,
1168 };
1169 let mut site_rule = rule.clone();
1170 site_rule.state = state;
1171 for subscriber in &self.rule_done_subscribers {
1172 let result = self.catch_callback("ruleDone subscriber", src, || {
1173 subscriber(rule, context, &done)
1174 });
1175 result.map_err(|error| {
1176 self.attach_active_error(
1177 error,
1178 &site_rule,
1179 Self::ancestors_for(&site_rule, stack),
1180 Self::phase_token(&site_rule),
1181 )
1182 })?;
1183 }
1184 Ok(())
1185 }
1186
1187 fn notify_forced_close(
1188 &self,
1189 rule: &Rule,
1190 context: &Context,
1191 src: &str,
1192 stack: &[Rule],
1193 ) -> Result<(), TabnasError> {
1194 if self.rule_done_subscribers.is_empty() {
1195 return Ok(());
1196 }
1197 let done = RuleDone {
1198 state: RuleState::Close,
1199 alt: None,
1200 forced: true,
1201 };
1202 let mut site_rule = rule.clone();
1203 site_rule.state = RuleState::Close;
1204 for subscriber in &self.rule_done_subscribers {
1205 let result = self.catch_callback("ruleDone subscriber", src, || {
1206 subscriber(rule, context, &done)
1207 });
1208 result.map_err(|error| {
1209 self.attach_active_error(
1210 error,
1211 &site_rule,
1212 Self::ancestors_for(&site_rule, stack),
1213 Self::phase_token(&site_rule),
1214 )
1215 })?;
1216 }
1217 Ok(())
1218 }
1219
1220 fn attempt_recover(
1221 &self,
1222 error: TabnasError,
1223 current_rule: &mut Rule,
1224 stack: &mut Vec<Rule>,
1225 context: &mut Context,
1226 lexer: &mut Lexer,
1227 mode: &mut ParseMode<'_>,
1228 ) -> Result<bool, TabnasError> {
1229 let src = error.full_source.clone();
1230 let recover = &self.options.parse.recover;
1231
1232 let suppressed = context
1239 .recover_at
1240 .is_some_and(|at| context.v_abs.saturating_sub(at) < recover.suppress);
1241 let recorded = (!suppressed).then(|| {
1242 mode.errors.push(error.clone());
1243 context.errs.push(error.clone());
1244 mode.errors.len() - 1
1245 });
1246 if recover.max_recoveries < mode.errors.len() {
1247 return Ok(false);
1248 }
1249
1250 let no_progress = context.recover_at == Some(context.v_abs);
1251 let last_si = context.recover_si;
1252 context.recover_at = Some(context.v_abs);
1253
1254 let sync = compute_sync_tins(current_rule, stack, &self.rules, &self.options);
1255 let mut pending: std::collections::VecDeque<Token> = std::mem::take(&mut context.t).into();
1256 let mut skipped = 0usize;
1257
1258 let candidate = loop {
1259 let next = if let Some(token) = pending.pop_front() {
1260 Some(token)
1261 } else {
1262 loop {
1263 let next_raw = self.catch_callback("lexer callback", &src, || {
1264 lexer.next_raw_for_rule(current_rule, context)
1265 });
1266 let next_raw = next_raw.map_err(|error| {
1267 self.attach_active_error(
1268 error,
1269 current_rule,
1270 stack,
1271 Self::phase_token(current_rule),
1272 )
1273 })?;
1274 match next_raw {
1275 Ok(mut token) => {
1276 for subscriber in &self.lex_subscribers {
1277 let result = self.catch_callback("lex subscriber", &src, || {
1278 subscriber(&mut token, current_rule, context)
1279 });
1280 result.map_err(|error| {
1281 self.attach_active_error(
1282 error,
1283 current_rule,
1284 stack,
1285 Some(&token),
1286 )
1287 })?;
1288 }
1289 if self.ignore_tins.contains(&token.tin) {
1290 continue;
1291 }
1292 for subscriber in &self.token_subscribers {
1293 let result = self.catch_callback("token subscriber", &src, || {
1294 subscriber(&token)
1295 });
1296 result.map_err(|error| {
1297 self.attach_active_error(
1298 error,
1299 current_rule,
1300 stack,
1301 Some(&token),
1302 )
1303 })?;
1304 }
1305 break Some(token);
1306 }
1307 Err(lex_error) => {
1308 let mut token = error_token(&lex_error);
1309 for subscriber in &self.lex_subscribers {
1310 let result = self.catch_callback("lex subscriber", &src, || {
1311 subscriber(&mut token, current_rule, context)
1312 });
1313 result.map_err(|error| {
1314 self.attach_active_error(
1315 error,
1316 current_rule,
1317 stack,
1318 Some(&token),
1319 )
1320 })?;
1321 }
1322 lexer.skip_bad(&token, mid_construct(&lex_error.code));
1323 if skipped >= recover.max_skip {
1324 break None;
1325 }
1326 skipped += 1;
1327 }
1328 }
1329 }
1330 };
1331 let Some(token) = next else {
1332 return Ok(false);
1333 };
1334 if token.tin == TIN_ZZ
1335 || (sync.contains(&token.tin)
1336 && !(no_progress && last_si.is_some_and(|si| token.site.pos <= si)))
1337 {
1338 break token;
1339 }
1340 if token.tin == TIN_BD {
1346 lexer.skip_bad(&token, mid_construct(&token.why));
1347 }
1348 if skipped >= recover.max_skip {
1349 return Ok(false);
1350 }
1351 skipped += 1;
1352 };
1353
1354 if candidate.tin == TIN_ZZ
1355 && no_progress
1356 && last_si.is_some_and(|si| candidate.site.pos <= si)
1357 {
1358 return Ok(false);
1359 }
1360 context.recover_si = Some(candidate.site.pos);
1361 if let Some(index) = recorded {
1362 let recovered = Some(crate::RecoveredAt {
1363 skipped,
1364 sync: Some(candidate.tin),
1365 bad: false,
1366 });
1367 if let Some(entry) = context.errs.get_mut(index) {
1368 entry.recovered.clone_from(&recovered);
1369 }
1370 if let Some(entry) = mode.errors.get_mut(index) {
1371 entry.recovered = recovered;
1372 }
1373 }
1374
1375 context.t.push(candidate.clone());
1376 context.t.extend(pending);
1377 context.bad_to = None;
1378 context.bad_error = None;
1379
1380 if !recover.pop_until_valid {
1381 if let Some(parent) = stack.pop() {
1387 *current_rule = parent;
1388 return Ok(true);
1389 }
1390 return Ok(false);
1391 }
1392
1393 if accepts_close(current_rule, candidate.tin, &self.rules, &self.options) {
1394 if current_rule.state == RuleState::Open {
1395 current_rule.state = RuleState::Close;
1396 } else {
1397 current_rule.skip_befores = true;
1398 }
1399 return Ok(true);
1400 }
1401
1402 self.notify_forced_close(current_rule, context, &src, stack)?;
1403 while let Some(mut parent) = stack.pop() {
1404 parent.accept_child(current_rule);
1405 if accepts_close(&parent, candidate.tin, &self.rules, &self.options) {
1406 *current_rule = parent;
1407 return Ok(true);
1408 }
1409 self.notify_forced_close(&parent, context, &src, stack)?;
1410 *current_rule = parent;
1411 }
1412 Ok(false)
1413 }
1414
1415 #[allow(clippy::too_many_arguments)]
1416 fn recover_error_pass(
1417 &self,
1418 error: TabnasError,
1419 state: RuleState,
1420 mut alt: Option<RuleDoneAlt>,
1421 fallback_error_token: bool,
1422 src: &str,
1423 current_rule: &mut Rule,
1424 stack: &mut Vec<Rule>,
1425 context: &mut Context,
1426 lexer: &mut Lexer,
1427 mode: &mut ParseMode<'_>,
1428 ) -> Result<(), TabnasError> {
1429 let event_rule = current_rule.clone();
1434 let recovered = mode.recovering
1435 && self.attempt_recover(error.clone(), current_rule, stack, context, lexer, mode)?;
1436 if !recovered && fallback_error_token {
1437 if let Some(alt) = alt.as_mut().filter(|alt| alt.err.is_none()) {
1438 let tin = self.options.token(&error.token.name).unwrap_or(TIN_BD);
1439 let mut token = Token::new(
1440 error.token.name.clone(),
1441 tin,
1442 Value::Undefined,
1443 error.token.src.clone(),
1444 crate::Point {
1445 len: error.len,
1446 site: crate::Site {
1447 si: error.pos,
1448 pos: error.pos,
1449 ri: error.row,
1450 ci: error.col,
1451 },
1452 },
1453 );
1454 token.bad(&error.code);
1455 alt.err = Some(token);
1456 }
1457 }
1458 self.notify_rule_done(&event_rule, context, state, alt, src, stack)?;
1459 if recovered {
1460 Ok(())
1461 } else {
1462 if mode.recovering && !mode.errors.is_empty() {
1467 mode.gave_up = true;
1468 }
1469 Err(error)
1470 }
1471 }
1472
1473 #[allow(clippy::too_many_arguments)]
1474 fn recover_after_actions(
1475 &self,
1476 result: Result<(), TabnasError>,
1477 state: RuleState,
1478 alt: Option<RuleDoneAlt>,
1479 src: &str,
1480 current_rule: &mut Rule,
1481 stack: &mut Vec<Rule>,
1482 context: &mut Context,
1483 lexer: &mut Lexer,
1484 mode: &mut ParseMode<'_>,
1485 ) -> Result<bool, TabnasError> {
1486 let Err(error) = result else {
1487 return Ok(false);
1488 };
1489 self.recover_error_pass(
1490 error,
1491 state,
1492 alt,
1493 true,
1494 src,
1495 current_rule,
1496 stack,
1497 context,
1498 lexer,
1499 mode,
1500 )?;
1501 Ok(true)
1502 }
1503
1504 pub fn parse(&self, src: &str) -> Result<Value, TabnasError> {
1505 self.parse_with_meta(src, Value::Undefined)
1506 }
1507
1508 pub fn parse_with_meta(&self, src: &str, meta: Value) -> Result<Value, TabnasError> {
1509 self.parse_with_owner(src, meta, None, None)
1510 }
1511
1512 pub(crate) fn parse_for(
1513 &self,
1514 owner: &crate::Tabnas,
1515 src: &str,
1516 meta: Value,
1517 ) -> Result<Value, TabnasError> {
1518 self.parse_with_owner(src, meta, Some(owner), None)
1519 }
1520
1521 pub(crate) fn parse_for_with_context(
1522 &self,
1523 owner: &crate::Tabnas,
1524 src: &str,
1525 meta: Value,
1526 parent: &ContextSeed,
1527 ) -> Result<Value, TabnasError> {
1528 self.parse_with_owner(src, meta, Some(owner), Some(parent))
1529 }
1530
1531 fn parse_with_owner(
1532 &self,
1533 src: &str,
1534 meta: Value,
1535 owner: Option<&crate::Tabnas>,
1536 parent: Option<&ContextSeed>,
1537 ) -> Result<Value, TabnasError> {
1538 match catch_unwind(AssertUnwindSafe(|| {
1539 self.parse_uncaught(src, meta, owner, parent)
1540 })) {
1541 Ok(result) => result,
1542 Err(payload) => {
1543 let mut error =
1544 TabnasError::from_panic(payload, "Parser::parse", src, 0, 1, 1, &self.options);
1545 self.decorate_error(&mut error);
1546 Err(error)
1547 }
1548 }
1549 }
1550
1551 fn parse_uncaught(
1552 &self,
1553 src: &str,
1554 meta: Value,
1555 owner: Option<&crate::Tabnas>,
1556 parent: Option<&ContextSeed>,
1557 ) -> Result<Value, TabnasError> {
1558 if let Some(result) = self.run_parser_start(src, &meta, owner, parent) {
1559 return result.map_err(|mut error| {
1560 self.decorate_error(&mut error);
1561 error
1562 });
1563 }
1564 let mut errors = Vec::new();
1565 let recovering = self.options.parse.recover.enabled;
1566 let mut mode = ParseMode {
1567 continuation: None,
1568 recovering,
1569 errors: &mut errors,
1570 partial: None,
1571 gave_up: false,
1572 };
1573 let result = self
1574 .parse_inner(src, meta, owner, parent, &mut mode)
1575 .map_err(|mut error| {
1576 self.decorate_error(&mut error);
1577 error
1578 });
1579 match result {
1580 Err(_) if recovering => Ok(mode
1581 .partial
1582 .and_then(PartialValue::into_value)
1583 .unwrap_or(Value::Undefined)),
1584 other => other,
1585 }
1586 }
1587
1588 pub fn parse_recover(&self, src: &str) -> ParseRecovery {
1589 self.parse_recover_with_meta(src, Value::Undefined)
1590 }
1591
1592 pub fn parse_recover_with_meta(&self, src: &str, meta: Value) -> ParseRecovery {
1593 self.parse_recover_with_owner(src, meta, None, None)
1594 }
1595
1596 pub(crate) fn parse_recover_for(
1597 &self,
1598 owner: &crate::Tabnas,
1599 src: &str,
1600 meta: Value,
1601 ) -> ParseRecovery {
1602 self.parse_recover_with_owner(src, meta, Some(owner), None)
1603 }
1604
1605 pub(crate) fn parse_recover_for_with_context(
1606 &self,
1607 owner: &crate::Tabnas,
1608 src: &str,
1609 meta: Value,
1610 parent: &ContextSeed,
1611 ) -> ParseRecovery {
1612 self.parse_recover_with_owner(src, meta, Some(owner), Some(parent))
1613 }
1614
1615 fn parse_recover_with_owner(
1616 &self,
1617 src: &str,
1618 meta: Value,
1619 owner: Option<&crate::Tabnas>,
1620 parent: Option<&ContextSeed>,
1621 ) -> ParseRecovery {
1622 match catch_unwind(AssertUnwindSafe(|| {
1623 self.parse_recover_uncaught(src, meta, owner, parent)
1624 })) {
1625 Ok(result) => result,
1626 Err(payload) => {
1627 let mut error = TabnasError::from_panic(
1628 payload,
1629 "Parser::parse_recover",
1630 src,
1631 0,
1632 1,
1633 1,
1634 &self.options,
1635 );
1636 self.decorate_error(&mut error);
1637 ParseRecovery {
1638 value: None,
1639 errors: Vec::new(),
1640 fatal: Some(error),
1641 }
1642 }
1643 }
1644 }
1645
1646 fn parse_recover_uncaught(
1647 &self,
1648 src: &str,
1649 meta: Value,
1650 owner: Option<&crate::Tabnas>,
1651 parent: Option<&ContextSeed>,
1652 ) -> ParseRecovery {
1653 if let Some(result) = self.run_parser_start(src, &meta, owner, parent) {
1654 return match result {
1655 Ok(value) => ParseRecovery {
1656 value: Some(value),
1657 errors: Vec::new(),
1658 fatal: None,
1659 },
1660 Err(mut error) => {
1661 self.decorate_error(&mut error);
1662 ParseRecovery {
1663 value: None,
1664 errors: Vec::new(),
1665 fatal: Some(error),
1666 }
1667 }
1668 };
1669 }
1670 let mut errors = Vec::new();
1671 let recovering = self.options.parse.recover.enabled;
1672 let (result, partial, gave_up) = {
1673 let mut mode = ParseMode {
1674 continuation: None,
1675 recovering,
1676 errors: &mut errors,
1677 partial: None,
1678 gave_up: false,
1679 };
1680 let result = self
1681 .parse_inner(src, meta, owner, parent, &mut mode)
1682 .map_err(|mut error| {
1683 self.decorate_error(&mut error);
1684 error
1685 });
1686 (
1687 result,
1688 mode.partial.and_then(PartialValue::into_value),
1689 mode.gave_up,
1690 )
1691 };
1692 for error in &mut errors {
1693 self.decorate_error(error);
1694 }
1695 match result {
1696 Ok(value) => ParseRecovery {
1697 value: Some(value),
1698 errors,
1699 fatal: None,
1700 },
1701 Err(error) => {
1702 if !gave_up {
1706 errors.push(error.clone());
1707 }
1708 ParseRecovery {
1709 value: recovering.then_some(partial).flatten(),
1710 errors,
1711 fatal: (!recovering).then_some(error),
1712 }
1713 }
1714 }
1715 }
1716
1717 fn run_parser_start(
1718 &self,
1719 src: &str,
1720 meta: &Value,
1721 owner: Option<&crate::Tabnas>,
1722 parent: Option<&ContextSeed>,
1723 ) -> Option<Result<Value, TabnasError>> {
1724 let result = if let Some(start) = self.options.parser.start_with_context.as_ref() {
1725 let Some(owner) = owner else {
1726 let mut error = TabnasError::new("internal", "", src, 0, 1, 1);
1727 error.detail =
1728 "parser.start requires an owning Tabnas instance; call Tabnas::parse".into();
1729 self.decorate_error(&mut error);
1730 return Some(Err(error));
1731 };
1732 catch_unwind(AssertUnwindSafe(|| start(src, owner, meta, parent)))
1733 } else if let Some(start) = self.options.parser.start_with_instance.as_ref() {
1734 let Some(owner) = owner else {
1735 let mut error = TabnasError::new("internal", "", src, 0, 1, 1);
1736 error.detail =
1737 "parser.start requires an owning Tabnas instance; call Tabnas::parse".into();
1738 self.decorate_error(&mut error);
1739 return Some(Err(error));
1740 };
1741 catch_unwind(AssertUnwindSafe(|| start(src, owner, meta)))
1742 } else {
1743 let start = self.options.parser.start.as_ref()?;
1744 catch_unwind(AssertUnwindSafe(|| start(src)))
1745 };
1746 Some(match result {
1747 Ok(result) => result.map_err(|error| *error),
1748 Err(payload) => Err(TabnasError::from_panic(
1749 payload,
1750 "parser.start",
1751 src,
1752 0,
1753 1,
1754 1,
1755 &self.options,
1756 )),
1757 })
1758 }
1759
1760 pub fn continuations(&self, src: &str) -> Continuations {
1764 self.continuations_with_owner(src, None)
1765 }
1766
1767 pub(crate) fn continuations_for(&self, owner: &crate::Tabnas, src: &str) -> Continuations {
1768 self.continuations_with_owner(src, Some(owner))
1769 }
1770
1771 fn continuations_with_owner(&self, src: &str, owner: Option<&crate::Tabnas>) -> Continuations {
1772 catch_unwind(AssertUnwindSafe(|| self.continuations_uncaught(src, owner)))
1773 .unwrap_or_else(|_| self.start_continuations())
1774 }
1775
1776 fn continuations_uncaught(&self, src: &str, owner: Option<&crate::Tabnas>) -> Continuations {
1777 let mut capture = ContinuationCapture::default();
1778 let mut errors = Vec::new();
1779 let result = {
1780 let mut mode = ParseMode {
1781 continuation: Some(&mut capture),
1782 recovering: false,
1783 errors: &mut errors,
1784 partial: None,
1785 gave_up: false,
1786 };
1787 self.parse_inner(src, Value::Undefined, owner, None, &mut mode)
1788 };
1789 let mut tins = if result.is_ok() {
1790 if capture.have_end {
1791 capture.at_end.insert(TIN_ZZ);
1792 capture.at_end.into_iter().collect()
1793 } else {
1794 self.start_openers()
1795 }
1796 } else if capture.failure.is_empty() {
1797 self.start_openers()
1798 } else {
1799 capture.failure
1800 };
1801 tins.sort_unstable();
1802 tins.dedup();
1803 let tokens = tins
1804 .iter()
1805 .map(|tin| self.options.token_name(*tin))
1806 .collect();
1807 Continuations { tins, tokens }
1808 }
1809
1810 fn start_continuations(&self) -> Continuations {
1811 let tins = self.start_openers();
1812 let tokens = tins
1813 .iter()
1814 .map(|tin| self.options.token_name(*tin))
1815 .collect();
1816 Continuations { tins, tokens }
1817 }
1818
1819 fn start_openers(&self) -> Vec<Tin> {
1820 let start = self.rules.get(&self.options.rule.start);
1821 let mut out = BTreeSet::new();
1822 if let Some(spec) = start {
1823 for alt in &spec.open {
1824 if groups_enabled(alt, &self.options) {
1825 if let Some(slot) = alt.s.first() {
1826 out.extend(completion_tins(slot));
1827 }
1828 }
1829 }
1830 }
1831 out.into_iter().collect()
1832 }
1833
1834 fn expected_match_tins(&self, rule: &Rule, slot: usize) -> Cow<'_, [Tin]> {
1859 if self.options.match_tokens.is_empty() {
1860 return Cow::Borrowed(&[]);
1861 }
1862 let index = match self.names.get(rule.slot) {
1870 Some(installed) if *installed == rule.name => rule.slot,
1871 _ => match self.rules.get_index_of(&*rule.name) {
1872 Some(index) => index,
1873 None => return Cow::Borrowed(&[]),
1874 },
1875 };
1876 let is_open = rule.state == RuleState::Open;
1877 if self.options.rule.include == self.prepared_include
1878 && self.options.rule.exclude == self.prepared_exclude
1879 {
1880 return Cow::Borrowed(self.expected_tins[index].at(is_open, slot));
1881 }
1882 let installed = &self.rules[index];
1883 let alts = if is_open {
1884 &installed.open
1885 } else {
1886 &installed.close
1887 };
1888 Cow::Owned(ExpectedTins::live(alts, &self.options, slot))
1889 }
1890
1891 fn capture_fetch_failure(
1905 &self,
1906 context: &Context,
1907 rule: &Rule,
1908 stack: &[Rule],
1909 mode: &mut ParseMode<'_>,
1910 fetch: Fetch,
1911 ) {
1912 if fetch != Fetch::Rule {
1913 return;
1914 }
1915 if let Some(capture) = mode.continuation.as_deref_mut() {
1916 capture.failure =
1917 continuation_tins(context, rule, stack, &self.rules, &self.options, 0, None);
1918 }
1919 }
1920
1921 #[allow(clippy::too_many_arguments)]
1922 fn ensure_lookahead(
1923 &self,
1924 lexer: &mut Lexer,
1925 context: &mut Context,
1926 rule: &mut Rule,
1927 count: usize,
1928 mode: &mut ParseMode<'_>,
1929 site: ParseSite<'_>,
1930 fetch: Fetch,
1931 ) -> Result<(), TabnasError> {
1932 while context.t.len() < count {
1933 if context.t.last().is_some_and(|token| token.tin == TIN_ZZ) {
1934 break;
1935 }
1936 let expected_match_tins = self.expected_match_tins(rule, context.t.len());
1937 let token = loop {
1938 let next = match context.next_replay() {
1939 Some(token) => Ok(token),
1940 None => {
1941 let result = self.catch_callback("lexer callback", site.source, || {
1942 lexer.next_rule_token(&expected_match_tins, rule, context)
1943 });
1944 result.map_err(|error| {
1945 self.attach_active_error(
1946 error,
1947 rule,
1948 site.stack,
1949 Self::phase_token(rule),
1950 )
1951 })?
1952 }
1953 };
1954 let mut token = match next {
1955 Ok(token) => token,
1956 Err(error) => error_token(&error),
1966 };
1967 for subscriber in &self.lex_subscribers {
1968 let result = self.catch_callback("lex subscriber", site.source, || {
1969 subscriber(&mut token, rule, context)
1970 });
1971 result.map_err(|error| {
1972 self.attach_active_error(error, rule, site.stack, Some(&token))
1973 })?;
1974 }
1975 if token.tin == TIN_BD && !self.options.lex.relex {
1988 let code = if token.why.is_empty() {
1989 "unexpected"
1990 } else {
1991 token.why.as_str()
1992 };
1993 let error = TabnasError::new(
1994 code,
1995 token.src.clone(),
1996 site.source,
1997 token.site.pos,
1998 token.site.ri,
1999 token.site.ci,
2000 );
2001 let error = self.attach_error(error, rule, site.stack, site.alts, Some(&token));
2002 if mode.recovering && fetch == Fetch::Rule {
2003 if absorb_lex_error(&error, context, &self.options, mode.errors) {
2004 lexer.skip_bad(&token, mid_construct(&error.code));
2005 continue;
2006 }
2007 mode.gave_up = true;
2008 }
2009 self.capture_fetch_failure(context, rule, site.stack, mode, fetch);
2010 return Err(error);
2011 }
2012 if token.tin == TIN_ZZ {
2013 if let Some(capture) = mode.continuation.as_deref_mut() {
2014 capture.have_end = true;
2022 if fetch == Fetch::Rule {
2023 capture.at_end.extend(continuation_tins(
2024 context,
2025 rule,
2026 site.stack,
2027 &self.rules,
2028 &self.options,
2029 context.t.len(),
2030 None,
2031 ));
2032 }
2033 }
2034 }
2035 if !self.ignore_tins.contains(&token.tin) {
2036 break token;
2037 }
2038 };
2039 for subscriber in &self.token_subscribers {
2040 let result =
2041 self.catch_callback("token subscriber", site.source, || subscriber(&token));
2042 result.map_err(|error| {
2043 self.attach_active_error(error, rule, site.stack, Some(&token))
2044 })?;
2045 }
2046 let is_end = token.tin == TIN_ZZ;
2047 context.t.push(token);
2048 if is_end {
2049 break;
2050 }
2051 }
2052 Ok(())
2053 }
2054
2055 fn parse_inner(
2056 &self,
2057 src: &str,
2058 meta: Value,
2059 owner: Option<&crate::Tabnas>,
2060 parent: Option<&ContextSeed>,
2061 mode: &mut ParseMode<'_>,
2062 ) -> Result<Value, TabnasError> {
2063 let input_meta = meta.clone();
2064 let mut context = Context::new(
2065 self.options.rewind.history,
2066 src,
2067 meta,
2068 Arc::clone(&self.options),
2069 self.instance.clone(),
2070 );
2071 if let Some(parent) = parent {
2072 context.apply_seed(parent);
2073 }
2074 for prepare in &self.options.parse.prepare {
2075 let outcome = self.catch_callback("parse.prepare", src, || {
2076 prepare.run(owner, &mut context, &input_meta)
2077 })?;
2078 if let Err(detail) = outcome {
2079 let mut error = TabnasError::new("internal", "", src, 0, 1, 1);
2080 error.detail = detail.into();
2081 return Err(error);
2082 }
2083 }
2084 for prepare in self.options.parse.named_prepare.values() {
2085 let outcome = self.catch_callback("parse.prepare", src, || {
2086 prepare.run(owner, &mut context, &input_meta)
2087 })?;
2088 if let Err(detail) = outcome {
2089 let mut error = TabnasError::new("internal", "", src, 0, 1, 1);
2090 error.detail = detail.into();
2091 return Err(error);
2092 }
2093 }
2094
2095 if src.is_empty() {
2096 return if self.options.lex.empty {
2097 Ok(self.options.lex.empty_result.clone())
2098 } else {
2099 Err(TabnasError::new("unexpected", "", src, 0, 1, 1))
2100 };
2101 }
2102
2103 let exclude_regex = if self.exclude_pattern == self.options.number.exclude {
2106 self.exclude_regex.clone()
2107 } else {
2108 compile_number_exclude(&self.options)
2109 };
2110 let mut lexer = Lexer::with_shared(src, Arc::clone(&self.options), exclude_regex);
2111
2112 let start_name = self.options.rule.start.as_str();
2115 let Some((start_slot, start_shared, start_spec)) = self.installed(start_name) else {
2116 return Ok(Value::Undefined);
2117 };
2118
2119 let mut current_rule = Rule::new(start_shared.clone(), Value::Undefined);
2120 current_rule.bind_spec(start_spec, start_shared, start_slot);
2121 current_rule.i = 0;
2122 let root_node = current_rule.node.clone();
2123 context.set_root(root_node.clone());
2124 let mut stack: Vec<Rule> = Vec::new();
2125 let park_child_nodes = self.options.parse.recover.pop_until_valid;
2130 let mut next_rule_id = 1;
2131 #[allow(unused_assignments)]
2132 let mut final_value = None;
2133
2134 let mut iterations = 0usize;
2135 let maxmul = if self.options.rule.maxmul == 0 {
2136 3
2137 } else {
2138 self.options.rule.maxmul
2139 };
2140 let max_iterations = self
2141 .rules
2142 .len()
2143 .saturating_mul(src.encode_utf16().count())
2144 .saturating_mul(4)
2145 .saturating_mul(maxmul)
2146 .max(100);
2147 let budget = &self.options.parse.budget;
2148
2149 let mut matched = AltMatch::default();
2157
2158 'parse: loop {
2159 context.set_active(¤t_rule, &stack);
2160 update_partial(mode, &root_node, ¤t_rule, &stack);
2161 iterations += 1;
2162 if iterations > max_iterations {
2163 let pnt = context
2164 .t
2165 .first()
2166 .map(|t| (t.site.pos, t.site.ri, t.site.ci))
2167 .unwrap_or((0, 1, 1));
2168 return Err(TabnasError::new("unexpected", "", src, pnt.0, pnt.1, pnt.2));
2169 }
2170 context.iteration = iterations - 1;
2171 if context.iteration > 0 {
2174 for guard in &self.parse_guards {
2175 let result = self.catch_callback("parse guard", src, || guard(&context));
2176 let keep_going = result.map_err(|error| {
2177 self.attach_active_error(
2178 error,
2179 ¤t_rule,
2180 &stack,
2181 Self::phase_token(¤t_rule).or_else(|| context.t.first()),
2182 )
2183 })?;
2184 if !keep_going {
2185 return Err(self.cancelled(src, &context, ¤t_rule, &stack));
2186 }
2187 }
2188 }
2189 if budget.check_every_n > 0
2190 && context.iteration > 0
2191 && context.iteration % budget.check_every_n == 0
2192 {
2193 if let Some(check) = &budget.on_check {
2194 let result =
2195 self.catch_callback("parse.budget.onCheck", src, || check(&context));
2196 let keep_going = result.map_err(|error| {
2197 self.attach_active_error(
2198 error,
2199 ¤t_rule,
2200 &stack,
2201 Self::phase_token(¤t_rule).or_else(|| context.t.first()),
2202 )
2203 })?;
2204 if !keep_going {
2205 return Err(self.cancelled(src, &context, ¤t_rule, &stack));
2206 }
2207 }
2208 }
2209
2210 let by_name;
2226 let (prepared, spec) = match self.prepared.get(current_rule.slot).filter(|prepared| {
2227 Arc::ptr_eq(&prepared.spec, ¤t_rule.spec)
2228 && prepared.name == current_rule.name
2229 }) {
2230 Some(prepared) => (Some(prepared), &prepared.spec),
2231 None => {
2232 by_name = if current_rule.spec.name == *current_rule.name {
2233 Arc::clone(¤t_rule.spec)
2234 } else {
2235 match self.rules.get(&*current_rule.name) {
2236 Some(s) => s.clone(),
2237 None => {
2238 let pnt = context
2239 .t
2240 .first()
2241 .map(|t| (t.site.pos, t.site.ri, t.site.ci))
2242 .unwrap_or((0, 1, 1));
2243 return Err(TabnasError::new(
2244 "unknown_rule",
2245 &*current_rule.name,
2246 src,
2247 pnt.0,
2248 pnt.1,
2249 pnt.2,
2250 ));
2251 }
2252 }
2253 };
2254 (None, &by_name)
2255 }
2256 };
2257
2258 let is_open = current_rule.state == RuleState::Open;
2259 let alts = if is_open { &spec.open } else { &spec.close };
2260
2261 for subscriber in &self.rule_subscribers {
2262 let result = self.catch_callback("rule subscriber", src, || {
2263 subscriber(&mut current_rule, &mut context)
2264 });
2265 result.map_err(|error| {
2266 self.attach_error(
2267 error,
2268 ¤t_rule,
2269 &stack,
2270 alts,
2271 Self::phase_token(¤t_rule).or_else(|| context.t.first()),
2272 )
2273 })?;
2274 }
2275 update_partial(mode, &root_node, ¤t_rule, &stack);
2276
2277 let skip_befores = current_rule.skip_befores;
2280 current_rule.skip_befores = false;
2281 let before_enabled = if is_open {
2282 current_rule.bo
2283 } else {
2284 current_rule.bc
2285 };
2286 let by_spec;
2291 let before_bindings: &[ActionBinding] = if skip_befores || !before_enabled {
2292 &[]
2293 } else {
2294 match prepared {
2295 Some(prepared) => prepared.before(is_open),
2296 None => {
2297 let (actions, callbacks, states, order) = if is_open {
2298 (&spec.bo, &spec.bo_fns, &spec.bo_state_fns, &spec.bo_order)
2299 } else {
2300 (&spec.bc, &spec.bc_fns, &spec.bc_state_fns, &spec.bc_order)
2301 };
2302 by_spec = resolved_action_order(actions, callbacks, states, order);
2303 &by_spec
2304 }
2305 }
2306 };
2307 if !before_bindings.is_empty() {
2308 let label = if is_open {
2309 "before-open action"
2310 } else {
2311 "before-close action"
2312 };
2313 let next = is_open.then(|| current_rule.snapshot());
2314 let site = ParseSite {
2315 source: src,
2316 stack: &stack,
2317 alts,
2318 };
2319 let mut output = None;
2320 let mut lifecycle_error = None;
2321 for binding in before_bindings {
2322 output = match binding {
2323 ActionBinding::Named(action) => {
2324 if let Some(callback) = self.state_actions.get(action) {
2325 self.run_state_callback(
2326 label,
2327 callback,
2328 &mut current_rule,
2329 &mut context,
2330 next.as_deref(),
2331 output,
2332 )
2333 .map_err(|error| {
2334 self.attach_action_error(
2335 error,
2336 src,
2337 ¤t_rule,
2338 &stack,
2339 alts,
2340 )
2341 })?
2342 } else {
2343 self.run_action(action, &mut current_rule, &mut context)
2344 .map_err(|error| {
2345 self.attach_action_error(
2346 error,
2347 src,
2348 ¤t_rule,
2349 &stack,
2350 alts,
2351 )
2352 })?;
2353 None
2354 }
2355 }
2356 ActionBinding::Callback(callback) => {
2357 self.run_context_callback(
2358 label,
2359 callback,
2360 &mut current_rule,
2361 &mut context,
2362 )
2363 .map_err(|error| {
2364 self.attach_action_error(error, src, ¤t_rule, &stack, alts)
2365 })?;
2366 None
2367 }
2368 ActionBinding::State(callback) => self
2369 .run_state_callback(
2370 label,
2371 callback,
2372 &mut current_rule,
2373 &mut context,
2374 next.as_deref(),
2375 output,
2376 )
2377 .map_err(|error| {
2378 self.attach_action_error(error, src, ¤t_rule, &stack, alts)
2379 })?,
2380 };
2381 match self.check_lifecycle_output(output, ¤t_rule, site) {
2382 Ok(next_output) => output = next_output,
2383 Err(error) => {
2384 lifecycle_error = Some(error);
2385 break;
2386 }
2387 }
2388 }
2389 if let Some(error) = lifecycle_error {
2390 update_partial(mode, &root_node, ¤t_rule, &stack);
2391 self.recover_error_pass(
2392 error,
2393 if is_open {
2394 RuleState::Open
2395 } else {
2396 RuleState::Close
2397 },
2398 None,
2399 false,
2400 src,
2401 &mut current_rule,
2402 &mut stack,
2403 &mut context,
2404 &mut lexer,
2405 mode,
2406 )?;
2407 continue 'parse;
2408 }
2409 }
2410 update_partial(mode, &root_node, ¤t_rule, &stack);
2411
2412 let mut matched_alt_idx: Option<usize> = None;
2414 let mut matched_count = 0;
2415 matched.reset();
2418 let mut record_written = false;
2424 let mut matched_tokens: Option<Rc<Vec<Token>>> = None;
2427
2428 let groups_prepared = self.options.rule.include == self.prepared_include
2434 && self.options.rule.exclude == self.prepared_exclude;
2435
2436 let first_index = if self.options.lex.relex {
2445 None
2446 } else {
2447 prepared.map(|prepared| prepared.first(is_open))
2448 };
2449 let mut lists: Option<(&[usize], &[usize])> = None;
2453 let mut key_tin = TIN_BD;
2454 let (mut ni, mut wi) = (0, 0);
2455 let mut next_idx = 0;
2456 loop {
2457 if lists.is_none() {
2458 if let (Some(index), Some(t0)) = (first_index, context.t.first()) {
2459 if t0.tin != TIN_BD {
2460 key_tin = t0.tin;
2461 let named = index.named(key_tin);
2462 let wild = index.wild.as_slice();
2463 (ni, wi) = (0, 0);
2464 while ni < named.len() && named[ni] < next_idx {
2465 ni += 1;
2466 }
2467 while wi < wild.len() && wild[wi] < next_idx {
2468 wi += 1;
2469 }
2470 lists = Some((named, wild));
2471 }
2472 }
2473 }
2474 let idx = match lists {
2475 Some((named, wild)) => {
2476 let n = named.get(ni).copied().unwrap_or(alts.len());
2477 let w = wild.get(wi).copied().unwrap_or(alts.len());
2478 if alts.len() <= n && alts.len() <= w {
2479 break;
2481 }
2482 if n < w {
2483 ni += 1;
2484 n
2485 } else {
2486 wi += 1;
2487 w
2488 }
2489 }
2490 None => {
2491 if alts.len() <= next_idx {
2492 break;
2493 }
2494 next_idx += 1;
2495 next_idx - 1
2496 }
2497 };
2498 let alt = &alts[idx];
2499 let enabled = match prepared
2500 .filter(|_| groups_prepared)
2501 .and_then(|prepared| prepared.alt(is_open, idx))
2502 {
2503 Some(prepared_alt) => prepared_alt.groups,
2504 None => groups_enabled(alt, &self.options),
2505 };
2506 if !enabled {
2507 continue;
2508 }
2509 let s_len = alt.s.len();
2510 let mut alt_matches = true;
2511 if record_written {
2512 matched.reset();
2513 record_written = false;
2514 }
2515 let mut relex_undo: Option<RelexUndo> = None;
2516 for (pos, pos_tins) in alt.s.iter().enumerate() {
2517 if let Err(error) = self.ensure_lookahead(
2518 &mut lexer,
2519 &mut context,
2520 &mut current_rule,
2521 pos + 1,
2522 mode,
2523 ParseSite {
2524 source: src,
2525 stack: &stack,
2526 alts,
2527 },
2528 Fetch::Rule,
2529 ) {
2530 return Err(self.attach_error(error, ¤t_rule, &stack, alts, None));
2531 }
2532 let Some(token) = context.t.get(pos).cloned() else {
2533 alt_matches = false;
2534 break;
2535 };
2536 if !slot_matches(pos_tins, token.tin) {
2537 let recut = if self.options.lex.relex
2538 && !token.src.is_empty()
2539 && !pos_tins.is_empty()
2540 {
2541 let result = self.catch_callback("lexer relex callback", src, || {
2542 lexer.relex(&token, pos_tins, &mut current_rule, &mut context)
2543 });
2544 result.map_err(|error| {
2545 self.attach_error(error, ¤t_rule, &stack, alts, Some(&token))
2546 })?
2547 } else {
2548 None
2549 };
2550 let Some((mut recut, checkpoint)) = recut else {
2551 alt_matches = false;
2552 break;
2553 };
2554 for subscriber in &self.lex_subscribers {
2555 let result = self.catch_callback("lex subscriber", src, || {
2556 subscriber(&mut recut, &mut current_rule, &mut context)
2557 });
2558 result.map_err(|error| {
2559 self.attach_error(error, ¤t_rule, &stack, alts, Some(&recut))
2560 })?;
2561 }
2562 if !pos_tins.contains(&recut.tin) {
2563 lexer.unrelex(checkpoint, &mut context);
2564 alt_matches = false;
2565 break;
2566 }
2567 if relex_undo.is_none() {
2568 relex_undo = Some(RelexUndo {
2569 position: pos,
2570 token,
2571 checkpoint,
2572 tokens: context.t.clone(),
2573 });
2574 }
2575 context.t[pos] = recut;
2576 context.t.truncate(pos + 1);
2577 }
2578 }
2579
2580 if alt_matches {
2581 let tokens: Rc<Vec<Token>> =
2582 Rc::new(context.t.iter().take(s_len).cloned().collect());
2583 if alt.c_ref.is_some() || !alt.c.is_empty() {
2591 let mut candidate = current_rule.clone();
2592 if is_open {
2593 candidate.o = Rc::clone(&tokens);
2594 } else {
2595 candidate.c = Rc::clone(&tokens);
2596 }
2597 if !builtin_condition_matches(alt.c_ref.as_deref(), &candidate)
2598 || !conditions_match(&alt.c, &candidate, &stack)
2599 {
2600 alt_matches = false;
2601 }
2602 }
2603 if alt_matches {
2604 if is_open {
2605 current_rule.o = Rc::clone(&tokens);
2606 } else {
2607 current_rule.c = Rc::clone(&tokens);
2608 }
2609 if let Some(condition) = &alt.c_fn {
2610 context.set_rule(¤t_rule);
2611 let result = self.catch_callback("alternate condition", src, || {
2612 condition(&mut current_rule, &mut context)
2613 });
2614 alt_matches = result.map_err(|error| {
2615 self.attach_error(
2616 error,
2617 ¤t_rule,
2618 &stack,
2619 alts,
2620 Self::phase_token(¤t_rule),
2621 )
2622 })?;
2623 }
2624 if alt_matches {
2625 if let Some(condition) = &alt.c_match {
2626 context.set_rule(¤t_rule);
2627 record_written = true;
2628 let result =
2629 self.catch_callback("matched alternate condition", src, || {
2630 condition(&mut current_rule, &mut context, &mut matched)
2631 });
2632 alt_matches = result.map_err(|error| {
2633 self.attach_error(
2634 error,
2635 ¤t_rule,
2636 &stack,
2637 alts,
2638 Self::phase_token(¤t_rule),
2639 )
2640 })?;
2641 }
2642 }
2643 if alt_matches {
2644 if let Some(condition) = &alt.c_lex_match {
2645 context.set_rule(¤t_rule);
2646 record_written = true;
2647 let result = self.catch_callback(
2648 "matched alternate lexer condition",
2649 src,
2650 || {
2651 condition(
2652 &mut current_rule,
2653 &mut context,
2654 &mut matched,
2655 &mut lexer,
2656 )
2657 },
2658 );
2659 alt_matches = result.map_err(|error| {
2660 self.attach_error(
2661 error,
2662 ¤t_rule,
2663 &stack,
2664 alts,
2665 Self::phase_token(¤t_rule),
2666 )
2667 })?;
2668 }
2669 }
2670 if alt_matches {
2671 if let Some(condition) = &alt.c_lex {
2672 context.set_rule(¤t_rule);
2673 let result =
2674 self.catch_callback("alternate lexer condition", src, || {
2675 condition(&mut current_rule, &mut context, &mut lexer)
2676 });
2677 alt_matches = result.map_err(|error| {
2678 self.attach_error(
2679 error,
2680 ¤t_rule,
2681 &stack,
2682 alts,
2683 Self::phase_token(¤t_rule),
2684 )
2685 })?;
2686 }
2687 }
2688 }
2689 if alt_matches {
2690 matched_alt_idx = Some(idx);
2691 matched_count = s_len;
2692 if alt.c_fn.is_none() && alt.c_match.is_none() {
2702 matched_tokens = Some(Rc::clone(&tokens));
2703 }
2704 break;
2705 }
2706 }
2707 if let Some(undo) = relex_undo {
2708 lexer.unrelex(undo.checkpoint, &mut context);
2709 context.t = undo.tokens;
2710 for subscriber in &self.lex_subscribers {
2711 let mut restored = undo.token.clone();
2712 let result = self.catch_callback("lex subscriber", src, || {
2713 subscriber(&mut restored, &mut current_rule, &mut context)
2714 });
2715 result.map_err(|error| {
2716 self.attach_error(error, ¤t_rule, &stack, alts, Some(&restored))
2717 })?;
2718 }
2719 debug_assert_eq!(context.t.get(undo.position), Some(&undo.token));
2720 }
2721 if lists.is_some() && context.t.first().map(|t0| t0.tin) != Some(key_tin) {
2727 lists = None;
2728 next_idx = idx + 1;
2729 }
2730 }
2731
2732 if let Some(idx) = matched_alt_idx {
2733 let matched_tokens = matched_tokens.unwrap_or_else(|| {
2735 Rc::new(context.t.iter().take(matched_count).cloned().collect())
2736 });
2737 if is_open {
2738 current_rule.o = matched_tokens;
2739 } else {
2740 current_rule.c = matched_tokens;
2741 }
2742
2743 let rewritten: AltSpec;
2754 let alt: &AltSpec = if let Some(modifier) = alts[idx].h.clone() {
2755 context.set_rule(¤t_rule);
2756 let source = alts[idx].clone();
2757 let result = self.catch_callback("alternate modifier", src, || {
2758 modifier(source, &mut current_rule, &mut context)
2759 });
2760 rewritten = result.map_err(|error| {
2761 self.attach_error(
2762 error,
2763 ¤t_rule,
2764 &stack,
2765 alts,
2766 Self::phase_token(¤t_rule),
2767 )
2768 })?;
2769 &rewritten
2770 } else {
2771 &alts[idx]
2772 };
2773
2774 matched.h = alt.h_match.clone();
2775 if !alt.n.is_empty() {
2776 matched.n = alt.n.clone();
2777 }
2778 if !alt.u.is_empty() {
2779 matched.u = alt.u.clone();
2780 }
2781 if !alt.k.is_empty() {
2782 matched.k = alt.k.clone();
2783 }
2784 let prepared_alt = if alts[idx].h.is_some() {
2790 None
2791 } else {
2792 prepared.and_then(|prepared| prepared.alt(is_open, idx))
2793 };
2794 match prepared_alt {
2795 Some(prepared_alt) => matched.g.clone_from(&prepared_alt.group_tags),
2799 None if !alt.g.is_empty() => {
2800 matched.g = listed(&alt.g).map(str::to_owned).collect();
2801 }
2802 None => {}
2803 }
2804 let prepared_alt = prepared_alt.filter(|prepared_alt| {
2814 !prepared_alt.observed
2815 && (!prepared_alt.named || self.matched_actions.is_empty())
2816 });
2817 if prepared_alt.is_none() {
2818 let actions = resolved_alt_action_order(
2819 &alt.a,
2820 &alt.action_fns,
2821 &alt.matched_action_fns,
2822 &alt.action_order,
2823 );
2824 if !actions.is_empty() {
2825 matched.actions = actions;
2826 }
2827 }
2828 if !alt.action_configs.is_empty() {
2829 matched.action_configs = alt.action_configs.clone();
2830 }
2831
2832 if let Some(route) = &alt.p_fn {
2833 context.set_rule(¤t_rule);
2834 matched.p = self
2835 .catch_callback("alternate push", src, || {
2836 route(&mut current_rule, &mut context)
2837 })
2838 .map_err(|error| {
2839 self.attach_error(
2840 error,
2841 ¤t_rule,
2842 &stack,
2843 alts,
2844 Self::phase_token(¤t_rule),
2845 )
2846 })?
2847 .filter(|name| !name.is_empty());
2848 }
2849 if let Some(route) = &alt.p_match {
2850 context.set_rule(¤t_rule);
2851 matched.p = self
2852 .catch_callback("matched alternate push", src, || {
2853 route(&mut current_rule, &mut context, &mut matched)
2854 })
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 .filter(|name| !name.is_empty());
2865 } else if alt.p_fn.is_none() {
2866 if let Some(route) = alt.p.clone() {
2867 matched.p = (!route.is_empty()).then_some(route);
2868 }
2869 }
2870 if let Some(route) = &alt.r_fn {
2871 context.set_rule(¤t_rule);
2872 matched.r = self
2873 .catch_callback("alternate replace", src, || {
2874 route(&mut current_rule, &mut context)
2875 })
2876 .map_err(|error| {
2877 self.attach_error(
2878 error,
2879 ¤t_rule,
2880 &stack,
2881 alts,
2882 Self::phase_token(¤t_rule),
2883 )
2884 })?
2885 .filter(|name| !name.is_empty());
2886 }
2887 if let Some(route) = &alt.r_match {
2888 context.set_rule(¤t_rule);
2889 matched.r = self
2890 .catch_callback("matched alternate replace", src, || {
2891 route(&mut current_rule, &mut context, &mut matched)
2892 })
2893 .map_err(|error| {
2894 self.attach_error(
2895 error,
2896 ¤t_rule,
2897 &stack,
2898 alts,
2899 Self::phase_token(¤t_rule),
2900 )
2901 })?
2902 .filter(|name| !name.is_empty());
2903 } else if alt.r_fn.is_none() {
2904 if let Some(route) = alt.r.clone() {
2905 matched.r = (!route.is_empty()).then_some(route);
2906 }
2907 }
2908 if let Some(backtrack) = &alt.b_fn {
2909 context.set_rule(¤t_rule);
2910 matched.b = self
2911 .catch_callback("alternate backtrack", src, || {
2912 backtrack(&mut current_rule, &mut context)
2913 })
2914 .map_err(|error| {
2915 self.attach_error(
2916 error,
2917 ¤t_rule,
2918 &stack,
2919 alts,
2920 Self::phase_token(¤t_rule),
2921 )
2922 })?;
2923 }
2924 if let Some(backtrack) = &alt.b_match {
2925 context.set_rule(¤t_rule);
2926 matched.b = self
2927 .catch_callback("matched alternate backtrack", src, || {
2928 backtrack(&mut current_rule, &mut context, &mut matched)
2929 })
2930 .map_err(|error| {
2931 self.attach_error(
2932 error,
2933 ¤t_rule,
2934 &stack,
2935 alts,
2936 Self::phase_token(¤t_rule),
2937 )
2938 })?;
2939 } else if alt.b_fn.is_none() && alt.b != 0 {
2940 matched.b = alt.b;
2941 }
2942
2943 if let Some(modifier) = alt.h_match.clone() {
2944 context.set_rule(¤t_rule);
2945 let next = is_open.then(|| current_rule.snapshot());
2946 matched = self
2947 .catch_callback("matched alternate modifier", src, || {
2948 modifier(
2949 std::mem::take(&mut matched),
2950 &mut current_rule,
2951 &mut context,
2952 next.as_deref(),
2953 )
2954 })
2955 .map_err(|error| {
2956 self.attach_error(
2957 error,
2958 ¤t_rule,
2959 &stack,
2960 alts,
2961 Self::phase_token(¤t_rule),
2962 )
2963 })?;
2964 }
2965
2966 if let Some(error_hook) = alt.e.clone() {
2973 context.set_rule(¤t_rule);
2974 let result = self.catch_callback("alternate error", src, || {
2975 error_hook(&mut current_rule, &mut context)
2976 });
2977 matched.e = result
2978 .map_err(|error| {
2979 self.attach_error(
2980 error,
2981 ¤t_rule,
2982 &stack,
2983 alts,
2984 Self::phase_token(¤t_rule),
2985 )
2986 })?
2987 .map(Box::new);
2988 }
2989 if let Some(error_hook) = alt.e_match.clone() {
2990 context.set_rule(¤t_rule);
2991 let result = self.catch_callback("matched alternate error", src, || {
2992 error_hook(&mut current_rule, &mut context, &mut matched)
2993 });
2994 matched.e = result
2995 .map_err(|error| {
2996 self.attach_error(
2997 error,
2998 ¤t_rule,
2999 &stack,
3000 alts,
3001 Self::phase_token(¤t_rule),
3002 )
3003 })?
3004 .map(Box::new);
3005 }
3006 if let Some(token) = matched.e.clone() {
3009 let code = raised_error_code(&token);
3010 let error = TabnasError::new(
3011 code,
3012 token.src.clone(),
3013 src,
3014 token.site.pos,
3015 token.site.ri,
3016 token.site.ci,
3017 );
3018 let done_alt = (!self.rule_done_subscribers.is_empty()).then(|| RuleDoneAlt {
3019 b: matched.b,
3020 g: matched.g.clone(),
3021 p: matched.p.clone().unwrap_or_default(),
3022 r: matched.r.clone().unwrap_or_default(),
3023 err: Some((*token).clone()),
3024 });
3025 let error = self.attach_error(error, ¤t_rule, &stack, alts, Some(&token));
3026 self.recover_error_pass(
3027 error,
3028 if is_open {
3029 RuleState::Open
3030 } else {
3031 RuleState::Close
3032 },
3033 done_alt,
3034 false,
3035 src,
3036 &mut current_rule,
3037 &mut stack,
3038 &mut context,
3039 &mut lexer,
3040 mode,
3041 )?;
3042 continue;
3043 }
3044
3045 for (k, v) in &matched.n {
3047 if *v == 0 {
3048 current_rule.n_mut().insert(k.clone(), 0);
3049 } else {
3050 *current_rule.n_mut().entry(k.clone()).or_insert(0) += *v;
3051 }
3052 }
3053
3054 for (k, v) in &matched.u {
3056 current_rule.u_mut().insert(k.clone(), v.clone());
3057 }
3058
3059 for (k, v) in &matched.k {
3061 current_rule.k_mut().insert(k.clone(), v.clone());
3062 }
3063
3064 let backtrack = matched.b;
3065 let consumed = matched_count.saturating_sub(backtrack);
3066 context.record_consumed(consumed);
3067
3068 let mut matched_action_error = None;
3072 let mut matched_action_token = None;
3073 let published;
3079 let bindings: &[AltActionBinding] = match prepared_alt {
3080 Some(prepared_alt) => &prepared_alt.actions,
3081 None => {
3082 published = matched.actions.clone();
3083 &published
3084 }
3085 };
3086 for binding in bindings {
3087 let act_name = match binding {
3088 AltActionBinding::Context(callback) => {
3089 self.run_context_callback(
3090 "alternate action",
3091 callback,
3092 &mut current_rule,
3093 &mut context,
3094 )
3095 .map_err(|error| {
3096 self.attach_action_error(error, src, ¤t_rule, &stack, alts)
3097 })?;
3098 continue;
3099 }
3100 AltActionBinding::Matched(callback) => {
3101 context.set_rule(¤t_rule);
3102 let result = self
3103 .catch_callback("matched alternate action", src, || {
3104 callback(&mut current_rule, &mut context, &mut matched)
3105 })
3106 .map_err(|error| {
3107 self.attach_action_error(
3108 error,
3109 src,
3110 ¤t_rule,
3111 &stack,
3112 alts,
3113 )
3114 })?;
3115 let token = result.map_err(|action_error| {
3116 self.attach_action_error(
3117 action_error.into(),
3118 src,
3119 ¤t_rule,
3120 &stack,
3121 alts,
3122 )
3123 })?;
3124 if let Some(token) = token.filter(|token| !token.err.is_empty()) {
3125 matched_action_error = Some(self.raised_token_error(
3126 &token,
3127 ¤t_rule,
3128 ParseSite {
3129 source: src,
3130 stack: &stack,
3131 alts,
3132 },
3133 ));
3134 matched_action_token = Some(token);
3135 break;
3136 }
3137 continue;
3138 }
3139 AltActionBinding::Named(name) => name,
3140 };
3141 if let Some(callback) = self.matched_actions.get(act_name) {
3142 context.set_rule(¤t_rule);
3143 let result = self
3144 .catch_callback("named matched alternate action", src, || {
3145 callback(&mut current_rule, &mut context, &mut matched)
3146 })
3147 .map_err(|error| {
3148 self.attach_action_error(error, src, ¤t_rule, &stack, alts)
3149 })?;
3150 let token = result.map_err(|action_error| {
3151 self.attach_action_error(
3152 action_error.into(),
3153 src,
3154 ¤t_rule,
3155 &stack,
3156 alts,
3157 )
3158 })?;
3159 if let Some(token) = token.filter(|token| !token.err.is_empty()) {
3160 matched_action_error = Some(self.raised_token_error(
3161 &token,
3162 ¤t_rule,
3163 ParseSite {
3164 source: src,
3165 stack: &stack,
3166 alts,
3167 },
3168 ));
3169 matched_action_token = Some(token);
3170 break;
3171 }
3172 continue;
3173 }
3174 match act_name.as_str() {
3175 "@probeInit$" => {
3176 current_rule
3177 .k_mut()
3178 .insert("pd_phase".into(), Value::Number(0.0));
3179 let mark = Value::Number(context.mark() as f64);
3180 current_rule.k_mut().insert("pd_mark".into(), mark);
3181 }
3182 "@probeDecide$" => {
3183 let mark = current_rule.k.get("pd_mark").and_then(|value| {
3184 if let Value::Number(mark) = value {
3185 usize::try_from(*mark as u64).ok()
3186 } else {
3187 None
3188 }
3189 });
3190 let Some(mark) = mark.filter(|mark| *mark <= context.v_abs) else {
3191 let mut error = TabnasError::new("internal", "", src, 0, 1, 1);
3192 error.detail =
3193 "@probeDecide$: phase-0 @probeInit$ did not record a valid mark"
3194 .into();
3195 return Err(error);
3196 };
3197 if let Err(error) = self.ensure_lookahead(
3198 &mut lexer,
3199 &mut context,
3200 &mut current_rule,
3201 1,
3202 mode,
3203 ParseSite {
3204 source: src,
3205 stack: &stack,
3206 alts,
3207 },
3208 Fetch::Rule,
3209 ) {
3210 return Err(self.attach_error(
3211 error,
3212 ¤t_rule,
3213 &stack,
3214 alts,
3215 None,
3216 ));
3217 }
3218 let disambiguator =
3219 current_rule.k.get("pd_d").and_then(|value| match value {
3220 Value::String(name) => Some(name.as_str()),
3221 _ => None,
3222 });
3223 let phase = if context
3224 .t
3225 .first()
3226 .is_some_and(|token| Some(token.name.as_str()) == disambiguator)
3227 {
3228 1.0
3229 } else {
3230 2.0
3231 };
3232 context.rewind(mark)?;
3233 current_rule
3234 .k_mut()
3235 .insert("pd_phase".into(), Value::Number(phase));
3236 }
3237 _ => self
3238 .run_action_with_config(
3239 act_name,
3240 &mut current_rule,
3241 &mut context,
3242 matched.action_configs.get(act_name),
3243 )
3244 .map_err(|error| {
3245 self.attach_action_error(error, src, ¤t_rule, &stack, alts)
3246 })?,
3247 }
3248 }
3249 if let Some(error) = matched_action_error {
3250 let recovered_alt = Some(RuleDoneAlt {
3251 b: matched.b,
3252 g: matched.g.clone(),
3253 p: matched.p.clone().unwrap_or_default(),
3254 r: matched.r.clone().unwrap_or_default(),
3255 err: None,
3256 });
3257 self.recover_error_pass(
3258 error,
3259 if is_open {
3260 RuleState::Open
3261 } else {
3262 RuleState::Close
3263 },
3264 recovered_alt,
3265 matched_action_token.is_some(),
3266 src,
3267 &mut current_rule,
3268 &mut stack,
3269 &mut context,
3270 &mut lexer,
3271 mode,
3272 )?;
3273 update_partial(mode, &root_node, ¤t_rule, &stack);
3274 continue 'parse;
3275 }
3276 update_partial(mode, &root_node, ¤t_rule, &stack);
3277
3278 let push_name = matched.p.take();
3286 let replace_name = matched.r.take();
3287 let done_alt = (!self.rule_done_subscribers.is_empty()).then(|| RuleDoneAlt {
3292 b: matched.b,
3293 g: matched.g.clone(),
3294 p: push_name.clone().unwrap_or_default(),
3295 r: replace_name.clone().unwrap_or_default(),
3296 err: None,
3297 });
3298
3299 let mut route = match push_name.as_deref().or(replace_name.as_deref()) {
3318 Some(name) => match prepared
3319 .and_then(|prepared| prepared.alt(is_open, idx))
3320 .map(|alt| if push_name.is_some() { &alt.p } else { &alt.r })
3321 .and_then(|route| route.resolved(name))
3322 .or_else(|| self.installed(name))
3323 {
3324 Some(resolved) => Some(resolved),
3325 None => {
3326 let mut token = Self::phase_token(¤t_rule)
3327 .cloned()
3328 .or_else(|| context.t.first().cloned())
3329 .unwrap_or_else(Token::no_token);
3330 token.bad("unknown_rule");
3331 token
3332 .use_data_mut()
3333 .insert("rulename".into(), Value::String(name.to_string()));
3334 let error = self.raised_token_error(
3335 &token,
3336 ¤t_rule,
3337 ParseSite {
3338 source: src,
3339 stack: &stack,
3340 alts,
3341 },
3342 );
3343 self.recover_error_pass(
3344 error,
3345 if is_open {
3346 RuleState::Open
3347 } else {
3348 RuleState::Close
3349 },
3350 done_alt,
3351 false,
3352 src,
3353 &mut current_rule,
3354 &mut stack,
3355 &mut context,
3356 &mut lexer,
3357 mode,
3358 )?;
3359 update_partial(mode, &root_node, ¤t_rule, &stack);
3360 continue 'parse;
3361 }
3362 },
3363 None => None,
3364 };
3365
3366 let completed_rule: Option<Rule>;
3370 let mut completed_value = None;
3371 if push_name.is_some() {
3372 let (push_slot, push_shared, push_spec) =
3373 route.take().expect("a push route was resolved above");
3374 let mut child = Rule::bound(
3375 push_shared.clone(),
3376 current_rule.node.clone(),
3377 Some(push_spec),
3378 push_slot,
3379 );
3380 child.i = next_rule_id;
3381 next_rule_id += 1;
3382 child.d = stack.len() + 1;
3383 child.parent_node = Some(current_rule.node.clone());
3384 child.n = Rc::clone(¤t_rule.n);
3385 child.k = Rc::clone(¤t_rule.k);
3386 child.parent_rule = Some(bounded_history(
3387 current_rule.snapshot(),
3388 self.options.rule.history,
3389 Link::PusherBefore,
3390 ));
3391 current_rule.next_rule_name = Some(push_shared);
3392 current_rule.child_rule = Some(child.snapshot());
3393 current_rule.next_rule = current_rule.child_rule.clone();
3394 current_rule.note_child_push(&child);
3395 let linked = current_rule.child_rule.clone();
3398 let after = self.run_after_actions(
3399 spec,
3400 prepared,
3401 is_open,
3402 &mut current_rule,
3403 &mut context,
3404 ParseSite {
3405 source: src,
3406 stack: &stack,
3407 alts,
3408 },
3409 );
3410 update_partial(mode, &root_node, ¤t_rule, &stack);
3411 if self.recover_after_actions(
3412 after,
3413 if is_open {
3414 RuleState::Open
3415 } else {
3416 RuleState::Close
3417 },
3418 done_alt.clone(),
3419 src,
3420 &mut current_rule,
3421 &mut stack,
3422 &mut context,
3423 &mut lexer,
3424 mode,
3425 )? {
3426 continue 'parse;
3427 }
3428 if is_open {
3429 current_rule.state = RuleState::Close;
3430 }
3431 child.parent_rule = Some(bounded_history(
3432 current_rule.snapshot(),
3433 self.options.rule.history,
3434 Link::Parent,
3435 ));
3436 if crate::options::effective_rule_history(self.options.rule.history).is_none()
3456 && current_rule.links_unchanged(&linked)
3457 {
3458 current_rule.relink_child(&child);
3459 child.parent_rule = Some(current_rule.snapshot());
3460 }
3461 completed_rule = self.rule_done_copy(¤t_rule);
3462 if park_child_nodes {
3471 current_rule.park_child_node();
3472 }
3473 stack.push(current_rule);
3474 current_rule = child;
3475 } else if replace_name.is_some() {
3476 let (replace_slot, replace_shared, replace_spec) =
3477 route.take().expect("a replace route was resolved above");
3478 let mut next = Rule::bound(
3479 replace_shared.clone(),
3480 current_rule.node.clone(),
3481 Some(replace_spec),
3482 replace_slot,
3483 );
3484 next.i = next_rule_id;
3485 next_rule_id += 1;
3486 next.d = current_rule.d;
3487 next.parent_node = current_rule.parent_node.clone();
3488 next.parent_rule = current_rule.parent_rule.clone();
3489 next.n = Rc::clone(¤t_rule.n);
3490 next.k = Rc::clone(¤t_rule.k);
3491 current_rule.next_rule_name = Some(replace_shared);
3492 current_rule.next_rule = Some(next.snapshot());
3493 let after = self.run_after_actions(
3494 spec,
3495 prepared,
3496 is_open,
3497 &mut current_rule,
3498 &mut context,
3499 ParseSite {
3500 source: src,
3501 stack: &stack,
3502 alts,
3503 },
3504 );
3505 update_partial(mode, &root_node, ¤t_rule, &stack);
3506 if self.recover_after_actions(
3507 after,
3508 if is_open {
3509 RuleState::Open
3510 } else {
3511 RuleState::Close
3512 },
3513 done_alt.clone(),
3514 src,
3515 &mut current_rule,
3516 &mut stack,
3517 &mut context,
3518 &mut lexer,
3519 mode,
3520 )? {
3521 continue 'parse;
3522 }
3523 if is_open {
3524 current_rule.state = RuleState::Close;
3525 }
3526 next.prev_rule = Some(bounded_history(
3527 current_rule.snapshot(),
3528 self.options.rule.history,
3529 Link::Prev,
3530 ));
3531 if let Some(parent) = stack.last_mut() {
3538 parent.freeze_child(¤t_rule);
3539 }
3540 completed_rule = Some(current_rule);
3544 current_rule = next;
3545 } else if is_open {
3546 current_rule.next_rule_name = Some(current_rule.name.clone());
3547 current_rule.next_rule = Some(current_rule.snapshot());
3548 let after = self.run_after_actions(
3549 spec,
3550 prepared,
3551 true,
3552 &mut current_rule,
3553 &mut context,
3554 ParseSite {
3555 source: src,
3556 stack: &stack,
3557 alts,
3558 },
3559 );
3560 update_partial(mode, &root_node, ¤t_rule, &stack);
3561 if self.recover_after_actions(
3562 after,
3563 RuleState::Open,
3564 done_alt.clone(),
3565 src,
3566 &mut current_rule,
3567 &mut stack,
3568 &mut context,
3569 &mut lexer,
3570 mode,
3571 )? {
3572 continue 'parse;
3573 }
3574 current_rule.state = RuleState::Close;
3575 completed_rule = self.rule_done_copy(¤t_rule);
3576 } else {
3577 current_rule.next_rule_name = stack.last().map(|rule| rule.name.clone());
3579 current_rule.next_rule = stack.last().map(Rule::snapshot);
3580 let after = self.run_after_actions(
3581 spec,
3582 prepared,
3583 false,
3584 &mut current_rule,
3585 &mut context,
3586 ParseSite {
3587 source: src,
3588 stack: &stack,
3589 alts,
3590 },
3591 );
3592 update_partial(mode, &root_node, ¤t_rule, &stack);
3593 if self.recover_after_actions(
3594 after,
3595 RuleState::Close,
3596 done_alt.clone(),
3597 src,
3598 &mut current_rule,
3599 &mut stack,
3600 &mut context,
3601 &mut lexer,
3602 mode,
3603 )? {
3604 continue 'parse;
3605 }
3606 let parent = stack.pop();
3607 completed_rule = self.rule_done_copy(¤t_rule);
3608 if let Some(mut parent) = parent {
3609 parent.accept_child(¤t_rule);
3610 current_rule = parent;
3611 } else {
3612 completed_value = Some(current_rule.node.borrow().clone());
3614 }
3615 }
3616 if let Some(completed_rule) = &completed_rule {
3617 self.notify_rule_done(
3618 completed_rule,
3619 &context,
3620 if is_open {
3621 RuleState::Open
3622 } else {
3623 RuleState::Close
3624 },
3625 done_alt,
3626 src,
3627 &stack,
3628 )?;
3629 }
3630 if let Some(value) = completed_value {
3631 final_value = Some(value);
3632 break;
3633 }
3634 update_partial(mode, &root_node, ¤t_rule, &stack);
3635 } else if alts.is_empty() {
3636 let completed_rule: Option<Rule>;
3639 let mut completed_value = None;
3640 if is_open {
3641 current_rule.next_rule_name = Some(current_rule.name.clone());
3642 current_rule.next_rule = Some(current_rule.snapshot());
3643 let after = self.run_after_actions(
3644 spec,
3645 prepared,
3646 true,
3647 &mut current_rule,
3648 &mut context,
3649 ParseSite {
3650 source: src,
3651 stack: &stack,
3652 alts,
3653 },
3654 );
3655 update_partial(mode, &root_node, ¤t_rule, &stack);
3656 if self.recover_after_actions(
3657 after,
3658 RuleState::Open,
3659 None,
3660 src,
3661 &mut current_rule,
3662 &mut stack,
3663 &mut context,
3664 &mut lexer,
3665 mode,
3666 )? {
3667 continue 'parse;
3668 }
3669 current_rule.state = RuleState::Close;
3670 completed_rule = self.rule_done_copy(¤t_rule);
3671 } else {
3672 current_rule.next_rule_name = stack.last().map(|rule| rule.name.clone());
3673 current_rule.next_rule = stack.last().map(Rule::snapshot);
3674 let after = self.run_after_actions(
3675 spec,
3676 prepared,
3677 false,
3678 &mut current_rule,
3679 &mut context,
3680 ParseSite {
3681 source: src,
3682 stack: &stack,
3683 alts,
3684 },
3685 );
3686 update_partial(mode, &root_node, ¤t_rule, &stack);
3687 if self.recover_after_actions(
3688 after,
3689 RuleState::Close,
3690 None,
3691 src,
3692 &mut current_rule,
3693 &mut stack,
3694 &mut context,
3695 &mut lexer,
3696 mode,
3697 )? {
3698 continue 'parse;
3699 }
3700 let parent = stack.pop();
3701 completed_rule = self.rule_done_copy(¤t_rule);
3702 if let Some(mut parent) = parent {
3703 parent.accept_child(¤t_rule);
3704 current_rule = parent;
3705 } else {
3706 completed_value = Some(current_rule.node.borrow().clone());
3707 }
3708 }
3709 if let Some(completed_rule) = &completed_rule {
3710 self.notify_rule_done(
3711 completed_rule,
3712 &context,
3713 if is_open {
3714 RuleState::Open
3715 } else {
3716 RuleState::Close
3717 },
3718 None,
3719 src,
3720 &stack,
3721 )?;
3722 }
3723 if let Some(value) = completed_value {
3724 final_value = Some(value);
3725 break;
3726 }
3727 update_partial(mode, &root_node, ¤t_rule, &stack);
3728 } else {
3729 if is_open {
3731 if let Err(error) = self.ensure_lookahead(
3732 &mut lexer,
3733 &mut context,
3734 &mut current_rule,
3735 1,
3736 mode,
3737 ParseSite {
3738 source: src,
3739 stack: &stack,
3740 alts,
3741 },
3742 Fetch::Rule,
3743 ) {
3744 return Err(self.attach_error(error, ¤t_rule, &stack, alts, None));
3745 }
3746 if let Some(capture) = mode.continuation.as_deref_mut() {
3747 let base = failed_alt_tins(&context, alts, &self.options);
3748 capture.failure = continuation_tins(
3749 &context,
3750 ¤t_rule,
3751 &stack,
3752 &self.rules,
3753 &self.options,
3754 0,
3755 Some(&base),
3756 );
3757 }
3758 let t0 = context.t.first().cloned();
3759 let (src_token, si, ri, ci) = if let Some(t) = t0.as_ref() {
3760 (t.src.to_string(), t.site.pos, t.site.ri, t.site.ci)
3761 } else {
3762 (String::new(), src.len(), 1, 1)
3763 };
3764 let code = t0
3765 .as_ref()
3766 .map_or("unexpected", |t| deferred_error_code(t, mode.recovering));
3767 let error = TabnasError::new(code, src_token, src, si, ri, ci);
3768 let done_alt = (!alts.is_empty() && !self.rule_done_subscribers.is_empty())
3769 .then(|| RuleDoneAlt {
3770 b: 0,
3771 g: Vec::new(),
3772 p: String::new(),
3773 r: String::new(),
3774 err: t0.clone(),
3775 });
3776 let error = self.attach_error(error, ¤t_rule, &stack, alts, t0.as_ref());
3777 self.recover_error_pass(
3778 error,
3779 RuleState::Open,
3780 done_alt,
3781 false,
3782 src,
3783 &mut current_rule,
3784 &mut stack,
3785 &mut context,
3786 &mut lexer,
3787 mode,
3788 )?;
3789 continue;
3790 } else {
3791 if let Err(error) = self.ensure_lookahead(
3792 &mut lexer,
3793 &mut context,
3794 &mut current_rule,
3795 1,
3796 mode,
3797 ParseSite {
3798 source: src,
3799 stack: &stack,
3800 alts,
3801 },
3802 Fetch::Rule,
3803 ) {
3804 return Err(self.attach_error(error, ¤t_rule, &stack, alts, None));
3805 }
3806 if let Some(capture) = mode.continuation.as_deref_mut() {
3807 let base = failed_alt_tins(&context, alts, &self.options);
3808 capture.failure = continuation_tins(
3809 &context,
3810 ¤t_rule,
3811 &stack,
3812 &self.rules,
3813 &self.options,
3814 0,
3815 Some(&base),
3816 );
3817 }
3818 let token = context.t.first().cloned();
3819 let (source, pos, row, col) = token.as_ref().map_or_else(
3820 || (String::new(), src.chars().count(), 1, 1),
3821 |value| {
3822 (
3823 value.src.to_string(),
3824 value.site.pos,
3825 value.site.ri,
3826 value.site.ci,
3827 )
3828 },
3829 );
3830 let code = token
3831 .as_ref()
3832 .map_or("unexpected", |t| deferred_error_code(t, mode.recovering));
3833 let error = TabnasError::new(code, source, src, pos, row, col);
3834 let done_alt = Some(RuleDoneAlt {
3835 b: 0,
3836 g: Vec::new(),
3837 p: String::new(),
3838 r: String::new(),
3839 err: token.clone(),
3840 });
3841 let error =
3842 self.attach_error(error, ¤t_rule, &stack, alts, token.as_ref());
3843 self.recover_error_pass(
3844 error,
3845 RuleState::Close,
3846 done_alt,
3847 false,
3848 src,
3849 &mut current_rule,
3850 &mut stack,
3851 &mut context,
3852 &mut lexer,
3853 mode,
3854 )?;
3855 continue;
3856 }
3857 }
3858 }
3859
3860 let res = final_value.unwrap_or(Value::Null).unwrap_undefined();
3861 if mode.recovering {
3862 mode.partial = Some(PartialValue::Complete(res.clone()));
3863 }
3864
3865 if let Err(error) = self.ensure_lookahead(
3871 &mut lexer,
3872 &mut context,
3873 &mut current_rule,
3874 1,
3875 mode,
3876 ParseSite {
3877 source: src,
3878 stack: &stack,
3879 alts: &[],
3880 },
3881 Fetch::Trailing,
3882 ) {
3883 let error = self.attach_error(error, ¤t_rule, &stack, &[], None);
3884 if mode.recovering {
3885 mode.errors.push(error.clone());
3886 context.errs.push(error);
3887 return Ok(res);
3888 }
3889 return Err(error);
3890 }
3891 if let Some(t0) = context.t.first() {
3892 if t0.tin != TIN_ZZ {
3893 let code = if t0.tin == TIN_BD && !t0.why.is_empty() {
3894 t0.why.as_str()
3895 } else {
3896 "unexpected"
3897 };
3898 let error =
3899 TabnasError::new(code, &*t0.src, src, t0.site.pos, t0.site.ri, t0.site.ci);
3900 let error = self.attach_error(
3901 error,
3902 ¤t_rule,
3903 &stack,
3904 &[AltSpec {
3905 s: vec![vec![TIN_ZZ]],
3906 ..Default::default()
3907 }],
3908 Some(t0),
3909 );
3910 if mode.recovering {
3911 mode.errors.push(error.clone());
3912 context.errs.push(error);
3913 return Ok(res);
3914 }
3915 return Err(error);
3916 }
3917 }
3918 if self
3919 .options
3920 .result
3921 .fail
3922 .iter()
3923 .any(|failed| failed.deep_equal(&res))
3924 {
3925 let token = context.t.first();
3926 let error = token.map_or_else(
3927 || TabnasError::new("unexpected", "", src, 0, 1, 1),
3928 |token| {
3929 TabnasError::new(
3930 "unexpected",
3931 &*token.src,
3932 src,
3933 token.site.pos,
3934 token.site.ri,
3935 token.site.ci,
3936 )
3937 },
3938 );
3939 if mode.recovering {
3940 mode.errors.push(error.clone());
3941 context.errs.push(error);
3942 return Ok(res);
3943 }
3944 return Err(error);
3945 }
3946 Ok(res)
3947 }
3948}
3949
3950#[inline]
3970fn update_partial(
3971 mode: &mut ParseMode<'_>,
3972 root_node: &Rc<RefCell<Value>>,
3973 current_rule: &Rule,
3974 stack: &[Rule],
3975) {
3976 if mode.recovering {
3977 mode.partial = best_partial_node(root_node, current_rule, stack).map(PartialValue::Node);
3978 }
3979}
3980
3981#[inline(never)]
3982fn best_partial_node(
3983 root_node: &Rc<RefCell<Value>>,
3984 current_rule: &Rule,
3985 stack: &[Rule],
3986) -> Option<Rc<RefCell<Value>>> {
3987 let usable = |node: &Rc<RefCell<Value>>| {
3988 (!matches!(*node.borrow(), Value::Undefined | Value::Null)).then(|| Rc::clone(node))
3989 };
3990
3991 usable(root_node)
3992 .or_else(|| stack.iter().find_map(|rule| usable(&rule.node)))
3993 .or_else(|| usable(¤t_rule.node))
3994}
3995
3996fn error_token(error: &TabnasError) -> Token {
3997 let byte_position = error
3998 .full_source
3999 .char_indices()
4000 .nth(error.pos)
4001 .map_or(error.full_source.len(), |(index, _)| index);
4002 let mut token = Token::new(
4003 "#BD",
4004 TIN_BD,
4005 Value::Undefined,
4006 error.src.clone(),
4007 crate::Point {
4008 len: error.len,
4009 site: crate::Site {
4010 si: byte_position,
4011 pos: error.pos,
4012 ri: error.row,
4013 ci: error.col,
4014 },
4015 },
4016 );
4017 token.err = crate::TokenCode::from(error.code.as_str());
4018 token.why = token.err.clone();
4019 token
4020}
4021
4022fn deferred_error_code(token: &Token, recovering: bool) -> &str {
4032 if token.tin != TIN_BD {
4033 "unexpected"
4034 } else if recovering && !token.err.is_empty() {
4035 &token.err
4036 } else if !token.why.is_empty() {
4037 &token.why
4038 } else {
4039 "unexpected"
4040 }
4041}
4042
4043fn raised_error_code(token: &Token) -> &str {
4044 if !token.err.is_empty() {
4045 &token.err
4046 } else if !token.why.is_empty() {
4047 &token.why
4048 } else {
4049 "unexpected"
4050 }
4051}
4052
4053fn mid_construct(code: &str) -> bool {
4054 matches!(code, "unprintable" | "invalid_unicode" | "invalid_ascii")
4055}
4056
4057fn absorb_lex_error(
4066 error: &TabnasError,
4067 context: &mut Context,
4068 options: &Options,
4069 errors: &mut Vec<TabnasError>,
4070) -> bool {
4071 let recover = &options.parse.recover;
4072 let run = context
4073 .bad_error
4074 .filter(|index| *index < errors.len())
4075 .filter(|_| context.bad_to.is_some_and(|bad_to| error.pos <= bad_to));
4076 if let Some(index) = run {
4077 let previous = &mut errors[index];
4078 let recovered = previous.recovered.get_or_insert(crate::RecoveredAt {
4079 skipped: 0,
4080 sync: None,
4081 bad: true,
4082 });
4083 recovered.skipped = recovered.skipped.saturating_add(1);
4084 let skipped = recovered.skipped;
4085 if let Some(context_previous) = context.errs.get_mut(index) {
4086 *context_previous = previous.clone();
4087 }
4088 if recover.max_skip < skipped {
4089 return false;
4090 }
4091 } else if context
4092 .recover_at
4093 .is_some_and(|at| context.v_abs.saturating_sub(at) < recover.suppress)
4094 {
4095 context.bad_error = None;
4096 } else {
4097 let mut recorded = error.clone();
4098 recorded.recovered = Some(crate::RecoveredAt {
4099 skipped: 1,
4100 sync: None,
4101 bad: true,
4102 });
4103 errors.push(recorded.clone());
4104 context.errs.push(recorded);
4105 context.bad_error = Some(errors.len() - 1);
4106 context.recover_at = Some(context.v_abs);
4107 }
4108 context.bad_to = Some(error.pos.saturating_add(error.len.max(1)));
4109 errors.len() <= recover.max_recoveries
4110}
4111
4112fn slot_matches(slot: &[Tin], tin: Tin) -> bool {
4113 tin != TIN_BD && (slot.is_empty() || slot.contains(&tin) || slot.contains(&TIN_AA))
4114}
4115
4116fn alt_match_depth(alt: &AltSpec, context: &Context) -> usize {
4117 let mut depth = 0;
4118 while depth < alt.s.len() {
4119 let Some(token) = context.t.get(depth) else {
4120 break;
4121 };
4122 if !slot_matches(&alt.s[depth], token.tin) {
4123 break;
4124 }
4125 depth += 1;
4126 }
4127 depth
4128}
4129
4130fn completion_tins(slot: &[Tin]) -> impl Iterator<Item = Tin> + '_ {
4131 slot.iter()
4132 .copied()
4133 .chain(slot.is_empty().then_some(TIN_AA))
4134}
4135
4136fn failed_alt_tins(context: &Context, alts: &[AltSpec], options: &Options) -> Vec<Tin> {
4137 let mut out = BTreeSet::new();
4138 for alt in alts {
4139 if !groups_enabled(alt, options) {
4140 continue;
4141 }
4142 let depth = alt_match_depth(alt, context);
4143 if let Some(slot) = alt.s.get(depth) {
4144 out.extend(completion_tins(slot));
4145 }
4146 }
4147 out.into_iter().collect()
4148}
4149
4150fn lead_tins(alts: &[AltSpec], options: &Options, out: &mut BTreeSet<Tin>) {
4151 for alt in alts {
4152 if !groups_enabled(alt, options) {
4153 continue;
4154 }
4155 if let Some(slot) = alt.s.first() {
4156 out.extend(completion_tins(slot));
4157 }
4158 }
4159}
4160
4161fn has_empty_close(spec: &RuleSpec, options: &Options) -> bool {
4162 spec.close
4163 .iter()
4164 .any(|alt| groups_enabled(alt, options) && alt.s.is_empty())
4165}
4166
4167fn alt_has_sync_group(alt: &AltSpec, sync_groups: &[String]) -> bool {
4168 alt.g
4169 .split(',')
4170 .map(str::trim)
4171 .any(|tag| sync_groups.iter().any(|wanted| wanted == tag))
4172}
4173
4174fn add_close_tins(
4175 rule: &Rule,
4176 rules: &IndexMap<String, Arc<RuleSpec>>,
4177 options: &Options,
4178 tagged_only: bool,
4179 out: &mut BTreeSet<Tin>,
4180) {
4181 let Some(spec) = rules.get(&*rule.name) else {
4182 return;
4183 };
4184 for alt in &spec.close {
4185 if !groups_enabled(alt, options)
4186 || (tagged_only && !alt_has_sync_group(alt, &options.parse.recover.sync_groups))
4187 {
4188 continue;
4189 }
4190 if let Some(slot) = alt.s.first() {
4191 out.extend(completion_tins(slot));
4192 }
4193 }
4194}
4195
4196fn compute_sync_tins(
4197 rule: &Rule,
4198 stack: &[Rule],
4199 rules: &IndexMap<String, Arc<RuleSpec>>,
4200 options: &Options,
4201) -> BTreeSet<Tin> {
4202 let mut out = BTreeSet::new();
4203 add_close_tins(rule, rules, options, true, &mut out);
4204 for parent in stack.iter().rev() {
4205 add_close_tins(parent, rules, options, true, &mut out);
4206 }
4207 if out.is_empty() {
4208 add_close_tins(rule, rules, options, false, &mut out);
4209 for parent in stack.iter().rev() {
4210 add_close_tins(parent, rules, options, false, &mut out);
4211 }
4212 }
4213 for name in &options.parse.recover.sync_tokens {
4214 if let Some(tin) = options.token(name) {
4215 out.insert(tin);
4216 }
4217 if let Some(tins) = options.token_set.get(name.trim_start_matches('#')) {
4218 out.extend(tins.iter().copied());
4219 }
4220 }
4221 out
4222}
4223
4224fn accepts_close(
4225 rule: &Rule,
4226 tin: Tin,
4227 rules: &IndexMap<String, Arc<RuleSpec>>,
4228 options: &Options,
4229) -> bool {
4230 rules.get(&*rule.name).is_some_and(|spec| {
4231 spec.close.iter().any(|alt| {
4232 groups_enabled(alt, options)
4233 && (alt.s.is_empty() || alt.s.first().is_some_and(|slot| slot_matches(slot, tin)))
4234 })
4235 })
4236}
4237
4238fn add_openers(
4239 name: &str,
4240 rules: &IndexMap<String, Arc<RuleSpec>>,
4241 options: &Options,
4242 opened: &mut BTreeSet<String>,
4243 out: &mut BTreeSet<Tin>,
4244) {
4245 if name.is_empty() || !opened.insert(name.to_owned()) {
4246 return;
4247 }
4248 let Some(spec) = rules.get(name) else {
4249 return;
4250 };
4251 lead_tins(&spec.open, options, out);
4252 for alt in &spec.open {
4253 if !groups_enabled(alt, options) || !alt.s.is_empty() {
4254 continue;
4255 }
4256 if let Some(push) = alt.p.as_deref() {
4257 add_openers(push, rules, options, opened, out);
4258 }
4259 if let Some(replace) = alt.r.as_deref() {
4260 add_openers(replace, rules, options, opened, out);
4261 }
4262 }
4263}
4264
4265fn continuation_tins(
4266 context: &Context,
4267 rule: &Rule,
4268 stack: &[Rule],
4269 rules: &IndexMap<String, Arc<RuleSpec>>,
4270 options: &Options,
4271 query_pos: usize,
4272 failed: Option<&[Tin]>,
4273) -> Vec<Tin> {
4274 let Some(spec) = rules.get(&*rule.name) else {
4275 return Vec::new();
4276 };
4277 let state_alts = if rule.state == RuleState::Open {
4278 &spec.open
4279 } else {
4280 &spec.close
4281 };
4282 let mut out = BTreeSet::new();
4283
4284 if let Some(failed) = failed.filter(|tins| !tins.is_empty()) {
4285 out.extend(failed.iter().copied());
4286 } else {
4287 for alt in state_alts {
4288 if !groups_enabled(alt, options) {
4289 continue;
4290 }
4291 let depth = alt_match_depth(alt, context);
4292 if depth == query_pos {
4293 if let Some(slot) = alt.s.get(depth) {
4294 out.extend(completion_tins(slot));
4295 }
4296 }
4297 }
4298 }
4299
4300 let mut close_rule = rule;
4303 let mut parent_index = stack.len();
4304 while let Some(close_spec) = rules.get(&*close_rule.name) {
4305 if !has_empty_close(close_spec, options) || parent_index == 0 {
4306 break;
4307 }
4308 parent_index -= 1;
4309 let parent = &stack[parent_index];
4310 if let Some(parent_spec) = rules.get(&*parent.name) {
4311 lead_tins(&parent_spec.close, options, &mut out);
4312 }
4313 close_rule = parent;
4314 }
4315
4316 let mut opened = BTreeSet::new();
4319 for alt in state_alts {
4320 if !groups_enabled(alt, options) || alt_match_depth(alt, context) != alt.s.len() {
4321 continue;
4322 }
4323 if alt.b_fn.is_some() {
4326 continue;
4327 }
4328 if alt.s.len().checked_sub(alt.b) != Some(query_pos) {
4329 continue;
4330 }
4331 if let Some(push) = alt.p.as_deref() {
4332 add_openers(push, rules, options, &mut opened, &mut out);
4333 }
4334 if let Some(replace) = alt.r.as_deref() {
4335 add_openers(replace, rules, options, &mut opened, &mut out);
4336 }
4337 }
4338
4339 out.into_iter().collect()
4340}
4341
4342fn listed(list: &str) -> impl Iterator<Item = &str> {
4348 list.split(',')
4349 .map(str::trim)
4350 .filter(|entry| !entry.is_empty())
4351}
4352
4353pub(crate) fn groups_enabled(alt: &AltSpec, options: &Options) -> bool {
4354 let include = options.rule.include.as_str();
4359 let exclude = options.rule.exclude.as_str();
4360 if include.is_empty() && exclude.is_empty() {
4361 return true;
4362 }
4363 let declares = |wanted: &str| listed(&alt.g).any(|group| group == wanted);
4370 let included = listed(include).next().is_none() || listed(include).any(&declares);
4371 included && !listed(exclude).any(&declares)
4372}
4373
4374fn builtin_condition_matches(reference: Option<&str>, rule: &Rule) -> bool {
4375 let phase = match rule.k.get("pd_phase") {
4376 Some(Value::Number(value)) => *value as i32,
4377 _ => 0,
4378 };
4379 match reference {
4380 None => true,
4381 Some("@probePhase0$") => phase == 0,
4382 Some("@probePhase1$") => phase == 1,
4383 Some("@probePhase2$") => phase == 2,
4384 Some(_) => false,
4385 }
4386}
4387
4388fn conditions_match(conditions: &[Condition], rule: &Rule, ancestors: &[Rule]) -> bool {
4389 conditions.iter().all(|condition| {
4390 let resolved = resolve_condition_path(rule, ancestors, &condition.path);
4391 if condition.op == CompareOp::Exist {
4392 let exists = condition_exists(rule, ancestors, &condition.path);
4393 let wanted = matches!(condition.value, Value::Bool(true));
4394 return exists == wanted;
4395 }
4396 let Some(actual) = resolved else {
4397 return !matches!(condition.op, CompareOp::Eq);
4398 };
4399 match condition.op {
4400 CompareOp::Eq => actual.deep_equal(&condition.value),
4401 CompareOp::Ne => !actual.deep_equal(&condition.value),
4402 CompareOp::Lt => ordered(&actual, &condition.value).is_none_or(|value| value < 0),
4403 CompareOp::Lte => ordered(&actual, &condition.value).is_none_or(|value| value <= 0),
4404 CompareOp::Gt => ordered(&actual, &condition.value).is_none_or(|value| value > 0),
4405 CompareOp::Gte => ordered(&actual, &condition.value).is_none_or(|value| value >= 0),
4406 CompareOp::Exist => unreachable!("handled above"),
4407 }
4408 })
4409}
4410
4411fn ordered(left: &Value, right: &Value) -> Option<i8> {
4412 match (left, right) {
4413 (Value::Number(left), Value::Number(right)) => Some(if left < right {
4414 -1
4415 } else if left > right {
4416 1
4417 } else {
4418 0
4419 }),
4420 (Value::String(left), Value::String(right)) => Some(match left.cmp(right) {
4421 std::cmp::Ordering::Less => -1,
4422 std::cmp::Ordering::Equal => 0,
4423 std::cmp::Ordering::Greater => 1,
4424 }),
4425 _ => None,
4426 }
4427}
4428
4429fn condition_exists(rule: &Rule, ancestors: &[Rule], path: &[String]) -> bool {
4430 if path.first().map(String::as_str) == Some("n") && path.len() == 2 {
4431 rule.n.contains_key(&path[1])
4432 } else if path.first().map(String::as_str) == Some("parent") {
4433 ancestors
4434 .split_last()
4435 .is_some_and(|(parent, parent_ancestors)| {
4436 condition_exists(parent, parent_ancestors, &path[1..])
4437 })
4438 } else if path.first().map(String::as_str) == Some("child") {
4439 rule.child_rule
4440 .as_deref()
4441 .is_some_and(|child| snapshot_condition_exists(child, &path[1..]))
4442 } else if path.first().map(String::as_str) == Some("prev") {
4443 rule.prev_rule
4444 .as_deref()
4445 .is_some_and(|prev| snapshot_condition_exists(prev, &path[1..]))
4446 } else if path.first().map(String::as_str) == Some("next") {
4447 if let Some(next) = rule.next_rule.as_deref() {
4448 snapshot_condition_exists(next, &path[1..])
4449 } else if rule.next_rule_name.as_deref() == Some(&*rule.name) {
4450 condition_exists(rule, ancestors, &path[1..])
4451 } else {
4452 false
4453 }
4454 } else {
4455 resolve_condition_path(rule, ancestors, path).is_some()
4456 }
4457}
4458
4459fn resolve_condition_path(rule: &Rule, ancestors: &[Rule], path: &[String]) -> Option<Value> {
4460 let root = path.first()?.as_str();
4461 let rest = &path[1..];
4462 match root {
4463 "n" if rest.len() == 1 => Some(Value::Number(*rule.n.get(&rest[0]).unwrap_or(&0) as f64)),
4464 "u" => map_path(&rule.u, rest),
4465 "k" => map_path(&rule.k, rest),
4466 "d" if rest.is_empty() => Some(Value::Number(rule.d as f64)),
4467 "i" if rest.is_empty() => Some(Value::Number(rule.i as f64)),
4468 "name" if rest.is_empty() => Some(Value::String(rule.name.to_string())),
4469 "state" if rest.is_empty() => Some(Value::String(
4470 match rule.state {
4471 RuleState::Open => "o",
4472 RuleState::Close => "c",
4473 }
4474 .into(),
4475 )),
4476 "node" => value_path(rule.node.borrow().clone(), rest),
4477 "need" if rest.is_empty() => Some(Value::Number(rule.need as f64)),
4478 "oN" if rest.is_empty() => Some(Value::Number(rule.o.len() as f64)),
4479 "cN" if rest.is_empty() => Some(Value::Number(rule.c.len() as f64)),
4480 "o" => token_list_path(&rule.o, rest),
4481 "c" => token_list_path(&rule.c, rest),
4482 "o0" => token_path(rule.o.first(), rest),
4483 "o1" => token_path(rule.o.get(1), rest),
4484 "c0" => token_path(rule.c.first(), rest),
4485 "c1" => token_path(rule.c.get(1), rest),
4486 "parent" => {
4487 let (parent, parent_ancestors) = ancestors.split_last()?;
4488 resolve_condition_path(parent, parent_ancestors, rest)
4489 }
4490 "child" => resolve_snapshot_path(rule.child_rule.as_deref()?, rest),
4491 "prev" => resolve_snapshot_path(rule.prev_rule.as_deref()?, rest),
4492 "next" => {
4493 if let Some(next) = rule.next_rule.as_deref() {
4494 resolve_snapshot_path(next, rest)
4495 } else if rule.next_rule_name.as_deref() == Some(&*rule.name) {
4496 resolve_condition_path(rule, ancestors, rest)
4497 } else {
4498 None
4499 }
4500 }
4501 "spec" if rest == ["name"] => Some(Value::String(rule.name.to_string())),
4502 _ => None,
4503 }
4504}
4505
4506#[derive(Clone, Copy, PartialEq, Eq)]
4508enum Link {
4509 Parent,
4512 PusherBefore,
4524 Prev,
4526}
4527
4528fn bounded_history(
4561 snapshot: Rc<RuleSnapshot>,
4562 history: Option<usize>,
4563 link: Link,
4564) -> Rc<RuleSnapshot> {
4565 let Some(history) = crate::options::effective_rule_history(history) else {
4566 return snapshot;
4567 };
4568 let mut links: Vec<&Rc<RuleSnapshot>> = Vec::with_capacity(history);
4574 let mut current = Some(&snapshot);
4575 while let Some(snapshot) = current {
4576 if links.len() == history {
4577 break;
4578 }
4579 links.push(snapshot);
4580 current = snapshot.prev_rule.as_ref();
4581 }
4582 let mut prev: Option<Rc<RuleSnapshot>> = None;
4583 for (depth, original) in links.into_iter().enumerate().rev() {
4585 let mut copy = (**original).clone();
4586 if depth != 0 || link != Link::Parent {
4587 copy.child_rule = None;
4588 copy.next_rule = None;
4589 copy.next_rule_name = None;
4590 }
4591 copy.prev_rule = prev.take();
4592 prev = Some(Rc::new(copy));
4593 }
4594 prev.expect("at least the snapshot itself is copied")
4595}
4596
4597fn snapshot_condition_exists(rule: &RuleSnapshot, path: &[String]) -> bool {
4598 if path.first().map(String::as_str) == Some("n") && path.len() == 2 {
4599 rule.n.contains_key(&path[1])
4600 } else if path.first().map(String::as_str) == Some("parent") {
4601 rule.parent_rule
4602 .as_deref()
4603 .is_some_and(|parent| snapshot_condition_exists(parent, &path[1..]))
4604 } else if path.first().map(String::as_str) == Some("child") {
4605 rule.child_rule
4606 .as_deref()
4607 .is_some_and(|child| snapshot_condition_exists(child, &path[1..]))
4608 } else if path.first().map(String::as_str) == Some("prev") {
4609 rule.prev_rule
4610 .as_deref()
4611 .is_some_and(|prev| snapshot_condition_exists(prev, &path[1..]))
4612 } else if path.first().map(String::as_str) == Some("next") {
4613 if let Some(next) = rule.next_rule.as_deref() {
4614 snapshot_condition_exists(next, &path[1..])
4615 } else if rule.next_rule_name.as_deref() == Some(&*rule.name) {
4616 snapshot_condition_exists(rule, &path[1..])
4617 } else {
4618 false
4619 }
4620 } else {
4621 resolve_snapshot_path(rule, path).is_some()
4622 }
4623}
4624
4625fn resolve_snapshot_path(rule: &RuleSnapshot, path: &[String]) -> Option<Value> {
4626 let root = path.first()?.as_str();
4627 let rest = &path[1..];
4628 match root {
4629 "n" if rest.len() == 1 => Some(Value::Number(*rule.n.get(&rest[0]).unwrap_or(&0) as f64)),
4630 "u" => map_path(&rule.u, rest),
4631 "k" => map_path(&rule.k, rest),
4632 "d" if rest.is_empty() => Some(Value::Number(rule.d as f64)),
4633 "i" if rest.is_empty() => Some(Value::Number(rule.i as f64)),
4634 "name" if rest.is_empty() => Some(Value::String(rule.name.to_string())),
4635 "state" if rest.is_empty() => Some(Value::String(
4636 match rule.state {
4637 RuleState::Open => "o",
4638 RuleState::Close => "c",
4639 }
4640 .into(),
4641 )),
4642 "node" => value_path(rule.node.borrow().clone(), rest),
4643 "need" if rest.is_empty() => Some(Value::Number(rule.need as f64)),
4644 "oN" if rest.is_empty() => Some(Value::Number(rule.o.len() as f64)),
4645 "cN" if rest.is_empty() => Some(Value::Number(rule.c.len() as f64)),
4646 "o" => token_list_path(&rule.o, rest),
4647 "c" => token_list_path(&rule.c, rest),
4648 "o0" => token_path(rule.o.first(), rest),
4649 "o1" => token_path(rule.o.get(1), rest),
4650 "c0" => token_path(rule.c.first(), rest),
4651 "c1" => token_path(rule.c.get(1), rest),
4652 "parent" => resolve_snapshot_path(rule.parent_rule.as_deref()?, rest),
4653 "child" => resolve_snapshot_path(rule.child_rule.as_deref()?, rest),
4654 "prev" => resolve_snapshot_path(rule.prev_rule.as_deref()?, rest),
4655 "next" => {
4656 if let Some(next) = rule.next_rule.as_deref() {
4657 resolve_snapshot_path(next, rest)
4658 } else if rule.next_rule_name.as_deref() == Some(&*rule.name) {
4659 resolve_snapshot_path(rule, rest)
4660 } else {
4661 None
4662 }
4663 }
4664 "spec" if rest == ["name"] => Some(Value::String(rule.name.to_string())),
4665 _ => None,
4666 }
4667}
4668
4669fn map_path(map: &HashMap<String, Value>, path: &[String]) -> Option<Value> {
4670 let (name, rest) = path.split_first()?;
4671 value_path(map.get(name)?.clone(), rest)
4672}
4673
4674fn value_path(mut value: Value, path: &[String]) -> Option<Value> {
4675 for part in path {
4676 value = match value {
4677 Value::Object(map) => map.get(part)?.clone(),
4678 Value::Array(items) => items.get(part.parse::<usize>().ok()?)?.clone(),
4679 _ => return None,
4680 };
4681 }
4682 Some(value)
4683}
4684
4685fn token_list_path(tokens: &[Token], path: &[String]) -> Option<Value> {
4686 let (index, rest) = path.split_first()?;
4687 token_path(tokens.get(index.parse::<usize>().ok()?), rest)
4688}
4689
4690fn token_path(token: Option<&Token>, path: &[String]) -> Option<Value> {
4691 let token = token?;
4692 if path.is_empty() {
4693 let mut value = IndexMap::new();
4694 value.insert("tin".into(), Value::Number(token.tin as f64));
4695 value.insert("name".into(), Value::String(token.name.to_string()));
4696 value.insert("src".into(), Value::String(token.src.to_string()));
4697 value.insert("val".into(), token.val.clone());
4698 value.insert("why".into(), Value::String(token.why.to_string()));
4699 return Some(Value::object(value));
4700 }
4701 let (field, rest) = path.split_first()?;
4702 let value = match field.as_str() {
4703 "tin" => Value::Number(token.tin as f64),
4704 "name" => Value::String(token.name.to_string()),
4705 "src" => Value::String(token.src.to_string()),
4706 "val" => token.val.clone(),
4707 "why" => Value::String(token.why.to_string()),
4708 _ => return None,
4709 };
4710 value_path(value, rest)
4711}
4712
4713#[cfg(test)]
4714mod tests {
4715 use super::*;
4716
4717 #[test]
4727 fn replacing_a_rule_replaces_the_tables_derived_from_it() {
4728 let mut parser = Parser::new(crate::Options::default());
4729
4730 let mut first = RuleSpec::new("val");
4731 first.bo.push("@enter".into());
4732 first.open.push(AltSpec {
4733 s: vec![vec![crate::TIN_NR]],
4734 a: vec!["@act".into()],
4735 ..Default::default()
4736 });
4737 parser.add_rule(first);
4738 let slot = parser
4739 .rules()
4740 .get_index_of("val")
4741 .expect("the rule was just installed");
4742 assert_eq!(parser.expected_tins[slot].at(true, 0), [crate::TIN_NR]);
4743 assert_eq!(&*parser.names[slot], "val");
4744 assert_eq!(parser.prepared[slot].before(true).len(), 1);
4745 assert_eq!(parser.prepared[slot].open[0].actions.len(), 1);
4746
4747 let mut second = RuleSpec::new("val");
4748 second.open.push(AltSpec {
4749 s: vec![vec![crate::TIN_ST]],
4750 ..Default::default()
4751 });
4752 parser.add_rule(second);
4753
4754 assert_eq!(parser.rules().len(), 1, "a replacement, not an addition");
4755 assert_eq!(
4756 parser.expected_tins[slot].at(true, 0),
4757 [crate::TIN_ST],
4758 "lookahead would still expect the replaced rule's tokens"
4759 );
4760 assert_eq!(parser.names.len(), 1, "one rule, one shared name");
4765 assert_eq!(parser.rules().get_index_of("val"), Some(slot));
4766 assert_eq!(&*parser.names[slot], "val");
4767 assert_eq!(parser.prepared.len(), 1);
4773 assert_eq!(&*parser.prepared[slot].name, "val");
4774 assert!(Arc::ptr_eq(
4775 &parser.prepared[slot].spec,
4776 &parser.rules()["val"]
4777 ));
4778 assert!(parser.prepared[slot].before(true).is_empty());
4783 assert!(parser.prepared[slot].open[0].actions.is_empty());
4784 assert!(!parser.prepared[slot].open[0].named);
4785 }
4786
4787 #[test]
4795 fn expected_match_tins_follows_the_rule_name_when_the_slot_goes_stale() {
4796 fn rule_named(name: &str, tin: Tin) -> RuleSpec {
4797 let mut spec = RuleSpec::new(name);
4798 spec.open.push(AltSpec {
4799 s: vec![vec![tin]],
4800 ..Default::default()
4801 });
4802 spec
4803 }
4804
4805 let mut options = crate::Options::default();
4806 let tin = options.register_token("#QQ");
4807 options.match_tokens.insert(
4808 "#QQ".into(),
4809 crate::options::MatchToken {
4810 name: "#QQ".into(),
4811 tin,
4812 matcher: crate::options::MatchTokenMatcher::Regex(regex::Regex::new("^q").unwrap()),
4813 eager: false,
4814 },
4815 );
4816 let mut parser = Parser::new(options);
4817 parser.add_rule(rule_named("val", crate::TIN_NR));
4818 parser.add_rule(rule_named("other", crate::TIN_ST));
4819
4820 let val_slot = parser.rules().get_index_of("val").expect("installed");
4821 let other_slot = parser.rules().get_index_of("other").expect("installed");
4822 assert_ne!(val_slot, other_slot);
4823
4824 let mut rule = Rule::new("val", Value::Undefined);
4827 rule.bind_spec(
4828 &parser.rules()["val"],
4829 parser.names[val_slot].clone(),
4830 val_slot,
4831 );
4832 assert_eq!(&*parser.expected_match_tins(&rule, 0), [crate::TIN_NR]);
4833
4834 rule.name = parser.names[other_slot].clone();
4839 assert_eq!(
4840 &*parser.expected_match_tins(&rule, 0),
4841 [crate::TIN_ST],
4842 "the rule is called `other` now, so `other`'s row answers"
4843 );
4844
4845 rule.name = parser.names[val_slot].clone();
4849 rule.spec = Arc::clone(&parser.rules()["other"]);
4850 assert_eq!(
4851 &*parser.expected_match_tins(&rule, 0),
4852 [crate::TIN_NR],
4853 "still called `val`, so still gated by `val`'s row"
4854 );
4855
4856 let ghost = Rule::new("ghost", Value::Undefined);
4859 assert_eq!(
4860 &*parser.expected_match_tins(&ghost, 0),
4861 &[] as &[Tin],
4862 "an uninstalled name has no row, not another rule's"
4863 );
4864 }
4865
4866 #[test]
4874 fn expected_match_tins_is_empty_until_a_match_token_exists() {
4875 fn val_rule() -> RuleSpec {
4876 let mut spec = RuleSpec::new("val");
4877 spec.open.push(AltSpec {
4878 s: vec![vec![crate::TIN_NR]],
4879 ..Default::default()
4880 });
4881 spec
4882 }
4883 let rule = Rule::new("val", Value::Undefined);
4884
4885 let mut without = Parser::new(crate::Options::default());
4886 without.add_rule(val_rule());
4887 assert!(without.options.match_tokens.is_empty());
4888 assert_eq!(without.expected_tins[0].at(true, 0), [crate::TIN_NR]);
4889 assert_eq!(
4890 &*without.expected_match_tins(&rule, 0),
4891 &[] as &[Tin],
4892 "no custom matcher: nothing to gate, so nothing to look up"
4893 );
4894
4895 let mut options = crate::Options::default();
4896 let tin = options.register_token("#QQ");
4897 options.match_tokens.insert(
4898 "#QQ".into(),
4899 crate::options::MatchToken {
4900 name: "#QQ".into(),
4901 tin,
4902 matcher: crate::options::MatchTokenMatcher::Regex(regex::Regex::new("^q").unwrap()),
4903 eager: false,
4904 },
4905 );
4906 let mut with = Parser::new(options);
4907 with.add_rule(val_rule());
4908 assert_eq!(
4909 &*with.expected_match_tins(&rule, 0),
4910 [crate::TIN_NR],
4911 "a custom matcher is present, so the slot's tins gate it"
4912 );
4913 assert_eq!(
4914 &*with.expected_match_tins(&rule, 1),
4915 &[] as &[Tin],
4916 "a slot the rule never fills expects nothing"
4917 );
4918 }
4919}