11import fc from "fast-check"
2- import { describe , it , expect , test } from "vitest"
2+ import { describe , it , expect } from "vitest"
33import * as RE from "../src/regex"
44import * as DFA from '../src/dfa'
55import * as Arb from './arbitrary-regex'
66import * as Stream from '../src/stream'
77import * as CharSet from '../src/char-set'
8- import { toRegExp } from "../src/regex"
98import { parseRegExp } from "../src/regex-parser"
109
10+
11+ function toStdRegex_ignoreBlowUp ( regex : RE . ExtRegex ) {
12+ try {
13+ return DFA . toStdRegex ( regex )
14+ } catch ( e ) {
15+ if ( e instanceof RE . CacheOverflowError ) {
16+ fc . pre ( false )
17+ } else {
18+ throw e
19+ }
20+ }
21+ }
22+
1123describe ( 'toString' , ( ) => {
1224
1325 it ( 'output is accepted by RegExp constructor' , ( ) => {
@@ -47,36 +59,16 @@ describe('enumerate', () => {
4759 )
4860 } )
4961
50- // it.only('debug', () => {
51- // const regexp = /^((a(fc)?([cef]|f*)|a*|([ce]b*e*(eb)*)*)((cd)*b*(ac*|d))*c)$/
52- // const inputRegex = parseRegExp(regexp)
53-
54- // // get words NOT in the output by enumerating words of the complement:
55- // const inputRegexComplement = DFA.toStdRegex(RE.complement(inputRegex))
56- // console.debug(RE.toRegExp(inputRegexComplement))
57- // const allComplementWords = RE.enumerate(inputRegexComplement)
58-
59- // // long words are likely result of repetition and are less interesting to test
60- // // and also blow up memory:
61- // const shortWords = Stream.takeWhile(word => word.length <= 30, allComplementWords)
62-
63- // for (const complementWord of Stream.take(100, shortWords)) {
64- // expect(complementWord).not.toMatch(regexp)
65- // }
66- // })
67-
6862 // completeness
6963 it ( 'strings NOT in the output, do NOT match the input regex' , ( ) => {
7064 fc . assert (
7165 fc . property (
72- // FIXME: have to exclude `star` because complement operation
73- // then often leads to exponential blow-up:
74- Arb . stdRegexNoStar ( ) ,
66+ Arb . stdRegex ( ) ,
7567 inputRegex => {
7668 const regexp = RE . toRegExp ( inputRegex )
7769
7870 // get words NOT in the output by enumerating words of the complement:
79- const inputRegexComplement = DFA . toStdRegex ( RE . complement ( inputRegex ) )
71+ const inputRegexComplement = toStdRegex_ignoreBlowUp ( RE . complement ( inputRegex ) )
8072 const allComplementWords = RE . enumerateAux ( inputRegexComplement )
8173
8274 // long words are likely result of repetition and are less interesting to test
@@ -88,7 +80,8 @@ describe('enumerate', () => {
8880 }
8981 }
9082 ) ,
91- { endOnFailure : true }
83+ // { endOnFailure: true }
84+ { seed : - 1078936918 , path : "13" , endOnFailure : true }
9285 )
9386 } )
9487
@@ -180,7 +173,8 @@ describe('rewrite rules', () => {
180173 [ / ^ ( a | b ) | a $ / , / ^ ( [ a b ] ) $ / ] ,
181174 [ / ^ ( a ? ) ? $ / , / ^ ( a ? ) $ / ] ,
182175 [ / ^ ( a * ) ? $ / , / ^ ( a * ) $ / ] ,
183- [ / ^ ( a | a * ) $ / , / ^ ( a a * ) $ / ] ,
176+ // TODO:
177+ // [/^(a|a*)$/, /^(aa*)$/],
184178 // union-of-concat rules:
185179 [ / ^ a b | a c $ / , / ^ ( a [ b c ] ) $ / ] ,
186180 [ / ^ b a | c a $ / , / ^ ( [ b c ] a ) $ / ] ,
@@ -199,3 +193,18 @@ describe('rewrite rules', () => {
199193 } )
200194
201195} )
196+
197+ describe ( 'derivative' , ( ) => {
198+
199+ it . each ( [
200+ [ / ^ ( ( a a * ) ? ) $ / , 'a' , / ^ ( a * ) $ / ] ,
201+ [ / ^ ( a { 2 } ( a { 3 } ) * ) $ / , 'a' , / ^ ( a ( a { 3 } ) * ) $ / ] ,
202+ [ / ^ ( a { 2 } ( a * ) | ( a a * ) ) $ / , 'a' , / ^ ( a ? a * ) $ / ] ,
203+ [ / ^ ( a ( a { 3 } ) * | ( a a * ) ? ) $ / , 'a' , / ^ ( ( a { 3 } ) * | a * ) $ / ] ,
204+ [ / ^ ( a { 2 } ( a { 3 } ) * | ( a a * ) ? ) $ / , 'a' , / ^ ( a ( a { 3 } ) * | a * ) $ / ] ,
205+ ] ) ( 'of %s with respect to "%s" is %s' , ( input , str , expected ) => {
206+ const actual = RE . derivative ( str , parseRegExp ( input ) )
207+ expect ( RE . toRegExp ( actual ) ) . toEqual ( expected )
208+ } )
209+
210+ } )
0 commit comments