@@ -6,7 +6,7 @@ import * as Table from './table';
6
6
/**
7
7
* TODO
8
8
*/
9
- type StdRegexWithoutHash = (
9
+ type StdRegexWithoutMetaInfo = (
10
10
| { type : "epsilon" }
11
11
| { type : "literal" , charset : CharSet . CharSet }
12
12
| { type : "concat" , left : StdRegex , right : StdRegex }
@@ -17,7 +17,7 @@ type StdRegexWithoutHash = (
17
17
/**
18
18
* TODO
19
19
*/
20
- type ExtRegexWithoutHash = (
20
+ type ExtRegexWithoutMetaInfo = (
21
21
| { type : "epsilon" }
22
22
| { type : "literal" , charset : CharSet . CharSet }
23
23
| { type : "concat" , left : ExtRegex , right : ExtRegex }
@@ -31,40 +31,81 @@ type ExtRegexWithoutHash = (
31
31
/**
32
32
* TODO: docs
33
33
*/
34
- export type StdRegex = StdRegexWithoutHash & { hash : number }
34
+ export type StdRegex = StdRegexWithoutMetaInfo & { hash : number , isStdRegex : true }
35
35
36
36
/**
37
37
* TODO: docs
38
38
*/
39
- export type ExtRegex = ExtRegexWithoutHash & { hash : number }
39
+ export type ExtRegex = ExtRegexWithoutMetaInfo & { hash : number , isStdRegex : boolean }
40
40
41
- export function withHash ( regex : StdRegexWithoutHash ) : StdRegex
42
- export function withHash ( regex : ExtRegexWithoutHash ) : ExtRegex
43
- export function withHash ( regex : ExtRegexWithoutHash ) : ExtRegex {
41
+ export function withMetaInfo ( regex : StdRegexWithoutMetaInfo ) : StdRegex
42
+ export function withMetaInfo ( regex : ExtRegexWithoutMetaInfo ) : ExtRegex
43
+ export function withMetaInfo ( regex : ExtRegexWithoutMetaInfo ) : ExtRegex {
44
44
if ( regex . type === 'epsilon' )
45
- return { ...regex , hash : hashStr ( regex . type ) }
45
+ return {
46
+ ...regex ,
47
+ hash : hashStr ( regex . type ) ,
48
+ isStdRegex : true ,
49
+ }
46
50
else if ( regex . type === 'literal' )
47
- return { ...regex , hash : hashNums ( [ hashStr ( regex . type ) , regex . charset . hash ] ) }
48
- else if ( regex . type === 'concat' || regex . type === 'union' || regex . type === 'intersection' )
49
- return { ...regex , hash : hashNums ( [
50
- hashStr ( regex . type ) ,
51
- // Need non-commutative hash operator for `concat`, otherwise "ac" and "ca" are the same:
52
- regex . left . hash ,
53
- regex . right . hash ,
54
- ] ) }
55
- else if ( regex . type === 'star' || regex . type === 'complement' )
56
- return { ...regex , hash : hashNums ( [ hashStr ( regex . type ) , regex . inner . hash ] ) }
51
+ return {
52
+ ...regex ,
53
+ hash : hashNums ( [ hashStr ( regex . type ) , regex . charset . hash ] ) ,
54
+ isStdRegex : true ,
55
+ }
56
+ else if ( regex . type === 'concat' || regex . type === 'union' )
57
+ return {
58
+ ...regex ,
59
+ hash : hashNums ( [
60
+ hashStr ( regex . type ) ,
61
+ // Need non-commutative hash operator for `concat`, otherwise "ac" and "ca" are the same:
62
+ regex . left . hash ,
63
+ regex . right . hash ,
64
+ ] ) ,
65
+ isStdRegex : regex . left . isStdRegex && regex . right . isStdRegex ,
66
+ }
67
+ else if ( regex . type === 'intersection' )
68
+ return {
69
+ ...regex ,
70
+ hash : hashNums ( [
71
+ hashStr ( regex . type ) ,
72
+ regex . left . hash ,
73
+ regex . right . hash ,
74
+ ] ) ,
75
+ isStdRegex : false ,
76
+ }
77
+ else if ( regex . type === 'star' )
78
+ return {
79
+ ...regex ,
80
+ hash : hashNums ( [ hashStr ( regex . type ) , regex . inner . hash ] ) ,
81
+ isStdRegex : regex . inner . isStdRegex ,
82
+ }
83
+ else if ( regex . type === 'complement' )
84
+ return {
85
+ ...regex ,
86
+ hash : hashNums ( [ hashStr ( regex . type ) , regex . inner . hash ] ) ,
87
+ isStdRegex : false
88
+ }
57
89
checkedAllCases ( regex )
58
90
}
59
91
92
+ /**
93
+ * TODO
94
+ *
95
+ * @public
96
+ */
97
+ export function isStdRegex ( regex : ExtRegex ) : regex is StdRegex {
98
+ return regex . isStdRegex
99
+ }
100
+
60
101
//////////////////////////////////////////////
61
102
///// primitive composite constructors ///////
62
103
//////////////////////////////////////////////
63
104
64
- export const epsilon : StdRegex = withHash ( { type : 'epsilon' } )
105
+ export const epsilon : StdRegex = withMetaInfo ( { type : 'epsilon' } )
65
106
66
107
export function literal ( charset : CharSet . CharSet ) : StdRegex {
67
- return withHash ( { type : 'literal' , charset } )
108
+ return withMetaInfo ( { type : 'literal' , charset } )
68
109
}
69
110
70
111
export const empty : StdRegex = literal ( CharSet . empty )
@@ -113,7 +154,7 @@ export function concat(left: ExtRegex, right: ExtRegex): ExtRegex {
113
154
return concat ( left , right . right )
114
155
}
115
156
116
- return withHash ( { type : 'concat' , left, right } )
157
+ return withMetaInfo ( { type : 'concat' , left, right } )
117
158
}
118
159
119
160
function extractFront ( regex : StdRegex ) : [ StdRegex , StdRegex ]
@@ -212,7 +253,7 @@ export function union(left: ExtRegex, right: ExtRegex): ExtRegex {
212
253
// r + (s · r) = (s + ε) · r
213
254
return concat ( union ( leftInit , rightInit ) , leftLast )
214
255
215
- return withHash ( { type : 'union' , left, right } )
256
+ return withMetaInfo ( { type : 'union' , left, right } )
216
257
}
217
258
218
259
export function star ( inner : StdRegex ) : StdRegex
@@ -231,7 +272,7 @@ export function star(inner: ExtRegex): ExtRegex {
231
272
// (r∗ · s∗)∗ = (r + s)∗
232
273
return star ( union ( inner . left . inner , inner . right . inner ) )
233
274
else
234
- return withHash ( { type : "star" , inner } )
275
+ return withMetaInfo ( { type : "star" , inner } )
235
276
}
236
277
237
278
export function intersection ( left : ExtRegex , right : ExtRegex ) : ExtRegex {
@@ -257,7 +298,7 @@ export function intersection(left: ExtRegex, right: ExtRegex): ExtRegex {
257
298
// R & S ≈ R∩S
258
299
return literal ( CharSet . intersection ( left . charset , right . charset ) )
259
300
260
- return withHash ( { type : "intersection" , left, right } )
301
+ return withMetaInfo ( { type : "intersection" , left, right } )
261
302
}
262
303
263
304
/**
@@ -274,7 +315,7 @@ export function complement(inner: ExtRegex): ExtRegex {
274
315
// // ¬S ≈ (Σ\S
275
316
// return literal(CharSet.complement(inner.charset))
276
317
else
277
- return withHash ( { type : "complement" , inner } )
318
+ return withMetaInfo ( { type : "complement" , inner } )
278
319
}
279
320
280
321
//////////////////////////////////////////////
@@ -733,7 +774,7 @@ export function toString(regex: ExtRegex): string {
733
774
// Render parenthesis as non-capturing groups if there is a large number of them,
734
775
// i.e. `/(?:abc)` instead of `/(abc)/`. `new RegExp(...)` throws an error if there
735
776
// is a large number of capturing groups. Non-capturing groups are a bit more verbose
736
- // but at large sizes like this it doesn't matter anyway :
777
+ // but at large sizes like this it hardly still hurts readability :
737
778
const useNonCapturingGroups = size > 10_000
738
779
739
780
return '^(' + astToString ( toRegExpAST ( regex ) , { useNonCapturingGroups } ) + ')$'
0 commit comments