1mod build;
58pub mod deriv;
59
60use quickcheck::{Arbitrary, Gen};
61use smallvec::{smallvec, SmallVec};
62
63use itertools::Itertools;
64
65use std::cell::RefCell;
66
67use std::hash::Hash;
68use std::ops::Index;
69use std::{fmt::Display, rc::Rc};
70
71pub use build::ReBuilder;
72
73use crate::alphabet::{partition::AlphabetPartition, Alphabet, CharRange};
74use crate::SmtString;
75
76pub type ReId = usize;
77
78type LazyProp<T> = RefCell<Option<T>>;
79
80pub type Regex = Rc<ReNode>;
85
86#[derive(Debug, Clone)]
125pub struct ReNode {
126 id: ReId,
128 op: ReOp,
130
131 simple: LazyProp<bool>,
133
134 nullable: LazyProp<bool>,
136 universal: LazyProp<Option<bool>>,
138 none: LazyProp<Option<bool>>,
140 epsi: LazyProp<Option<bool>>,
142 first: LazyProp<Rc<AlphabetPartition>>,
145
146 alphabet: LazyProp<Rc<Alphabet>>,
148 is_constant: LazyProp<Option<SmtString>>,
150
151 prefix: LazyProp<Option<SmtString>>,
154
155 suffix: LazyProp<Option<SmtString>>,
158
159 contains_complement: LazyProp<bool>,
162}
163
164impl PartialEq for ReNode {
165 fn eq(&self, other: &Self) -> bool {
166 self.id == other.id
167 }
168}
169impl Eq for ReNode {}
170impl Hash for ReNode {
171 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
172 self.id.hash(state)
173 }
174}
175impl PartialOrd for ReNode {
176 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
177 Some(self.cmp(other))
178 }
179}
180impl Ord for ReNode {
181 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
182 self.id.cmp(&other.id)
183 }
184}
185
186impl Index<usize> for ReNode {
187 type Output = Regex;
188
189 fn index(&self, index: usize) -> &Self::Output {
193 match self.op() {
194 ReOp::Concat(v) | ReOp::Union(v) | ReOp::Inter(v) => &v[index],
195 ReOp::Star(r)
196 | ReOp::Plus(r)
197 | ReOp::Opt(r)
198 | ReOp::Comp(r)
199 | ReOp::Pow(r, _)
200 | ReOp::Loop(r, _, _)
201 if index == 0 =>
202 {
203 r
204 }
205 ReOp::Diff(r, _) if index == 0 => r,
206 ReOp::Diff(_, r) if index == 1 => r,
207 _ => panic!("Index out of bounds"),
208 }
209 }
210}
211
212impl ReNode {
213 fn new(id: ReId, op: ReOp) -> Self {
216 Self {
217 id,
218 op,
219 nullable: RefCell::new(None),
220 universal: RefCell::new(None),
221 simple: RefCell::new(None),
222 none: RefCell::new(None),
223 epsi: RefCell::new(None),
224 first: RefCell::new(None),
225 alphabet: RefCell::new(None),
226 is_constant: RefCell::new(None),
227 prefix: RefCell::new(None),
228 suffix: RefCell::new(None),
229 contains_complement: RefCell::new(None),
230 }
231 }
232
233 pub fn id(&self) -> ReId {
236 self.id
237 }
238
239 pub fn op(&self) -> &ReOp {
253 &self.op
254 }
255
256 pub fn nullable(&self) -> bool {
269 *self
270 .nullable
271 .borrow_mut()
272 .get_or_insert_with(|| self.op.nullable())
273 }
274
275 pub fn simple(&self) -> bool {
298 *self
299 .simple
300 .borrow_mut()
301 .get_or_insert_with(|| self.op.simple())
302 }
303
304 pub fn universal(&self) -> Option<bool> {
326 *self
327 .universal
328 .borrow_mut()
329 .get_or_insert_with(|| self.op.universal())
330 }
331
332 pub fn none(&self) -> Option<bool> {
353 *self.none.borrow_mut().get_or_insert_with(|| self.op.none())
354 }
355
356 pub fn epsilon(&self) -> Option<bool> {
377 *self
378 .epsi
379 .borrow_mut()
380 .get_or_insert_with(|| self.op.epsilon())
381 }
382
383 pub fn first(&self) -> Rc<AlphabetPartition> {
387 self.first
388 .borrow_mut()
389 .get_or_insert_with(|| self.op.first())
390 .clone()
391 }
392
393 pub fn alphabet(&self) -> Rc<Alphabet> {
420 self.alphabet
421 .borrow_mut()
422 .get_or_insert_with(|| self.op.alphabet())
423 .clone()
424 }
425
426 pub fn is_constant(&self) -> Option<SmtString> {
448 self.is_constant
449 .borrow_mut()
450 .get_or_insert_with(|| self.op().is_constant())
451 .clone()
452 }
453
454 pub fn prefix(&self) -> Option<SmtString> {
474 self.prefix
475 .borrow_mut()
476 .get_or_insert_with(|| self.op().prefix())
477 .clone()
478 }
479
480 pub fn suffix(&self) -> Option<SmtString> {
500 self.suffix
501 .borrow_mut()
502 .get_or_insert_with(|| self.op().suffix())
503 .clone()
504 }
505
506 pub fn contains_complement(&self) -> bool {
525 *self
526 .contains_complement
527 .borrow_mut()
528 .get_or_insert_with(|| self.op().contains_complement())
529 }
530
531 pub fn accepts(&self, w: &SmtString) -> bool {
544 let mut builder_tmp = ReBuilder::default();
545 let mnged = builder_tmp.regex(&Rc::new(self.clone()));
546 deriv::deriv_word(&mnged, w.clone(), &mut builder_tmp).nullable()
547 }
548
549 pub fn subexpr(&self) -> SubExpressions {
571 SubExpressions {
572 node: self,
573 index: 0,
574 }
575 }
576}
577
578impl Display for ReNode {
579 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
580 write!(f, "{}", self.op)
581 }
582}
583
584pub struct SubExpressions<'a> {
590 node: &'a ReNode,
591 index: usize,
592}
593
594impl<'a> Iterator for SubExpressions<'a> {
595 type Item = &'a Regex;
596
597 fn next(&mut self) -> Option<Self::Item> {
598 match self.node.op() {
599 ReOp::Literal(_) | ReOp::Range(_) | ReOp::None | ReOp::Any | ReOp::All => None,
600 ReOp::Concat(rs) | ReOp::Union(rs) | ReOp::Inter(rs) if self.index < rs.len() => {
601 let r = &rs[self.index];
602 self.index += 1;
603 Some(r)
604 }
605 ReOp::Star(r)
606 | ReOp::Plus(r)
607 | ReOp::Opt(r)
608 | ReOp::Comp(r)
609 | ReOp::Pow(r, _)
610 | ReOp::Loop(r, _, _)
611 if self.index == 0 =>
612 {
613 Some(r)
614 }
615 ReOp::Diff(r1, r2) => {
616 if self.index == 0 {
617 self.index += 1;
618 Some(r1)
619 } else if self.index == 1 {
620 self.index += 1;
621 Some(r2)
622 } else {
623 None
624 }
625 }
626 _ => None,
627 }
628 }
629}
630
631#[derive(Debug, Clone, PartialEq, Eq, Hash)]
663pub enum ReOp {
664 Literal(SmtString),
667 Range(CharRange),
669 None,
671 Any,
673 All,
675 Concat(SmallVec<[Regex; 2]>),
679 Union(SmallVec<[Regex; 2]>),
682 Inter(SmallVec<[Regex; 2]>),
685 Star(Regex),
687 Plus(Regex),
689 Opt(Regex),
691 Diff(Regex, Regex),
693 Comp(Regex),
695 Pow(Regex, u32),
697 Loop(Regex, u32, u32),
699}
700
701impl ReOp {
702 fn nullable(&self) -> bool {
704 match self {
705 ReOp::Literal(word) => word.is_empty(),
706 ReOp::Range(_) | ReOp::None | ReOp::Any => false,
707 ReOp::All | ReOp::Star(_) | ReOp::Opt(_) => true,
708 ReOp::Inter(rs) | ReOp::Concat(rs) => rs.iter().all(|r| r.nullable()),
709 ReOp::Union(rs) => rs.iter().any(|r| r.nullable()),
710 ReOp::Plus(r) => r.nullable(),
711 ReOp::Diff(r1, r2) => r1.nullable() && !r2.nullable(),
712 ReOp::Comp(r) => !r.nullable(),
713 ReOp::Pow(r, e) => *e == 0 || r.nullable(),
714 ReOp::Loop(r, l, u) => {
715 if l <= u {
716 *l == 0 || r.nullable()
717 } else {
718 false
720 }
721 }
722 }
723 }
724
725 fn universal(&self) -> Option<bool> {
727 match self {
728 ReOp::Literal(_) | ReOp::None | ReOp::Range(_) | ReOp::Any => Some(false),
729 ReOp::All => Some(true),
730 ReOp::Concat(rs) | ReOp::Inter(rs) => {
731 if rs.is_empty() {
732 return match self {
733 ReOp::Concat(_) => Some(false), ReOp::Inter(_) => Some(true), _ => unreachable!(),
736 };
737 }
738 for r in rs {
740 if !r.universal()? {
741 return Some(false);
742 }
743 }
744 Some(true)
745 }
746 ReOp::Union(rs) => {
747 if rs.is_empty() {
748 return Some(false);
749 }
750 if rs.iter().any(|r| r.universal().unwrap_or(false)) {
752 Some(true)
753 } else {
754 None
756 }
757 }
758 ReOp::Star(r) | ReOp::Plus(r) | ReOp::Opt(r) => r.universal(),
759 ReOp::Diff(r1, r2) => match (r1.universal(), r2.none()) {
760 (Some(false), _) => Some(false),
761 (Some(true), Some(true)) => Some(true),
762 (_, Some(false)) => Some(false),
763 _ => None,
764 },
765 ReOp::Comp(r) => r.none(),
766 ReOp::Pow(_, 0) => Some(false),
767 ReOp::Pow(r, _) => r.universal(),
768 ReOp::Loop(_, l, u) if l > u || *u == 0 => Some(false),
769 ReOp::Loop(r, _, _) => r.universal(),
770 }
771 }
772
773 fn none(&self) -> Option<bool> {
775 match self {
776 ReOp::None => Some(true), ReOp::Literal(_) | ReOp::Any | ReOp::All => Some(false),
778 ReOp::Range(r) => Some(r.is_empty()),
779 ReOp::Concat(rs) => rs.iter().try_fold(false, |a, r| r.none().map(|b| a || b)),
780 ReOp::Inter(rs) => {
781 if rs.iter().any(|r| r.none().unwrap_or(false)) {
782 Some(true)
783 } else {
784 None
786 }
787 }
788 ReOp::Union(rs) => rs.iter().all(|r| r.none().unwrap_or(false)).into(),
789 ReOp::Star(_) | ReOp::Opt(_) => Some(false), ReOp::Plus(r) => r.none(),
791 ReOp::Diff(r1, r2) => match (r1.none(), r2.universal()) {
792 (Some(true), _) => Some(true), (_, Some(true)) => Some(true), _ => None,
795 },
796 ReOp::Comp(r) => r.universal(), ReOp::Pow(_, 0) => Some(false), ReOp::Pow(r, _) => r.none(), ReOp::Loop(_, l, u) if l > u || *u == 0 => Some(true), ReOp::Loop(r, _, _) => r.none(), }
802 }
803
804 fn epsilon(&self) -> Option<bool> {
806 match self {
807 ReOp::None | ReOp::Any | ReOp::All | ReOp::Range(_) => Some(false),
808 ReOp::Literal(w) => Some(w.is_empty()),
809 ReOp::Union(rs) | ReOp::Concat(rs) => {
810 if rs.is_empty() {
811 return match self {
812 ReOp::Union(_) => Some(false),
813 ReOp::Concat(_) => Some(true),
814 _ => unreachable!(),
815 };
816 }
817 for r in rs {
819 if !r.epsilon()? {
820 return Some(false);
821 }
822 }
823 Some(true)
824 }
825 ReOp::Inter(rs) => {
826 if rs.is_empty() {
827 Some(false)
828 } else if rs.iter().all(|r| r.epsilon().unwrap_or(false)) {
829 Some(true)
831 } else {
832 None
834 }
835 }
836 ReOp::Plus(r) | ReOp::Star(r) | ReOp::Opt(r) => r.epsilon(),
837 ReOp::Diff(_, _) | ReOp::Comp(_) => None, ReOp::Pow(_, 0) => Some(true), ReOp::Pow(r, _) => r.epsilon(), ReOp::Loop(_, l, u) if l > u => Some(false), ReOp::Loop(_, 0, 0) => Some(true), ReOp::Loop(r, _, _) => r.epsilon(), }
844 }
845
846 fn first(&self) -> Rc<AlphabetPartition> {
849 match self {
850 ReOp::Literal(w) => {
851 if let Some(c) = w.first() {
852 Rc::new(AlphabetPartition::singleton(CharRange::singleton(c)))
853 } else {
854 Rc::new(AlphabetPartition::empty())
855 }
856 }
857 ReOp::None => Rc::new(AlphabetPartition::empty()),
858 ReOp::All | ReOp::Any => Rc::new(AlphabetPartition::singleton(CharRange::all())),
859 ReOp::Concat(rs) => {
860 let mut first = rs
861 .first()
862 .map(|r| r.first().as_ref().clone()) .unwrap_or_else(AlphabetPartition::empty); for (i, r) in rs.iter().enumerate().skip(1) {
865 if !rs[i - 1].nullable() {
866 break;
867 } else {
868 let r_first = r.first();
869 first = first.refine(&r_first);
870 }
871 }
872 Rc::new(first)
873 }
874 ReOp::Union(rs) | ReOp::Inter(rs) => {
875 let mut first = AlphabetPartition::empty();
876 for r in rs {
877 first = first.refine(&r.first());
878 }
879 Rc::new(first)
880 }
881 ReOp::Star(r) | ReOp::Plus(r) | ReOp::Opt(r) | ReOp::Comp(r) => r.first().clone(),
882 ReOp::Range(rs) => Rc::new(AlphabetPartition::singleton(*rs)),
883 ReOp::Diff(r, s) => {
884 let first = r.first().as_ref().clone();
885 Rc::new(first.refine(&s.first()))
886 }
887 ReOp::Pow(r, _) | ReOp::Loop(r, _, _) => r.first().clone(),
888 }
889 }
890
891 fn alphabet(&self) -> Rc<Alphabet> {
892 let mut alph = Alphabet::empty();
893 match self {
894 ReOp::Literal(word) => {
895 for c in word.iter() {
896 alph.insert_char(*c);
897 }
898 }
899 ReOp::Range(r) => {
900 alph.insert(*r);
901 }
902 ReOp::None | ReOp::Any | ReOp::All => {}
903 ReOp::Concat(rs) | ReOp::Union(rs) | ReOp::Inter(rs) => {
904 for r in rs {
905 alph = alph.union(r.alphabet().as_ref());
906 }
907 }
908 ReOp::Comp(r)
909 | ReOp::Star(r)
910 | ReOp::Plus(r)
911 | ReOp::Opt(r)
912 | ReOp::Pow(r, _)
913 | ReOp::Loop(r, _, _) => return r.alphabet().clone(),
914 ReOp::Diff(r1, r2) => {
915 alph = alph.union(r1.alphabet().as_ref());
916 alph = alph.union(r2.alphabet().as_ref());
917 }
918 }
919
920 Rc::new(alph)
921 }
922
923 fn is_constant(&self) -> Option<SmtString> {
924 match self {
925 ReOp::Literal(word) => Some(word.clone()),
926 ReOp::Range(r) => {
927 if r.start() == r.end() {
928 Some(SmtString::new(vec![r.start()]))
929 } else {
930 None
931 }
932 }
933 ReOp::None | ReOp::Any | ReOp::All => None,
934 ReOp::Concat(r) => {
935 let mut word = SmtString::empty();
936 for re in r {
937 if let Some(w) = re.is_constant() {
938 word = word.concat(&w);
939 } else {
940 return None;
941 }
942 }
943 Some(word)
944 }
945 ReOp::Union(rs) | ReOp::Inter(rs) => {
946 let mut words = rs.iter().map(|r| r.is_constant()).collect_vec();
947 if words.iter().all(|w| w.is_some()) {
948 let word = words.pop().unwrap().unwrap();
949 for w in words {
951 if word != w.unwrap() {
952 return None;
953 }
954 }
955 Some(word)
956 } else {
957 None
958 }
959 }
960 ReOp::Star(r) | ReOp::Opt(r) | ReOp::Plus(r) => {
961 if r.epsilon().unwrap_or(false) {
962 Some(SmtString::empty())
963 } else {
964 None
965 }
966 }
967
968 ReOp::Diff(_, _) | ReOp::Comp(_) => None, ReOp::Pow(_, 0) | ReOp::Loop(_, _, 0) => Some(SmtString::empty()),
970 ReOp::Pow(r, _) => {
971 if r.epsilon().unwrap_or(false) {
972 Some(SmtString::empty())
973 } else {
974 None
975 }
976 }
977 ReOp::Loop(r, l, u) if l <= u => {
978 if r.epsilon().unwrap_or(false) {
979 Some(SmtString::empty())
980 } else {
981 None
982 }
983 }
984 ReOp::Loop(_, _, _) => None,
985 }
986 }
987
988 fn prefix(&self) -> Option<SmtString> {
989 match self {
990 ReOp::Literal(word) => Some(word.clone()),
991 ReOp::None | ReOp::Any | ReOp::All => Some(SmtString::empty()),
992 ReOp::Range(r) => r.is_singleton().map(|c| c.into()),
993 ReOp::Concat(rs) => {
994 let mut prefix = SmtString::empty();
995 if rs.is_empty() {
996 return Some(SmtString::empty());
997 }
998 let mut i = 0;
1000 while let Some(w) = rs[i].is_constant() {
1001 prefix = prefix.concat(&w);
1002 i += 1;
1003 }
1004 if i == rs.len() {
1005 Some(prefix)
1006 } else {
1007 prefix = prefix.concat(&rs[i].prefix()?);
1008 Some(prefix)
1009 }
1010 }
1011 ReOp::Union(rs) => {
1012 let mut prefixes = Vec::with_capacity(rs.len());
1013 for r in rs {
1014 prefixes.push(r.prefix()?);
1015 }
1016 if prefixes.is_empty() {
1017 return Some(SmtString::empty());
1018 }
1019 let mut i = 0;
1021 let mut done = false;
1022 while !done {
1023 if prefixes.iter().all(|p| i < p.len()) {
1024 if !prefixes.iter().map(|p| p[i]).all_equal() {
1025 done = true;
1027 } else {
1028 i += 1;
1030 }
1031 } else {
1032 done = true;
1033 }
1034 }
1035 Some(prefixes.first().unwrap().take(i))
1036 }
1037 ReOp::Star(_) | ReOp::Opt(_) => Some(SmtString::empty()),
1038 ReOp::Plus(r) => r.prefix(),
1039 ReOp::Diff(_, _) | ReOp::Comp(_) | ReOp::Inter(_) => None, ReOp::Pow(r, _) => r.prefix(),
1041 ReOp::Loop(r, l, u) if l <= u => r.prefix(),
1042 ReOp::Loop(_, _, _) => None,
1043 }
1044 }
1045
1046 fn suffix(&self) -> Option<SmtString> {
1047 match self {
1048 ReOp::Literal(word) => Some(word.clone()),
1049 ReOp::None | ReOp::Any | ReOp::All => Some(SmtString::empty()),
1050 ReOp::Range(r) => r.is_singleton().map(|c| c.into()),
1051 ReOp::Concat(rs) => {
1052 let mut suffix = SmtString::empty();
1053 if rs.is_empty() {
1054 return Some(SmtString::empty());
1055 }
1056 let mut i = rs.len() - 1;
1058 while let Some(w) = rs[i].is_constant() {
1059 suffix = w.concat(&suffix);
1060 i -= 1;
1061 }
1062 if i == 0 {
1063 Some(suffix)
1064 } else {
1065 suffix = rs[i].suffix()?.concat(&suffix);
1066 Some(suffix)
1067 }
1068 }
1069 ReOp::Union(rs) => {
1070 let mut suffixes = Vec::with_capacity(rs.len());
1071 for r in rs {
1072 suffixes.push(r.suffix()?);
1073 }
1074 if suffixes.is_empty() {
1075 return Some(SmtString::empty());
1076 }
1077 let suffixed_revd = suffixes.iter_mut().map(|w| w.reversed()).collect_vec();
1079 let mut i = 0;
1080 let mut done = false;
1081 while !done {
1082 if suffixed_revd.iter().all(|p| i < p.len()) {
1083 if !suffixed_revd.iter().map(|p| p[i]).all_equal() {
1084 done = true;
1086 } else {
1087 i += 1;
1089 }
1090 } else {
1091 done = true;
1092 }
1093 }
1094 let lcs_rev = suffixed_revd.first().unwrap().take(i);
1095 Some(lcs_rev.reversed())
1097 }
1098 ReOp::Star(_) | ReOp::Opt(_) => Some(SmtString::empty()),
1099 ReOp::Plus(r) => r.suffix(),
1100 ReOp::Diff(_, _) | ReOp::Comp(_) | ReOp::Inter(_) => None, ReOp::Pow(r, _) => r.suffix(),
1102 ReOp::Loop(r, l, u) if l <= u => r.suffix(),
1103 ReOp::Loop(_, _, _) => None,
1104 }
1105 }
1106
1107 fn contains_complement(&self) -> bool {
1108 match self {
1109 ReOp::Literal(_) | ReOp::Range(_) | ReOp::None | ReOp::Any | ReOp::All => false,
1110 ReOp::Concat(rs) | ReOp::Union(rs) | ReOp::Inter(rs) => {
1111 rs.iter().any(|r| r.contains_complement())
1112 }
1113 ReOp::Star(r) | ReOp::Plus(r) | ReOp::Opt(r) => r.contains_complement(),
1114 ReOp::Diff(_, _) | ReOp::Comp(_) => true,
1115 ReOp::Pow(_, 0) => false,
1116 ReOp::Pow(r, _) => r.contains_complement(),
1117 ReOp::Loop(_, l, u) if l > u || *u == 0 => false,
1118 ReOp::Loop(r, _, _) => r.contains_complement(),
1119 }
1120 }
1121
1122 fn simple(&self) -> bool {
1123 match self {
1124 ReOp::Literal(_) | ReOp::Range(_) | ReOp::None | ReOp::Any | ReOp::All => true,
1125 ReOp::Diff(_, _) | ReOp::Comp(_) | ReOp::Inter(_) => false,
1126 ReOp::Concat(rs) | ReOp::Union(rs) => rs.iter().all(|r| r.simple()),
1127 ReOp::Star(r)
1128 | ReOp::Plus(r)
1129 | ReOp::Opt(r)
1130 | ReOp::Pow(r, _)
1131 | ReOp::Loop(r, _, _) => r.simple(),
1132 }
1133 }
1134}
1135
1136impl Display for ReOp {
1137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1138 match self {
1139 ReOp::Literal(w) => write!(f, "(str.to_re \"{}\")", w),
1140 ReOp::None => write!(f, "re.none"),
1141 ReOp::All => write!(f, "re.all"),
1142 ReOp::Any => write!(f, "re.allchar"),
1143 ReOp::Concat(rs) => {
1144 write!(f, "(re.++")?;
1145 for r in rs {
1146 write!(f, " {}", r)?;
1147 }
1148 write!(f, ")")
1149 }
1150 ReOp::Union(rs) => {
1151 write!(f, "(re.union")?;
1152 for r in rs.iter() {
1153 write!(f, " {}", r)?;
1154 }
1155 write!(f, ")")
1156 }
1157 ReOp::Inter(rs) => {
1158 write!(f, "(re.inter")?;
1159 for r in rs.iter() {
1160 write!(f, " {}", r)?;
1161 }
1162 write!(f, ")")
1163 }
1164 ReOp::Star(r) => write!(f, "(re.* {})", r),
1165 ReOp::Plus(p) => write!(f, "(re.+ {})", p),
1166 ReOp::Opt(r) => write!(f, "(re.opt {})", r),
1167 ReOp::Range(r) => write!(f, "(re.range \"{}\" \"{}\")", r.start(), r.end()),
1168 ReOp::Comp(c) => write!(f, "(re.comp {})", c),
1169 ReOp::Diff(r1, r2) => write!(f, "(re.diff {} {})", r1, r2),
1170 ReOp::Pow(r, n) => write!(f, "((_ re.^ {}) {})", n, r),
1171 ReOp::Loop(r, l, u) => write!(f, "((_ re.loop {} {}) {})", l, u, r),
1172 }
1173 }
1174}
1175
1176pub fn union_of_chars(re: &Regex) -> Option<Vec<CharRange>> {
1179 match re.op() {
1180 ReOp::Literal(w) if w.len() == 1 => {
1181 let c = w.first().unwrap();
1182 Some(vec![CharRange::singleton(c)])
1183 }
1184 ReOp::None => Some(vec![]),
1185 ReOp::Any => Some(vec![CharRange::all()]),
1186 ReOp::Union(rs) => {
1187 let mut ranges = vec![];
1188 for r in rs {
1189 ranges.append(&mut union_of_chars(r)?);
1190 }
1191 Some(ranges)
1192 }
1193 ReOp::Range(r) => Some(vec![*r]),
1194 _ => None,
1195 }
1196}
1197
1198impl Arbitrary for ReNode {
1199 fn arbitrary(g: &mut Gen) -> Self {
1200 use smallvec::smallvec;
1201
1202 fn gen_regex(g: &mut Gen, builder: &mut ReBuilder, depth: u8) -> Regex {
1203 fn base_case(g: &mut Gen, n: usize, builder: &mut ReBuilder) -> Regex {
1204 match n {
1205 0 => builder.epsilon(),
1206 1 => builder.none(),
1207 2 => builder.allchar(),
1208 3 => builder.to_re(SmtString::arbitrary(g)),
1209 4 => builder.range(CharRange::arbitrary(g)),
1210 _ => unreachable!(),
1211 }
1212 }
1213 let choice = usize::arbitrary(g) % if depth == 0 { 5 } else { 15 };
1214
1215 match choice {
1216 n if n < 5 => base_case(g, n, builder),
1217 5 => {
1218 let inner = gen_regex(g, builder, depth - 1);
1219 builder.star(inner)
1220 }
1221 6 => {
1222 let inner = gen_regex(g, builder, depth - 1);
1223 builder.plus(inner)
1224 }
1225 7 => {
1226 let inner = gen_regex(g, builder, depth - 1);
1227 builder.opt(inner)
1228 }
1229 8 => {
1230 let inner = gen_regex(g, builder, depth - 1);
1231 builder.comp(inner)
1232 }
1233 9 => {
1234 let left = gen_regex(g, builder, depth - 1);
1235 let right = gen_regex(g, builder, depth - 1);
1236 builder.concat(smallvec![left, right])
1237 }
1238 10 => {
1239 let left = gen_regex(g, builder, depth - 1);
1240 let right = gen_regex(g, builder, depth - 1);
1241 builder.union(smallvec![left, right])
1242 }
1243 11 => {
1244 let left = gen_regex(g, builder, depth - 1);
1245 let right = gen_regex(g, builder, depth - 1);
1246 builder.inter(smallvec![left, right])
1247 }
1248 12 => {
1249 let left = gen_regex(g, builder, depth - 1);
1250 let right = gen_regex(g, builder, depth - 1);
1251 builder.diff(left, right)
1252 }
1253 13 => {
1254 let inner = gen_regex(g, builder, depth - 1);
1255 let count = u32::arbitrary(g) % 5;
1256 builder.pow(inner, count)
1257 }
1258 14 => {
1259 let inner = gen_regex(g, builder, depth - 1);
1260 let lo = u32::arbitrary(g) % 4;
1261 let hi = lo + (u32::arbitrary(g) % 4);
1262 builder.loop_(inner, lo, hi)
1263 }
1264 _ => unreachable!(),
1265 }
1266 }
1267
1268 let mut builder = ReBuilder::default();
1269 let depth = g.size().min(5) as u8;
1270 gen_regex(g, &mut builder, depth).as_ref().clone()
1271 }
1272}
1273
1274#[cfg(test)]
1275mod tests {
1276 use crate::re::ReBuilder;
1277
1278 use super::*;
1279
1280 use quickcheck_macros::quickcheck;
1281 use smallvec::smallvec;
1282
1283 #[test]
1284 fn test_union_of_ranges_const() {
1285 let mut builder = ReBuilder::non_optimizing();
1286 let re = builder.to_re("a".into());
1287 let result = union_of_chars(&re);
1288 assert_eq!(result, Some(vec![CharRange::singleton('a')]));
1289 }
1290
1291 #[test]
1292 fn test_union_of_ranges_const_word() {
1293 let mut builder = ReBuilder::non_optimizing();
1294 let re = builder.to_re("abc".into());
1295 let result = union_of_chars(&re);
1296 assert_eq!(result, None);
1297 }
1298
1299 #[test]
1300 fn test_union_of_ranges_none() {
1301 let builder = ReBuilder::non_optimizing();
1302 let re = builder.none();
1303 let result = union_of_chars(&re);
1304 assert_eq!(result, Some(vec![]));
1305 }
1306
1307 #[test]
1308 fn test_union_of_ranges_all_char() {
1309 let builder = ReBuilder::non_optimizing();
1310 let re = builder.allchar();
1311 let result = union_of_chars(&re);
1312 assert_eq!(result, Some(vec![CharRange::all()]));
1313 }
1314
1315 #[test]
1316 fn test_union_of_ranges_union() {
1317 let mut builder = ReBuilder::non_optimizing();
1318 let alternatives = smallvec![
1319 builder.to_re("a".into()),
1320 builder.to_re("b".into()),
1321 builder.to_re("c".into()),
1322 ];
1323 let reg = builder.union(alternatives);
1324 let result = union_of_chars(®);
1325 assert_eq!(
1326 result,
1327 Some(vec![
1328 CharRange::singleton('a'),
1329 CharRange::singleton('b'),
1330 CharRange::singleton('c')
1331 ])
1332 );
1333 }
1334
1335 #[test]
1336 fn test_union_of_ranges_range() {
1337 let mut builder = ReBuilder::non_optimizing();
1338 let re = builder.range_from_to('a', 'z');
1339 let result = union_of_chars(&re);
1340 assert_eq!(result, Some(vec![CharRange::new('a', 'z')]));
1341 }
1342
1343 #[quickcheck]
1346 fn nullable_literal(s: SmtString) {
1347 let mut builder = ReBuilder::non_optimizing();
1348 let epsi = builder.to_re(s.clone());
1349 if s.is_empty() {
1350 assert!(epsi.nullable());
1351 } else {
1352 assert!(!epsi.nullable());
1353 }
1354 }
1355
1356 #[quickcheck]
1357 fn nullable_range(r: CharRange) {
1358 let mut builder = ReBuilder::non_optimizing();
1359 let r = builder.range(r);
1360 assert!(!r.nullable());
1361 }
1362
1363 #[test]
1364 fn nullable_base_cases() {
1365 let builder = ReBuilder::non_optimizing();
1366 assert!(!builder.none().nullable());
1367 assert!(!builder.allchar().nullable());
1368 assert!(builder.epsilon().nullable());
1369 assert!(builder.all().nullable());
1370 }
1371
1372 #[quickcheck]
1373 fn nullable_star(r: ReNode) {
1374 let mut builder = ReBuilder::non_optimizing();
1375 let r = builder.regex(&Rc::new(r));
1376 let star = builder.star(r);
1377 assert!(star.nullable());
1378 }
1379
1380 #[quickcheck]
1381 fn nullable_opt(r: ReNode) {
1382 let mut builder = ReBuilder::non_optimizing();
1383 let r = builder.regex(&Rc::new(r));
1384 let opt = builder.opt(r);
1385 assert!(opt.nullable());
1386 }
1387
1388 #[quickcheck]
1389 fn nullable_concat(rs: Vec<ReNode>) {
1390 let mut builder = ReBuilder::non_optimizing();
1391 let rs: SmallVec<_> = rs.into_iter().map(|r| builder.regex(&Rc::new(r))).collect();
1392 let concat = builder.concat(rs.clone());
1393 if rs.iter().all(|r| r.nullable()) {
1394 assert!(concat.nullable());
1395 } else {
1396 assert!(!concat.nullable());
1397 }
1398 }
1399
1400 #[test]
1401 fn nullable_concat_all_parts_nullable() {
1402 let mut builder = ReBuilder::non_optimizing();
1403 let epsi = builder.epsilon();
1404 let a = builder.to_re("a".into());
1405
1406 let r1 = builder.concat(smallvec![epsi.clone(), epsi.clone()]);
1407 assert!(r1.nullable());
1408
1409 let r2 = builder.concat(smallvec![epsi, a]);
1410 assert!(!r2.nullable());
1411 }
1412
1413 #[test]
1414 fn nullable_inter_all_parts_nullable() {
1415 let mut builder = ReBuilder::non_optimizing();
1416 let epsi = builder.epsilon();
1417 let also_epsi = builder.to_re("".into());
1418
1419 let r1 = builder.inter(smallvec![epsi.clone(), also_epsi.clone()]);
1420 assert!(r1.nullable());
1421
1422 let a = builder.to_re("a".into());
1423 let r2 = builder.inter(smallvec![epsi, a]);
1424 assert!(!r2.nullable());
1425 }
1426
1427 #[quickcheck]
1428 fn nullable_inter(rs: Vec<ReNode>) {
1429 let mut builder = ReBuilder::non_optimizing();
1430 let rs: SmallVec<_> = rs.into_iter().map(|r| builder.regex(&Rc::new(r))).collect();
1431 let inter = builder.inter(rs.clone());
1432 if rs.iter().all(|r| r.nullable()) {
1433 assert!(inter.nullable());
1434 } else {
1435 assert!(!inter.nullable());
1436 }
1437 }
1438
1439 #[quickcheck]
1440 fn nullable_union(rs: Vec<ReNode>) {
1441 let mut builder = ReBuilder::non_optimizing();
1442 let rs: SmallVec<_> = rs.into_iter().map(|r| builder.regex(&Rc::new(r))).collect();
1443 let union = builder.union(rs.clone());
1444 if rs.iter().any(|r| r.nullable()) {
1445 assert!(union.nullable());
1446 } else {
1447 assert!(!union.nullable());
1448 }
1449 }
1450
1451 #[quickcheck]
1452 fn nullable_plus(r: ReNode) {
1453 let mut builder = ReBuilder::non_optimizing();
1454 let r = builder.regex(&Rc::new(r));
1455 let plus = builder.plus(r.clone());
1456 if r.nullable() {
1457 assert!(plus.nullable());
1458 } else {
1459 assert!(!plus.nullable());
1460 }
1461 }
1462
1463 #[quickcheck]
1464 fn nullable_diff(l: ReNode, r: ReNode) {
1465 let mut builder = ReBuilder::non_optimizing();
1466 let l = builder.regex(&Rc::new(l));
1467 let r = builder.regex(&Rc::new(r));
1468 let diff = builder.diff(l.clone(), r.clone());
1469
1470 if l.nullable() && !r.nullable() {
1471 assert!(diff.nullable());
1472 } else {
1473 assert!(!diff.nullable());
1474 }
1475 }
1476
1477 #[quickcheck]
1478 fn nullable_comp(r: ReNode) {
1479 let mut builder = ReBuilder::non_optimizing();
1480 let r = builder.regex(&Rc::new(r));
1481 let comp = builder.comp(r.clone());
1482 if !r.nullable() {
1483 assert!(comp.nullable());
1484 } else {
1485 assert!(!comp.nullable());
1486 }
1487 }
1488
1489 #[quickcheck]
1490 fn nullable_pow(r: ReNode, e: u32) {
1491 let mut builder = ReBuilder::non_optimizing();
1492 let r = builder.regex(&Rc::new(r));
1493 let pow = builder.pow(r.clone(), e);
1494
1495 if e == 0 || r.nullable() {
1496 assert!(pow.nullable());
1497 } else {
1498 assert!(!pow.nullable());
1499 }
1500 }
1501
1502 #[quickcheck]
1503 fn nullable_loop(r: ReNode, l: u32, u: u32) {
1504 let mut builder = ReBuilder::non_optimizing();
1505 let r = builder.regex(&Rc::new(r));
1506 let loop_ = builder.loop_(r.clone(), l, u);
1507
1508 if l <= u {
1509 if l == 0 || r.nullable() {
1510 assert!(loop_.nullable());
1511 } else {
1512 assert!(!loop_.nullable());
1513 }
1514 } else {
1515 assert!(!loop_.nullable());
1516 }
1517 }
1518
1519 #[quickcheck]
1522 fn epsilon_literal(s: SmtString) {
1523 let mut builder = ReBuilder::non_optimizing();
1524 let lit = builder.to_re(s.clone());
1525 assert_eq!(lit.epsilon(), Some(s.is_empty()));
1526 }
1527
1528 #[quickcheck]
1529 fn epsilon_range(r: CharRange) {
1530 let mut builder = ReBuilder::non_optimizing();
1531 let r = builder.range(r);
1532 assert_eq!(r.epsilon(), Some(false));
1533 }
1534
1535 #[test]
1536 fn epsilon_base_cases() {
1537 let builder = ReBuilder::non_optimizing();
1538 assert_eq!(builder.none().epsilon(), Some(false));
1539 assert_eq!(builder.allchar().epsilon(), Some(false));
1540 assert_eq!(builder.all().epsilon(), Some(false));
1541 assert_eq!(builder.epsilon().epsilon(), Some(true));
1542 }
1543
1544 #[quickcheck]
1545 fn epsilon_star(r: ReNode) {
1546 let mut builder = ReBuilder::non_optimizing();
1547 let r = builder.regex(&Rc::new(r));
1548 let star = builder.star(r.clone());
1549 assert_eq!(star.epsilon(), r.epsilon());
1550 }
1551
1552 #[quickcheck]
1553 fn epsilon_opt(r: ReNode) {
1554 let mut builder = ReBuilder::non_optimizing();
1555 let r = builder.regex(&Rc::new(r));
1556 let opt = builder.opt(r.clone());
1557 assert_eq!(opt.epsilon(), r.epsilon());
1558 }
1559
1560 #[test]
1561 fn epsi_concat_bug() {
1562 let mut builder = ReBuilder::non_optimizing();
1563 let inner = smallvec![builder.none()];
1564 let concat = builder.concat(inner);
1565 assert_eq!(concat.epsilon(), Some(false));
1566 }
1567
1568 #[quickcheck]
1569 fn epsilon_concat(rs: Vec<ReNode>) {
1570 let mut builder = ReBuilder::non_optimizing();
1571 let rs: SmallVec<_> = rs.into_iter().map(|r| builder.regex(&Rc::new(r))).collect();
1572 let concat = builder.concat(rs.clone());
1573
1574 let mut expected = Some(true);
1575 for r in rs {
1576 match r.epsilon() {
1577 Some(true) => {}
1578 Some(false) => {
1579 expected = Some(false);
1581 break;
1582 }
1583 None => {
1584 expected = None;
1586 break;
1587 }
1588 }
1589 }
1590 assert_eq!(concat.epsilon(), expected);
1591 }
1592
1593 #[quickcheck]
1594 fn epsilon_inter(rs: Vec<ReNode>) {
1595 let mut builder = ReBuilder::non_optimizing();
1596 let rs: SmallVec<_> = rs.into_iter().map(|r| builder.regex(&Rc::new(r))).collect();
1597 let inter = builder.inter(rs.clone());
1598
1599 let mut expected = Some(!rs.is_empty());
1600 for r in rs {
1601 match r.epsilon() {
1602 Some(false) | None => {
1603 expected = None;
1605 break;
1606 }
1607 _ => {}
1608 }
1609 }
1610 assert_eq!(inter.epsilon(), expected);
1611 }
1612
1613 #[quickcheck]
1614 fn epsilon_union(rs: Vec<ReNode>) {
1615 let mut builder = ReBuilder::non_optimizing();
1616 let rs: SmallVec<_> = rs.into_iter().map(|r| builder.regex(&Rc::new(r))).collect();
1617 let union = builder.union(rs.clone());
1618
1619 let mut expected = Some(!rs.is_empty());
1620 for r in rs {
1621 match r.epsilon() {
1622 Some(true) => {}
1623 Some(false) => {
1624 expected = Some(false);
1626 break;
1627 }
1628 None => {
1629 expected = None;
1631 break;
1632 }
1633 }
1634 }
1635
1636 assert_eq!(union.epsilon(), expected);
1637 }
1638
1639 #[quickcheck]
1640 fn epsilon_plus(r: ReNode) {
1641 let mut builder = ReBuilder::non_optimizing();
1642 let r = builder.regex(&Rc::new(r));
1643 let plus = builder.plus(r.clone());
1644 assert_eq!(plus.epsilon(), r.epsilon());
1645 }
1646
1647 #[quickcheck]
1648 fn epsilon_diff(r1: ReNode, r2: ReNode) {
1649 let mut builder = ReBuilder::non_optimizing();
1650 let r1 = builder.regex(&Rc::new(r1));
1651 let r2 = builder.regex(&Rc::new(r2));
1652 let diff = builder.diff(r1, r2);
1653
1654 assert_eq!(diff.epsilon(), None);
1656 }
1657
1658 #[quickcheck]
1659 fn epsilon_comp(r: ReNode) {
1660 let mut builder = ReBuilder::non_optimizing();
1661 let r = builder.regex(&Rc::new(r));
1662 let comp = builder.comp(r);
1663 assert_eq!(comp.epsilon(), None);
1664 }
1665
1666 #[quickcheck]
1667 fn epsilon_pow(r: ReNode, e: u32) {
1668 let mut builder = ReBuilder::non_optimizing();
1669 let r = builder.regex(&Rc::new(r));
1670 let pow = builder.pow(r.clone(), e);
1671
1672 let expected = if e == 0 { Some(true) } else { r.epsilon() };
1673 assert_eq!(pow.epsilon(), expected);
1674 }
1675
1676 #[quickcheck]
1677 fn epsilon_loop(r: ReNode, l: u32, u: u32) {
1678 let mut builder = ReBuilder::non_optimizing();
1679 let r = builder.regex(&Rc::new(r));
1680 let loop_ = builder.loop_(r.clone(), l, u);
1681
1682 let expected = if l > u {
1683 Some(false)
1684 } else if u == 0 {
1685 Some(true)
1686 } else {
1687 r.epsilon()
1688 };
1689 assert_eq!(loop_.epsilon(), expected);
1690 }
1691
1692 #[quickcheck]
1695 fn universal_literal(s: SmtString) {
1696 let mut builder = ReBuilder::non_optimizing();
1697 let lit = builder.to_re(s.clone());
1698 assert_eq!(lit.universal(), Some(false));
1699 }
1700
1701 #[quickcheck]
1702 fn universal_range(r: CharRange) {
1703 let mut builder = ReBuilder::non_optimizing();
1704 let r = builder.range(r);
1705 assert_eq!(r.universal(), Some(false));
1706 }
1707
1708 #[test]
1709 fn universal_base_cases() {
1710 let builder = ReBuilder::non_optimizing();
1711 assert_eq!(builder.none().universal(), Some(false));
1712 assert_eq!(builder.allchar().universal(), Some(false));
1713 assert_eq!(builder.all().universal(), Some(true));
1714 assert_eq!(builder.epsilon().universal(), Some(false));
1715 }
1716
1717 #[quickcheck]
1718 fn universal_star(r: ReNode) {
1719 let mut builder = ReBuilder::non_optimizing();
1720 let r = builder.regex(&Rc::new(r));
1721 let star = builder.star(r.clone());
1722 assert_eq!(star.universal(), r.universal());
1723 }
1724
1725 #[quickcheck]
1726 fn universal_opt(r: ReNode) {
1727 let mut builder = ReBuilder::non_optimizing();
1728 let r = builder.regex(&Rc::new(r));
1729 let opt = builder.opt(r.clone());
1730 assert_eq!(opt.universal(), r.universal());
1731 }
1732
1733 #[quickcheck]
1734 fn universal_concat(rs: Vec<ReNode>) {
1735 let mut builder = ReBuilder::non_optimizing();
1736 let rs: SmallVec<_> = rs.into_iter().map(|r| builder.regex(&Rc::new(r))).collect();
1737 let concat = builder.concat(rs.clone());
1738
1739 let mut expected = Some(false);
1740 for r in rs {
1741 match r.universal() {
1742 Some(true) => {
1743 expected = Some(true);
1744 }
1745 Some(false) => {
1746 expected = Some(false);
1748 break;
1749 }
1750 None => {
1751 expected = None;
1753 break;
1754 }
1755 }
1756 }
1757 assert_eq!(concat.universal(), expected);
1758 }
1759
1760 #[quickcheck]
1761 fn universal_inter(rs: Vec<ReNode>) {
1762 let mut builder = ReBuilder::non_optimizing();
1763 let rs: SmallVec<_> = rs.into_iter().map(|r| builder.regex(&Rc::new(r))).collect();
1764 let inter = builder.inter(rs.clone());
1765
1766 let mut expected = Some(rs.is_empty());
1767 for r in rs {
1768 match r.universal() {
1769 Some(true) => {}
1770 Some(false) => {
1771 expected = Some(false);
1773 break;
1774 }
1775 None => {
1776 expected = None;
1778 break;
1779 }
1780 }
1781 }
1782 assert_eq!(inter.universal(), expected);
1783 }
1784
1785 #[quickcheck]
1786 fn universal_union(rs: Vec<ReNode>) {
1787 let mut builder = ReBuilder::non_optimizing();
1788 let rs: SmallVec<_> = rs.into_iter().map(|r| builder.regex(&Rc::new(r))).collect();
1789 let union = builder.union(rs.clone());
1790
1791 let mut expected = if rs.is_empty() { Some(false) } else { None };
1792 for r in rs {
1793 if let Some(true) = r.universal() {
1794 expected = Some(true);
1795 break;
1796 }
1797 }
1798 assert_eq!(union.universal(), expected);
1799 }
1800
1801 #[quickcheck]
1802 fn universal_plus(r: ReNode) {
1803 let mut builder = ReBuilder::non_optimizing();
1804 let r = builder.regex(&Rc::new(r));
1805 let plus = builder.plus(r.clone());
1806 assert_eq!(plus.universal(), r.universal());
1807 }
1808
1809 #[quickcheck]
1810 fn universal_diff(r1: ReNode, r2: ReNode) {
1811 let mut builder = ReBuilder::non_optimizing();
1812 let r1 = builder.regex(&Rc::new(r1));
1813 let r2 = builder.regex(&Rc::new(r2));
1814 let diff = builder.diff(r1.clone(), r2.clone());
1815
1816 let expected = match (r1.universal(), r2.none()) {
1818 (Some(false), _) => Some(false), (Some(true), Some(true)) => Some(true), (_, Some(false)) => Some(false), _ => None,
1822 };
1823 assert_eq!(diff.universal(), expected);
1824 }
1825
1826 #[quickcheck]
1827 fn universal_comp(r: ReNode) {
1828 let mut builder = ReBuilder::non_optimizing();
1829 let r = builder.regex(&Rc::new(r));
1830 let comp = builder.comp(r.clone());
1831 if let Some(true) = r.none() {
1832 assert_eq!(comp.universal(), Some(true));
1833 }
1834 }
1835
1836 #[quickcheck]
1837 fn universal_pow(r: ReNode, e: u32) {
1838 let e = e % 20;
1839 let mut builder = ReBuilder::non_optimizing();
1840 let r = builder.regex(&Rc::new(r));
1841 let pow = builder.pow(r.clone(), e);
1842
1843 if r.universal().unwrap_or(false) {
1844 if e == 0 {
1845 assert_eq!(pow.universal(), Some(false));
1846 } else {
1847 assert_eq!(pow.universal(), Some(true));
1848 }
1849 }
1850 }
1851
1852 #[quickcheck]
1853 fn universal_loop(r: ReNode, l: u32, u: u32) {
1854 let mut builder = ReBuilder::non_optimizing();
1855 let r = builder.regex(&Rc::new(r));
1856 let loop_ = builder.loop_(r.clone(), l, u);
1857 if l > u {
1858 assert_eq!(loop_.universal(), Some(false));
1859 } else if r.universal().unwrap_or(false) {
1860 if u == 0 {
1861 assert_eq!(loop_.universal(), Some(false));
1862 } else {
1863 assert_eq!(loop_.universal(), Some(true));
1864 }
1865 }
1866 }
1867
1868 #[test]
1869 fn test_accept() {
1870 let mut builder = ReBuilder::non_optimizing();
1872 let x = builder.to_re("x".into());
1873 let e = builder.to_re("e".into());
1874 let d = builder.to_re("d".into());
1875 let union = builder.union(smallvec![e.clone(), d.clone()]);
1876 let looped = builder.loop_(union.clone(), 4, 4);
1877 let re = builder.concat(smallvec![x.clone(), looped.clone(), x.clone()]);
1878
1879 assert!(
1880 re.accepts(&SmtString::from("xededx")),
1881 "Expected xededx to be accepted by {}",
1882 re
1883 );
1884 }
1885
1886 #[test]
1887 fn test_is_const_none() {
1888 let builder = ReBuilder::non_optimizing();
1889 let none = builder.none();
1890 let result = none.is_constant();
1891 assert_eq!(result, None);
1892 }
1893
1894 #[test]
1895 fn test_is_const_all() {
1896 let builder = ReBuilder::non_optimizing();
1897 let all = builder.all();
1898 let result = all.is_constant();
1899 assert_eq!(result, None);
1900 }
1901
1902 #[test]
1903 fn test_is_const_allchar() {
1904 let builder = ReBuilder::non_optimizing();
1905 let any = builder.allchar();
1906 let result = any.is_constant();
1907 assert_eq!(result, None);
1908 }
1909
1910 #[test]
1911 fn test_is_const_concat_consts() {
1912 let mut builder = ReBuilder::non_optimizing();
1913 let a = builder.to_re("a".into());
1914 let b = builder.to_re("b".into());
1915 let c = builder.to_re("c".into());
1916 let abc = builder.concat(smallvec![a.clone(), b.clone(), c.clone()]);
1917 let result = abc.is_constant();
1918 assert_eq!(result, Some(SmtString::from("abc")));
1919 }
1920
1921 #[test]
1922 fn test_is_const_const() {
1923 let mut builder = ReBuilder::non_optimizing();
1924 let abc = builder.to_re("abc".into());
1925
1926 let result = abc.is_constant();
1927 assert_eq!(result, Some(SmtString::from("abc")));
1928 }
1929
1930 #[test]
1931 fn test_is_const_union() {
1932 let mut builder = ReBuilder::non_optimizing();
1933 let abc = builder.to_re("abc".into());
1934 let def = builder.to_re("def".into());
1935
1936 let equal_union = builder.union(smallvec![abc.clone(), abc.clone()]);
1937 let different_union = builder.union(smallvec![abc.clone(), def.clone()]);
1938 assert_eq!(equal_union.is_constant(), Some(SmtString::from("abc")));
1939 assert_eq!(different_union.is_constant(), None);
1940 }
1941
1942 #[test]
1943 fn test_is_const_inter() {
1944 let mut builder = ReBuilder::non_optimizing();
1945 let abc = builder.to_re("abc".into());
1946 let def = builder.to_re("def".into());
1947
1948 let equal_union = builder.inter(smallvec![abc.clone(), abc.clone()]);
1949 let different_union = builder.inter(smallvec![abc.clone(), def.clone()]);
1950 assert_eq!(equal_union.is_constant(), Some(SmtString::from("abc")));
1951 assert_eq!(different_union.is_constant(), None);
1952 }
1953
1954 #[test]
1955 fn test_is_const_star() {
1956 let mut builder = ReBuilder::non_optimizing();
1957 let epsi = builder.to_re("".into());
1958 let a = builder.to_re("a".into());
1959 let star_a = builder.star(a.clone());
1960 let star_epsi = builder.star(epsi.clone());
1961 assert_eq!(star_a.is_constant(), None);
1962 assert_eq!(star_epsi.is_constant(), Some(SmtString::empty()));
1963 }
1964
1965 #[test]
1966 fn test_is_const_plus() {
1967 let mut builder = ReBuilder::non_optimizing();
1968 let epsi = builder.to_re("".into());
1969 let a = builder.to_re("a".into());
1970 let plus_a = builder.plus(a.clone());
1971 let plus_epsi = builder.plus(epsi.clone());
1972 assert_eq!(plus_a.is_constant(), None);
1973 assert_eq!(plus_epsi.is_constant(), Some(SmtString::empty()));
1974 }
1975
1976 #[test]
1977 fn test_is_const_opt() {
1978 let mut builder = ReBuilder::non_optimizing();
1979 let epsi = builder.to_re("".into());
1980 let a = builder.to_re("a".into());
1981 let opt_a = builder.opt(a.clone());
1982 let opt_epsi = builder.opt(epsi.clone());
1983 assert_eq!(opt_a.is_constant(), None);
1984 assert_eq!(opt_epsi.is_constant(), Some(SmtString::empty()));
1985 }
1986
1987 #[test]
1988 fn test_is_const_range() {
1989 let mut builder = ReBuilder::non_optimizing();
1990 let a = builder.range_from_to('a', 'a');
1991 let ab = builder.range_from_to('a', 'b');
1992 assert_eq!(a.is_constant(), Some(SmtString::from("a")));
1993 assert_eq!(ab.is_constant(), None);
1994 }
1995
1996 #[test]
1997 fn prefix_bug() {
1998 let mut builder = ReBuilder::non_optimizing();
2000 let x = builder.to_re("x".into());
2001 let e = builder.to_re("e".into());
2002 let d = builder.to_re("d".into());
2003 let union = builder.union(smallvec![e.clone(), d.clone()]);
2004 let pow = builder.pow(union.clone(), 4);
2005 let re = builder.concat(smallvec![x.clone(), pow.clone(), x.clone()]);
2006 let prefix = re.prefix();
2007 assert_eq!(prefix, Some(SmtString::from("x")));
2008 }
2009
2010 #[test]
2011 fn prefix_suf() {
2012 let mut builder = ReBuilder::non_optimizing();
2014 let x = builder.to_re("x".into());
2015 let e = builder.to_re("e".into());
2016 let d = builder.to_re("d".into());
2017 let union = builder.union(smallvec![e.clone(), d.clone()]);
2018 let pow = builder.pow(union.clone(), 4);
2019 let re = builder.concat(smallvec![x.clone(), pow.clone(), x.clone()]);
2020 let prefix = re.suffix();
2021 assert_eq!(prefix, Some(SmtString::from("x")));
2022 }
2023}