@pattern-algebra/core 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +571 -0
- package/dist/automaton/complement.d.ts +20 -0
- package/dist/automaton/complement.d.ts.map +1 -0
- package/dist/automaton/complement.js +36 -0
- package/dist/automaton/complement.js.map +1 -0
- package/dist/automaton/complement.test.d.ts +2 -0
- package/dist/automaton/complement.test.d.ts.map +1 -0
- package/dist/automaton/complement.test.js +114 -0
- package/dist/automaton/complement.test.js.map +1 -0
- package/dist/automaton/determinize.d.ts +41 -0
- package/dist/automaton/determinize.d.ts.map +1 -0
- package/dist/automaton/determinize.js +310 -0
- package/dist/automaton/determinize.js.map +1 -0
- package/dist/automaton/determinize.test.d.ts +2 -0
- package/dist/automaton/determinize.test.d.ts.map +1 -0
- package/dist/automaton/determinize.test.js +134 -0
- package/dist/automaton/determinize.test.js.map +1 -0
- package/dist/automaton/emptiness.d.ts +41 -0
- package/dist/automaton/emptiness.d.ts.map +1 -0
- package/dist/automaton/emptiness.js +262 -0
- package/dist/automaton/emptiness.js.map +1 -0
- package/dist/automaton/emptiness.test.d.ts +2 -0
- package/dist/automaton/emptiness.test.d.ts.map +1 -0
- package/dist/automaton/emptiness.test.js +154 -0
- package/dist/automaton/emptiness.test.js.map +1 -0
- package/dist/automaton/index.d.ts +10 -0
- package/dist/automaton/index.d.ts.map +1 -0
- package/dist/automaton/index.js +11 -0
- package/dist/automaton/index.js.map +1 -0
- package/dist/automaton/intersect.d.ts +35 -0
- package/dist/automaton/intersect.d.ts.map +1 -0
- package/dist/automaton/intersect.js +302 -0
- package/dist/automaton/intersect.js.map +1 -0
- package/dist/automaton/pattern-algebra.d.ts +62 -0
- package/dist/automaton/pattern-algebra.d.ts.map +1 -0
- package/dist/automaton/pattern-algebra.js +309 -0
- package/dist/automaton/pattern-algebra.js.map +1 -0
- package/dist/automaton/pattern-algebra.test.d.ts +2 -0
- package/dist/automaton/pattern-algebra.test.d.ts.map +1 -0
- package/dist/automaton/pattern-algebra.test.js +223 -0
- package/dist/automaton/pattern-algebra.test.js.map +1 -0
- package/dist/compile/automaton-builder.d.ts +47 -0
- package/dist/compile/automaton-builder.d.ts.map +1 -0
- package/dist/compile/automaton-builder.js +211 -0
- package/dist/compile/automaton-builder.js.map +1 -0
- package/dist/compile/compiler.d.ts +32 -0
- package/dist/compile/compiler.d.ts.map +1 -0
- package/dist/compile/compiler.js +47 -0
- package/dist/compile/compiler.js.map +1 -0
- package/dist/compile/index.d.ts +8 -0
- package/dist/compile/index.d.ts.map +1 -0
- package/dist/compile/index.js +8 -0
- package/dist/compile/index.js.map +1 -0
- package/dist/compile/quick-reject.d.ts +28 -0
- package/dist/compile/quick-reject.d.ts.map +1 -0
- package/dist/compile/quick-reject.js +147 -0
- package/dist/compile/quick-reject.js.map +1 -0
- package/dist/containment/analysis.d.ts +60 -0
- package/dist/containment/analysis.d.ts.map +1 -0
- package/dist/containment/analysis.js +378 -0
- package/dist/containment/analysis.js.map +1 -0
- package/dist/containment/containment.d.ts +23 -0
- package/dist/containment/containment.d.ts.map +1 -0
- package/dist/containment/containment.js +681 -0
- package/dist/containment/containment.js.map +1 -0
- package/dist/containment/containment.test.d.ts +2 -0
- package/dist/containment/containment.test.d.ts.map +1 -0
- package/dist/containment/containment.test.js +209 -0
- package/dist/containment/containment.test.js.map +1 -0
- package/dist/containment/index.d.ts +7 -0
- package/dist/containment/index.d.ts.map +1 -0
- package/dist/containment/index.js +7 -0
- package/dist/containment/index.js.map +1 -0
- package/dist/core-alpha.d.ts +1253 -0
- package/dist/core-beta.d.ts +1253 -0
- package/dist/core-public.d.ts +1253 -0
- package/dist/core-unstripped.d.ts +1253 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/match/index.d.ts +8 -0
- package/dist/match/index.d.ts.map +1 -0
- package/dist/match/index.js +8 -0
- package/dist/match/index.js.map +1 -0
- package/dist/match/matcher.d.ts +40 -0
- package/dist/match/matcher.d.ts.map +1 -0
- package/dist/match/matcher.js +256 -0
- package/dist/match/matcher.js.map +1 -0
- package/dist/match/matcher.test.d.ts +2 -0
- package/dist/match/matcher.test.d.ts.map +1 -0
- package/dist/match/matcher.test.js +185 -0
- package/dist/match/matcher.test.js.map +1 -0
- package/dist/match/path-utils.d.ts +132 -0
- package/dist/match/path-utils.d.ts.map +1 -0
- package/dist/match/path-utils.js +223 -0
- package/dist/match/path-utils.js.map +1 -0
- package/dist/match/path-utils.test.d.ts +2 -0
- package/dist/match/path-utils.test.d.ts.map +1 -0
- package/dist/match/path-utils.test.js +193 -0
- package/dist/match/path-utils.test.js.map +1 -0
- package/dist/match/segment-matcher.d.ts +25 -0
- package/dist/match/segment-matcher.d.ts.map +1 -0
- package/dist/match/segment-matcher.js +267 -0
- package/dist/match/segment-matcher.js.map +1 -0
- package/dist/parse/brace-expansion.d.ts +34 -0
- package/dist/parse/brace-expansion.d.ts.map +1 -0
- package/dist/parse/brace-expansion.js +294 -0
- package/dist/parse/brace-expansion.js.map +1 -0
- package/dist/parse/brace-expansion.test.d.ts +2 -0
- package/dist/parse/brace-expansion.test.d.ts.map +1 -0
- package/dist/parse/brace-expansion.test.js +105 -0
- package/dist/parse/brace-expansion.test.js.map +1 -0
- package/dist/parse/index.d.ts +8 -0
- package/dist/parse/index.d.ts.map +1 -0
- package/dist/parse/index.js +8 -0
- package/dist/parse/index.js.map +1 -0
- package/dist/parse/parser.d.ts +15 -0
- package/dist/parse/parser.d.ts.map +1 -0
- package/dist/parse/parser.js +526 -0
- package/dist/parse/parser.js.map +1 -0
- package/dist/parse/parser.test.d.ts +2 -0
- package/dist/parse/parser.test.d.ts.map +1 -0
- package/dist/parse/parser.test.js +266 -0
- package/dist/parse/parser.test.js.map +1 -0
- package/dist/parse/validator.d.ts +30 -0
- package/dist/parse/validator.d.ts.map +1 -0
- package/dist/parse/validator.js +115 -0
- package/dist/parse/validator.js.map +1 -0
- package/dist/parse/validator.test.d.ts +2 -0
- package/dist/parse/validator.test.d.ts.map +1 -0
- package/dist/parse/validator.test.js +45 -0
- package/dist/parse/validator.test.js.map +1 -0
- package/dist/types/ast.d.ts +158 -0
- package/dist/types/ast.d.ts.map +1 -0
- package/dist/types/ast.js +2 -0
- package/dist/types/ast.js.map +1 -0
- package/dist/types/automaton.d.ts +150 -0
- package/dist/types/automaton.d.ts.map +1 -0
- package/dist/types/automaton.js +2 -0
- package/dist/types/automaton.js.map +1 -0
- package/dist/types/containment.d.ts +257 -0
- package/dist/types/containment.d.ts.map +1 -0
- package/dist/types/containment.js +5 -0
- package/dist/types/containment.js.map +1 -0
- package/dist/types/errors.d.ts +37 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +24 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automaton intersection using product construction.
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Compute the intersection of two automata using product construction.
|
|
7
|
+
*
|
|
8
|
+
* The resulting automaton accepts a string iff both input automata accept it.
|
|
9
|
+
* L(A ∩ B) = L(A) ∩ L(B)
|
|
10
|
+
*
|
|
11
|
+
* @param a - First automaton
|
|
12
|
+
* @param b - Second automaton
|
|
13
|
+
* @returns Intersection automaton
|
|
14
|
+
*
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export function intersect(a, b) {
|
|
18
|
+
return productConstruction(a, b, 'intersection');
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Compute the union of two automata using NFA construction.
|
|
22
|
+
*
|
|
23
|
+
* The resulting automaton accepts a string iff either input automaton accepts it.
|
|
24
|
+
* L(A ∪ B) = L(A) ∪ L(B)
|
|
25
|
+
*
|
|
26
|
+
* We use NFA union: create a new initial state with epsilon transitions
|
|
27
|
+
* to both automata's initial states, then merge the states.
|
|
28
|
+
*
|
|
29
|
+
* @param a - First automaton
|
|
30
|
+
* @param b - Second automaton
|
|
31
|
+
* @returns Union automaton (NFA)
|
|
32
|
+
*
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
export function union(a, b) {
|
|
36
|
+
// Renumber states: a's states stay as-is, b's states are shifted by a.states.length
|
|
37
|
+
const aOffset = 0;
|
|
38
|
+
const bOffset = a.states.length;
|
|
39
|
+
const newInitialState = a.states.length + b.states.length;
|
|
40
|
+
// Copy a's states
|
|
41
|
+
const states = a.states.map((state) => ({
|
|
42
|
+
id: state.id + aOffset,
|
|
43
|
+
accepting: state.accepting,
|
|
44
|
+
transitions: state.transitions.map((t) => renumberTransition(t, aOffset)),
|
|
45
|
+
}));
|
|
46
|
+
// Copy b's states with renumbered IDs
|
|
47
|
+
for (const state of b.states) {
|
|
48
|
+
states.push({
|
|
49
|
+
id: state.id + bOffset,
|
|
50
|
+
accepting: state.accepting,
|
|
51
|
+
transitions: state.transitions.map((t) => renumberTransition(t, bOffset)),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
// Create new initial state with epsilon transitions to both original initial states
|
|
55
|
+
states.push({
|
|
56
|
+
id: newInitialState,
|
|
57
|
+
accepting: false,
|
|
58
|
+
transitions: [
|
|
59
|
+
{ type: 'epsilon', target: a.initialState + aOffset },
|
|
60
|
+
{ type: 'epsilon', target: b.initialState + bOffset },
|
|
61
|
+
],
|
|
62
|
+
});
|
|
63
|
+
// Accepting states from both automata
|
|
64
|
+
const acceptingStates = [...a.acceptingStates.map((s) => s + aOffset), ...b.acceptingStates.map((s) => s + bOffset)];
|
|
65
|
+
return {
|
|
66
|
+
states,
|
|
67
|
+
initialState: newInitialState,
|
|
68
|
+
acceptingStates,
|
|
69
|
+
isDeterministic: false, // NFA union is non-deterministic
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Renumber a transition's targets by adding an offset.
|
|
74
|
+
*/
|
|
75
|
+
function renumberTransition(t, offset) {
|
|
76
|
+
switch (t.type) {
|
|
77
|
+
case 'literal':
|
|
78
|
+
return { ...t, target: t.target + offset };
|
|
79
|
+
case 'wildcard':
|
|
80
|
+
return { ...t, target: t.target + offset };
|
|
81
|
+
case 'epsilon':
|
|
82
|
+
return { ...t, target: t.target + offset };
|
|
83
|
+
case 'globstar':
|
|
84
|
+
return { ...t, selfLoop: t.selfLoop + offset, exit: t.exit + offset };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Product construction for intersection or union.
|
|
89
|
+
*/
|
|
90
|
+
function productConstruction(a, b, mode) {
|
|
91
|
+
// Map from (stateA, stateB) pair to product state ID
|
|
92
|
+
const pairToState = new Map();
|
|
93
|
+
const productStates = [];
|
|
94
|
+
const getPairKey = (sa, sb) => `${sa},${sb}`;
|
|
95
|
+
const getOrCreateState = (sa, sb) => {
|
|
96
|
+
const key = getPairKey(sa, sb);
|
|
97
|
+
let stateId = pairToState.get(key);
|
|
98
|
+
if (stateId === undefined) {
|
|
99
|
+
stateId = productStates.length;
|
|
100
|
+
pairToState.set(key, stateId);
|
|
101
|
+
const acceptA = a.states[sa]?.accepting ?? false;
|
|
102
|
+
const acceptB = b.states[sb]?.accepting ?? false;
|
|
103
|
+
// For intersection: accepting iff both accept
|
|
104
|
+
// For union: accepting iff either accepts
|
|
105
|
+
const accepting = mode === 'intersection' ? acceptA && acceptB : acceptA || acceptB;
|
|
106
|
+
productStates.push({
|
|
107
|
+
id: stateId,
|
|
108
|
+
transitions: [],
|
|
109
|
+
accepting,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return stateId;
|
|
113
|
+
};
|
|
114
|
+
// Start with initial states
|
|
115
|
+
const initialState = getOrCreateState(a.initialState, b.initialState);
|
|
116
|
+
// Worklist of state pairs to process
|
|
117
|
+
const worklist = [
|
|
118
|
+
{ stateId: initialState, sa: a.initialState, sb: b.initialState },
|
|
119
|
+
];
|
|
120
|
+
const processed = new Set();
|
|
121
|
+
while (worklist.length > 0) {
|
|
122
|
+
const { stateId, sa, sb } = worklist.pop();
|
|
123
|
+
const key = getPairKey(sa, sb);
|
|
124
|
+
if (processed.has(key))
|
|
125
|
+
continue;
|
|
126
|
+
processed.add(key);
|
|
127
|
+
const stateA = a.states[sa];
|
|
128
|
+
const stateB = b.states[sb];
|
|
129
|
+
const transitions = [];
|
|
130
|
+
// For each pair of transitions that can fire together
|
|
131
|
+
for (const transA of stateA?.transitions ?? []) {
|
|
132
|
+
for (const transB of stateB?.transitions ?? []) {
|
|
133
|
+
const combined = combineTransitions(transA, transB);
|
|
134
|
+
if (combined) {
|
|
135
|
+
const targetState = getOrCreateState(combined.targetA, combined.targetB);
|
|
136
|
+
transitions.push({
|
|
137
|
+
...combined.transition,
|
|
138
|
+
target: targetState,
|
|
139
|
+
});
|
|
140
|
+
const targetKey = getPairKey(combined.targetA, combined.targetB);
|
|
141
|
+
if (!processed.has(targetKey)) {
|
|
142
|
+
worklist.push({
|
|
143
|
+
stateId: targetState,
|
|
144
|
+
sa: combined.targetA,
|
|
145
|
+
sb: combined.targetB,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
productStates[stateId] = {
|
|
152
|
+
...productStates[stateId],
|
|
153
|
+
transitions,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
const acceptingStates = productStates.filter((s) => s.accepting).map((s) => s.id);
|
|
157
|
+
return {
|
|
158
|
+
states: productStates,
|
|
159
|
+
initialState,
|
|
160
|
+
acceptingStates,
|
|
161
|
+
isDeterministic: a.isDeterministic && b.isDeterministic,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Combine two transitions if they can fire on the same input.
|
|
166
|
+
*/
|
|
167
|
+
function combineTransitions(transA, transB) {
|
|
168
|
+
// Skip epsilon transitions in product (they're handled differently)
|
|
169
|
+
if (transA.type === 'epsilon' || transB.type === 'epsilon') {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
// Literal + Literal: must be same literal
|
|
173
|
+
if (transA.type === 'literal' && transB.type === 'literal') {
|
|
174
|
+
if (transA.segment === transB.segment) {
|
|
175
|
+
return {
|
|
176
|
+
transition: { type: 'literal', segment: transA.segment },
|
|
177
|
+
targetA: transA.target,
|
|
178
|
+
targetB: transB.target,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
// Literal + Wildcard: literal must match wildcard pattern
|
|
184
|
+
if (transA.type === 'literal' && transB.type === 'wildcard') {
|
|
185
|
+
if (transB.pattern.test(transA.segment)) {
|
|
186
|
+
return {
|
|
187
|
+
transition: { type: 'literal', segment: transA.segment },
|
|
188
|
+
targetA: transA.target,
|
|
189
|
+
targetB: transB.target,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
// Wildcard + Literal: literal must match wildcard pattern
|
|
195
|
+
if (transA.type === 'wildcard' && transB.type === 'literal') {
|
|
196
|
+
if (transA.pattern.test(transB.segment)) {
|
|
197
|
+
return {
|
|
198
|
+
transition: { type: 'literal', segment: transB.segment },
|
|
199
|
+
targetA: transA.target,
|
|
200
|
+
targetB: transB.target,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
// Wildcard + Wildcard: compute intersection of patterns
|
|
206
|
+
if (transA.type === 'wildcard' && transB.type === 'wildcard') {
|
|
207
|
+
// Create a combined matcher that tests both patterns
|
|
208
|
+
const combinedPattern = createIntersectionPattern(transA.pattern, transB.pattern);
|
|
209
|
+
return {
|
|
210
|
+
transition: {
|
|
211
|
+
type: 'wildcard',
|
|
212
|
+
pattern: combinedPattern,
|
|
213
|
+
patternSource: `(${transA.patternSource})∩(${transB.patternSource})`,
|
|
214
|
+
},
|
|
215
|
+
targetA: transA.target,
|
|
216
|
+
targetB: transB.target,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
// Globstar transitions
|
|
220
|
+
if (transA.type === 'globstar' || transB.type === 'globstar') {
|
|
221
|
+
return handleGlobstarProduct(transA, transB);
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Create a pattern that matches the intersection of two patterns.
|
|
227
|
+
*
|
|
228
|
+
* Since true regex intersection is complex (undecidable in general),
|
|
229
|
+
* we create a composite matcher that tests both patterns.
|
|
230
|
+
*
|
|
231
|
+
* @param patternA - First pattern to test
|
|
232
|
+
* @param patternB - Second pattern to test
|
|
233
|
+
* @returns A SegmentMatcher that matches if both patterns match
|
|
234
|
+
*/
|
|
235
|
+
function createIntersectionPattern(patternA, patternB) {
|
|
236
|
+
return {
|
|
237
|
+
test: (str) => patternA.test(str) && patternB.test(str),
|
|
238
|
+
source: `(${patternA.source})∩(${patternB.source})`,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Handle product of globstar transitions.
|
|
243
|
+
*/
|
|
244
|
+
function handleGlobstarProduct(transA, transB) {
|
|
245
|
+
// Globstar matches any segment, so it can combine with anything
|
|
246
|
+
if (transA.type === 'globstar' && transB.type === 'globstar') {
|
|
247
|
+
// Both globstars: product stays in globstar state for both
|
|
248
|
+
return {
|
|
249
|
+
transition: {
|
|
250
|
+
type: 'wildcard',
|
|
251
|
+
pattern: /^.+$/,
|
|
252
|
+
patternSource: '**',
|
|
253
|
+
},
|
|
254
|
+
targetA: transA.selfLoop,
|
|
255
|
+
targetB: transB.selfLoop,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
if (transA.type === 'globstar') {
|
|
259
|
+
// A is globstar, B is something else
|
|
260
|
+
if (transB.type === 'literal') {
|
|
261
|
+
return {
|
|
262
|
+
transition: { type: 'literal', segment: transB.segment },
|
|
263
|
+
targetA: transA.selfLoop, // Stay in globstar
|
|
264
|
+
targetB: transB.target,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
if (transB.type === 'wildcard') {
|
|
268
|
+
return {
|
|
269
|
+
transition: {
|
|
270
|
+
type: 'wildcard',
|
|
271
|
+
pattern: transB.pattern,
|
|
272
|
+
patternSource: transB.patternSource,
|
|
273
|
+
},
|
|
274
|
+
targetA: transA.selfLoop,
|
|
275
|
+
targetB: transB.target,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (transB.type === 'globstar') {
|
|
280
|
+
// B is globstar, A is something else
|
|
281
|
+
if (transA.type === 'literal') {
|
|
282
|
+
return {
|
|
283
|
+
transition: { type: 'literal', segment: transA.segment },
|
|
284
|
+
targetA: transA.target,
|
|
285
|
+
targetB: transB.selfLoop,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
if (transA.type === 'wildcard') {
|
|
289
|
+
return {
|
|
290
|
+
transition: {
|
|
291
|
+
type: 'wildcard',
|
|
292
|
+
pattern: transA.pattern,
|
|
293
|
+
patternSource: transA.patternSource,
|
|
294
|
+
},
|
|
295
|
+
targetA: transA.target,
|
|
296
|
+
targetB: transB.selfLoop,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=intersect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intersect.js","sourceRoot":"","sources":["../../src/automaton/intersect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern-level set operations (pattern algebra).
|
|
3
|
+
*
|
|
4
|
+
* These functions operate on CompiledPattern objects and return new
|
|
5
|
+
* CompiledPattern objects, providing a higher-level API than the raw
|
|
6
|
+
* automaton operations.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import type { CompiledPattern } from '../types';
|
|
11
|
+
/**
|
|
12
|
+
* Compute the intersection of two patterns.
|
|
13
|
+
*
|
|
14
|
+
* The result matches paths that match BOTH input patterns.
|
|
15
|
+
* L(result) = L(a) ∩ L(b)
|
|
16
|
+
*
|
|
17
|
+
* @param a - First pattern
|
|
18
|
+
* @param b - Second pattern
|
|
19
|
+
* @returns Pattern matching paths in both a and b
|
|
20
|
+
*
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
export declare function patternIntersect(a: CompiledPattern, b: CompiledPattern): CompiledPattern;
|
|
24
|
+
/**
|
|
25
|
+
* Compute the union of two patterns.
|
|
26
|
+
*
|
|
27
|
+
* The result matches paths that match EITHER input pattern.
|
|
28
|
+
* L(result) = L(a) ∪ L(b)
|
|
29
|
+
*
|
|
30
|
+
* @param a - First pattern
|
|
31
|
+
* @param b - Second pattern
|
|
32
|
+
* @returns Pattern matching paths in a or b (or both)
|
|
33
|
+
*
|
|
34
|
+
* @public
|
|
35
|
+
*/
|
|
36
|
+
export declare function patternUnion(a: CompiledPattern, b: CompiledPattern): CompiledPattern;
|
|
37
|
+
/**
|
|
38
|
+
* Compute the complement of a pattern.
|
|
39
|
+
*
|
|
40
|
+
* The result matches paths that do NOT match the input pattern.
|
|
41
|
+
* L(result) = Σ* - L(a)
|
|
42
|
+
*
|
|
43
|
+
* @param a - Pattern to complement
|
|
44
|
+
* @returns Pattern matching paths not matched by a
|
|
45
|
+
*
|
|
46
|
+
* @public
|
|
47
|
+
*/
|
|
48
|
+
export declare function patternComplement(a: CompiledPattern): CompiledPattern;
|
|
49
|
+
/**
|
|
50
|
+
* Compute the difference of two patterns.
|
|
51
|
+
*
|
|
52
|
+
* The result matches paths that match a but NOT b.
|
|
53
|
+
* L(result) = L(a) - L(b) = L(a) ∩ L(¬b)
|
|
54
|
+
*
|
|
55
|
+
* @param a - Pattern to subtract from
|
|
56
|
+
* @param b - Pattern to subtract
|
|
57
|
+
* @returns Pattern matching paths in a but not in b
|
|
58
|
+
*
|
|
59
|
+
* @public
|
|
60
|
+
*/
|
|
61
|
+
export declare function patternDifference(a: CompiledPattern, b: CompiledPattern): CompiledPattern;
|
|
62
|
+
//# sourceMappingURL=pattern-algebra.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-algebra.d.ts","sourceRoot":"","sources":["../../src/automaton/pattern-algebra.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAA+C,MAAM,UAAU,CAAA;AAS5F;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,eAAe,GAAG,eAAe,CAkBxF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,eAAe,GAAG,eAAe,CAkBpF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,eAAe,GAAG,eAAe,CAqBrE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,eAAe,GAAG,eAAe,CAyBzF"}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern-level set operations (pattern algebra).
|
|
3
|
+
*
|
|
4
|
+
* These functions operate on CompiledPattern objects and return new
|
|
5
|
+
* CompiledPattern objects, providing a higher-level API than the raw
|
|
6
|
+
* automaton operations.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import { intersect, union } from './intersect';
|
|
11
|
+
import { complement } from './complement';
|
|
12
|
+
import { determinize } from './determinize';
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// PATTERN SET OPERATIONS
|
|
15
|
+
// =============================================================================
|
|
16
|
+
/**
|
|
17
|
+
* Compute the intersection of two patterns.
|
|
18
|
+
*
|
|
19
|
+
* The result matches paths that match BOTH input patterns.
|
|
20
|
+
* L(result) = L(a) ∩ L(b)
|
|
21
|
+
*
|
|
22
|
+
* @param a - First pattern
|
|
23
|
+
* @param b - Second pattern
|
|
24
|
+
* @returns Pattern matching paths in both a and b
|
|
25
|
+
*
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
export function patternIntersect(a, b) {
|
|
29
|
+
// Determinize inputs to handle epsilon transitions properly
|
|
30
|
+
const dfaA = a.automaton.isDeterministic ? a.automaton : determinize(a.automaton);
|
|
31
|
+
const dfaB = b.automaton.isDeterministic ? b.automaton : determinize(b.automaton);
|
|
32
|
+
const automaton = intersect(dfaA, dfaB);
|
|
33
|
+
const source = `(${a.source}) ∩ (${b.source})`;
|
|
34
|
+
const ast = createSyntheticAst(source, 'intersection', [a.ast, b.ast]);
|
|
35
|
+
const quickReject = mergeQuickRejectForIntersection(a.quickReject, b.quickReject);
|
|
36
|
+
return {
|
|
37
|
+
source,
|
|
38
|
+
ast,
|
|
39
|
+
quickReject,
|
|
40
|
+
automaton,
|
|
41
|
+
isUnbounded: a.isUnbounded && b.isUnbounded,
|
|
42
|
+
minSegments: Math.max(a.minSegments, b.minSegments),
|
|
43
|
+
maxSegments: computeIntersectionMaxSegments(a.maxSegments, b.maxSegments),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Compute the union of two patterns.
|
|
48
|
+
*
|
|
49
|
+
* The result matches paths that match EITHER input pattern.
|
|
50
|
+
* L(result) = L(a) ∪ L(b)
|
|
51
|
+
*
|
|
52
|
+
* @param a - First pattern
|
|
53
|
+
* @param b - Second pattern
|
|
54
|
+
* @returns Pattern matching paths in a or b (or both)
|
|
55
|
+
*
|
|
56
|
+
* @public
|
|
57
|
+
*/
|
|
58
|
+
export function patternUnion(a, b) {
|
|
59
|
+
// Determinize inputs to handle epsilon transitions properly
|
|
60
|
+
const dfaA = a.automaton.isDeterministic ? a.automaton : determinize(a.automaton);
|
|
61
|
+
const dfaB = b.automaton.isDeterministic ? b.automaton : determinize(b.automaton);
|
|
62
|
+
const automaton = union(dfaA, dfaB);
|
|
63
|
+
const source = `(${a.source}) ∪ (${b.source})`;
|
|
64
|
+
const ast = createSyntheticAst(source, 'union', [a.ast, b.ast]);
|
|
65
|
+
const quickReject = mergeQuickRejectForUnion(a.quickReject, b.quickReject);
|
|
66
|
+
return {
|
|
67
|
+
source,
|
|
68
|
+
ast,
|
|
69
|
+
quickReject,
|
|
70
|
+
automaton,
|
|
71
|
+
isUnbounded: a.isUnbounded || b.isUnbounded,
|
|
72
|
+
minSegments: Math.min(a.minSegments, b.minSegments),
|
|
73
|
+
maxSegments: computeUnionMaxSegments(a.maxSegments, b.maxSegments, a.isUnbounded, b.isUnbounded),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Compute the complement of a pattern.
|
|
78
|
+
*
|
|
79
|
+
* The result matches paths that do NOT match the input pattern.
|
|
80
|
+
* L(result) = Σ* - L(a)
|
|
81
|
+
*
|
|
82
|
+
* @param a - Pattern to complement
|
|
83
|
+
* @returns Pattern matching paths not matched by a
|
|
84
|
+
*
|
|
85
|
+
* @public
|
|
86
|
+
*/
|
|
87
|
+
export function patternComplement(a) {
|
|
88
|
+
// Determinize input (complement already does this, but be explicit)
|
|
89
|
+
const dfa = a.automaton.isDeterministic ? a.automaton : determinize(a.automaton);
|
|
90
|
+
const automaton = complement(dfa);
|
|
91
|
+
const source = `¬(${a.source})`;
|
|
92
|
+
const ast = createSyntheticAst(source, 'complement', [a.ast]);
|
|
93
|
+
// Complement has no useful quick-reject filters
|
|
94
|
+
// (the complement of any bounded set is unbounded)
|
|
95
|
+
const quickReject = {};
|
|
96
|
+
return {
|
|
97
|
+
source,
|
|
98
|
+
ast,
|
|
99
|
+
quickReject,
|
|
100
|
+
automaton,
|
|
101
|
+
// Complement is always unbounded (matches infinite set of paths)
|
|
102
|
+
isUnbounded: true,
|
|
103
|
+
minSegments: 0,
|
|
104
|
+
maxSegments: undefined,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Compute the difference of two patterns.
|
|
109
|
+
*
|
|
110
|
+
* The result matches paths that match a but NOT b.
|
|
111
|
+
* L(result) = L(a) - L(b) = L(a) ∩ L(¬b)
|
|
112
|
+
*
|
|
113
|
+
* @param a - Pattern to subtract from
|
|
114
|
+
* @param b - Pattern to subtract
|
|
115
|
+
* @returns Pattern matching paths in a but not in b
|
|
116
|
+
*
|
|
117
|
+
* @public
|
|
118
|
+
*/
|
|
119
|
+
export function patternDifference(a, b) {
|
|
120
|
+
// A \ B = A ∩ ¬B
|
|
121
|
+
// Determinize inputs to handle epsilon transitions properly
|
|
122
|
+
const dfaA = a.automaton.isDeterministic ? a.automaton : determinize(a.automaton);
|
|
123
|
+
const dfaB = b.automaton.isDeterministic ? b.automaton : determinize(b.automaton);
|
|
124
|
+
const bComplement = complement(dfaB);
|
|
125
|
+
const automaton = intersect(dfaA, bComplement);
|
|
126
|
+
const source = `(${a.source}) \\ (${b.source})`;
|
|
127
|
+
const ast = createSyntheticAst(source, 'difference', [a.ast, b.ast]);
|
|
128
|
+
// Difference inherits quick-reject from a (paths must match a)
|
|
129
|
+
// But we can't use b's filters since we're excluding b
|
|
130
|
+
const quickReject = a.quickReject;
|
|
131
|
+
return {
|
|
132
|
+
source,
|
|
133
|
+
ast,
|
|
134
|
+
quickReject,
|
|
135
|
+
automaton,
|
|
136
|
+
// Difference of A and B has same unbounded status as A
|
|
137
|
+
// (we're only removing paths from A)
|
|
138
|
+
isUnbounded: a.isUnbounded,
|
|
139
|
+
minSegments: a.minSegments,
|
|
140
|
+
maxSegments: a.maxSegments,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Create a synthetic AST for algebraic pattern operations.
|
|
145
|
+
*/
|
|
146
|
+
function createSyntheticAst(source, _operation, operands) {
|
|
147
|
+
// For synthetic patterns, we create an alternation node containing
|
|
148
|
+
// references to the original patterns. This preserves the structure
|
|
149
|
+
// while indicating this is a computed pattern.
|
|
150
|
+
const root = {
|
|
151
|
+
type: 'alternation',
|
|
152
|
+
branches: operands.map((p) => p.root),
|
|
153
|
+
};
|
|
154
|
+
return {
|
|
155
|
+
source,
|
|
156
|
+
root,
|
|
157
|
+
// Synthetic patterns inherit absoluteness from operands
|
|
158
|
+
isAbsolute: operands.some((p) => p.isAbsolute),
|
|
159
|
+
isNegation: false,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Merge quick-reject filters for intersection (AND semantics).
|
|
164
|
+
*
|
|
165
|
+
* For intersection, a path must satisfy BOTH patterns, so we take
|
|
166
|
+
* the more restrictive constraint for each field.
|
|
167
|
+
*/
|
|
168
|
+
function mergeQuickRejectForIntersection(a, b) {
|
|
169
|
+
return {
|
|
170
|
+
requiredPrefix: mergePrefix(a.requiredPrefix, b.requiredPrefix, 'intersection'),
|
|
171
|
+
requiredSuffix: mergeSuffix(a.requiredSuffix, b.requiredSuffix, 'intersection'),
|
|
172
|
+
minLength: mergeMinLength(a.minLength, b.minLength, 'intersection'),
|
|
173
|
+
requiredLiterals: mergeLiterals(a.requiredLiterals, b.requiredLiterals, 'intersection'),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Merge quick-reject filters for union (OR semantics).
|
|
178
|
+
*
|
|
179
|
+
* For union, a path need only satisfy ONE pattern, so we take
|
|
180
|
+
* the less restrictive (common) constraint for each field.
|
|
181
|
+
*/
|
|
182
|
+
function mergeQuickRejectForUnion(a, b) {
|
|
183
|
+
return {
|
|
184
|
+
requiredPrefix: mergePrefix(a.requiredPrefix, b.requiredPrefix, 'union'),
|
|
185
|
+
requiredSuffix: mergeSuffix(a.requiredSuffix, b.requiredSuffix, 'union'),
|
|
186
|
+
minLength: mergeMinLength(a.minLength, b.minLength, 'union'),
|
|
187
|
+
requiredLiterals: mergeLiterals(a.requiredLiterals, b.requiredLiterals, 'union'),
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Merge prefix constraints.
|
|
192
|
+
*/
|
|
193
|
+
function mergePrefix(a, b, mode) {
|
|
194
|
+
if (a === undefined)
|
|
195
|
+
return mode === 'intersection' ? b : undefined;
|
|
196
|
+
if (b === undefined)
|
|
197
|
+
return mode === 'intersection' ? a : undefined;
|
|
198
|
+
if (mode === 'intersection') {
|
|
199
|
+
// For intersection, take longer prefix if one is substring of other
|
|
200
|
+
if (a.startsWith(b))
|
|
201
|
+
return a;
|
|
202
|
+
if (b.startsWith(a))
|
|
203
|
+
return b;
|
|
204
|
+
// Incompatible prefixes - keep the longer one (will likely reject more)
|
|
205
|
+
return a.length >= b.length ? a : b;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
// For union, take common prefix only
|
|
209
|
+
let common = '';
|
|
210
|
+
for (let i = 0; i < Math.min(a.length, b.length); i++) {
|
|
211
|
+
if (a[i] === b[i]) {
|
|
212
|
+
common += a[i];
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return common || undefined;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Merge suffix constraints.
|
|
223
|
+
*/
|
|
224
|
+
function mergeSuffix(a, b, mode) {
|
|
225
|
+
if (a === undefined)
|
|
226
|
+
return mode === 'intersection' ? b : undefined;
|
|
227
|
+
if (b === undefined)
|
|
228
|
+
return mode === 'intersection' ? a : undefined;
|
|
229
|
+
if (mode === 'intersection') {
|
|
230
|
+
// For intersection, take longer suffix if one is substring of other
|
|
231
|
+
if (a.endsWith(b))
|
|
232
|
+
return a;
|
|
233
|
+
if (b.endsWith(a))
|
|
234
|
+
return b;
|
|
235
|
+
// Incompatible suffixes - keep the longer one
|
|
236
|
+
return a.length >= b.length ? a : b;
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
// For union, take common suffix only
|
|
240
|
+
let common = '';
|
|
241
|
+
for (let i = 0; i < Math.min(a.length, b.length); i++) {
|
|
242
|
+
if (a[a.length - 1 - i] === b[b.length - 1 - i]) {
|
|
243
|
+
common = a[a.length - 1 - i] + common;
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return common || undefined;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Merge minLength constraints.
|
|
254
|
+
*/
|
|
255
|
+
function mergeMinLength(a, b, mode) {
|
|
256
|
+
if (a === undefined)
|
|
257
|
+
return mode === 'intersection' ? b : undefined;
|
|
258
|
+
if (b === undefined)
|
|
259
|
+
return mode === 'intersection' ? a : undefined;
|
|
260
|
+
if (mode === 'intersection') {
|
|
261
|
+
// For intersection, take max (more restrictive)
|
|
262
|
+
return Math.max(a, b);
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
// For union, take min (less restrictive)
|
|
266
|
+
return Math.min(a, b);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Merge requiredLiterals constraints.
|
|
271
|
+
*/
|
|
272
|
+
function mergeLiterals(a, b, mode) {
|
|
273
|
+
if (a === undefined)
|
|
274
|
+
return mode === 'intersection' ? b : undefined;
|
|
275
|
+
if (b === undefined)
|
|
276
|
+
return mode === 'intersection' ? a : undefined;
|
|
277
|
+
if (mode === 'intersection') {
|
|
278
|
+
// For intersection, union of sets (all must be present)
|
|
279
|
+
const combined = new Set([...a, ...b]);
|
|
280
|
+
return combined.size > 0 ? [...combined] : undefined;
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
// For union, intersection of sets (must be in all branches)
|
|
284
|
+
const bSet = new Set(b);
|
|
285
|
+
const common = a.filter((lit) => bSet.has(lit));
|
|
286
|
+
return common.length > 0 ? common : undefined;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Compute maxSegments for intersection.
|
|
291
|
+
*/
|
|
292
|
+
function computeIntersectionMaxSegments(a, b) {
|
|
293
|
+
if (a === undefined)
|
|
294
|
+
return b;
|
|
295
|
+
if (b === undefined)
|
|
296
|
+
return a;
|
|
297
|
+
return Math.min(a, b);
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Compute maxSegments for union.
|
|
301
|
+
*/
|
|
302
|
+
function computeUnionMaxSegments(a, b, aUnbounded, bUnbounded) {
|
|
303
|
+
if (aUnbounded || bUnbounded)
|
|
304
|
+
return undefined;
|
|
305
|
+
if (a === undefined || b === undefined)
|
|
306
|
+
return undefined;
|
|
307
|
+
return Math.max(a, b);
|
|
308
|
+
}
|
|
309
|
+
//# sourceMappingURL=pattern-algebra.js.map
|