1use crate::charset::{refine, refine_all, CharSet};
38use std::collections::HashMap;
39use std::sync::Arc;
40
41#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
43pub struct TermId(u32);
44
45impl TermId {
46 pub fn index(self) -> usize {
48 self.0 as usize
49 }
50}
51
52pub const NO_AUX: u8 = 255;
54pub const MAX_AUX: usize = 48;
56pub const MAX_TRACKERS: usize = 16;
58
59#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
61pub enum AssertKind {
62 TextStart,
64 TextEnd,
66 LineStart,
68 LineEnd,
70 WordBoundary,
72 NotWordBoundary,
74 WordStart,
76 WordEnd,
78}
79
80impl AssertKind {
81 pub const fn letter(self) -> char {
83 match self {
84 AssertKind::TextStart => 'A',
85 AssertKind::TextEnd => 'z',
86 AssertKind::LineStart => '^',
87 AssertKind::LineEnd => '$',
88 AssertKind::WordBoundary => 'b',
89 AssertKind::NotWordBoundary => 'B',
90 AssertKind::WordStart => '<',
91 AssertKind::WordEnd => '>',
92 }
93 }
94}
95
96#[derive(Clone, PartialEq, Eq, Hash, Debug)]
98pub enum TermKind {
99 Empty,
101 Epsilon,
103 Class(CharSet),
105 Concat(TermId, TermId),
107 Union(Arc<[TermId]>),
109 Star(TermId),
111 Inter(Arc<[TermId]>),
113 Not(TermId),
115 Assert {
117 kind: AssertKind,
119 word: u8,
121 line: u8,
123 },
124 LookAhead {
126 neg: bool,
128 body: TermId,
130 },
131 LookBehind {
133 neg: bool,
135 tracker: u8,
137 },
138}
139
140struct Node {
141 kind: TermKind,
142 nullable: bool,
144 ctx_dep: bool,
146 has_look: bool,
148}
149
150#[derive(Clone, PartialEq, Eq, Hash, Debug)]
152pub struct Ctx {
153 pub start: bool,
155 pub bits: u64,
157 pub tracks: Vec<TermId>,
159}
160
161#[derive(Clone, Copy, Debug)]
163struct Tracker {
164 body: TermId,
165 root: TermId,
166}
167
168pub struct TermStore {
170 nodes: Vec<Node>,
171 index: HashMap<TermKind, TermId>,
172 universe: CharSet,
173 empty: TermId,
174 epsilon: TermId,
175 universal: TermId,
176 deriv_cache: HashMap<(TermId, u32, u32), TermId>,
177 part_cache: HashMap<TermId, Arc<Vec<CharSet>>>,
178 look_cache: HashMap<(TermId, u32, u32), TermId>,
179 aux_sets: Vec<CharSet>,
180 trackers: Vec<Tracker>,
181 ctxs: Vec<Ctx>,
182 ctx_index: HashMap<Ctx, u32>,
183 node_bytes: u64,
184}
185
186pub const NO_CTX: u32 = 0;
188
189impl TermStore {
190 pub fn new(universe: CharSet) -> Self {
192 let mut s = TermStore {
193 nodes: Vec::new(),
194 index: HashMap::new(),
195 universe,
196 empty: TermId(0),
197 epsilon: TermId(0),
198 universal: TermId(0),
199 deriv_cache: HashMap::new(),
200 part_cache: HashMap::new(),
201 look_cache: HashMap::new(),
202 aux_sets: Vec::new(),
203 trackers: Vec::new(),
204 ctxs: Vec::new(),
205 ctx_index: HashMap::new(),
206 node_bytes: 0,
207 };
208 s.empty = s.intern(TermKind::Empty);
209 s.epsilon = s.intern(TermKind::Epsilon);
210 s.universal = s.intern(TermKind::Not(s.empty));
211 s.intern_ctx(Ctx {
213 start: false,
214 bits: u64::MAX,
215 tracks: Vec::new(),
216 });
217 s
218 }
219
220 pub fn universe(&self) -> &CharSet {
222 &self.universe
223 }
224 pub fn len(&self) -> usize {
226 self.nodes.len()
227 }
228 pub fn approx_bytes(&self) -> u64 {
230 self.node_bytes
231 + 64 * (self.deriv_cache.len() + self.part_cache.len() + self.look_cache.len()) as u64
232 }
233 pub fn is_empty(&self) -> bool {
235 self.nodes.len() <= 3
236 }
237 pub fn empty(&self) -> TermId {
239 self.empty
240 }
241 pub fn epsilon(&self) -> TermId {
243 self.epsilon
244 }
245 pub fn universal(&self) -> TermId {
247 self.universal
248 }
249 pub fn kind(&self, t: TermId) -> &TermKind {
251 &self.nodes[t.index()].kind
252 }
253 pub fn nullable(&self, t: TermId) -> bool {
256 self.nodes[t.index()].nullable
257 }
258 pub fn ctx_dep(&self, t: TermId) -> bool {
260 self.nodes[t.index()].ctx_dep
261 }
262 pub fn aux_sets(&self) -> &[CharSet] {
264 &self.aux_sets
265 }
266 pub fn tracker_body(&self, i: u8) -> Option<TermId> {
268 self.trackers.get(i as usize).map(|t| t.body)
269 }
270
271 fn intern(&mut self, kind: TermKind) -> TermId {
272 if let Some(&id) = self.index.get(&kind) {
273 return id;
274 }
275 self.node_bytes += 128
276 + match &kind {
277 TermKind::Union(v) | TermKind::Inter(v) => 8 * v.len() as u64,
278 _ => 0,
279 };
280 let n = |s: &Self, x: TermId| (s.nullable(x), s.ctx_dep(x), s.nodes[x.index()].has_look);
281 let (nullable, ctx_dep, has_look) = match &kind {
282 TermKind::Empty | TermKind::Class(_) => (false, false, false),
283 TermKind::Epsilon | TermKind::Star(_) => {
284 let child = if let TermKind::Star(x) = &kind {
285 n(self, *x)
286 } else {
287 (true, false, false)
288 };
289 (true, child.1, child.2)
290 }
291 TermKind::Concat(a, b) => {
292 let (x, y) = (n(self, *a), n(self, *b));
293 (x.0 && y.0, x.1 || y.1, x.2 || y.2)
294 }
295 TermKind::Union(v) => {
296 let cs: Vec<_> = v.iter().map(|&x| n(self, x)).collect();
297 (
298 cs.iter().any(|c| c.0),
299 cs.iter().any(|c| c.1),
300 cs.iter().any(|c| c.2),
301 )
302 }
303 TermKind::Inter(v) => {
304 let cs: Vec<_> = v.iter().map(|&x| n(self, x)).collect();
305 (
306 cs.iter().all(|c| c.0),
307 cs.iter().any(|c| c.1),
308 cs.iter().any(|c| c.2),
309 )
310 }
311 TermKind::Not(x) => {
312 let c = n(self, *x);
313 (!c.0, c.1, c.2)
314 }
315 TermKind::Assert { .. } | TermKind::LookBehind { .. } => (false, true, false),
316 TermKind::LookAhead { .. } => (false, true, true),
317 };
318 let id = TermId(self.nodes.len() as u32);
319 self.nodes.push(Node {
320 kind: kind.clone(),
321 nullable,
322 ctx_dep,
323 has_look,
324 });
325 self.index.insert(kind, id);
326 id
327 }
328
329 fn intern_ctx(&mut self, c: Ctx) -> u32 {
330 if let Some(&id) = self.ctx_index.get(&c) {
331 return id;
332 }
333 let id = self.ctxs.len() as u32;
334 self.ctxs.push(c.clone());
335 self.ctx_index.insert(c, id);
336 id
337 }
338
339 pub fn class(&mut self, set: &CharSet) -> TermId {
343 let s = set.intersect(&self.universe);
344 if s.is_empty() {
345 self.empty
346 } else {
347 self.intern(TermKind::Class(s))
348 }
349 }
350
351 pub fn any_symbol(&mut self) -> TermId {
353 let u = self.universe.clone();
354 self.class(&u)
355 }
356
357 pub fn concat_all(&mut self, factors: &[TermId]) -> TermId {
360 let mut acc = self.epsilon;
361 for &f in factors.iter().rev() {
362 acc = self.prepend(f, acc);
363 }
364 acc
365 }
366
367 fn prepend(&mut self, f: TermId, acc: TermId) -> TermId {
369 if f == self.empty || acc == self.empty {
370 return self.empty;
371 }
372 let mut items = Vec::new();
373 let mut cur = f;
374 loop {
375 match self.kind(cur) {
376 TermKind::Concat(a, b) => {
377 items.push(*a);
378 cur = *b;
379 }
380 TermKind::Epsilon => break,
381 _ => {
382 items.push(cur);
383 break;
384 }
385 }
386 }
387 let mut acc = acc;
388 for &item in items.iter().rev() {
389 acc = self.cons(item, acc);
390 }
391 acc
392 }
393
394 fn cons(&mut self, f: TermId, acc: TermId) -> TermId {
397 if acc == self.empty || f == self.empty {
398 return self.empty;
399 }
400 if acc == self.epsilon {
401 return f;
402 }
403 self.intern(TermKind::Concat(f, acc))
404 }
405
406 pub fn concat(&mut self, a: TermId, b: TermId) -> TermId {
408 self.prepend(a, b)
409 }
410
411 pub fn union(&mut self, items: &[TermId]) -> TermId {
413 let mut flat: Vec<TermId> = Vec::new();
414 let mut merged = CharSet::empty();
415 for &t in items {
416 self.collect_union(t, &mut flat, &mut merged);
417 }
418 if flat.contains(&self.universal) {
419 return self.universal;
420 }
421 if !merged.is_empty() {
422 let c = self.class(&merged);
423 flat.push(c);
424 }
425 flat.sort_unstable();
426 flat.dedup();
427 match flat.len() {
428 0 => self.empty,
429 1 => flat[0],
430 _ => self.intern(TermKind::Union(flat.into())),
431 }
432 }
433
434 fn collect_union(&self, t: TermId, flat: &mut Vec<TermId>, merged: &mut CharSet) {
435 match self.kind(t) {
436 TermKind::Empty => {}
437 TermKind::Union(v) => {
438 for &x in v.iter() {
439 self.collect_union(x, flat, merged);
440 }
441 }
442 TermKind::Class(s) => *merged = merged.union(s),
443 _ => flat.push(t),
444 }
445 }
446
447 pub fn inter(&mut self, items: &[TermId]) -> TermId {
449 let mut flat: Vec<TermId> = Vec::new();
450 let mut merged: Option<CharSet> = None;
451 for &t in items {
452 if !self.collect_inter(t, &mut flat, &mut merged) {
453 return self.empty;
454 }
455 }
456 if let Some(m) = merged {
457 let c = self.class(&m);
458 if c == self.empty {
459 return self.empty;
460 }
461 flat.push(c);
462 }
463 flat.sort_unstable();
464 flat.dedup();
465 for &t in &flat {
467 if let TermKind::Not(y) = self.kind(t) {
468 if flat.contains(y) {
469 return self.empty;
470 }
471 }
472 }
473 match flat.len() {
474 0 => self.universal,
475 1 => flat[0],
476 _ => self.intern(TermKind::Inter(flat.into())),
477 }
478 }
479
480 fn collect_inter(
482 &self,
483 t: TermId,
484 flat: &mut Vec<TermId>,
485 merged: &mut Option<CharSet>,
486 ) -> bool {
487 match self.kind(t) {
488 TermKind::Empty => return false,
489 TermKind::Inter(v) => {
490 for &x in v.iter() {
491 if !self.collect_inter(x, flat, merged) {
492 return false;
493 }
494 }
495 }
496 TermKind::Class(s) => {
497 *merged = Some(match merged.take() {
498 Some(m) => m.intersect(s),
499 None => s.clone(),
500 });
501 }
502 _ if t == self.universal => {}
503 _ => flat.push(t),
504 }
505 true
506 }
507
508 pub fn star(&mut self, t: TermId) -> TermId {
510 match self.kind(t).clone() {
511 TermKind::Empty | TermKind::Epsilon => self.epsilon,
512 TermKind::Star(_) => t,
513 _ if !self.may_consume(t) => self.epsilon,
516 TermKind::Union(v) if v.contains(&self.epsilon) => {
518 let rest: Vec<TermId> = v.iter().copied().filter(|&x| x != self.epsilon).collect();
519 let u = self.union(&rest);
520 self.star(u)
521 }
522 _ => self.intern(TermKind::Star(t)),
523 }
524 }
525
526 pub fn not(&mut self, t: TermId) -> TermId {
528 match self.kind(t) {
529 TermKind::Not(x) => *x,
530 _ => self.intern(TermKind::Not(t)),
531 }
532 }
533
534 pub fn opt(&mut self, t: TermId) -> TermId {
536 let e = self.epsilon;
537 self.union(&[e, t])
538 }
539
540 fn aux_set(&mut self, set: &CharSet) -> Option<u8> {
543 if let Some(i) = self.aux_sets.iter().position(|s| s == set) {
544 return Some(i as u8);
545 }
546 if self.aux_sets.len() >= MAX_AUX {
547 return None;
548 }
549 self.aux_sets.push(set.clone());
550 Some((self.aux_sets.len() - 1) as u8)
551 }
552
553 pub fn assertion(
557 &mut self,
558 kind: AssertKind,
559 word: Option<&CharSet>,
560 line: Option<&CharSet>,
561 ) -> Option<TermId> {
562 let w = match (kind, word) {
563 (
564 AssertKind::WordBoundary
565 | AssertKind::NotWordBoundary
566 | AssertKind::WordStart
567 | AssertKind::WordEnd,
568 Some(s),
569 ) => self.aux_set(s)?,
570 _ => NO_AUX,
571 };
572 let l = match (kind, line) {
573 (AssertKind::LineStart | AssertKind::LineEnd, Some(s)) => self.aux_set(s)?,
574 _ => NO_AUX,
575 };
576 Some(self.intern(TermKind::Assert {
577 kind,
578 word: w,
579 line: l,
580 }))
581 }
582
583 pub fn look_ahead(&mut self, neg: bool, body: TermId) -> TermId {
585 self.intern(TermKind::LookAhead { neg, body })
586 }
587
588 pub fn look_behind(&mut self, neg: bool, body: TermId) -> Option<TermId> {
591 if self.ctx_dep(body) {
592 return None;
593 }
594 let tracker = match self.trackers.iter().position(|t| t.body == body) {
595 Some(i) => i,
596 None => {
597 if self.trackers.len() >= MAX_TRACKERS {
598 return None;
599 }
600 let any = self.any_symbol();
601 let sigma = self.star(any);
602 let root = self.concat_all(&[sigma, body]);
603 self.trackers.push(Tracker { body, root });
604 self.trackers.len() - 1
605 }
606 };
607 Some(self.intern(TermKind::LookBehind {
608 neg,
609 tracker: tracker as u8,
610 }))
611 }
612
613 pub fn ctx_start(&mut self) -> u32 {
617 let tracks = self.trackers.iter().map(|t| t.root).collect();
618 self.intern_ctx(Ctx {
619 start: true,
620 bits: 0,
621 tracks,
622 })
623 }
624
625 pub fn ctx(&self, id: u32) -> &Ctx {
627 &self.ctxs[id as usize]
628 }
629
630 pub fn advance_ctx(&mut self, id: u32, c: u32) -> u32 {
632 let cur = self.ctxs[id as usize].clone();
633 let mut bits = 0u64;
634 for (i, s) in self.aux_sets.iter().enumerate() {
635 if s.contains(c) {
636 bits |= 1 << i;
637 }
638 }
639 let tracks: Vec<TermId> = cur
640 .tracks
641 .iter()
642 .map(|&t| self.deriv_in(t, c, NO_CTX))
643 .collect();
644 self.intern_ctx(Ctx {
645 start: false,
646 bits,
647 tracks,
648 })
649 }
650
651 fn eval_assert(&self, kind: AssertKind, w: u8, l: u8, ctx: &Ctx, next: Option<u32>) -> bool {
652 let in_next =
653 |id: u8| id != NO_AUX && next.is_some_and(|c| self.aux_sets[id as usize].contains(c));
654 let in_prev = |id: u8| id != NO_AUX && (ctx.bits >> id) & 1 == 1;
655 match kind {
656 AssertKind::TextStart => ctx.start,
657 AssertKind::TextEnd => next.is_none(),
658 AssertKind::LineStart => ctx.start || in_prev(l),
659 AssertKind::LineEnd => next.is_none() || in_next(l),
660 AssertKind::WordBoundary => in_prev(w) != in_next(w),
661 AssertKind::NotWordBoundary => in_prev(w) == in_next(w),
662 AssertKind::WordStart => !in_prev(w) && in_next(w),
663 AssertKind::WordEnd => in_prev(w) && !in_next(w),
664 }
665 }
666
667 pub fn nullable_in(&self, t: TermId, ctx: &Ctx, next: Option<u32>) -> bool {
670 let mut cur = t;
671 loop {
672 let node = &self.nodes[cur.index()];
673 if !node.ctx_dep {
674 return node.nullable;
675 }
676 return match &node.kind {
677 TermKind::Concat(a, b) => {
678 if !self.nullable_in(*a, ctx, next) {
679 return false;
680 }
681 cur = *b;
682 continue;
683 }
684 TermKind::Union(v) => v.iter().any(|&x| self.nullable_in(x, ctx, next)),
685 TermKind::Inter(v) => v.iter().all(|&x| self.nullable_in(x, ctx, next)),
686 TermKind::Not(x) => !self.nullable_in(*x, ctx, next),
687 TermKind::Star(_) => true,
688 TermKind::Assert { kind, word, line } => {
689 self.eval_assert(*kind, *word, *line, ctx, next)
690 }
691 TermKind::LookAhead { neg, body } => {
693 next.is_none() && (self.nullable_in(*body, ctx, None) != *neg)
694 }
695 TermKind::LookBehind { neg, tracker } => {
696 let holds = ctx
697 .tracks
698 .get(*tracker as usize)
699 .is_some_and(|&t| self.nodes[t.index()].nullable);
700 holds != *neg
701 }
702 TermKind::Empty | TermKind::Class(_) => false,
703 TermKind::Epsilon => true,
704 };
705 }
706 }
707
708 pub fn accepting(&self, t: TermId, ctx_id: u32) -> bool {
710 self.nullable_in(t, &self.ctxs[ctx_id as usize], None)
711 }
712
713 pub fn deriv(&mut self, t: TermId, c: u32) -> TermId {
718 self.deriv_in(t, c, NO_CTX)
719 }
720
721 pub fn deriv_in(&mut self, t: TermId, c: u32, ctx_id: u32) -> TermId {
728 enum Step {
729 Enter(TermId),
730 Exit(TermId),
731 }
732 if self.nodes[t.index()].has_look {
733 return self.deriv_look(t, c, ctx_id);
734 }
735 let ctx = self.ctxs[ctx_id as usize].clone();
736 let key = |s: &Self, x: TermId| (x, c, if s.ctx_dep(x) { ctx_id } else { NO_CTX });
737 let mut stack = vec![Step::Enter(t)];
738 while let Some(step) = stack.pop() {
739 match step {
740 Step::Enter(x) => {
741 if self.deriv_cache.contains_key(&key(self, x)) {
742 continue;
743 }
744 match self.kind(x).clone() {
745 TermKind::Empty
746 | TermKind::Epsilon
747 | TermKind::Assert { .. }
748 | TermKind::LookAhead { .. }
749 | TermKind::LookBehind { .. } => {
750 let k = key(self, x);
751 self.deriv_cache.insert(k, self.empty);
752 }
753 TermKind::Class(s) => {
754 let r = if s.contains(c) {
755 self.epsilon
756 } else {
757 self.empty
758 };
759 let k = key(self, x);
760 self.deriv_cache.insert(k, r);
761 }
762 TermKind::Concat(a, b) => {
763 stack.push(Step::Exit(x));
764 stack.push(Step::Enter(a));
765 if self.nullable_in(a, &ctx, Some(c)) {
766 stack.push(Step::Enter(b));
767 }
768 }
769 TermKind::Union(v) | TermKind::Inter(v) => {
770 stack.push(Step::Exit(x));
771 stack.extend(v.iter().map(|&y| Step::Enter(y)));
772 }
773 TermKind::Star(y) | TermKind::Not(y) => {
774 stack.push(Step::Exit(x));
775 stack.push(Step::Enter(y));
776 }
777 }
778 }
779 Step::Exit(x) => {
780 let d = |s: &Self, y: TermId| s.deriv_cache[&key(s, y)];
782 let r = match self.kind(x).clone() {
783 TermKind::Concat(a, b) => {
784 let left = self.concat(d(self, a), b);
785 if self.nullable_in(a, &ctx, Some(c)) {
786 let db = d(self, b);
787 self.union(&[left, db])
788 } else {
789 left
790 }
791 }
792 TermKind::Union(v) => {
793 let ds: Vec<TermId> = v.iter().map(|&y| d(self, y)).collect();
794 self.union(&ds)
795 }
796 TermKind::Inter(v) => {
797 let ds: Vec<TermId> = v.iter().map(|&y| d(self, y)).collect();
798 self.inter(&ds)
799 }
800 TermKind::Star(y) => self.concat(d(self, y), x),
801 TermKind::Not(y) => self.not(d(self, y)),
802 _ => self.empty,
804 };
805 let k = key(self, x);
806 self.deriv_cache.insert(k, r);
807 }
808 }
809 }
810 self.deriv_cache[&key(self, t)]
811 }
812
813 pub fn may_consume(&self, t: TermId) -> bool {
815 match self.kind(t) {
816 TermKind::Empty
817 | TermKind::Epsilon
818 | TermKind::Assert { .. }
819 | TermKind::LookAhead { .. }
820 | TermKind::LookBehind { .. } => false,
821 TermKind::Class(_) | TermKind::Inter(_) | TermKind::Not(_) => true,
822 TermKind::Concat(a, b) => self.may_consume(*a) || self.may_consume(*b),
823 TermKind::Union(v) => v.iter().any(|&x| self.may_consume(x)),
824 TermKind::Star(x) => self.may_consume(*x),
825 }
826 }
827
828 fn deriv_look(&mut self, t: TermId, c: u32, ctx_id: u32) -> TermId {
830 let key = (t, c, ctx_id);
831 if let Some(&r) = self.look_cache.get(&key) {
832 return r;
833 }
834 let ctx = self.ctxs[ctx_id as usize].clone();
835 let mut guard = std::collections::HashSet::new();
836 let eps = self.epsilon;
837 let r = self.dk(t, eps, c, &ctx, ctx_id, &mut guard);
838 self.look_cache.insert(key, r);
839 r
840 }
841
842 fn dk(
844 &mut self,
845 t: TermId,
846 k: TermId,
847 c: u32,
848 ctx: &Ctx,
849 ctx_id: u32,
850 guard: &mut std::collections::HashSet<(TermId, TermId)>,
851 ) -> TermId {
852 if !self.nodes[t.index()].has_look && !self.nodes[k.index()].has_look {
854 let tk = self.concat(t, k);
855 return self.deriv_in(tk, c, ctx_id);
856 }
857 if !guard.insert((t, k)) {
858 return self.empty; }
860 let eps = self.epsilon;
861 let r = match self.kind(t).clone() {
862 TermKind::Class(s) => {
863 if s.contains(c) {
864 k
865 } else {
866 self.empty
867 }
868 }
869 TermKind::Empty
870 | TermKind::Epsilon
871 | TermKind::Assert { .. }
872 | TermKind::LookBehind { .. } => self.empty,
873 TermKind::Concat(a, b) => {
874 let bk = self.concat(b, k);
875 let left = self.dk(a, bk, c, ctx, ctx_id, guard);
876 if self.nullable_in(a, ctx, Some(c)) {
877 let right = self.dk(b, k, c, ctx, ctx_id, guard);
878 self.union(&[left, right])
879 } else {
880 left
881 }
882 }
883 TermKind::Union(v) => {
884 let ds: Vec<TermId> = v
885 .iter()
886 .map(|&x| self.dk(x, k, c, ctx, ctx_id, guard))
887 .collect();
888 self.union(&ds)
889 }
890 TermKind::Star(x) => {
891 let tk = self.concat(t, k);
892 self.dk(x, tk, c, ctx, ctx_id, guard)
893 }
894 TermKind::Inter(v) => {
895 let ds: Vec<TermId> = v
896 .iter()
897 .map(|&x| self.dk(x, eps, c, ctx, ctx_id, guard))
898 .collect();
899 let inner = self.inter(&ds);
900 self.concat(inner, k)
901 }
902 TermKind::Not(x) => {
903 let d = self.dk(x, eps, c, ctx, ctx_id, guard);
904 let inner = self.not(d);
905 self.concat(inner, k)
906 }
907 TermKind::LookAhead { neg, body } => {
908 let any = self.any_symbol();
910 let sigma = self.star(any);
911 let reach = self.concat_all(&[body, sigma]);
912 let dreach = self.dk(reach, eps, c, ctx, ctx_id, guard);
913 let dcond = if neg { self.not(dreach) } else { dreach };
914 let dk_ = self.dk(k, eps, c, ctx, ctx_id, guard);
915 self.inter(&[dcond, dk_])
916 }
917 };
918 guard.remove(&(t, k));
919 r
920 }
921
922 fn ranges_text(s: &CharSet) -> String {
925 let mut out = String::from("[");
926 for (i, &(lo, hi)) in s.ranges().iter().enumerate() {
927 if i > 0 {
928 out.push(',');
929 }
930 if lo == hi {
931 out.push_str(&format!("{lo:X}"));
932 } else {
933 out.push_str(&format!("{lo:X}-{hi:X}"));
934 }
935 }
936 out.push(']');
937 out
938 }
939
940 pub fn to_spec(&self, t: TermId) -> String {
947 enum Item {
948 T(TermId),
949 S(&'static str),
950 }
951 let mut out = String::new();
952 let mut stack = vec![Item::T(t)];
953 while let Some(item) = stack.pop() {
954 match item {
955 Item::S(s) => out.push_str(s),
956 Item::T(x) => match self.kind(x) {
957 TermKind::Empty => out.push('0'),
958 TermKind::Epsilon => out.push('e'),
959 TermKind::Class(s) => out.push_str(&Self::ranges_text(s)),
960 TermKind::Concat(a, b) => {
961 out.push_str("(. ");
962 stack.push(Item::S(")"));
963 stack.push(Item::T(*b));
964 stack.push(Item::S(" "));
965 stack.push(Item::T(*a));
966 }
967 TermKind::Union(v) | TermKind::Inter(v) => {
968 out.push_str(if matches!(self.kind(x), TermKind::Union(_)) {
969 "(|"
970 } else {
971 "(&"
972 });
973 stack.push(Item::S(")"));
974 for &y in v.iter().rev() {
975 stack.push(Item::T(y));
976 stack.push(Item::S(" "));
977 }
978 }
979 TermKind::Star(y) => {
980 out.push_str("(* ");
981 stack.push(Item::S(")"));
982 stack.push(Item::T(*y));
983 }
984 TermKind::Not(y) => {
985 out.push_str("(! ");
986 stack.push(Item::S(")"));
987 stack.push(Item::T(*y));
988 }
989 TermKind::Assert { kind, word, line } => {
990 let set = |i: u8| {
991 if i == NO_AUX {
992 "_".to_string()
993 } else {
994 Self::ranges_text(&self.aux_sets[i as usize])
995 }
996 };
997 out.push_str(&format!(
998 "(#{} {} {})",
999 kind.letter(),
1000 set(*word),
1001 set(*line)
1002 ));
1003 }
1004 TermKind::LookAhead { neg, body } => {
1005 out.push_str(if *neg { "(?! " } else { "(?= " });
1006 stack.push(Item::S(")"));
1007 stack.push(Item::T(*body));
1008 }
1009 TermKind::LookBehind { neg, tracker } => {
1010 out.push_str(if *neg { "(<! " } else { "(<= " });
1011 stack.push(Item::S(")"));
1012 if let Some(b) = self.tracker_body(*tracker) {
1013 stack.push(Item::T(b));
1014 }
1015 }
1016 },
1017 }
1018 }
1019 out
1020 }
1021
1022 pub fn partition(&mut self, t: TermId) -> Arc<Vec<CharSet>> {
1031 enum Step {
1032 Enter(TermId),
1033 Exit(TermId),
1034 }
1035 let mut stack = vec![Step::Enter(t)];
1036 while let Some(step) = stack.pop() {
1037 match step {
1038 Step::Enter(x) => {
1039 if self.part_cache.contains_key(&x) {
1040 continue;
1041 }
1042 match self.kind(x).clone() {
1043 TermKind::Empty | TermKind::Epsilon => {
1044 let whole = Arc::new(vec![self.universe.clone()]);
1045 self.part_cache.insert(x, whole);
1046 }
1047 TermKind::Class(s) => {
1048 let rest = self.universe.difference(&s);
1049 let mut v = vec![s];
1050 if !rest.is_empty() {
1051 v.push(rest);
1052 }
1053 v.sort_by_key(|b| b.smallest());
1054 self.part_cache.insert(x, Arc::new(v));
1055 }
1056 TermKind::Assert { word, line, .. } => {
1057 let mut p = vec![self.universe.clone()];
1058 for id in [word, line] {
1059 if id != NO_AUX {
1060 p = refine(&p, &self.aux_sets[id as usize]);
1061 }
1062 }
1063 p.sort_by_key(|b| b.smallest());
1064 self.part_cache.insert(x, Arc::new(p));
1065 }
1066 TermKind::Concat(a, b) => {
1067 stack.push(Step::Exit(x));
1068 stack.push(Step::Enter(a));
1069 stack.push(Step::Enter(b));
1070 }
1071 TermKind::Union(v) | TermKind::Inter(v) => {
1072 stack.push(Step::Exit(x));
1073 stack.extend(v.iter().map(|&y| Step::Enter(y)));
1074 }
1075 TermKind::Star(y)
1076 | TermKind::Not(y)
1077 | TermKind::LookAhead { body: y, .. } => {
1078 stack.push(Step::Exit(x));
1079 stack.push(Step::Enter(y));
1080 }
1081 TermKind::LookBehind { tracker, .. } => {
1082 stack.push(Step::Exit(x));
1083 if let Some(b) = self.tracker_body(tracker) {
1084 stack.push(Step::Enter(b));
1085 }
1086 }
1087 }
1088 }
1089 Step::Exit(x) => {
1090 let p: Vec<CharSet> = match self.kind(x).clone() {
1091 TermKind::Concat(a, b) => {
1092 refine_all(&self.part_cache[&a], &self.part_cache[&b])
1093 }
1094 TermKind::Union(v) | TermKind::Inter(v) => {
1095 let mut acc = vec![self.universe.clone()];
1096 for y in v.iter() {
1097 acc = refine_all(&acc, &self.part_cache[y]);
1098 }
1099 acc
1100 }
1101 TermKind::Star(y)
1102 | TermKind::Not(y)
1103 | TermKind::LookAhead { body: y, .. } => (*self.part_cache[&y]).clone(),
1104 TermKind::LookBehind { tracker, .. } => match self.tracker_body(tracker) {
1105 Some(b) => (*self.part_cache[&b]).clone(),
1106 None => vec![self.universe.clone()],
1107 },
1108 _ => vec![self.universe.clone()],
1109 };
1110 self.part_cache.insert(x, Arc::new(p));
1111 }
1112 }
1113 }
1114 self.part_cache[&t].clone()
1115 }
1116}
1117
1118#[cfg(test)]
1119mod tests {
1120 use super::*;
1121
1122 fn store() -> TermStore {
1123 TermStore::new(CharSet::range(0, 0x7F))
1124 }
1125 fn ch(s: &mut TermStore, c: char) -> TermId {
1126 s.class(&CharSet::single(c as u32))
1127 }
1128
1129 #[test]
1130 fn interning_gives_one_id_per_term() {
1131 let mut s = store();
1132 let (a1, a2) = (ch(&mut s, 'a'), ch(&mut s, 'a'));
1133 assert_eq!(a1, a2);
1134 }
1135
1136 #[test]
1137 fn normalisation_laws() {
1138 let mut s = store();
1139 let (a, b, c) = (ch(&mut s, 'a'), ch(&mut s, 'b'), ch(&mut s, 'c'));
1140 let (e, z) = (s.epsilon(), s.empty());
1141 assert_eq!(s.union(&[a, a]), a);
1143 assert_eq!(s.union(&[a, b]), s.union(&[b, a]));
1144 let ab = s.union(&[a, b]);
1145 let bc = s.union(&[b, c]);
1146 assert_eq!(s.union(&[ab, c]), s.union(&[a, bc]));
1147 assert_eq!(s.union(&[a, z]), a);
1148 assert_eq!(s.concat(a, e), a);
1150 assert_eq!(s.concat(e, a), a);
1151 assert_eq!(s.concat(a, z), z);
1152 let (x, y) = (s.concat(a, b), s.concat(b, c));
1153 assert_eq!(s.concat(x, c), s.concat(a, y));
1154 let sa = s.star(a);
1156 assert_eq!(s.star(sa), sa);
1157 assert_eq!(s.star(z), e);
1158 let na = s.not(a);
1159 assert_eq!(s.not(na), a);
1160 let u = s.universal();
1161 assert_eq!(s.union(&[a, u]), u);
1162 assert_eq!(s.inter(&[a, u]), a);
1163 assert_eq!(s.inter(&[a, na]), z);
1164 assert!(matches!(s.kind(ab), TermKind::Class(set) if set.count() == 2));
1166 }
1167
1168 #[test]
1169 fn nullable_follows_the_definitions() {
1170 let mut s = store();
1171 let a = ch(&mut s, 'a');
1172 let (e, z) = (s.epsilon(), s.empty());
1173 let sa = s.star(a);
1174 let na = s.not(a);
1175 assert!(!s.nullable(a) && s.nullable(e) && !s.nullable(z) && s.nullable(sa));
1176 assert!(s.nullable(na)); let u = s.universal();
1178 assert!(s.nullable(u));
1179 }
1180
1181 #[test]
1182 fn derivative_of_a_star_b() {
1183 let mut s = store();
1184 let (a, b) = (ch(&mut s, 'a'), ch(&mut s, 'b'));
1185 let sa = s.star(a);
1186 let t = s.concat(sa, b); assert_eq!(s.deriv(t, 'a' as u32), t);
1188 assert_eq!(s.deriv(t, 'b' as u32), s.epsilon());
1189 assert_eq!(s.deriv(t, 'c' as u32), s.empty());
1190 }
1191
1192 #[test]
1193 fn partition_separates_exactly_what_the_term_distinguishes() {
1194 let mut s = store();
1195 let (a, b) = (ch(&mut s, 'a'), ch(&mut s, 'b'));
1196 let t = s.concat(a, b);
1197 let p = s.partition(t);
1198 assert_eq!(p.len(), 3);
1200 assert_eq!(p.iter().map(|x| x.count()).sum::<u64>(), 128);
1201 }
1202
1203 #[test]
1204 fn long_concat_chain_does_not_recurse() {
1205 let mut s = store();
1206 let a = ch(&mut s, 'a');
1207 let t = s.concat_all(&vec![a; 100_000]);
1208 assert!(!s.nullable(t));
1209 }
1210}