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 after = self.run_after_actions(
3396 spec,
3397 prepared,
3398 is_open,
3399 &mut current_rule,
3400 &mut context,
3401 ParseSite {
3402 source: src,
3403 stack: &stack,
3404 alts,
3405 },
3406 );
3407 update_partial(mode, &root_node, ¤t_rule, &stack);
3408 if self.recover_after_actions(
3409 after,
3410 if is_open {
3411 RuleState::Open
3412 } else {
3413 RuleState::Close
3414 },
3415 done_alt.clone(),
3416 src,
3417 &mut current_rule,
3418 &mut stack,
3419 &mut context,
3420 &mut lexer,
3421 mode,
3422 )? {
3423 continue 'parse;
3424 }
3425 if is_open {
3426 current_rule.state = RuleState::Close;
3427 }
3428 child.parent_rule = Some(bounded_history(
3429 current_rule.snapshot(),
3430 self.options.rule.history,
3431 Link::Parent,
3432 ));
3433 completed_rule = self.rule_done_copy(¤t_rule);
3434 if park_child_nodes {
3443 current_rule.park_child_node();
3444 }
3445 stack.push(current_rule);
3446 current_rule = child;
3447 } else if replace_name.is_some() {
3448 let (replace_slot, replace_shared, replace_spec) =
3449 route.take().expect("a replace route was resolved above");
3450 let mut next = Rule::bound(
3451 replace_shared.clone(),
3452 current_rule.node.clone(),
3453 Some(replace_spec),
3454 replace_slot,
3455 );
3456 next.i = next_rule_id;
3457 next_rule_id += 1;
3458 next.d = current_rule.d;
3459 next.parent_node = current_rule.parent_node.clone();
3460 next.parent_rule = current_rule.parent_rule.clone();
3461 next.n = Rc::clone(¤t_rule.n);
3462 next.k = Rc::clone(¤t_rule.k);
3463 current_rule.next_rule_name = Some(replace_shared);
3464 current_rule.next_rule = Some(next.snapshot());
3465 let after = self.run_after_actions(
3466 spec,
3467 prepared,
3468 is_open,
3469 &mut current_rule,
3470 &mut context,
3471 ParseSite {
3472 source: src,
3473 stack: &stack,
3474 alts,
3475 },
3476 );
3477 update_partial(mode, &root_node, ¤t_rule, &stack);
3478 if self.recover_after_actions(
3479 after,
3480 if is_open {
3481 RuleState::Open
3482 } else {
3483 RuleState::Close
3484 },
3485 done_alt.clone(),
3486 src,
3487 &mut current_rule,
3488 &mut stack,
3489 &mut context,
3490 &mut lexer,
3491 mode,
3492 )? {
3493 continue 'parse;
3494 }
3495 if is_open {
3496 current_rule.state = RuleState::Close;
3497 }
3498 next.prev_rule = Some(bounded_history(
3499 current_rule.snapshot(),
3500 self.options.rule.history,
3501 Link::Prev,
3502 ));
3503 if let Some(parent) = stack.last_mut() {
3510 parent.freeze_child(¤t_rule);
3511 }
3512 completed_rule = Some(current_rule);
3516 current_rule = next;
3517 } else if is_open {
3518 current_rule.next_rule_name = Some(current_rule.name.clone());
3519 current_rule.next_rule = Some(current_rule.snapshot());
3520 let after = self.run_after_actions(
3521 spec,
3522 prepared,
3523 true,
3524 &mut current_rule,
3525 &mut context,
3526 ParseSite {
3527 source: src,
3528 stack: &stack,
3529 alts,
3530 },
3531 );
3532 update_partial(mode, &root_node, ¤t_rule, &stack);
3533 if self.recover_after_actions(
3534 after,
3535 RuleState::Open,
3536 done_alt.clone(),
3537 src,
3538 &mut current_rule,
3539 &mut stack,
3540 &mut context,
3541 &mut lexer,
3542 mode,
3543 )? {
3544 continue 'parse;
3545 }
3546 current_rule.state = RuleState::Close;
3547 completed_rule = self.rule_done_copy(¤t_rule);
3548 } else {
3549 current_rule.next_rule_name = stack.last().map(|rule| rule.name.clone());
3551 current_rule.next_rule = stack.last().map(Rule::snapshot);
3552 let after = self.run_after_actions(
3553 spec,
3554 prepared,
3555 false,
3556 &mut current_rule,
3557 &mut context,
3558 ParseSite {
3559 source: src,
3560 stack: &stack,
3561 alts,
3562 },
3563 );
3564 update_partial(mode, &root_node, ¤t_rule, &stack);
3565 if self.recover_after_actions(
3566 after,
3567 RuleState::Close,
3568 done_alt.clone(),
3569 src,
3570 &mut current_rule,
3571 &mut stack,
3572 &mut context,
3573 &mut lexer,
3574 mode,
3575 )? {
3576 continue 'parse;
3577 }
3578 let parent = stack.pop();
3579 completed_rule = self.rule_done_copy(¤t_rule);
3580 if let Some(mut parent) = parent {
3581 parent.accept_child(¤t_rule);
3582 current_rule = parent;
3583 } else {
3584 completed_value = Some(current_rule.node.borrow().clone());
3586 }
3587 }
3588 if let Some(completed_rule) = &completed_rule {
3589 self.notify_rule_done(
3590 completed_rule,
3591 &context,
3592 if is_open {
3593 RuleState::Open
3594 } else {
3595 RuleState::Close
3596 },
3597 done_alt,
3598 src,
3599 &stack,
3600 )?;
3601 }
3602 if let Some(value) = completed_value {
3603 final_value = Some(value);
3604 break;
3605 }
3606 update_partial(mode, &root_node, ¤t_rule, &stack);
3607 } else if alts.is_empty() {
3608 let completed_rule: Option<Rule>;
3611 let mut completed_value = None;
3612 if is_open {
3613 current_rule.next_rule_name = Some(current_rule.name.clone());
3614 current_rule.next_rule = Some(current_rule.snapshot());
3615 let after = self.run_after_actions(
3616 spec,
3617 prepared,
3618 true,
3619 &mut current_rule,
3620 &mut context,
3621 ParseSite {
3622 source: src,
3623 stack: &stack,
3624 alts,
3625 },
3626 );
3627 update_partial(mode, &root_node, ¤t_rule, &stack);
3628 if self.recover_after_actions(
3629 after,
3630 RuleState::Open,
3631 None,
3632 src,
3633 &mut current_rule,
3634 &mut stack,
3635 &mut context,
3636 &mut lexer,
3637 mode,
3638 )? {
3639 continue 'parse;
3640 }
3641 current_rule.state = RuleState::Close;
3642 completed_rule = self.rule_done_copy(¤t_rule);
3643 } else {
3644 current_rule.next_rule_name = stack.last().map(|rule| rule.name.clone());
3645 current_rule.next_rule = stack.last().map(Rule::snapshot);
3646 let after = self.run_after_actions(
3647 spec,
3648 prepared,
3649 false,
3650 &mut current_rule,
3651 &mut context,
3652 ParseSite {
3653 source: src,
3654 stack: &stack,
3655 alts,
3656 },
3657 );
3658 update_partial(mode, &root_node, ¤t_rule, &stack);
3659 if self.recover_after_actions(
3660 after,
3661 RuleState::Close,
3662 None,
3663 src,
3664 &mut current_rule,
3665 &mut stack,
3666 &mut context,
3667 &mut lexer,
3668 mode,
3669 )? {
3670 continue 'parse;
3671 }
3672 let parent = stack.pop();
3673 completed_rule = self.rule_done_copy(¤t_rule);
3674 if let Some(mut parent) = parent {
3675 parent.accept_child(¤t_rule);
3676 current_rule = parent;
3677 } else {
3678 completed_value = Some(current_rule.node.borrow().clone());
3679 }
3680 }
3681 if let Some(completed_rule) = &completed_rule {
3682 self.notify_rule_done(
3683 completed_rule,
3684 &context,
3685 if is_open {
3686 RuleState::Open
3687 } else {
3688 RuleState::Close
3689 },
3690 None,
3691 src,
3692 &stack,
3693 )?;
3694 }
3695 if let Some(value) = completed_value {
3696 final_value = Some(value);
3697 break;
3698 }
3699 update_partial(mode, &root_node, ¤t_rule, &stack);
3700 } else {
3701 if is_open {
3703 if let Err(error) = self.ensure_lookahead(
3704 &mut lexer,
3705 &mut context,
3706 &mut current_rule,
3707 1,
3708 mode,
3709 ParseSite {
3710 source: src,
3711 stack: &stack,
3712 alts,
3713 },
3714 Fetch::Rule,
3715 ) {
3716 return Err(self.attach_error(error, ¤t_rule, &stack, alts, None));
3717 }
3718 if let Some(capture) = mode.continuation.as_deref_mut() {
3719 let base = failed_alt_tins(&context, alts, &self.options);
3720 capture.failure = continuation_tins(
3721 &context,
3722 ¤t_rule,
3723 &stack,
3724 &self.rules,
3725 &self.options,
3726 0,
3727 Some(&base),
3728 );
3729 }
3730 let t0 = context.t.first().cloned();
3731 let (src_token, si, ri, ci) = if let Some(t) = t0.as_ref() {
3732 (t.src.to_string(), t.site.pos, t.site.ri, t.site.ci)
3733 } else {
3734 (String::new(), src.len(), 1, 1)
3735 };
3736 let code = t0.as_ref().map_or("unexpected", deferred_error_code);
3737 let error = TabnasError::new(code, src_token, src, si, ri, ci);
3738 let done_alt = (!alts.is_empty() && !self.rule_done_subscribers.is_empty())
3739 .then(|| RuleDoneAlt {
3740 b: 0,
3741 g: Vec::new(),
3742 p: String::new(),
3743 r: String::new(),
3744 err: t0.clone(),
3745 });
3746 let error = self.attach_error(error, ¤t_rule, &stack, alts, t0.as_ref());
3747 self.recover_error_pass(
3748 error,
3749 RuleState::Open,
3750 done_alt,
3751 false,
3752 src,
3753 &mut current_rule,
3754 &mut stack,
3755 &mut context,
3756 &mut lexer,
3757 mode,
3758 )?;
3759 continue;
3760 } else {
3761 if let Err(error) = self.ensure_lookahead(
3762 &mut lexer,
3763 &mut context,
3764 &mut current_rule,
3765 1,
3766 mode,
3767 ParseSite {
3768 source: src,
3769 stack: &stack,
3770 alts,
3771 },
3772 Fetch::Rule,
3773 ) {
3774 return Err(self.attach_error(error, ¤t_rule, &stack, alts, None));
3775 }
3776 if let Some(capture) = mode.continuation.as_deref_mut() {
3777 let base = failed_alt_tins(&context, alts, &self.options);
3778 capture.failure = continuation_tins(
3779 &context,
3780 ¤t_rule,
3781 &stack,
3782 &self.rules,
3783 &self.options,
3784 0,
3785 Some(&base),
3786 );
3787 }
3788 let token = context.t.first().cloned();
3789 let (source, pos, row, col) = token.as_ref().map_or_else(
3790 || (String::new(), src.chars().count(), 1, 1),
3791 |value| {
3792 (
3793 value.src.to_string(),
3794 value.site.pos,
3795 value.site.ri,
3796 value.site.ci,
3797 )
3798 },
3799 );
3800 let code = token.as_ref().map_or("unexpected", deferred_error_code);
3801 let error = TabnasError::new(code, source, src, pos, row, col);
3802 let done_alt = Some(RuleDoneAlt {
3803 b: 0,
3804 g: Vec::new(),
3805 p: String::new(),
3806 r: String::new(),
3807 err: token.clone(),
3808 });
3809 let error =
3810 self.attach_error(error, ¤t_rule, &stack, alts, token.as_ref());
3811 self.recover_error_pass(
3812 error,
3813 RuleState::Close,
3814 done_alt,
3815 false,
3816 src,
3817 &mut current_rule,
3818 &mut stack,
3819 &mut context,
3820 &mut lexer,
3821 mode,
3822 )?;
3823 continue;
3824 }
3825 }
3826 }
3827
3828 let res = final_value.unwrap_or(Value::Null).unwrap_undefined();
3829 if mode.recovering {
3830 mode.partial = Some(PartialValue::Complete(res.clone()));
3831 }
3832
3833 if let Err(error) = self.ensure_lookahead(
3836 &mut lexer,
3837 &mut context,
3838 &mut current_rule,
3839 1,
3840 mode,
3841 ParseSite {
3842 source: src,
3843 stack: &stack,
3844 alts: &[],
3845 },
3846 Fetch::Trailing,
3847 ) {
3848 let error = self.attach_error(error, ¤t_rule, &stack, &[], None);
3849 if mode.recovering {
3850 mode.errors.push(error.clone());
3851 context.errs.push(error);
3852 return Ok(res);
3853 }
3854 return Err(error);
3855 }
3856 if let Some(t0) = context.t.first() {
3857 if t0.tin != TIN_ZZ {
3858 let code = if t0.tin == TIN_BD && !t0.why.is_empty() {
3859 t0.why.as_str()
3860 } else {
3861 "unexpected"
3862 };
3863 let error =
3864 TabnasError::new(code, &*t0.src, src, t0.site.pos, t0.site.ri, t0.site.ci);
3865 let error = self.attach_error(
3866 error,
3867 ¤t_rule,
3868 &stack,
3869 &[AltSpec {
3870 s: vec![vec![TIN_ZZ]],
3871 ..Default::default()
3872 }],
3873 Some(t0),
3874 );
3875 if mode.recovering {
3876 mode.errors.push(error.clone());
3877 context.errs.push(error);
3878 return Ok(res);
3879 }
3880 return Err(error);
3881 }
3882 }
3883 if self
3884 .options
3885 .result
3886 .fail
3887 .iter()
3888 .any(|failed| failed.deep_equal(&res))
3889 {
3890 let token = context.t.first();
3891 let error = token.map_or_else(
3892 || TabnasError::new("unexpected", "", src, 0, 1, 1),
3893 |token| {
3894 TabnasError::new(
3895 "unexpected",
3896 &*token.src,
3897 src,
3898 token.site.pos,
3899 token.site.ri,
3900 token.site.ci,
3901 )
3902 },
3903 );
3904 if mode.recovering {
3905 mode.errors.push(error.clone());
3906 context.errs.push(error);
3907 return Ok(res);
3908 }
3909 return Err(error);
3910 }
3911 Ok(res)
3912 }
3913}
3914
3915#[inline]
3935fn update_partial(
3936 mode: &mut ParseMode<'_>,
3937 root_node: &Rc<RefCell<Value>>,
3938 current_rule: &Rule,
3939 stack: &[Rule],
3940) {
3941 if mode.recovering {
3942 mode.partial = best_partial_node(root_node, current_rule, stack).map(PartialValue::Node);
3943 }
3944}
3945
3946#[inline(never)]
3947fn best_partial_node(
3948 root_node: &Rc<RefCell<Value>>,
3949 current_rule: &Rule,
3950 stack: &[Rule],
3951) -> Option<Rc<RefCell<Value>>> {
3952 let usable = |node: &Rc<RefCell<Value>>| {
3953 (!matches!(*node.borrow(), Value::Undefined | Value::Null)).then(|| Rc::clone(node))
3954 };
3955
3956 usable(root_node)
3957 .or_else(|| stack.iter().find_map(|rule| usable(&rule.node)))
3958 .or_else(|| usable(¤t_rule.node))
3959}
3960
3961fn error_token(error: &TabnasError) -> Token {
3962 let byte_position = error
3963 .full_source
3964 .char_indices()
3965 .nth(error.pos)
3966 .map_or(error.full_source.len(), |(index, _)| index);
3967 let mut token = Token::new(
3968 "#BD",
3969 TIN_BD,
3970 Value::Undefined,
3971 error.src.clone(),
3972 crate::Point {
3973 len: error.len,
3974 site: crate::Site {
3975 si: byte_position,
3976 pos: error.pos,
3977 ri: error.row,
3978 ci: error.col,
3979 },
3980 },
3981 );
3982 token.err = crate::TokenCode::from(error.code.as_str());
3983 token.why = token.err.clone();
3984 token
3985}
3986
3987fn deferred_error_code(token: &Token) -> &str {
3988 if token.tin != TIN_BD {
3989 "unexpected"
3990 } else if !token.why.is_empty() {
3991 &token.why
3992 } else if !token.err.is_empty() {
3993 &token.err
3994 } else {
3995 "unexpected"
3996 }
3997}
3998
3999fn raised_error_code(token: &Token) -> &str {
4000 if !token.err.is_empty() {
4001 &token.err
4002 } else if !token.why.is_empty() {
4003 &token.why
4004 } else {
4005 "unexpected"
4006 }
4007}
4008
4009fn mid_construct(code: &str) -> bool {
4010 matches!(code, "unprintable" | "invalid_unicode" | "invalid_ascii")
4011}
4012
4013fn absorb_lex_error(
4022 error: &TabnasError,
4023 context: &mut Context,
4024 options: &Options,
4025 errors: &mut Vec<TabnasError>,
4026) -> bool {
4027 let recover = &options.parse.recover;
4028 let run = context
4029 .bad_error
4030 .filter(|index| *index < errors.len())
4031 .filter(|_| context.bad_to.is_some_and(|bad_to| error.pos <= bad_to));
4032 if let Some(index) = run {
4033 let previous = &mut errors[index];
4034 let recovered = previous.recovered.get_or_insert(crate::RecoveredAt {
4035 skipped: 0,
4036 sync: None,
4037 bad: true,
4038 });
4039 recovered.skipped = recovered.skipped.saturating_add(1);
4040 let skipped = recovered.skipped;
4041 if let Some(context_previous) = context.errs.get_mut(index) {
4042 *context_previous = previous.clone();
4043 }
4044 if recover.max_skip < skipped {
4045 return false;
4046 }
4047 } else if context
4048 .recover_at
4049 .is_some_and(|at| context.v_abs.saturating_sub(at) < recover.suppress)
4050 {
4051 context.bad_error = None;
4052 } else {
4053 let mut recorded = error.clone();
4054 recorded.recovered = Some(crate::RecoveredAt {
4055 skipped: 1,
4056 sync: None,
4057 bad: true,
4058 });
4059 errors.push(recorded.clone());
4060 context.errs.push(recorded);
4061 context.bad_error = Some(errors.len() - 1);
4062 context.recover_at = Some(context.v_abs);
4063 }
4064 context.bad_to = Some(error.pos.saturating_add(error.len.max(1)));
4065 errors.len() <= recover.max_recoveries
4066}
4067
4068fn slot_matches(slot: &[Tin], tin: Tin) -> bool {
4069 tin != TIN_BD && (slot.is_empty() || slot.contains(&tin) || slot.contains(&TIN_AA))
4070}
4071
4072fn alt_match_depth(alt: &AltSpec, context: &Context) -> usize {
4073 let mut depth = 0;
4074 while depth < alt.s.len() {
4075 let Some(token) = context.t.get(depth) else {
4076 break;
4077 };
4078 if !slot_matches(&alt.s[depth], token.tin) {
4079 break;
4080 }
4081 depth += 1;
4082 }
4083 depth
4084}
4085
4086fn completion_tins(slot: &[Tin]) -> impl Iterator<Item = Tin> + '_ {
4087 slot.iter()
4088 .copied()
4089 .chain(slot.is_empty().then_some(TIN_AA))
4090}
4091
4092fn failed_alt_tins(context: &Context, alts: &[AltSpec], options: &Options) -> Vec<Tin> {
4093 let mut out = BTreeSet::new();
4094 for alt in alts {
4095 if !groups_enabled(alt, options) {
4096 continue;
4097 }
4098 let depth = alt_match_depth(alt, context);
4099 if let Some(slot) = alt.s.get(depth) {
4100 out.extend(completion_tins(slot));
4101 }
4102 }
4103 out.into_iter().collect()
4104}
4105
4106fn lead_tins(alts: &[AltSpec], options: &Options, out: &mut BTreeSet<Tin>) {
4107 for alt in alts {
4108 if !groups_enabled(alt, options) {
4109 continue;
4110 }
4111 if let Some(slot) = alt.s.first() {
4112 out.extend(completion_tins(slot));
4113 }
4114 }
4115}
4116
4117fn has_empty_close(spec: &RuleSpec, options: &Options) -> bool {
4118 spec.close
4119 .iter()
4120 .any(|alt| groups_enabled(alt, options) && alt.s.is_empty())
4121}
4122
4123fn alt_has_sync_group(alt: &AltSpec, sync_groups: &[String]) -> bool {
4124 alt.g
4125 .split(',')
4126 .map(str::trim)
4127 .any(|tag| sync_groups.iter().any(|wanted| wanted == tag))
4128}
4129
4130fn add_close_tins(
4131 rule: &Rule,
4132 rules: &IndexMap<String, Arc<RuleSpec>>,
4133 options: &Options,
4134 tagged_only: bool,
4135 out: &mut BTreeSet<Tin>,
4136) {
4137 let Some(spec) = rules.get(&*rule.name) else {
4138 return;
4139 };
4140 for alt in &spec.close {
4141 if !groups_enabled(alt, options)
4142 || (tagged_only && !alt_has_sync_group(alt, &options.parse.recover.sync_groups))
4143 {
4144 continue;
4145 }
4146 if let Some(slot) = alt.s.first() {
4147 out.extend(completion_tins(slot));
4148 }
4149 }
4150}
4151
4152fn compute_sync_tins(
4153 rule: &Rule,
4154 stack: &[Rule],
4155 rules: &IndexMap<String, Arc<RuleSpec>>,
4156 options: &Options,
4157) -> BTreeSet<Tin> {
4158 let mut out = BTreeSet::new();
4159 add_close_tins(rule, rules, options, true, &mut out);
4160 for parent in stack.iter().rev() {
4161 add_close_tins(parent, rules, options, true, &mut out);
4162 }
4163 if out.is_empty() {
4164 add_close_tins(rule, rules, options, false, &mut out);
4165 for parent in stack.iter().rev() {
4166 add_close_tins(parent, rules, options, false, &mut out);
4167 }
4168 }
4169 for name in &options.parse.recover.sync_tokens {
4170 if let Some(tin) = options.token(name) {
4171 out.insert(tin);
4172 }
4173 if let Some(tins) = options.token_set.get(name.trim_start_matches('#')) {
4174 out.extend(tins.iter().copied());
4175 }
4176 }
4177 out
4178}
4179
4180fn accepts_close(
4181 rule: &Rule,
4182 tin: Tin,
4183 rules: &IndexMap<String, Arc<RuleSpec>>,
4184 options: &Options,
4185) -> bool {
4186 rules.get(&*rule.name).is_some_and(|spec| {
4187 spec.close.iter().any(|alt| {
4188 groups_enabled(alt, options)
4189 && (alt.s.is_empty() || alt.s.first().is_some_and(|slot| slot_matches(slot, tin)))
4190 })
4191 })
4192}
4193
4194fn add_openers(
4195 name: &str,
4196 rules: &IndexMap<String, Arc<RuleSpec>>,
4197 options: &Options,
4198 opened: &mut BTreeSet<String>,
4199 out: &mut BTreeSet<Tin>,
4200) {
4201 if name.is_empty() || !opened.insert(name.to_owned()) {
4202 return;
4203 }
4204 let Some(spec) = rules.get(name) else {
4205 return;
4206 };
4207 lead_tins(&spec.open, options, out);
4208 for alt in &spec.open {
4209 if !groups_enabled(alt, options) || !alt.s.is_empty() {
4210 continue;
4211 }
4212 if let Some(push) = alt.p.as_deref() {
4213 add_openers(push, rules, options, opened, out);
4214 }
4215 if let Some(replace) = alt.r.as_deref() {
4216 add_openers(replace, rules, options, opened, out);
4217 }
4218 }
4219}
4220
4221fn continuation_tins(
4222 context: &Context,
4223 rule: &Rule,
4224 stack: &[Rule],
4225 rules: &IndexMap<String, Arc<RuleSpec>>,
4226 options: &Options,
4227 query_pos: usize,
4228 failed: Option<&[Tin]>,
4229) -> Vec<Tin> {
4230 let Some(spec) = rules.get(&*rule.name) else {
4231 return Vec::new();
4232 };
4233 let state_alts = if rule.state == RuleState::Open {
4234 &spec.open
4235 } else {
4236 &spec.close
4237 };
4238 let mut out = BTreeSet::new();
4239
4240 if let Some(failed) = failed.filter(|tins| !tins.is_empty()) {
4241 out.extend(failed.iter().copied());
4242 } else {
4243 for alt in state_alts {
4244 if !groups_enabled(alt, options) {
4245 continue;
4246 }
4247 let depth = alt_match_depth(alt, context);
4248 if depth == query_pos {
4249 if let Some(slot) = alt.s.get(depth) {
4250 out.extend(completion_tins(slot));
4251 }
4252 }
4253 }
4254 }
4255
4256 let mut close_rule = rule;
4259 let mut parent_index = stack.len();
4260 while let Some(close_spec) = rules.get(&*close_rule.name) {
4261 if !has_empty_close(close_spec, options) || parent_index == 0 {
4262 break;
4263 }
4264 parent_index -= 1;
4265 let parent = &stack[parent_index];
4266 if let Some(parent_spec) = rules.get(&*parent.name) {
4267 lead_tins(&parent_spec.close, options, &mut out);
4268 }
4269 close_rule = parent;
4270 }
4271
4272 let mut opened = BTreeSet::new();
4275 for alt in state_alts {
4276 if !groups_enabled(alt, options) || alt_match_depth(alt, context) != alt.s.len() {
4277 continue;
4278 }
4279 if alt.b_fn.is_some() {
4282 continue;
4283 }
4284 if alt.s.len().checked_sub(alt.b) != Some(query_pos) {
4285 continue;
4286 }
4287 if let Some(push) = alt.p.as_deref() {
4288 add_openers(push, rules, options, &mut opened, &mut out);
4289 }
4290 if let Some(replace) = alt.r.as_deref() {
4291 add_openers(replace, rules, options, &mut opened, &mut out);
4292 }
4293 }
4294
4295 out.into_iter().collect()
4296}
4297
4298fn listed(list: &str) -> impl Iterator<Item = &str> {
4304 list.split(',')
4305 .map(str::trim)
4306 .filter(|entry| !entry.is_empty())
4307}
4308
4309pub(crate) fn groups_enabled(alt: &AltSpec, options: &Options) -> bool {
4310 let include = options.rule.include.as_str();
4315 let exclude = options.rule.exclude.as_str();
4316 if include.is_empty() && exclude.is_empty() {
4317 return true;
4318 }
4319 let declares = |wanted: &str| listed(&alt.g).any(|group| group == wanted);
4326 let included = listed(include).next().is_none() || listed(include).any(&declares);
4327 included && !listed(exclude).any(&declares)
4328}
4329
4330fn builtin_condition_matches(reference: Option<&str>, rule: &Rule) -> bool {
4331 let phase = match rule.k.get("pd_phase") {
4332 Some(Value::Number(value)) => *value as i32,
4333 _ => 0,
4334 };
4335 match reference {
4336 None => true,
4337 Some("@probePhase0$") => phase == 0,
4338 Some("@probePhase1$") => phase == 1,
4339 Some("@probePhase2$") => phase == 2,
4340 Some(_) => false,
4341 }
4342}
4343
4344fn conditions_match(conditions: &[Condition], rule: &Rule, ancestors: &[Rule]) -> bool {
4345 conditions.iter().all(|condition| {
4346 let resolved = resolve_condition_path(rule, ancestors, &condition.path);
4347 if condition.op == CompareOp::Exist {
4348 let exists = condition_exists(rule, ancestors, &condition.path);
4349 let wanted = matches!(condition.value, Value::Bool(true));
4350 return exists == wanted;
4351 }
4352 let Some(actual) = resolved else {
4353 return !matches!(condition.op, CompareOp::Eq);
4354 };
4355 match condition.op {
4356 CompareOp::Eq => actual.deep_equal(&condition.value),
4357 CompareOp::Ne => !actual.deep_equal(&condition.value),
4358 CompareOp::Lt => ordered(&actual, &condition.value).is_none_or(|value| value < 0),
4359 CompareOp::Lte => ordered(&actual, &condition.value).is_none_or(|value| value <= 0),
4360 CompareOp::Gt => ordered(&actual, &condition.value).is_none_or(|value| value > 0),
4361 CompareOp::Gte => ordered(&actual, &condition.value).is_none_or(|value| value >= 0),
4362 CompareOp::Exist => unreachable!("handled above"),
4363 }
4364 })
4365}
4366
4367fn ordered(left: &Value, right: &Value) -> Option<i8> {
4368 match (left, right) {
4369 (Value::Number(left), Value::Number(right)) => Some(if left < right {
4370 -1
4371 } else if left > right {
4372 1
4373 } else {
4374 0
4375 }),
4376 (Value::String(left), Value::String(right)) => Some(match left.cmp(right) {
4377 std::cmp::Ordering::Less => -1,
4378 std::cmp::Ordering::Equal => 0,
4379 std::cmp::Ordering::Greater => 1,
4380 }),
4381 _ => None,
4382 }
4383}
4384
4385fn condition_exists(rule: &Rule, ancestors: &[Rule], path: &[String]) -> bool {
4386 if path.first().map(String::as_str) == Some("n") && path.len() == 2 {
4387 rule.n.contains_key(&path[1])
4388 } else if path.first().map(String::as_str) == Some("parent") {
4389 ancestors
4390 .split_last()
4391 .is_some_and(|(parent, parent_ancestors)| {
4392 condition_exists(parent, parent_ancestors, &path[1..])
4393 })
4394 } else if path.first().map(String::as_str) == Some("child") {
4395 rule.child_rule
4396 .as_deref()
4397 .is_some_and(|child| snapshot_condition_exists(child, &path[1..]))
4398 } else if path.first().map(String::as_str) == Some("prev") {
4399 rule.prev_rule
4400 .as_deref()
4401 .is_some_and(|prev| snapshot_condition_exists(prev, &path[1..]))
4402 } else if path.first().map(String::as_str) == Some("next") {
4403 if let Some(next) = rule.next_rule.as_deref() {
4404 snapshot_condition_exists(next, &path[1..])
4405 } else if rule.next_rule_name.as_deref() == Some(&*rule.name) {
4406 condition_exists(rule, ancestors, &path[1..])
4407 } else {
4408 false
4409 }
4410 } else {
4411 resolve_condition_path(rule, ancestors, path).is_some()
4412 }
4413}
4414
4415fn resolve_condition_path(rule: &Rule, ancestors: &[Rule], path: &[String]) -> Option<Value> {
4416 let root = path.first()?.as_str();
4417 let rest = &path[1..];
4418 match root {
4419 "n" if rest.len() == 1 => Some(Value::Number(*rule.n.get(&rest[0]).unwrap_or(&0) as f64)),
4420 "u" => map_path(&rule.u, rest),
4421 "k" => map_path(&rule.k, rest),
4422 "d" if rest.is_empty() => Some(Value::Number(rule.d as f64)),
4423 "i" if rest.is_empty() => Some(Value::Number(rule.i as f64)),
4424 "name" if rest.is_empty() => Some(Value::String(rule.name.to_string())),
4425 "state" if rest.is_empty() => Some(Value::String(
4426 match rule.state {
4427 RuleState::Open => "o",
4428 RuleState::Close => "c",
4429 }
4430 .into(),
4431 )),
4432 "node" => value_path(rule.node.borrow().clone(), rest),
4433 "need" if rest.is_empty() => Some(Value::Number(rule.need as f64)),
4434 "oN" if rest.is_empty() => Some(Value::Number(rule.o.len() as f64)),
4435 "cN" if rest.is_empty() => Some(Value::Number(rule.c.len() as f64)),
4436 "o" => token_list_path(&rule.o, rest),
4437 "c" => token_list_path(&rule.c, rest),
4438 "o0" => token_path(rule.o.first(), rest),
4439 "o1" => token_path(rule.o.get(1), rest),
4440 "c0" => token_path(rule.c.first(), rest),
4441 "c1" => token_path(rule.c.get(1), rest),
4442 "parent" => {
4443 let (parent, parent_ancestors) = ancestors.split_last()?;
4444 resolve_condition_path(parent, parent_ancestors, rest)
4445 }
4446 "child" => resolve_snapshot_path(rule.child_rule.as_deref()?, rest),
4447 "prev" => resolve_snapshot_path(rule.prev_rule.as_deref()?, rest),
4448 "next" => {
4449 if let Some(next) = rule.next_rule.as_deref() {
4450 resolve_snapshot_path(next, rest)
4451 } else if rule.next_rule_name.as_deref() == Some(&*rule.name) {
4452 resolve_condition_path(rule, ancestors, rest)
4453 } else {
4454 None
4455 }
4456 }
4457 "spec" if rest == ["name"] => Some(Value::String(rule.name.to_string())),
4458 _ => None,
4459 }
4460}
4461
4462#[derive(Clone, Copy, PartialEq, Eq)]
4464enum Link {
4465 Parent,
4468 PusherBefore,
4472 Prev,
4474}
4475
4476fn bounded_history(
4505 snapshot: Rc<RuleSnapshot>,
4506 history: Option<usize>,
4507 link: Link,
4508) -> Rc<RuleSnapshot> {
4509 let Some(history) = crate::options::effective_rule_history(history) else {
4510 return snapshot;
4511 };
4512 let mut links: Vec<&Rc<RuleSnapshot>> = Vec::with_capacity(history);
4518 let mut current = Some(&snapshot);
4519 while let Some(snapshot) = current {
4520 if links.len() == history {
4521 break;
4522 }
4523 links.push(snapshot);
4524 current = snapshot.prev_rule.as_ref();
4525 }
4526 let mut prev: Option<Rc<RuleSnapshot>> = None;
4527 for (depth, original) in links.into_iter().enumerate().rev() {
4529 let mut copy = (**original).clone();
4530 if depth != 0 || link != Link::Parent {
4531 copy.child_rule = None;
4532 copy.next_rule = None;
4533 copy.next_rule_name = None;
4534 }
4535 copy.prev_rule = prev.take();
4536 prev = Some(Rc::new(copy));
4537 }
4538 prev.expect("at least the snapshot itself is copied")
4539}
4540
4541fn snapshot_condition_exists(rule: &RuleSnapshot, path: &[String]) -> bool {
4542 if path.first().map(String::as_str) == Some("n") && path.len() == 2 {
4543 rule.n.contains_key(&path[1])
4544 } else if path.first().map(String::as_str) == Some("parent") {
4545 rule.parent_rule
4546 .as_deref()
4547 .is_some_and(|parent| snapshot_condition_exists(parent, &path[1..]))
4548 } else if path.first().map(String::as_str) == Some("child") {
4549 rule.child_rule
4550 .as_deref()
4551 .is_some_and(|child| snapshot_condition_exists(child, &path[1..]))
4552 } else if path.first().map(String::as_str) == Some("prev") {
4553 rule.prev_rule
4554 .as_deref()
4555 .is_some_and(|prev| snapshot_condition_exists(prev, &path[1..]))
4556 } else if path.first().map(String::as_str) == Some("next") {
4557 if let Some(next) = rule.next_rule.as_deref() {
4558 snapshot_condition_exists(next, &path[1..])
4559 } else if rule.next_rule_name.as_deref() == Some(&*rule.name) {
4560 snapshot_condition_exists(rule, &path[1..])
4561 } else {
4562 false
4563 }
4564 } else {
4565 resolve_snapshot_path(rule, path).is_some()
4566 }
4567}
4568
4569fn resolve_snapshot_path(rule: &RuleSnapshot, path: &[String]) -> Option<Value> {
4570 let root = path.first()?.as_str();
4571 let rest = &path[1..];
4572 match root {
4573 "n" if rest.len() == 1 => Some(Value::Number(*rule.n.get(&rest[0]).unwrap_or(&0) as f64)),
4574 "u" => map_path(&rule.u, rest),
4575 "k" => map_path(&rule.k, rest),
4576 "d" if rest.is_empty() => Some(Value::Number(rule.d as f64)),
4577 "i" if rest.is_empty() => Some(Value::Number(rule.i as f64)),
4578 "name" if rest.is_empty() => Some(Value::String(rule.name.to_string())),
4579 "state" if rest.is_empty() => Some(Value::String(
4580 match rule.state {
4581 RuleState::Open => "o",
4582 RuleState::Close => "c",
4583 }
4584 .into(),
4585 )),
4586 "node" => value_path(rule.node.borrow().clone(), rest),
4587 "need" if rest.is_empty() => Some(Value::Number(rule.need as f64)),
4588 "oN" if rest.is_empty() => Some(Value::Number(rule.o.len() as f64)),
4589 "cN" if rest.is_empty() => Some(Value::Number(rule.c.len() as f64)),
4590 "o" => token_list_path(&rule.o, rest),
4591 "c" => token_list_path(&rule.c, rest),
4592 "o0" => token_path(rule.o.first(), rest),
4593 "o1" => token_path(rule.o.get(1), rest),
4594 "c0" => token_path(rule.c.first(), rest),
4595 "c1" => token_path(rule.c.get(1), rest),
4596 "parent" => resolve_snapshot_path(rule.parent_rule.as_deref()?, rest),
4597 "child" => resolve_snapshot_path(rule.child_rule.as_deref()?, rest),
4598 "prev" => resolve_snapshot_path(rule.prev_rule.as_deref()?, rest),
4599 "next" => {
4600 if let Some(next) = rule.next_rule.as_deref() {
4601 resolve_snapshot_path(next, rest)
4602 } else if rule.next_rule_name.as_deref() == Some(&*rule.name) {
4603 resolve_snapshot_path(rule, rest)
4604 } else {
4605 None
4606 }
4607 }
4608 "spec" if rest == ["name"] => Some(Value::String(rule.name.to_string())),
4609 _ => None,
4610 }
4611}
4612
4613fn map_path(map: &HashMap<String, Value>, path: &[String]) -> Option<Value> {
4614 let (name, rest) = path.split_first()?;
4615 value_path(map.get(name)?.clone(), rest)
4616}
4617
4618fn value_path(mut value: Value, path: &[String]) -> Option<Value> {
4619 for part in path {
4620 value = match value {
4621 Value::Object(map) => map.get(part)?.clone(),
4622 Value::Array(items) => items.get(part.parse::<usize>().ok()?)?.clone(),
4623 _ => return None,
4624 };
4625 }
4626 Some(value)
4627}
4628
4629fn token_list_path(tokens: &[Token], path: &[String]) -> Option<Value> {
4630 let (index, rest) = path.split_first()?;
4631 token_path(tokens.get(index.parse::<usize>().ok()?), rest)
4632}
4633
4634fn token_path(token: Option<&Token>, path: &[String]) -> Option<Value> {
4635 let token = token?;
4636 if path.is_empty() {
4637 let mut value = IndexMap::new();
4638 value.insert("tin".into(), Value::Number(token.tin as f64));
4639 value.insert("name".into(), Value::String(token.name.to_string()));
4640 value.insert("src".into(), Value::String(token.src.to_string()));
4641 value.insert("val".into(), token.val.clone());
4642 value.insert("why".into(), Value::String(token.why.to_string()));
4643 return Some(Value::object(value));
4644 }
4645 let (field, rest) = path.split_first()?;
4646 let value = match field.as_str() {
4647 "tin" => Value::Number(token.tin as f64),
4648 "name" => Value::String(token.name.to_string()),
4649 "src" => Value::String(token.src.to_string()),
4650 "val" => token.val.clone(),
4651 "why" => Value::String(token.why.to_string()),
4652 _ => return None,
4653 };
4654 value_path(value, rest)
4655}
4656
4657#[cfg(test)]
4658mod tests {
4659 use super::*;
4660
4661 #[test]
4671 fn replacing_a_rule_replaces_the_tables_derived_from_it() {
4672 let mut parser = Parser::new(crate::Options::default());
4673
4674 let mut first = RuleSpec::new("val");
4675 first.bo.push("@enter".into());
4676 first.open.push(AltSpec {
4677 s: vec![vec![crate::TIN_NR]],
4678 a: vec!["@act".into()],
4679 ..Default::default()
4680 });
4681 parser.add_rule(first);
4682 let slot = parser
4683 .rules()
4684 .get_index_of("val")
4685 .expect("the rule was just installed");
4686 assert_eq!(parser.expected_tins[slot].at(true, 0), [crate::TIN_NR]);
4687 assert_eq!(&*parser.names[slot], "val");
4688 assert_eq!(parser.prepared[slot].before(true).len(), 1);
4689 assert_eq!(parser.prepared[slot].open[0].actions.len(), 1);
4690
4691 let mut second = RuleSpec::new("val");
4692 second.open.push(AltSpec {
4693 s: vec![vec![crate::TIN_ST]],
4694 ..Default::default()
4695 });
4696 parser.add_rule(second);
4697
4698 assert_eq!(parser.rules().len(), 1, "a replacement, not an addition");
4699 assert_eq!(
4700 parser.expected_tins[slot].at(true, 0),
4701 [crate::TIN_ST],
4702 "lookahead would still expect the replaced rule's tokens"
4703 );
4704 assert_eq!(parser.names.len(), 1, "one rule, one shared name");
4709 assert_eq!(parser.rules().get_index_of("val"), Some(slot));
4710 assert_eq!(&*parser.names[slot], "val");
4711 assert_eq!(parser.prepared.len(), 1);
4717 assert_eq!(&*parser.prepared[slot].name, "val");
4718 assert!(Arc::ptr_eq(
4719 &parser.prepared[slot].spec,
4720 &parser.rules()["val"]
4721 ));
4722 assert!(parser.prepared[slot].before(true).is_empty());
4727 assert!(parser.prepared[slot].open[0].actions.is_empty());
4728 assert!(!parser.prepared[slot].open[0].named);
4729 }
4730
4731 #[test]
4739 fn expected_match_tins_follows_the_rule_name_when_the_slot_goes_stale() {
4740 fn rule_named(name: &str, tin: Tin) -> RuleSpec {
4741 let mut spec = RuleSpec::new(name);
4742 spec.open.push(AltSpec {
4743 s: vec![vec![tin]],
4744 ..Default::default()
4745 });
4746 spec
4747 }
4748
4749 let mut options = crate::Options::default();
4750 let tin = options.register_token("#QQ");
4751 options.match_tokens.insert(
4752 "#QQ".into(),
4753 crate::options::MatchToken {
4754 name: "#QQ".into(),
4755 tin,
4756 matcher: crate::options::MatchTokenMatcher::Regex(regex::Regex::new("^q").unwrap()),
4757 eager: false,
4758 },
4759 );
4760 let mut parser = Parser::new(options);
4761 parser.add_rule(rule_named("val", crate::TIN_NR));
4762 parser.add_rule(rule_named("other", crate::TIN_ST));
4763
4764 let val_slot = parser.rules().get_index_of("val").expect("installed");
4765 let other_slot = parser.rules().get_index_of("other").expect("installed");
4766 assert_ne!(val_slot, other_slot);
4767
4768 let mut rule = Rule::new("val", Value::Undefined);
4771 rule.bind_spec(
4772 &parser.rules()["val"],
4773 parser.names[val_slot].clone(),
4774 val_slot,
4775 );
4776 assert_eq!(&*parser.expected_match_tins(&rule, 0), [crate::TIN_NR]);
4777
4778 rule.name = parser.names[other_slot].clone();
4783 assert_eq!(
4784 &*parser.expected_match_tins(&rule, 0),
4785 [crate::TIN_ST],
4786 "the rule is called `other` now, so `other`'s row answers"
4787 );
4788
4789 rule.name = parser.names[val_slot].clone();
4793 rule.spec = Arc::clone(&parser.rules()["other"]);
4794 assert_eq!(
4795 &*parser.expected_match_tins(&rule, 0),
4796 [crate::TIN_NR],
4797 "still called `val`, so still gated by `val`'s row"
4798 );
4799
4800 let ghost = Rule::new("ghost", Value::Undefined);
4803 assert_eq!(
4804 &*parser.expected_match_tins(&ghost, 0),
4805 &[] as &[Tin],
4806 "an uninstalled name has no row, not another rule's"
4807 );
4808 }
4809
4810 #[test]
4818 fn expected_match_tins_is_empty_until_a_match_token_exists() {
4819 fn val_rule() -> RuleSpec {
4820 let mut spec = RuleSpec::new("val");
4821 spec.open.push(AltSpec {
4822 s: vec![vec![crate::TIN_NR]],
4823 ..Default::default()
4824 });
4825 spec
4826 }
4827 let rule = Rule::new("val", Value::Undefined);
4828
4829 let mut without = Parser::new(crate::Options::default());
4830 without.add_rule(val_rule());
4831 assert!(without.options.match_tokens.is_empty());
4832 assert_eq!(without.expected_tins[0].at(true, 0), [crate::TIN_NR]);
4833 assert_eq!(
4834 &*without.expected_match_tins(&rule, 0),
4835 &[] as &[Tin],
4836 "no custom matcher: nothing to gate, so nothing to look up"
4837 );
4838
4839 let mut options = crate::Options::default();
4840 let tin = options.register_token("#QQ");
4841 options.match_tokens.insert(
4842 "#QQ".into(),
4843 crate::options::MatchToken {
4844 name: "#QQ".into(),
4845 tin,
4846 matcher: crate::options::MatchTokenMatcher::Regex(regex::Regex::new("^q").unwrap()),
4847 eager: false,
4848 },
4849 );
4850 let mut with = Parser::new(options);
4851 with.add_rule(val_rule());
4852 assert_eq!(
4853 &*with.expected_match_tins(&rule, 0),
4854 [crate::TIN_NR],
4855 "a custom matcher is present, so the slot's tins gate it"
4856 );
4857 assert_eq!(
4858 &*with.expected_match_tins(&rule, 1),
4859 &[] as &[Tin],
4860 "a slot the rule never fills expects nothing"
4861 );
4862 }
4863}