1use crate::options::{
10 CommentDef, ConfigModifier, FixedToken, LexCheck, LexMatcher, MatchToken, MatchTokenMatcher,
11 MatchValue, TextModifier, ValueDef,
12};
13use crate::{
14 Action, ActionBinding, AltActionBinding, AltSpec, ContextAction, LexSubscriber, Options,
15 Plugin, PluginError, RuleDoneSubscriber, RuleSpec, RuleSubscriber, Tabnas, TokenSubscriber,
16 Value,
17};
18use indexmap::IndexMap;
19use std::collections::{BTreeSet, HashMap};
20use std::fmt;
21use std::sync::Arc;
22
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct MergeError(pub String);
25
26impl fmt::Display for MergeError {
27 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
28 formatter.write_str(&self.0)
29 }
30}
31
32impl std::error::Error for MergeError {}
33
34fn conflict(path: &str) -> MergeError {
35 MergeError(format!("merge: conflicting option values at {path}"))
36}
37
38fn pick<T: Clone>(
39 left: &T,
40 right: &T,
41 default: &T,
42 path: &str,
43 equal: &dyn Fn(&T, &T) -> bool,
44) -> Result<T, MergeError> {
45 if equal(left, right) {
46 Ok(left.clone())
47 } else if equal(left, default) {
48 Ok(right.clone())
49 } else if equal(right, default) {
50 Ok(left.clone())
51 } else {
52 Err(conflict(path))
53 }
54}
55
56fn pick_without_default<T: Clone>(
57 left: &T,
58 right: &T,
59 path: &str,
60 equal: &dyn Fn(&T, &T) -> bool,
61) -> Result<T, MergeError> {
62 equal(left, right)
63 .then(|| left.clone())
64 .ok_or_else(|| conflict(path))
65}
66
67fn eq_value(left: &Value, right: &Value) -> bool {
68 left.deep_equal(right)
69}
70
71fn eq_f64(left: &f64, right: &f64) -> bool {
72 (left.is_nan() && right.is_nan()) || left.to_bits() == right.to_bits()
73}
74
75fn eq_option_arc<T: ?Sized>(left: &Option<Arc<T>>, right: &Option<Arc<T>>) -> bool {
76 match (left, right) {
77 (None, None) => true,
78 (Some(left), Some(right)) => Arc::ptr_eq(left, right),
79 _ => false,
80 }
81}
82
83fn eq_arc_vec<T: ?Sized>(left: &[Arc<T>], right: &[Arc<T>]) -> bool {
84 left.len() == right.len()
85 && left
86 .iter()
87 .zip(right)
88 .all(|(left, right)| Arc::ptr_eq(left, right))
89}
90
91fn eq_text_modifier_vec(left: &[TextModifier], right: &[TextModifier]) -> bool {
92 left.len() == right.len()
93 && left
94 .iter()
95 .zip(right)
96 .all(|(left, right)| left.same_callback(right))
97}
98
99fn eq_prepare_vec(left: &[crate::ParsePrepare], right: &[crate::ParsePrepare]) -> bool {
100 left.len() == right.len()
101 && left
102 .iter()
103 .zip(right)
104 .all(|(left, right)| left.same_callback(right))
105}
106
107fn eq_option_check(left: &Option<LexCheck>, right: &Option<LexCheck>) -> bool {
108 match (left, right) {
109 (None, None) => true,
110 (Some(left), Some(right)) => left.same_callback(right),
111 _ => false,
112 }
113}
114
115fn ordered_keys<T>(left: &IndexMap<String, T>, right: &IndexMap<String, T>) -> Vec<String> {
116 let mut keys = left.keys().cloned().collect::<Vec<_>>();
117 keys.extend(right.keys().filter(|key| !left.contains_key(*key)).cloned());
118 keys
119}
120
121fn sorted_hash_keys<T>(left: &HashMap<String, T>, right: &HashMap<String, T>) -> Vec<String> {
122 let mut keys = left
123 .keys()
124 .chain(right.keys())
125 .cloned()
126 .collect::<BTreeSet<_>>()
127 .into_iter()
128 .collect::<Vec<_>>();
129 keys.shrink_to_fit();
130 keys
131}
132
133fn merge_index_map<T: Clone>(
134 left: &IndexMap<String, T>,
135 right: &IndexMap<String, T>,
136 default: &IndexMap<String, T>,
137 prefix: &str,
138 equal: &dyn Fn(&T, &T) -> bool,
139) -> Result<IndexMap<String, T>, MergeError> {
140 let mut out = IndexMap::new();
141 for key in ordered_keys(left, right) {
142 let value = match (left.get(&key), right.get(&key), default.get(&key)) {
143 (Some(left), Some(right), Some(default)) => Some(pick(
144 left,
145 right,
146 default,
147 &format!("{prefix}.{key}"),
148 equal,
149 )?),
150 (Some(left), Some(right), None) => Some(pick_without_default(
151 left,
152 right,
153 &format!("{prefix}.{key}"),
154 equal,
155 )?),
156 (Some(value), None, Some(default)) | (None, Some(value), Some(default)) => {
160 if equal(value, default) {
161 None
162 } else {
163 return Err(conflict(&format!("{prefix}.{key}")));
164 }
165 }
166 (Some(value), None, None) | (None, Some(value), None) => Some(value.clone()),
167 (None, None, _) => unreachable!(),
168 };
169 if let Some(value) = value {
170 out.insert(key, value);
171 }
172 }
173 Ok(out)
174}
175
176fn merge_hash_map<T: Clone>(
177 left: &HashMap<String, T>,
178 right: &HashMap<String, T>,
179 default: &HashMap<String, T>,
180 prefix: &str,
181 equal: &dyn Fn(&T, &T) -> bool,
182) -> Result<HashMap<String, T>, MergeError> {
183 let mut out = HashMap::new();
184 for key in sorted_hash_keys(left, right) {
185 let value = match (left.get(&key), right.get(&key), default.get(&key)) {
186 (Some(left), Some(right), Some(default)) => Some(pick(
187 left,
188 right,
189 default,
190 &format!("{prefix}.{key}"),
191 equal,
192 )?),
193 (Some(left), Some(right), None) => Some(pick_without_default(
194 left,
195 right,
196 &format!("{prefix}.{key}"),
197 equal,
198 )?),
199 (Some(value), None, Some(default)) | (None, Some(value), Some(default)) => {
200 if equal(value, default) {
201 None
202 } else {
203 return Err(conflict(&format!("{prefix}.{key}")));
204 }
205 }
206 (Some(value), None, None) | (None, Some(value), None) => Some(value.clone()),
207 (None, None, _) => unreachable!(),
208 };
209 if let Some(value) = value {
210 out.insert(key, value);
211 }
212 }
213 Ok(out)
214}
215
216fn merge_char_map(
217 left: &HashMap<char, String>,
218 right: &HashMap<char, String>,
219 default: &HashMap<char, String>,
220 prefix: &str,
221) -> Result<HashMap<char, String>, MergeError> {
222 let keys = left
223 .keys()
224 .chain(right.keys())
225 .copied()
226 .collect::<BTreeSet<_>>();
227 let mut out = HashMap::new();
228 for key in keys {
229 let path = format!("{prefix}.{key}");
230 let value = match (left.get(&key), right.get(&key), default.get(&key)) {
231 (Some(left), Some(right), Some(default)) => {
232 Some(pick(left, right, default, &path, &PartialEq::eq)?)
233 }
234 (Some(left), Some(right), None) => {
235 Some(pick_without_default(left, right, &path, &PartialEq::eq)?)
236 }
237 (Some(value), None, Some(default)) | (None, Some(value), Some(default)) => {
238 if value == default {
239 None
240 } else {
241 return Err(conflict(&path));
242 }
243 }
244 (Some(value), None, None) | (None, Some(value), None) => Some(value.clone()),
245 (None, None, _) => unreachable!(),
246 };
247 if let Some(value) = value {
248 out.insert(key, value);
249 }
250 }
251 Ok(out)
252}
253
254fn eq_matcher(left: &MatchTokenMatcher, right: &MatchTokenMatcher) -> bool {
255 match (left, right) {
256 (MatchTokenMatcher::Regex(left), MatchTokenMatcher::Regex(right)) => {
257 left.as_str() == right.as_str()
258 }
259 (MatchTokenMatcher::Callback(left), MatchTokenMatcher::Callback(right)) => {
260 Arc::ptr_eq(left, right)
261 }
262 _ => false,
263 }
264}
265
266fn eq_fixed_token(left: &FixedToken, right: &FixedToken) -> bool {
267 left.name == right.name && left.source == right.source
268}
269
270fn eq_match_token(left: &MatchToken, right: &MatchToken) -> bool {
271 left.name == right.name
272 && left.eager == right.eager
273 && eq_matcher(&left.matcher, &right.matcher)
274}
275
276fn eq_match_value(left: &MatchValue, right: &MatchValue) -> bool {
277 left.name == right.name
278 && eq_matcher(&left.matcher, &right.matcher)
279 && match (&left.val, &right.val) {
280 (None, None) => true,
281 (Some(left), Some(right)) => left.deep_equal(right),
282 _ => false,
283 }
284 && eq_option_arc(&left.transform, &right.transform)
285}
286
287fn eq_value_def(left: &ValueDef, right: &ValueDef) -> bool {
288 match (&left.val, &right.val) {
289 (None, None) => {}
290 (Some(left), Some(right)) if left.deep_equal(right) => {}
291 _ => return false,
292 }
293 match (&left.matcher, &right.matcher) {
294 (None, None) => {}
295 (Some(left), Some(right)) if left.as_str() == right.as_str() => {}
296 _ => return false,
297 }
298 left.consume == right.consume && eq_option_arc(&left.transform, &right.transform)
299}
300
301fn eq_comment_def(left: &CommentDef, right: &CommentDef) -> bool {
302 left.line == right.line
303 && left.start == right.start
304 && left.end == right.end
305 && left.lex == right.lex
306 && left.suffixes == right.suffixes
307 && left.eat_line == right.eat_line
308 && match (&left.suffix_matcher, &right.suffix_matcher) {
309 (None, None) => true,
310 (Some(left), Some(right)) => left.same_callback(right),
311 _ => false,
312 }
313}
314
315fn eq_lex_matcher(left: &LexMatcher, right: &LexMatcher) -> bool {
316 left.name == right.name
317 && eq_f64(&left.order, &right.order)
318 && eq_option_arc(&left.matcher, &right.matcher)
319 && eq_option_arc(&left.imperative, &right.imperative)
320 && eq_option_arc(&left.factory, &right.factory)
321}
322
323fn merge_options(left: &Options, right: &Options) -> Result<Options, MergeError> {
324 let default = Options::default();
325 let mut out = default.clone();
326
327 out.safe.key = pick(
328 &left.safe.key,
329 &right.safe.key,
330 &default.safe.key,
331 "safe.key",
332 &PartialEq::eq,
333 )?;
334
335 out.fixed.lex = pick(
336 &left.fixed.lex,
337 &right.fixed.lex,
338 &default.fixed.lex,
339 "fixed.lex",
340 &PartialEq::eq,
341 )?;
342 out.fixed.check = pick(
343 &left.fixed.check,
344 &right.fixed.check,
345 &default.fixed.check,
346 "fixed.check",
347 &eq_option_check,
348 )?;
349 out.fixed.tokens = merge_index_map(
350 &left.fixed.tokens,
351 &right.fixed.tokens,
352 &default.fixed.tokens,
353 "fixed.token",
354 &eq_fixed_token,
355 )?;
356
357 out.space.lex = pick(
358 &left.space.lex,
359 &right.space.lex,
360 &default.space.lex,
361 "space.lex",
362 &PartialEq::eq,
363 )?;
364 out.space.chars = pick(
365 &left.space.chars,
366 &right.space.chars,
367 &default.space.chars,
368 "space.chars",
369 &PartialEq::eq,
370 )?;
371 out.space.check = pick(
372 &left.space.check,
373 &right.space.check,
374 &default.space.check,
375 "space.check",
376 &eq_option_check,
377 )?;
378
379 out.text.lex = pick(
380 &left.text.lex,
381 &right.text.lex,
382 &default.text.lex,
383 "text.lex",
384 &PartialEq::eq,
385 )?;
386 out.text.modify = pick(
387 &left.text.modify,
388 &right.text.modify,
389 &default.text.modify,
390 "text.modify",
391 &|left, right| eq_text_modifier_vec(left, right),
392 )?;
393 out.text.check = pick(
394 &left.text.check,
395 &right.text.check,
396 &default.text.check,
397 "text.check",
398 &eq_option_check,
399 )?;
400
401 out.number.lex = pick(
402 &left.number.lex,
403 &right.number.lex,
404 &default.number.lex,
405 "number.lex",
406 &PartialEq::eq,
407 )?;
408 out.number.hex = pick(
409 &left.number.hex,
410 &right.number.hex,
411 &default.number.hex,
412 "number.hex",
413 &PartialEq::eq,
414 )?;
415 out.number.oct = pick(
416 &left.number.oct,
417 &right.number.oct,
418 &default.number.oct,
419 "number.oct",
420 &PartialEq::eq,
421 )?;
422 out.number.bin = pick(
423 &left.number.bin,
424 &right.number.bin,
425 &default.number.bin,
426 "number.bin",
427 &PartialEq::eq,
428 )?;
429 out.number.sep = pick(
430 &left.number.sep,
431 &right.number.sep,
432 &default.number.sep,
433 "number.sep",
434 &PartialEq::eq,
435 )?;
436 out.number.exclude = pick(
437 &left.number.exclude,
438 &right.number.exclude,
439 &default.number.exclude,
440 "number.exclude",
441 &PartialEq::eq,
442 )?;
443 out.number.check = pick(
444 &left.number.check,
445 &right.number.check,
446 &default.number.check,
447 "number.check",
448 &eq_option_check,
449 )?;
450
451 out.string.lex = pick(
452 &left.string.lex,
453 &right.string.lex,
454 &default.string.lex,
455 "string.lex",
456 &PartialEq::eq,
457 )?;
458 out.string.chars = pick(
459 &left.string.chars,
460 &right.string.chars,
461 &default.string.chars,
462 "string.chars",
463 &PartialEq::eq,
464 )?;
465 out.string.multi_chars = pick(
466 &left.string.multi_chars,
467 &right.string.multi_chars,
468 &default.string.multi_chars,
469 "string.multiChars",
470 &PartialEq::eq,
471 )?;
472 out.string.escape_char = pick(
473 &left.string.escape_char,
474 &right.string.escape_char,
475 &default.string.escape_char,
476 "string.escapeChar",
477 &PartialEq::eq,
478 )?;
479 out.string.escape = merge_char_map(
480 &left.string.escape,
481 &right.string.escape,
482 &default.string.escape,
483 "string.escape",
484 )?;
485 out.string.replace = merge_char_map(
486 &left.string.replace,
487 &right.string.replace,
488 &default.string.replace,
489 "string.replace",
490 )?;
491 out.string.allow_unknown = pick(
492 &left.string.allow_unknown,
493 &right.string.allow_unknown,
494 &default.string.allow_unknown,
495 "string.allowUnknown",
496 &PartialEq::eq,
497 )?;
498 out.string.escape_strict = pick(
499 &left.string.escape_strict,
500 &right.string.escape_strict,
501 &default.string.escape_strict,
502 "string.escapeStrict",
503 &PartialEq::eq,
504 )?;
505 out.string.allow_control = pick(
506 &left.string.allow_control,
507 &right.string.allow_control,
508 &default.string.allow_control,
509 "string.allowControl",
510 &PartialEq::eq,
511 )?;
512 out.string.abandon = pick(
513 &left.string.abandon,
514 &right.string.abandon,
515 &default.string.abandon,
516 "string.abandon",
517 &PartialEq::eq,
518 )?;
519 out.string.check = pick(
520 &left.string.check,
521 &right.string.check,
522 &default.string.check,
523 "string.check",
524 &eq_option_check,
525 )?;
526
527 out.line.lex = pick(
528 &left.line.lex,
529 &right.line.lex,
530 &default.line.lex,
531 "line.lex",
532 &PartialEq::eq,
533 )?;
534 out.line.chars = pick(
535 &left.line.chars,
536 &right.line.chars,
537 &default.line.chars,
538 "line.chars",
539 &PartialEq::eq,
540 )?;
541 out.line.row_chars = pick(
542 &left.line.row_chars,
543 &right.line.row_chars,
544 &default.line.row_chars,
545 "line.rowChars",
546 &PartialEq::eq,
547 )?;
548 out.line.single = pick(
549 &left.line.single,
550 &right.line.single,
551 &default.line.single,
552 "line.single",
553 &PartialEq::eq,
554 )?;
555 out.line.fixed = pick(
556 &left.line.fixed,
557 &right.line.fixed,
558 &default.line.fixed,
559 "line.fixed",
560 &PartialEq::eq,
561 )?;
562 out.line.check = pick(
563 &left.line.check,
564 &right.line.check,
565 &default.line.check,
566 "line.check",
567 &eq_option_check,
568 )?;
569
570 out.comment.lex = pick(
571 &left.comment.lex,
572 &right.comment.lex,
573 &default.comment.lex,
574 "comment.lex",
575 &PartialEq::eq,
576 )?;
577 out.comment.check = pick(
578 &left.comment.check,
579 &right.comment.check,
580 &default.comment.check,
581 "comment.check",
582 &eq_option_check,
583 )?;
584 out.comment.definitions = merge_index_map(
585 &left.comment.definitions,
586 &right.comment.definitions,
587 &default.comment.definitions,
588 "comment.def",
589 &eq_comment_def,
590 )?;
591
592 out.value.lex = pick(
593 &left.value.lex,
594 &right.value.lex,
595 &default.value.lex,
596 "value.lex",
597 &PartialEq::eq,
598 )?;
599 out.value.definitions = merge_index_map(
600 &left.value.definitions,
601 &right.value.definitions,
602 &default.value.definitions,
603 "value.def",
604 &eq_value_def,
605 )?;
606 out.ender = pick(
607 &left.ender,
608 &right.ender,
609 &default.ender,
610 "ender",
611 &PartialEq::eq,
612 )?;
613
614 out.map.extend = pick(
615 &left.map.extend,
616 &right.map.extend,
617 &default.map.extend,
618 "map.extend",
619 &PartialEq::eq,
620 )?;
621 out.map.merge = pick(
622 &left.map.merge,
623 &right.map.merge,
624 &default.map.merge,
625 "map.merge",
626 &eq_option_arc,
627 )?;
628 out.map.child = pick(
629 &left.map.child,
630 &right.map.child,
631 &default.map.child,
632 "map.child",
633 &PartialEq::eq,
634 )?;
635 out.map.ordered = pick(
636 &left.map.ordered,
637 &right.map.ordered,
638 &default.map.ordered,
639 "map.ordered",
640 &PartialEq::eq,
641 )?;
642
643 out.list.property = pick(
644 &left.list.property,
645 &right.list.property,
646 &default.list.property,
647 "list.property",
648 &PartialEq::eq,
649 )?;
650 out.list.pair = pick(
651 &left.list.pair,
652 &right.list.pair,
653 &default.list.pair,
654 "list.pair",
655 &PartialEq::eq,
656 )?;
657 out.list.child = pick(
658 &left.list.child,
659 &right.list.child,
660 &default.list.child,
661 "list.child",
662 &PartialEq::eq,
663 )?;
664
665 out.info.map = pick(
666 &left.info.map,
667 &right.info.map,
668 &default.info.map,
669 "info.map",
670 &PartialEq::eq,
671 )?;
672 out.info.list = pick(
673 &left.info.list,
674 &right.info.list,
675 &default.info.list,
676 "info.list",
677 &PartialEq::eq,
678 )?;
679 out.info.text = pick(
680 &left.info.text,
681 &right.info.text,
682 &default.info.text,
683 "info.text",
684 &PartialEq::eq,
685 )?;
686 out.info.marker = pick(
687 &left.info.marker,
688 &right.info.marker,
689 &default.info.marker,
690 "info.marker",
691 &PartialEq::eq,
692 )?;
693
694 out.lex.empty = pick(
695 &left.lex.empty,
696 &right.lex.empty,
697 &default.lex.empty,
698 "lex.empty",
699 &PartialEq::eq,
700 )?;
701 out.lex.empty_result = pick(
702 &left.lex.empty_result,
703 &right.lex.empty_result,
704 &default.lex.empty_result,
705 "lex.emptyResult",
706 &eq_value,
707 )?;
708 out.lex.relex = pick(
709 &left.lex.relex,
710 &right.lex.relex,
711 &default.lex.relex,
712 "lex.relex",
713 &PartialEq::eq,
714 )?;
715 out.lex.matchers = merge_index_map(
716 &left.lex.matchers,
717 &right.lex.matchers,
718 &default.lex.matchers,
719 "lex.match",
720 &eq_lex_matcher,
721 )?;
722 out.lex.matchers.sort_by(|name_a, left, name_b, right| {
723 left.order
724 .total_cmp(&right.order)
725 .then_with(|| name_a.cmp(name_b))
726 });
727
728 out.rewind.history = pick(
729 &left.rewind.history,
730 &right.rewind.history,
731 &default.rewind.history,
732 "rewind.history",
733 &PartialEq::eq,
734 )?;
735 out.rule.finish = pick(
736 &left.rule.finish,
737 &right.rule.finish,
738 &default.rule.finish,
739 "rule.finish",
740 &PartialEq::eq,
741 )?;
742 out.rule.history = pick(
746 &crate::options::effective_rule_history(left.rule.history),
747 &crate::options::effective_rule_history(right.rule.history),
748 &default.rule.history,
749 "rule.history",
750 &PartialEq::eq,
751 )?;
752 out.rule.maxmul = pick(
753 &left.rule.maxmul,
754 &right.rule.maxmul,
755 &default.rule.maxmul,
756 "rule.maxmul",
757 &PartialEq::eq,
758 )?;
759 out.rule.include = pick(
760 &left.rule.include,
761 &right.rule.include,
762 &default.rule.include,
763 "rule.include",
764 &PartialEq::eq,
765 )?;
766 out.rule.exclude = pick(
767 &left.rule.exclude,
768 &right.rule.exclude,
769 &default.rule.exclude,
770 "rule.exclude",
771 &PartialEq::eq,
772 )?;
773 out.rule.start = pick(
774 &left.rule.start,
775 &right.rule.start,
776 &default.rule.start,
777 "rule.start",
778 &PartialEq::eq,
779 )?;
780 out.result.fail = pick(
781 &left.result.fail,
782 &right.result.fail,
783 &default.result.fail,
784 "result.fail",
785 &|left, right| {
786 left.len() == right.len()
787 && left
788 .iter()
789 .zip(right)
790 .all(|(left, right)| left.deep_equal(right))
791 },
792 )?;
793 out.plugin = merge_index_map(
794 &left.plugin,
795 &right.plugin,
796 &default.plugin,
797 "plugin",
798 &Value::deep_equal,
799 )?;
800
801 out.parse.prepare = pick(
802 &left.parse.prepare,
803 &right.parse.prepare,
804 &default.parse.prepare,
805 "parse.prepare",
806 &|left, right| eq_prepare_vec(left, right),
807 )?;
808 out.parse.named_prepare = merge_index_map(
809 &left.parse.named_prepare,
810 &right.parse.named_prepare,
811 &default.parse.named_prepare,
812 "parse.prepare",
813 &crate::ParsePrepare::same_callback,
814 )?;
815 out.parse.budget.check_every_n = pick(
816 &left.parse.budget.check_every_n,
817 &right.parse.budget.check_every_n,
818 &default.parse.budget.check_every_n,
819 "parse.budget.checkEveryN",
820 &PartialEq::eq,
821 )?;
822 out.parse.budget.on_check = pick(
823 &left.parse.budget.on_check,
824 &right.parse.budget.on_check,
825 &default.parse.budget.on_check,
826 "parse.budget.onCheck",
827 &eq_option_arc,
828 )?;
829 out.parse.recover.enabled = pick(
830 &left.parse.recover.enabled,
831 &right.parse.recover.enabled,
832 &default.parse.recover.enabled,
833 "parse.recover.enabled",
834 &PartialEq::eq,
835 )?;
836 out.parse.recover.sync_groups = pick(
837 &left.parse.recover.sync_groups,
838 &right.parse.recover.sync_groups,
839 &default.parse.recover.sync_groups,
840 "parse.recover.syncGroups",
841 &PartialEq::eq,
842 )?;
843 out.parse.recover.sync_tokens = pick(
844 &left.parse.recover.sync_tokens,
845 &right.parse.recover.sync_tokens,
846 &default.parse.recover.sync_tokens,
847 "parse.recover.syncTokens",
848 &PartialEq::eq,
849 )?;
850 out.parse.recover.pop_until_valid = pick(
851 &left.parse.recover.pop_until_valid,
852 &right.parse.recover.pop_until_valid,
853 &default.parse.recover.pop_until_valid,
854 "parse.recover.popUntilValid",
855 &PartialEq::eq,
856 )?;
857 out.parse.recover.max_skip = pick(
858 &left.parse.recover.max_skip,
859 &right.parse.recover.max_skip,
860 &default.parse.recover.max_skip,
861 "parse.recover.maxSkip",
862 &PartialEq::eq,
863 )?;
864 out.parse.recover.max_recoveries = pick(
865 &left.parse.recover.max_recoveries,
866 &right.parse.recover.max_recoveries,
867 &default.parse.recover.max_recoveries,
868 "parse.recover.maxRecoveries",
869 &PartialEq::eq,
870 )?;
871 out.parse.recover.suppress = pick(
872 &left.parse.recover.suppress,
873 &right.parse.recover.suppress,
874 &default.parse.recover.suppress,
875 "parse.recover.suppress",
876 &PartialEq::eq,
877 )?;
878 out.parser.start = pick(
879 &left.parser.start,
880 &right.parser.start,
881 &default.parser.start,
882 "parser.start",
883 &eq_option_arc,
884 )?;
885 out.parser.start_with_instance = pick(
886 &left.parser.start_with_instance,
887 &right.parser.start_with_instance,
888 &default.parser.start_with_instance,
889 "parser.start",
890 &eq_option_arc,
891 )?;
892 out.parser.start_with_context = pick(
893 &left.parser.start_with_context,
894 &right.parser.start_with_context,
895 &default.parser.start_with_context,
896 "parser.start",
897 &eq_option_arc,
898 )?;
899 out.debug.maxlen = pick(
900 &left.debug.maxlen,
901 &right.debug.maxlen,
902 &default.debug.maxlen,
903 "debug.maxlen",
904 &PartialEq::eq,
905 )?;
906 out.debug.print.config = pick(
907 &left.debug.print.config,
908 &right.debug.print.config,
909 &default.debug.print.config,
910 "debug.print.config",
911 &PartialEq::eq,
912 )?;
913 out.debug.print.source = pick(
914 &left.debug.print.source,
915 &right.debug.print.source,
916 &default.debug.print.source,
917 "debug.print.src",
918 &eq_option_arc,
919 )?;
920 out.debug.output = pick(
921 &left.debug.output,
922 &right.debug.output,
923 &default.debug.output,
924 "debug.get_console",
925 &eq_option_arc,
926 )?;
927
928 out.match_lex = pick(
929 &left.match_lex,
930 &right.match_lex,
931 &default.match_lex,
932 "match.lex",
933 &PartialEq::eq,
934 )?;
935 out.match_check = pick(
936 &left.match_check,
937 &right.match_check,
938 &default.match_check,
939 "match.check",
940 &eq_option_check,
941 )?;
942 out.match_tokens = merge_index_map(
943 &left.match_tokens,
944 &right.match_tokens,
945 &default.match_tokens,
946 "match.token",
947 &eq_match_token,
948 )?;
949 out.match_values = merge_index_map(
950 &left.match_values,
951 &right.match_values,
952 &default.match_values,
953 "match.value",
954 &eq_match_value,
955 )?;
956 out.error = merge_hash_map(
957 &left.error,
958 &right.error,
959 &default.error,
960 "error",
961 &PartialEq::eq,
962 )?;
963 out.hint = merge_hash_map(
964 &left.hint,
965 &right.hint,
966 &default.hint,
967 "hint",
968 &PartialEq::eq,
969 )?;
970
971 out.errmsg.name = pick(
972 &left.errmsg.name,
973 &right.errmsg.name,
974 &default.errmsg.name,
975 "errmsg.name",
976 &PartialEq::eq,
977 )?;
978 out.errmsg.suffix = pick(
979 &left.errmsg.suffix,
980 &right.errmsg.suffix,
981 &default.errmsg.suffix,
982 "errmsg.suffix",
983 &PartialEq::eq,
984 )?;
985 out.errmsg.link = pick(
986 &left.errmsg.link,
987 &right.errmsg.link,
988 &default.errmsg.link,
989 "errmsg.link",
990 &PartialEq::eq,
991 )?;
992 out.color.active = pick(
993 &left.color.active,
994 &right.color.active,
995 &default.color.active,
996 "color.active",
997 &PartialEq::eq,
998 )?;
999 out.color.reset = pick(
1000 &left.color.reset,
1001 &right.color.reset,
1002 &default.color.reset,
1003 "color.reset",
1004 &PartialEq::eq,
1005 )?;
1006 out.color.hi = pick(
1007 &left.color.hi,
1008 &right.color.hi,
1009 &default.color.hi,
1010 "color.hi",
1011 &PartialEq::eq,
1012 )?;
1013 out.color.lo = pick(
1014 &left.color.lo,
1015 &right.color.lo,
1016 &default.color.lo,
1017 "color.lo",
1018 &PartialEq::eq,
1019 )?;
1020 out.color.line = pick(
1021 &left.color.line,
1022 &right.color.line,
1023 &default.color.line,
1024 "color.line",
1025 &PartialEq::eq,
1026 )?;
1027 out.config_modify = merge_index_map(
1028 &left.config_modify,
1029 &right.config_modify,
1030 &default.config_modify,
1031 "config.modify",
1032 &ConfigModifier::same_callback,
1033 )?;
1034
1035 merge_token_space(left, right, &default, &mut out)?;
1036 Ok(out)
1037}
1038
1039fn token_set_names(options: &Options) -> HashMap<String, Vec<String>> {
1040 options
1041 .token_set
1042 .iter()
1043 .map(|(name, members)| {
1044 (
1045 name.clone(),
1046 members.iter().map(|tin| options.token_name(*tin)).collect(),
1047 )
1048 })
1049 .collect()
1050}
1051
1052fn merge_token_space(
1053 left: &Options,
1054 right: &Options,
1055 default: &Options,
1056 out: &mut Options,
1057) -> Result<(), MergeError> {
1058 let left_sets = token_set_names(left);
1059 let right_sets = token_set_names(right);
1060 let default_sets = token_set_names(default);
1061 let sets = merge_hash_map(
1062 &left_sets,
1063 &right_sets,
1064 &default_sets,
1065 "tokenSet",
1066 &PartialEq::eq,
1067 )?;
1068
1069 let mut plain_names = left
1070 .tokens
1071 .keys()
1072 .chain(right.tokens.keys())
1073 .cloned()
1074 .collect::<BTreeSet<_>>();
1075 for name in out.fixed.tokens.keys().chain(out.match_tokens.keys()) {
1076 plain_names.insert(name.clone());
1077 }
1078 for members in sets.values() {
1079 plain_names.extend(members.iter().cloned());
1080 }
1081
1082 let mut next_tin = crate::token::TIN_MAX;
1083 let mut tins = HashMap::new();
1084 for name in &plain_names {
1085 let tin = crate::token::name_to_tin(name).unwrap_or_else(|| {
1086 let allocated = next_tin;
1087 next_tin += 1;
1088 allocated
1089 });
1090 tins.insert(name.clone(), tin);
1091 }
1092
1093 for (name, token) in &mut out.fixed.tokens {
1094 token.tin = *tins.get(name).expect("fixed token was allocated");
1095 }
1096 for (name, token) in &mut out.match_tokens {
1097 token.tin = *tins.get(name).expect("match token was allocated");
1098 }
1099 out.tokens = plain_names
1100 .iter()
1101 .map(|name| (name.clone(), tins[name]))
1102 .collect();
1103 out.token_set = sets
1104 .into_iter()
1105 .map(|(name, members)| {
1106 let members = members.into_iter().map(|member| tins[&member]).collect();
1107 (name, members)
1108 })
1109 .collect();
1110
1111 let mut by_source: HashMap<&str, &str> = HashMap::new();
1112 for (name, token) in &out.fixed.tokens {
1113 if let Some(existing) = by_source.insert(&token.source, name) {
1114 if existing != name {
1115 return Err(MergeError(format!(
1116 "merge: fixed tokens {existing} and {name} both claim source {:?}",
1117 token.source
1118 )));
1119 }
1120 }
1121 }
1122 Ok(())
1123}
1124
1125#[derive(Clone, Debug, PartialEq, Eq)]
1126enum ActionIdentity {
1127 Simple(usize),
1128 Context(usize),
1129 Matched(usize),
1130 State(usize),
1131 Builtin(String),
1132 Missing(String),
1133}
1134
1135fn erased_ptr<T: ?Sized>(value: &Arc<T>) -> usize {
1136 Arc::as_ptr(value) as *const () as usize
1137}
1138
1139fn action_identity(tabnas: &Tabnas, name: &str) -> ActionIdentity {
1140 if name.contains('$') {
1141 ActionIdentity::Builtin(name.to_string())
1142 } else if let Some(action) = tabnas.actions.get(name) {
1143 ActionIdentity::Simple(erased_ptr(action))
1144 } else if let Some(action) = tabnas.context_actions.get(name) {
1145 ActionIdentity::Context(erased_ptr(action))
1146 } else if let Some(action) = tabnas.matched_actions.get(name) {
1147 ActionIdentity::Matched(erased_ptr(action))
1148 } else if let Some(action) = tabnas.state_actions.get(name) {
1149 ActionIdentity::State(erased_ptr(action))
1150 } else {
1151 ActionIdentity::Missing(name.to_string())
1152 }
1153}
1154
1155fn rename_ref(name: &str, tag: &str) -> String {
1156 if name.contains('$') {
1157 name.to_string()
1158 } else if let Some(name) = name.strip_prefix('@') {
1159 format!("@{tag}:{name}")
1160 } else {
1161 format!("{tag}:{name}")
1162 }
1163}
1164
1165#[derive(Clone)]
1166struct PortableAlt {
1167 alt: AltSpec,
1168 slots: Vec<Vec<String>>,
1169 keys: Vec<String>,
1170 declared: Vec<String>,
1175 complexity: [usize; 10],
1176 group: String,
1177 tag: String,
1178 action_identity: Vec<ActionIdentity>,
1179}
1180
1181fn portable_alt(tabnas: &Tabnas, alt: &AltSpec, tag: &str) -> PortableAlt {
1182 let slots = (0..alt.s.len())
1188 .map(|slot| {
1189 crate::parser::resolved_slot(alt, slot, &tabnas.options)
1190 .unwrap_or_else(|| alt.s[slot].clone())
1191 .iter()
1192 .map(|tin| tabnas.options.token_name(*tin))
1193 .collect::<Vec<_>>()
1194 })
1195 .collect::<Vec<_>>();
1196 let keys: Vec<String> = slots
1197 .iter()
1198 .map(|slot| {
1199 let mut names = slot.clone();
1200 names.sort();
1201 names.join(" ")
1202 })
1203 .collect();
1204 let mut cloned = alt.clone();
1205 let ordered_actions = crate::rule::resolved_alt_action_order(
1206 &alt.a,
1207 &alt.action_fns,
1208 &alt.matched_action_fns,
1209 &alt.action_order,
1210 );
1211 let action_identity = ordered_actions
1212 .iter()
1213 .map(|binding| match binding {
1214 AltActionBinding::Named(name) => action_identity(tabnas, name),
1215 AltActionBinding::Context(callback) => ActionIdentity::Context(erased_ptr(callback)),
1216 AltActionBinding::Matched(callback) => ActionIdentity::Matched(erased_ptr(callback)),
1217 })
1218 .collect();
1219 cloned.a = alt.a.iter().map(|name| rename_ref(name, tag)).collect();
1220 cloned.action_configs = alt
1221 .action_configs
1222 .iter()
1223 .map(|(name, value)| (rename_ref(name, tag), value.clone()))
1224 .collect();
1225 cloned.c_ref = alt.c_ref.as_ref().map(|name| rename_ref(name, tag));
1226 cloned.action_order = ordered_actions
1227 .into_iter()
1228 .map(|binding| match binding {
1229 AltActionBinding::Named(name) => AltActionBinding::Named(rename_ref(&name, tag)),
1230 AltActionBinding::Context(callback) => AltActionBinding::Context(callback),
1231 AltActionBinding::Matched(callback) => AltActionBinding::Matched(callback),
1232 })
1233 .collect();
1234 for (slot, names) in cloned.s_names.iter_mut().enumerate() {
1238 if alt.s.get(slot) != alt.s_bound.get(slot) {
1239 names.clear();
1240 }
1241 }
1242 let declared = keys
1243 .iter()
1244 .enumerate()
1245 .map(|(slot, key)| match cloned.s_names.get(slot) {
1246 Some(names) if !names.is_empty() => {
1247 let mut names = names.clone();
1248 names.sort();
1249 names.join(" ")
1250 }
1251 _ => key.clone(),
1252 })
1253 .collect();
1254 cloned.s.clear();
1255 PortableAlt {
1256 alt: cloned,
1257 slots,
1258 keys,
1259 declared,
1260 complexity: [
1261 usize::from(
1262 !alt.c.is_empty()
1263 || alt.c_fn.is_some()
1264 || alt.c_match.is_some()
1265 || alt.c_lex.is_some()
1266 || alt.c_lex_match.is_some(),
1267 ),
1268 usize::from(alt.e.is_some() || alt.e_match.is_some()),
1269 usize::from(alt.h.is_some() || alt.h_match.is_some()),
1270 usize::from(alt.b != 0 || alt.b_fn.is_some() || alt.b_match.is_some()),
1271 alt.n.len(),
1272 usize::from(
1273 !alt.a.is_empty()
1274 || !alt.action_fns.is_empty()
1275 || !alt.matched_action_fns.is_empty(),
1276 ),
1277 usize::from(!alt.u.is_empty()),
1278 usize::from(!alt.k.is_empty()),
1279 usize::from(alt.p.is_some() || alt.p_fn.is_some() || alt.p_match.is_some()),
1280 usize::from(alt.r.is_some() || alt.r_fn.is_some() || alt.r_match.is_some()),
1281 ],
1282 group: alt.g.clone(),
1283 tag: tag.to_string(),
1284 action_identity,
1285 }
1286}
1287
1288fn compare_alts(left: &PortableAlt, right: &PortableAlt) -> std::cmp::Ordering {
1289 for (left, right) in left.keys.iter().zip(&right.keys) {
1290 let ordering = left.cmp(right);
1291 if !ordering.is_eq() {
1292 return ordering;
1293 }
1294 }
1295 if left.keys.len() != right.keys.len() {
1296 return right.keys.len().cmp(&left.keys.len());
1297 }
1298 for (left, right) in left.complexity.iter().zip(right.complexity) {
1299 let ordering = right.cmp(left);
1300 if !ordering.is_eq() {
1301 return ordering;
1302 }
1303 }
1304 left.group
1305 .cmp(&right.group)
1306 .then_with(|| left.tag.cmp(&right.tag))
1307}
1308
1309fn eq_value_hash(left: &HashMap<String, Value>, right: &HashMap<String, Value>) -> bool {
1310 left.len() == right.len()
1311 && left
1312 .iter()
1313 .all(|(key, value)| right.get(key).is_some_and(|other| value.deep_equal(other)))
1314}
1315
1316fn eq_conditions(left: &[crate::Condition], right: &[crate::Condition]) -> bool {
1317 left.len() == right.len()
1318 && left.iter().zip(right).all(|(left, right)| {
1319 left.path == right.path && left.op == right.op && left.value.deep_equal(&right.value)
1320 })
1321}
1322
1323fn identical_alts(left: &PortableAlt, right: &PortableAlt) -> bool {
1324 let left_alt = &left.alt;
1325 let right_alt = &right.alt;
1326 left.keys == right.keys
1327 && left.declared == right.declared
1328 && left.group == right.group
1329 && left.action_identity == right.action_identity
1330 && eq_arc_vec(&left_alt.action_fns, &right_alt.action_fns)
1331 && eq_arc_vec(&left_alt.matched_action_fns, &right_alt.matched_action_fns)
1332 && eq_conditions(&left_alt.c, &right_alt.c)
1333 && eq_option_arc(&left_alt.c_fn, &right_alt.c_fn)
1334 && eq_option_arc(&left_alt.c_match, &right_alt.c_match)
1335 && eq_option_arc(&left_alt.c_lex, &right_alt.c_lex)
1336 && eq_option_arc(&left_alt.c_lex_match, &right_alt.c_lex_match)
1337 && eq_option_arc(&left_alt.h, &right_alt.h)
1338 && eq_option_arc(&left_alt.h_match, &right_alt.h_match)
1339 && eq_option_arc(&left_alt.e, &right_alt.e)
1340 && eq_option_arc(&left_alt.e_match, &right_alt.e_match)
1341 && left_alt.b == right_alt.b
1342 && eq_option_arc(&left_alt.b_fn, &right_alt.b_fn)
1343 && eq_option_arc(&left_alt.b_match, &right_alt.b_match)
1344 && left_alt.p == right_alt.p
1345 && eq_option_arc(&left_alt.p_fn, &right_alt.p_fn)
1346 && eq_option_arc(&left_alt.p_match, &right_alt.p_match)
1347 && left_alt.r == right_alt.r
1348 && eq_option_arc(&left_alt.r_fn, &right_alt.r_fn)
1349 && eq_option_arc(&left_alt.r_match, &right_alt.r_match)
1350 && left_alt.n == right_alt.n
1351 && eq_value_hash(&left_alt.u, &right_alt.u)
1352 && eq_value_hash(&left_alt.k, &right_alt.k)
1353 && eq_value_hash(&left_alt.action_configs, &right_alt.action_configs)
1354}
1355
1356fn interleave(left: Vec<PortableAlt>, right: Vec<PortableAlt>) -> Vec<PortableAlt> {
1357 let right = right
1358 .into_iter()
1359 .filter(|candidate| {
1360 !left
1361 .iter()
1362 .any(|existing| identical_alts(existing, candidate))
1363 })
1364 .collect::<Vec<_>>();
1365 let mut out = Vec::with_capacity(left.len() + right.len());
1366 let (mut left_i, mut right_i) = (0, 0);
1367 while left_i < left.len() && right_i < right.len() {
1368 if compare_alts(&left[left_i], &right[right_i]).is_le() {
1369 out.push(left[left_i].clone());
1370 left_i += 1;
1371 } else {
1372 out.push(right[right_i].clone());
1373 right_i += 1;
1374 }
1375 }
1376 out.extend(left[left_i..].iter().cloned());
1377 out.extend(right[right_i..].iter().cloned());
1378 out
1379}
1380
1381fn append_callbacks<T: ?Sized>(left: &[Arc<T>], right: &[Arc<T>]) -> Vec<Arc<T>> {
1382 left.iter().chain(right).cloned().collect()
1383}
1384
1385#[derive(Clone)]
1386struct MergedRule {
1387 name: String,
1388 open: Vec<PortableAlt>,
1389 close: Vec<PortableAlt>,
1390 bo: Vec<String>,
1391 ao: Vec<String>,
1392 bc: Vec<String>,
1393 ac: Vec<String>,
1394 bo_fns: Vec<ContextAction>,
1395 ao_fns: Vec<ContextAction>,
1396 bc_fns: Vec<ContextAction>,
1397 ac_fns: Vec<ContextAction>,
1398 bo_state_fns: Vec<crate::StateAction>,
1399 ao_state_fns: Vec<crate::StateAction>,
1400 bc_state_fns: Vec<crate::StateAction>,
1401 ac_state_fns: Vec<crate::StateAction>,
1402 bo_order: Vec<ActionBinding>,
1403 ao_order: Vec<ActionBinding>,
1404 bc_order: Vec<ActionBinding>,
1405 ac_order: Vec<ActionBinding>,
1406}
1407
1408impl MergedRule {
1409 fn materialize(&self, options: &mut Options) -> RuleSpec {
1410 fn alts(alts: &[PortableAlt], options: &mut Options) -> Vec<AltSpec> {
1411 alts.iter()
1412 .map(|portable| {
1413 let mut alt = portable.alt.clone();
1414 alt.s = portable
1415 .slots
1416 .iter()
1417 .map(|slot| {
1418 slot.iter()
1419 .map(|name| options.register_token(name))
1420 .collect()
1421 })
1422 .collect();
1423 alt.s_bound = alt.s.clone();
1428 alt
1429 })
1430 .collect()
1431 }
1432 RuleSpec {
1433 name: self.name.clone(),
1434 open: alts(&self.open, options),
1435 close: alts(&self.close, options),
1436 bo: self.bo.clone(),
1437 ao: self.ao.clone(),
1438 bc: self.bc.clone(),
1439 ac: self.ac.clone(),
1440 bo_fns: self.bo_fns.clone(),
1441 ao_fns: self.ao_fns.clone(),
1442 bc_fns: self.bc_fns.clone(),
1443 ac_fns: self.ac_fns.clone(),
1444 bo_state_fns: self.bo_state_fns.clone(),
1445 ao_state_fns: self.ao_state_fns.clone(),
1446 bc_state_fns: self.bc_state_fns.clone(),
1447 ac_state_fns: self.ac_state_fns.clone(),
1448 bo_order: self.bo_order.clone(),
1449 ao_order: self.ao_order.clone(),
1450 bc_order: self.bc_order.clone(),
1451 ac_order: self.ac_order.clone(),
1452 }
1453 }
1454}
1455
1456struct PhaseSource<'a> {
1457 tabnas: &'a Tabnas,
1458 named: &'a [String],
1459 callbacks: &'a [ContextAction],
1460 states: &'a [crate::StateAction],
1461 order: &'a [ActionBinding],
1462 tag: &'a str,
1463}
1464
1465fn merge_phase(
1466 left: PhaseSource<'_>,
1467 right: PhaseSource<'_>,
1468) -> (
1469 Vec<String>,
1470 Vec<ContextAction>,
1471 Vec<crate::StateAction>,
1472 Vec<ActionBinding>,
1473) {
1474 fn portable(
1475 tabnas: &Tabnas,
1476 named: &[String],
1477 callbacks: &[ContextAction],
1478 states: &[crate::StateAction],
1479 order: &[ActionBinding],
1480 tag: &str,
1481 ) -> Vec<(ActionBinding, ActionIdentity)> {
1482 crate::rule::resolved_action_order(named, callbacks, states, order)
1483 .into_iter()
1484 .map(|binding| match binding {
1485 ActionBinding::Named(name) => (
1486 ActionBinding::Named(rename_ref(&name, tag)),
1487 action_identity(tabnas, &name),
1488 ),
1489 ActionBinding::Callback(callback) => {
1490 let identity = ActionIdentity::Context(erased_ptr(&callback));
1491 (ActionBinding::Callback(callback), identity)
1492 }
1493 ActionBinding::State(callback) => {
1494 let identity = ActionIdentity::State(erased_ptr(&callback));
1495 (ActionBinding::State(callback), identity)
1496 }
1497 })
1498 .collect()
1499 }
1500
1501 let mut order = portable(
1502 left.tabnas,
1503 left.named,
1504 left.callbacks,
1505 left.states,
1506 left.order,
1507 left.tag,
1508 );
1509 for candidate in portable(
1510 right.tabnas,
1511 right.named,
1512 right.callbacks,
1513 right.states,
1514 right.order,
1515 right.tag,
1516 ) {
1517 if !order.iter().any(|(_, identity)| *identity == candidate.1) {
1518 order.push(candidate);
1519 }
1520 }
1521 let order = order
1522 .into_iter()
1523 .map(|(binding, _)| binding)
1524 .collect::<Vec<_>>();
1525 let named = order
1526 .iter()
1527 .filter_map(|binding| match binding {
1528 ActionBinding::Named(name) => Some(name.clone()),
1529 ActionBinding::Callback(_) => None,
1530 ActionBinding::State(_) => None,
1531 })
1532 .collect();
1533 let callbacks = order
1534 .iter()
1535 .filter_map(|binding| match binding {
1536 ActionBinding::Named(_) => None,
1537 ActionBinding::Callback(callback) => Some(callback.clone()),
1538 ActionBinding::State(_) => None,
1539 })
1540 .collect();
1541 let states = order
1542 .iter()
1543 .filter_map(|binding| match binding {
1544 ActionBinding::State(callback) => Some(callback.clone()),
1545 ActionBinding::Named(_) | ActionBinding::Callback(_) => None,
1546 })
1547 .collect();
1548 (named, callbacks, states, order)
1549}
1550
1551fn merged_rules(left: &Tabnas, left_tag: &str, right: &Tabnas, right_tag: &str) -> Vec<MergedRule> {
1552 let names = left
1553 .rules
1554 .keys()
1555 .chain(right.rules.keys())
1556 .cloned()
1557 .collect::<BTreeSet<_>>();
1558 names
1559 .into_iter()
1560 .map(|name| {
1561 let left_rule = left.rules.get(&name);
1562 let right_rule = right.rules.get(&name);
1563 let empty_named = Vec::new();
1564 let empty_callbacks = Vec::new();
1565 let empty_states = Vec::new();
1566 let empty_order = Vec::new();
1567 let left_open = left_rule
1568 .map(|rule| {
1569 rule.open
1570 .iter()
1571 .map(|alt| portable_alt(left, alt, left_tag))
1572 .collect()
1573 })
1574 .unwrap_or_default();
1575 let right_open = right_rule
1576 .map(|rule| {
1577 rule.open
1578 .iter()
1579 .map(|alt| portable_alt(right, alt, right_tag))
1580 .collect()
1581 })
1582 .unwrap_or_default();
1583 let left_close = left_rule
1584 .map(|rule| {
1585 rule.close
1586 .iter()
1587 .map(|alt| portable_alt(left, alt, left_tag))
1588 .collect()
1589 })
1590 .unwrap_or_default();
1591 let right_close = right_rule
1592 .map(|rule| {
1593 rule.close
1594 .iter()
1595 .map(|alt| portable_alt(right, alt, right_tag))
1596 .collect()
1597 })
1598 .unwrap_or_default();
1599 let phase =
1600 |select_named: fn(&RuleSpec) -> &Vec<String>,
1601 select_callbacks: fn(&RuleSpec) -> &Vec<ContextAction>,
1602 select_states: fn(&RuleSpec) -> &Vec<crate::StateAction>,
1603 select_order: fn(&RuleSpec) -> &Vec<ActionBinding>| {
1604 merge_phase(
1605 PhaseSource {
1606 tabnas: left,
1607 named: left_rule.map(select_named).unwrap_or(&empty_named),
1608 callbacks: left_rule.map(select_callbacks).unwrap_or(&empty_callbacks),
1609 states: left_rule.map(select_states).unwrap_or(&empty_states),
1610 order: left_rule.map(select_order).unwrap_or(&empty_order),
1611 tag: left_tag,
1612 },
1613 PhaseSource {
1614 tabnas: right,
1615 named: right_rule.map(select_named).unwrap_or(&empty_named),
1616 callbacks: right_rule.map(select_callbacks).unwrap_or(&empty_callbacks),
1617 states: right_rule.map(select_states).unwrap_or(&empty_states),
1618 order: right_rule.map(select_order).unwrap_or(&empty_order),
1619 tag: right_tag,
1620 },
1621 )
1622 };
1623 let (bo, bo_fns, bo_state_fns, bo_order) = phase(
1624 |rule| &rule.bo,
1625 |rule| &rule.bo_fns,
1626 |rule| &rule.bo_state_fns,
1627 |rule| &rule.bo_order,
1628 );
1629 let (ao, ao_fns, ao_state_fns, ao_order) = phase(
1630 |rule| &rule.ao,
1631 |rule| &rule.ao_fns,
1632 |rule| &rule.ao_state_fns,
1633 |rule| &rule.ao_order,
1634 );
1635 let (bc, bc_fns, bc_state_fns, bc_order) = phase(
1636 |rule| &rule.bc,
1637 |rule| &rule.bc_fns,
1638 |rule| &rule.bc_state_fns,
1639 |rule| &rule.bc_order,
1640 );
1641 let (ac, ac_fns, ac_state_fns, ac_order) = phase(
1642 |rule| &rule.ac,
1643 |rule| &rule.ac_fns,
1644 |rule| &rule.ac_state_fns,
1645 |rule| &rule.ac_order,
1646 );
1647 MergedRule {
1648 name,
1649 open: interleave(left_open, right_open),
1650 close: interleave(left_close, right_close),
1651 bo,
1652 ao,
1653 bc,
1654 ac,
1655 bo_fns,
1656 ao_fns,
1657 bc_fns,
1658 ac_fns,
1659 bo_state_fns,
1660 ao_state_fns,
1661 bc_state_fns,
1662 ac_state_fns,
1663 bo_order,
1664 ao_order,
1665 bc_order,
1666 ac_order,
1667 }
1668 })
1669 .collect()
1670}
1671
1672fn prefix_hash_map<T: Clone>(source: &HashMap<String, T>, tag: &str) -> HashMap<String, T> {
1673 source
1674 .iter()
1675 .map(|(name, value)| (rename_ref(name, tag), value.clone()))
1676 .collect()
1677}
1678
1679fn combine_guards(
1686 left: &IndexMap<String, crate::ParseGuard>,
1687 left_tag: &str,
1688 right: &IndexMap<String, crate::ParseGuard>,
1689 right_tag: &str,
1690) -> IndexMap<String, crate::ParseGuard> {
1691 let side = |guards: &IndexMap<String, crate::ParseGuard>, tag: &str| {
1692 guards
1693 .iter()
1694 .map(|(name, guard)| (format!("{tag}:{name}"), guard.clone()))
1695 .collect::<Vec<_>>()
1696 };
1697 side(left, left_tag)
1698 .into_iter()
1699 .chain(side(right, right_tag))
1700 .collect()
1701}
1702
1703fn combine_prefixed<T: Clone>(
1704 left: &HashMap<String, T>,
1705 left_tag: &str,
1706 right: &HashMap<String, T>,
1707 right_tag: &str,
1708) -> HashMap<String, T> {
1709 let mut out = prefix_hash_map(left, left_tag);
1710 out.extend(prefix_hash_map(right, right_tag));
1711 out
1712}
1713
1714#[derive(Clone)]
1715struct MergedInstall {
1716 rules: Vec<MergedRule>,
1717 actions: HashMap<String, Action>,
1718 context_actions: HashMap<String, ContextAction>,
1719 matched_actions: HashMap<String, crate::AltAction>,
1720 state_actions: HashMap<String, crate::StateAction>,
1721 token_subscribers: Vec<TokenSubscriber>,
1722 lex_subscribers: Vec<LexSubscriber>,
1723 rule_subscribers: Vec<RuleSubscriber>,
1724 rule_done_subscribers: Vec<RuleDoneSubscriber>,
1725 parse_guards: IndexMap<String, crate::ParseGuard>,
1726 alt_conditions: HashMap<String, crate::AltCondition>,
1727 alt_match_conditions: HashMap<String, crate::AltConditionWithMatch>,
1728 alt_lexer_conditions: HashMap<String, crate::AltConditionWithLexer>,
1729 alt_lexer_match_conditions: HashMap<String, crate::AltConditionWithLexerAndMatch>,
1730 alt_modifiers: HashMap<String, crate::AltModifier>,
1731 alt_match_modifiers: HashMap<String, crate::AltModifierWithMatch>,
1732 alt_errors: HashMap<String, crate::AltError>,
1733 alt_match_errors: HashMap<String, crate::AltErrorWithMatch>,
1734 alt_pushes: HashMap<String, crate::AltNext>,
1735 alt_match_pushes: HashMap<String, crate::AltNextWithMatch>,
1736 alt_replaces: HashMap<String, crate::AltNext>,
1737 alt_match_replaces: HashMap<String, crate::AltNextWithMatch>,
1738 alt_backtracks: HashMap<String, crate::AltBack>,
1739 alt_match_backtracks: HashMap<String, crate::AltBackWithMatch>,
1740 match_token_refs: HashMap<String, (crate::MatchTokenCallback, bool)>,
1741 value_transform_refs: HashMap<String, crate::ValueTransform>,
1742 text_modifier_refs: HashMap<String, crate::TextModifier>,
1743 lex_check_refs: HashMap<String, crate::LexCheck>,
1744 comment_suffix_refs: HashMap<String, crate::CommentSuffixMatcher>,
1745 match_value_refs: HashMap<String, crate::MatchTokenCallback>,
1746 parse_prepare_refs: HashMap<String, crate::ParsePrepare>,
1747 budget_check_refs: HashMap<String, crate::BudgetCheck>,
1748 lex_match_refs: HashMap<String, crate::LexMatcherCallback>,
1749 imperative_lex_match_refs: HashMap<String, crate::ImperativeLexMatcher>,
1750 lex_match_factory_refs: HashMap<String, crate::LexMatcherFactory>,
1751 error_suffix_refs: HashMap<String, crate::ErrorSuffixCallback>,
1752 config_modifier_refs: HashMap<String, crate::ConfigModifier>,
1753 parser_start_refs: HashMap<String, crate::ParserStart>,
1754 parser_start_instance_refs: HashMap<String, crate::ParserStartWithInstance>,
1755 parser_start_context_refs: HashMap<String, crate::ParserStartWithContext>,
1756 map_merge_refs: HashMap<String, crate::MapMerge>,
1757}
1758
1759impl MergedInstall {
1760 fn install(&self, tabnas: &mut Tabnas) {
1761 tabnas.rules = self
1762 .rules
1763 .iter()
1764 .map(|rule| {
1765 let rule = rule.materialize(&mut tabnas.options);
1766 (rule.name.clone(), rule)
1767 })
1768 .collect::<indexmap::IndexMap<_, _>>()
1769 .into();
1770 tabnas.actions = self.actions.clone().into();
1771 tabnas.context_actions = (self.context_actions.clone()).into();
1772 tabnas.matched_actions = (self.matched_actions.clone()).into();
1773 tabnas.state_actions = (self.state_actions.clone()).into();
1774 tabnas.token_subscribers = (self.token_subscribers.clone()).into();
1775 tabnas.lex_subscribers = (self.lex_subscribers.clone()).into();
1776 tabnas.rule_subscribers = (self.rule_subscribers.clone()).into();
1777 tabnas.rule_done_subscribers = (self.rule_done_subscribers.clone()).into();
1778 for (name, guard) in &self.parse_guards {
1782 tabnas.parse_guards.insert(name.clone(), guard.clone());
1783 }
1784 tabnas.alt_conditions = self.alt_conditions.clone();
1785 tabnas.alt_match_conditions = self.alt_match_conditions.clone();
1786 tabnas.alt_lexer_conditions = self.alt_lexer_conditions.clone();
1787 tabnas.alt_lexer_match_conditions = self.alt_lexer_match_conditions.clone();
1788 tabnas.alt_modifiers = self.alt_modifiers.clone();
1789 tabnas.alt_match_modifiers = self.alt_match_modifiers.clone();
1790 tabnas.alt_errors = self.alt_errors.clone();
1791 tabnas.alt_match_errors = self.alt_match_errors.clone();
1792 tabnas.alt_pushes = self.alt_pushes.clone();
1793 tabnas.alt_match_pushes = self.alt_match_pushes.clone();
1794 tabnas.alt_replaces = self.alt_replaces.clone();
1795 tabnas.alt_match_replaces = self.alt_match_replaces.clone();
1796 tabnas.alt_backtracks = self.alt_backtracks.clone();
1797 tabnas.alt_match_backtracks = self.alt_match_backtracks.clone();
1798 tabnas.match_token_refs = self.match_token_refs.clone();
1799 tabnas.value_transform_refs = self.value_transform_refs.clone();
1800 tabnas.text_modifier_refs = self.text_modifier_refs.clone();
1801 tabnas.lex_check_refs = self.lex_check_refs.clone();
1802 tabnas.comment_suffix_refs = self.comment_suffix_refs.clone();
1803 tabnas.match_value_refs = self.match_value_refs.clone();
1804 tabnas.parse_prepare_refs = self.parse_prepare_refs.clone();
1805 tabnas.budget_check_refs = self.budget_check_refs.clone();
1806 tabnas.lex_match_refs = self.lex_match_refs.clone();
1807 tabnas.imperative_lex_match_refs = self.imperative_lex_match_refs.clone();
1808 tabnas.lex_match_factory_refs = self.lex_match_factory_refs.clone();
1809 tabnas.error_suffix_refs = self.error_suffix_refs.clone();
1810 tabnas.config_modifier_refs = self.config_modifier_refs.clone();
1811 tabnas.parser_start_refs = self.parser_start_refs.clone();
1812 tabnas.parser_start_instance_refs = self.parser_start_instance_refs.clone();
1813 tabnas.parser_start_context_refs = self.parser_start_context_refs.clone();
1814 tabnas.map_merge_refs = self.map_merge_refs.clone();
1815 }
1816}
1817
1818fn merge_plugin_value(left: &Value, right: &Value, path: &str) -> Result<Value, MergeError> {
1819 match (left, right) {
1820 (Value::Undefined, value) | (value, Value::Undefined) => Ok(value.clone()),
1821 (Value::Object(left), Value::Object(right)) => {
1822 let mut out = IndexMap::new();
1823 for key in ordered_keys(left, right) {
1824 let value = match (left.get(&key), right.get(&key)) {
1825 (Some(left), Some(right)) => {
1826 merge_plugin_value(left, right, &format!("{path}.{key}"))?
1827 }
1828 (Some(value), None) | (None, Some(value)) => value.clone(),
1829 (None, None) => unreachable!(),
1830 };
1831 out.insert(key, value);
1832 }
1833 Ok(Value::object(out))
1834 }
1835 _ if left.deep_equal(right) => Ok(left.clone()),
1836 _ => Err(conflict(path)),
1837 }
1838}
1839
1840fn merge_decorations(
1841 left: &IndexMap<String, crate::Decoration>,
1842 right: &IndexMap<String, crate::Decoration>,
1843) -> Result<IndexMap<String, crate::Decoration>, MergeError> {
1844 let mut out = left.clone();
1845 for (name, value) in right {
1846 if let Some(previous) = out.get(name) {
1847 if !previous.equivalent(value) {
1848 return Err(conflict(&format!("decoration.{name}")));
1849 }
1850 } else {
1851 out.insert(name.clone(), value.clone());
1852 }
1853 }
1854 Ok(out)
1855}
1856
1857pub(crate) fn merge(left: &Tabnas, right: &Tabnas) -> Result<Tabnas, MergeError> {
1858 fn tag<'a>(tabnas: &'a Tabnas, which: &str) -> Result<&'a str, MergeError> {
1859 let tag = tabnas.options.tag.as_str();
1860 if tag.is_empty() || tag == "-" {
1861 Err(MergeError(format!(
1862 "merge: the {which} instance needs a tag option (used to prefix its named actions)"
1863 )))
1864 } else {
1865 Ok(tag)
1866 }
1867 }
1868
1869 let left_tag = tag(left, "first")?;
1870 let right_tag = tag(right, "second")?;
1871 if left_tag == right_tag {
1872 return Err(MergeError(format!(
1873 "merge: instance tags must differ, both are {left_tag:?}"
1874 )));
1875 }
1876 let (left, left_tag, right, right_tag) = if left_tag < right_tag {
1877 (left, left_tag, right, right_tag)
1878 } else {
1879 (right, right_tag, left, left_tag)
1880 };
1881
1882 let mut options = merge_options(&left.options, &right.options)?;
1883 options.tag = format!("{left_tag}~{right_tag}");
1884 let plugin_options = merge_plugin_value(
1885 &Value::object(left.plugin_options.clone()),
1886 &Value::object(right.plugin_options.clone()),
1887 "plugin",
1888 )?;
1889 let Value::Object(plugin_options) = plugin_options else {
1890 unreachable!()
1891 };
1892 let decorations = merge_decorations(&left.decorations, &right.decorations)?;
1893
1894 let install = MergedInstall {
1895 rules: merged_rules(left, left_tag, right, right_tag),
1896 actions: combine_prefixed(&left.actions, left_tag, &right.actions, right_tag),
1897 context_actions: combine_prefixed(
1898 &left.context_actions,
1899 left_tag,
1900 &right.context_actions,
1901 right_tag,
1902 ),
1903 matched_actions: combine_prefixed(
1904 &left.matched_actions,
1905 left_tag,
1906 &right.matched_actions,
1907 right_tag,
1908 ),
1909 state_actions: combine_prefixed(
1910 &left.state_actions,
1911 left_tag,
1912 &right.state_actions,
1913 right_tag,
1914 ),
1915 token_subscribers: append_callbacks(&left.token_subscribers, &right.token_subscribers),
1916 lex_subscribers: append_callbacks(&left.lex_subscribers, &right.lex_subscribers),
1917 rule_subscribers: append_callbacks(&left.rule_subscribers, &right.rule_subscribers),
1918 rule_done_subscribers: append_callbacks(
1919 &left.rule_done_subscribers,
1920 &right.rule_done_subscribers,
1921 ),
1922 parse_guards: combine_guards(&left.parse_guards, left_tag, &right.parse_guards, right_tag),
1923 alt_conditions: combine_prefixed(
1924 &left.alt_conditions,
1925 left_tag,
1926 &right.alt_conditions,
1927 right_tag,
1928 ),
1929 alt_match_conditions: combine_prefixed(
1930 &left.alt_match_conditions,
1931 left_tag,
1932 &right.alt_match_conditions,
1933 right_tag,
1934 ),
1935 alt_lexer_conditions: combine_prefixed(
1936 &left.alt_lexer_conditions,
1937 left_tag,
1938 &right.alt_lexer_conditions,
1939 right_tag,
1940 ),
1941 alt_lexer_match_conditions: combine_prefixed(
1942 &left.alt_lexer_match_conditions,
1943 left_tag,
1944 &right.alt_lexer_match_conditions,
1945 right_tag,
1946 ),
1947 alt_modifiers: combine_prefixed(
1948 &left.alt_modifiers,
1949 left_tag,
1950 &right.alt_modifiers,
1951 right_tag,
1952 ),
1953 alt_match_modifiers: combine_prefixed(
1954 &left.alt_match_modifiers,
1955 left_tag,
1956 &right.alt_match_modifiers,
1957 right_tag,
1958 ),
1959 alt_errors: combine_prefixed(&left.alt_errors, left_tag, &right.alt_errors, right_tag),
1960 alt_match_errors: combine_prefixed(
1961 &left.alt_match_errors,
1962 left_tag,
1963 &right.alt_match_errors,
1964 right_tag,
1965 ),
1966 alt_pushes: combine_prefixed(&left.alt_pushes, left_tag, &right.alt_pushes, right_tag),
1967 alt_match_pushes: combine_prefixed(
1968 &left.alt_match_pushes,
1969 left_tag,
1970 &right.alt_match_pushes,
1971 right_tag,
1972 ),
1973 alt_replaces: combine_prefixed(
1974 &left.alt_replaces,
1975 left_tag,
1976 &right.alt_replaces,
1977 right_tag,
1978 ),
1979 alt_match_replaces: combine_prefixed(
1980 &left.alt_match_replaces,
1981 left_tag,
1982 &right.alt_match_replaces,
1983 right_tag,
1984 ),
1985 alt_backtracks: combine_prefixed(
1986 &left.alt_backtracks,
1987 left_tag,
1988 &right.alt_backtracks,
1989 right_tag,
1990 ),
1991 alt_match_backtracks: combine_prefixed(
1992 &left.alt_match_backtracks,
1993 left_tag,
1994 &right.alt_match_backtracks,
1995 right_tag,
1996 ),
1997 match_token_refs: combine_prefixed(
1998 &left.match_token_refs,
1999 left_tag,
2000 &right.match_token_refs,
2001 right_tag,
2002 ),
2003 value_transform_refs: combine_prefixed(
2004 &left.value_transform_refs,
2005 left_tag,
2006 &right.value_transform_refs,
2007 right_tag,
2008 ),
2009 text_modifier_refs: combine_prefixed(
2010 &left.text_modifier_refs,
2011 left_tag,
2012 &right.text_modifier_refs,
2013 right_tag,
2014 ),
2015 lex_check_refs: combine_prefixed(
2016 &left.lex_check_refs,
2017 left_tag,
2018 &right.lex_check_refs,
2019 right_tag,
2020 ),
2021 comment_suffix_refs: combine_prefixed(
2022 &left.comment_suffix_refs,
2023 left_tag,
2024 &right.comment_suffix_refs,
2025 right_tag,
2026 ),
2027 match_value_refs: combine_prefixed(
2028 &left.match_value_refs,
2029 left_tag,
2030 &right.match_value_refs,
2031 right_tag,
2032 ),
2033 parse_prepare_refs: combine_prefixed(
2034 &left.parse_prepare_refs,
2035 left_tag,
2036 &right.parse_prepare_refs,
2037 right_tag,
2038 ),
2039 budget_check_refs: combine_prefixed(
2040 &left.budget_check_refs,
2041 left_tag,
2042 &right.budget_check_refs,
2043 right_tag,
2044 ),
2045 lex_match_refs: combine_prefixed(
2046 &left.lex_match_refs,
2047 left_tag,
2048 &right.lex_match_refs,
2049 right_tag,
2050 ),
2051 imperative_lex_match_refs: combine_prefixed(
2052 &left.imperative_lex_match_refs,
2053 left_tag,
2054 &right.imperative_lex_match_refs,
2055 right_tag,
2056 ),
2057 lex_match_factory_refs: combine_prefixed(
2058 &left.lex_match_factory_refs,
2059 left_tag,
2060 &right.lex_match_factory_refs,
2061 right_tag,
2062 ),
2063 error_suffix_refs: combine_prefixed(
2064 &left.error_suffix_refs,
2065 left_tag,
2066 &right.error_suffix_refs,
2067 right_tag,
2068 ),
2069 config_modifier_refs: combine_prefixed(
2070 &left.config_modifier_refs,
2071 left_tag,
2072 &right.config_modifier_refs,
2073 right_tag,
2074 ),
2075 parser_start_refs: combine_prefixed(
2076 &left.parser_start_refs,
2077 left_tag,
2078 &right.parser_start_refs,
2079 right_tag,
2080 ),
2081 parser_start_instance_refs: combine_prefixed(
2082 &left.parser_start_instance_refs,
2083 left_tag,
2084 &right.parser_start_instance_refs,
2085 right_tag,
2086 ),
2087 parser_start_context_refs: combine_prefixed(
2088 &left.parser_start_context_refs,
2089 left_tag,
2090 &right.parser_start_context_refs,
2091 right_tag,
2092 ),
2093 map_merge_refs: combine_prefixed(
2094 &left.map_merge_refs,
2095 left_tag,
2096 &right.map_merge_refs,
2097 right_tag,
2098 ),
2099 };
2100
2101 let mut out = Tabnas::with_options(options);
2102 out.plugin_options = crate::value::unwrap_arc(plugin_options);
2103 out.decorations = decorations;
2104 let install_callback = install.clone();
2105 out.use_plugin(
2106 Plugin::new("merged", move |tabnas, _| {
2107 install_callback.install(tabnas);
2108 Ok(())
2109 }),
2110 None,
2111 )
2112 .map_err(|PluginError(message)| MergeError(format!("merge: {message}")))?;
2113 Ok(out)
2114}