clarity-pattern-parser 11.0.2 → 11.0.4
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/dist/index.browser.js +132 -14
- package/dist/index.browser.js.map +1 -1
- package/dist/index.esm.js +132 -14
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +132 -14
- package/dist/index.js.map +1 -1
- package/dist/patterns/PrecedenceTree.d.ts +1 -1
- package/dist/patterns/RightAssociatedPattern.d.ts +31 -0
- package/package.json +1 -1
- package/src/grammar/Grammar.test.ts +11 -0
- package/src/grammar/Grammar.ts +24 -9
- package/src/grammar/patterns/optionsLiteral.ts +7 -1
- package/src/patterns/PrecedenceTree.test.ts +113 -1
- package/src/patterns/PrecedenceTree.ts +35 -7
- package/src/patterns/RightAssociatedPattern.ts +0 -2
|
@@ -11,9 +11,9 @@ export declare class PrecedenceTree {
|
|
|
11
11
|
private _binaryPlaceholder;
|
|
12
12
|
private _binaryNode;
|
|
13
13
|
private _atomNode;
|
|
14
|
-
private _orphanedAtom;
|
|
15
14
|
private _precedenceMap;
|
|
16
15
|
private _associationMap;
|
|
16
|
+
private _revertBinary;
|
|
17
17
|
constructor(precedenceMap?: Record<string, number>, associationMap?: Record<string, Association>);
|
|
18
18
|
addPrefix(name: string, ...prefix: Node[]): void;
|
|
19
19
|
addPostfix(name: string, ...postfix: Node[]): void;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Node } from "../ast/Node";
|
|
2
|
+
import { Cursor } from "./Cursor";
|
|
3
|
+
import { ParseResult } from "./ParseResult";
|
|
4
|
+
import { Pattern } from "./Pattern";
|
|
5
|
+
export declare class RightAssociatedPattern implements Pattern {
|
|
6
|
+
private _id;
|
|
7
|
+
private _type;
|
|
8
|
+
private _name;
|
|
9
|
+
private _parent;
|
|
10
|
+
private _children;
|
|
11
|
+
get id(): string;
|
|
12
|
+
get type(): string;
|
|
13
|
+
get name(): string;
|
|
14
|
+
get parent(): Pattern | null;
|
|
15
|
+
set parent(pattern: Pattern | null);
|
|
16
|
+
get children(): Pattern[];
|
|
17
|
+
get startedOnIndex(): number;
|
|
18
|
+
constructor(pattern: Pattern);
|
|
19
|
+
parse(cursor: Cursor): Node | null;
|
|
20
|
+
exec(text: string, record?: boolean | undefined): ParseResult;
|
|
21
|
+
test(text: string, record?: boolean | undefined): boolean;
|
|
22
|
+
clone(_name?: string | undefined): Pattern;
|
|
23
|
+
getTokens(): string[];
|
|
24
|
+
getTokensAfter(_childReference: Pattern): string[];
|
|
25
|
+
getNextTokens(): string[];
|
|
26
|
+
getPatterns(): Pattern[];
|
|
27
|
+
getPatternsAfter(_childReference: Pattern): Pattern[];
|
|
28
|
+
getNextPatterns(): Pattern[];
|
|
29
|
+
find(predicate: (pattern: Pattern) => boolean): Pattern | null;
|
|
30
|
+
isEqual(pattern: Pattern): boolean;
|
|
31
|
+
}
|
package/package.json
CHANGED
|
@@ -584,4 +584,15 @@ describe("Grammar", () => {
|
|
|
584
584
|
expect(result).toBe(result);
|
|
585
585
|
});
|
|
586
586
|
|
|
587
|
+
test("Expression Pattern With Right Association", () => {
|
|
588
|
+
const { expression } = patterns`
|
|
589
|
+
variables = "a" | "b" | "c" | "d" | "e"
|
|
590
|
+
ternary = expression + " ? " + expression + " : " + expression
|
|
591
|
+
expression = ternary right | variables
|
|
592
|
+
`;
|
|
593
|
+
let result = expression.exec("a ? b : c ? d : e");
|
|
594
|
+
debugger;
|
|
595
|
+
expect(result).toBe(result);
|
|
596
|
+
});
|
|
597
|
+
|
|
587
598
|
});
|
package/src/grammar/Grammar.ts
CHANGED
|
@@ -11,7 +11,8 @@ import { Repeat, RepeatOptions } from "../patterns/Repeat";
|
|
|
11
11
|
import { AutoComplete } from "../intellisense/AutoComplete";
|
|
12
12
|
import { Optional } from "../patterns/Optional";
|
|
13
13
|
import { Context } from "../patterns/Context";
|
|
14
|
-
import {ExpressionPattern} from "../patterns/ExpressionPattern";
|
|
14
|
+
import { ExpressionPattern } from "../patterns/ExpressionPattern";
|
|
15
|
+
import { RightAssociatedPattern } from "../patterns/RightAssociatedPattern";
|
|
15
16
|
|
|
16
17
|
let anonymousIndexId = 0;
|
|
17
18
|
|
|
@@ -248,14 +249,22 @@ export class Grammar {
|
|
|
248
249
|
private _buildOptions(name: string, node: Node) {
|
|
249
250
|
const patternNodes = node.children.filter(n => n.name !== "default-divider" && n.name !== "greedy-divider");
|
|
250
251
|
const isGreedy = node.find(n => n.name === "greedy-divider") != null;
|
|
251
|
-
const patterns = patternNodes.map(n =>
|
|
252
|
-
|
|
252
|
+
const patterns = patternNodes.map(n => {
|
|
253
|
+
const rightAssociated = n.find(n => n.name === "right-associated");
|
|
254
|
+
if (rightAssociated != null) {
|
|
255
|
+
return new RightAssociatedPattern(this._buildPattern(n.children[0]));
|
|
256
|
+
} else {
|
|
257
|
+
return this._buildPattern(n.children[0]);
|
|
258
|
+
}
|
|
253
259
|
|
|
254
|
-
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
const hasRecursivePattern = patterns.some(p => this._isRecursive(name, p));
|
|
263
|
+
if (hasRecursivePattern && !isGreedy) {
|
|
255
264
|
try {
|
|
256
265
|
const expression = new ExpressionPattern(name, patterns);
|
|
257
266
|
return expression;
|
|
258
|
-
} catch{}
|
|
267
|
+
} catch { }
|
|
259
268
|
}
|
|
260
269
|
|
|
261
270
|
const or = new Options(name, patterns, isGreedy);
|
|
@@ -271,10 +280,16 @@ export class Grammar {
|
|
|
271
280
|
}
|
|
272
281
|
|
|
273
282
|
private _isRecursivePattern(name: string, pattern: Pattern) {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
283
|
+
if (pattern.children.length === 0){
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const firstChild = pattern.children[0];
|
|
288
|
+
const lastChild = pattern.children[pattern.children.length - 1];
|
|
289
|
+
const isLongEnough = pattern.children.length >= 2;
|
|
290
|
+
return pattern.type === "sequence" && isLongEnough &&
|
|
291
|
+
(firstChild.type === "reference" && firstChild.name === name) ||
|
|
292
|
+
(lastChild.type === "reference" && lastChild.name === name);
|
|
278
293
|
}
|
|
279
294
|
|
|
280
295
|
private _buildPattern(node: Node): Pattern {
|
|
@@ -3,11 +3,17 @@ import { Regex } from "../../patterns/Regex";
|
|
|
3
3
|
import { name } from "./name";
|
|
4
4
|
import { anonymousPattern } from "./anonymousPattern";
|
|
5
5
|
import { Options } from "../../patterns/Options";
|
|
6
|
+
import { Sequence } from "../../patterns/Sequence";
|
|
7
|
+
import { Optional } from "../../patterns/Optional";
|
|
8
|
+
import { Literal } from "../../patterns/Literal";
|
|
6
9
|
|
|
7
10
|
const patternName = name.clone("pattern-name");
|
|
8
11
|
patternName.setTokens(["[PATTERN_NAME]"]);
|
|
9
12
|
|
|
10
|
-
const patterns = new
|
|
13
|
+
const patterns = new Sequence("patterns", [
|
|
14
|
+
new Options("options-patterns", [patternName, anonymousPattern]),
|
|
15
|
+
new Optional("optional-right-associated", new Literal("right-associated", " right"))
|
|
16
|
+
]);
|
|
11
17
|
const defaultDivider = new Regex("default-divider", "\\s*[|]\\s*");
|
|
12
18
|
defaultDivider.setTokens(["|"]);
|
|
13
19
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PrecedenceTree } from "./PrecedenceTree";
|
|
1
|
+
import { Association, PrecedenceTree } from "./PrecedenceTree";
|
|
2
2
|
import { Node } from "../ast/Node";
|
|
3
3
|
|
|
4
4
|
describe("Precedence Tree", () => {
|
|
@@ -159,4 +159,116 @@ describe("Precedence Tree", () => {
|
|
|
159
159
|
expect(result?.toString()).toBe("!a++*b+c");
|
|
160
160
|
expect(result?.toCycleFreeObject()).toEqual(expected.toCycleFreeObject());
|
|
161
161
|
});
|
|
162
|
+
|
|
163
|
+
test("add Partial Binary With Lower Precedence", () => {
|
|
164
|
+
const tree = new PrecedenceTree({
|
|
165
|
+
mul: 0,
|
|
166
|
+
add: 1,
|
|
167
|
+
bool: 2
|
|
168
|
+
}, {});
|
|
169
|
+
|
|
170
|
+
tree.addAtom(Node.createValueNode("literal", "a", "a"));
|
|
171
|
+
tree.addBinary("add", Node.createValueNode("literal", "+", "+"));
|
|
172
|
+
tree.addAtom(Node.createValueNode("literal", "b", "b"));
|
|
173
|
+
tree.addBinary("mul", Node.createValueNode("literal", "*", "*"));
|
|
174
|
+
tree.addAtom(Node.createValueNode("literal", "c", "c"));
|
|
175
|
+
tree.addBinary("bool", Node.createValueNode("literal", "||", "||"));
|
|
176
|
+
|
|
177
|
+
const result = tree.commit();
|
|
178
|
+
const expected = Node.createNode("expression", "add", [
|
|
179
|
+
Node.createValueNode("literal", "a", "a"),
|
|
180
|
+
Node.createValueNode("literal", "+", "+"),
|
|
181
|
+
Node.createNode("expression", "mul", [
|
|
182
|
+
Node.createValueNode("literal", "b", "b"),
|
|
183
|
+
Node.createValueNode("literal", "*", "*"),
|
|
184
|
+
Node.createValueNode("literal", "c", "c"),
|
|
185
|
+
]),
|
|
186
|
+
]);
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
expect(result?.toString()).toBe("a+b*c");
|
|
190
|
+
expect(result?.toCycleFreeObject()).toEqual(expected.toCycleFreeObject());
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
test("add Partial Binary With Equal Precedence", () => {
|
|
194
|
+
const tree = new PrecedenceTree({
|
|
195
|
+
mul: 0,
|
|
196
|
+
add: 1,
|
|
197
|
+
bool: 2
|
|
198
|
+
}, {});
|
|
199
|
+
|
|
200
|
+
tree.addAtom(Node.createValueNode("literal", "a", "a"));
|
|
201
|
+
tree.addBinary("add", Node.createValueNode("literal", "+", "+"));
|
|
202
|
+
tree.addAtom(Node.createValueNode("literal", "b", "b"));
|
|
203
|
+
tree.addBinary("mul", Node.createValueNode("literal", "*", "*"));
|
|
204
|
+
tree.addAtom(Node.createValueNode("literal", "c", "c"));
|
|
205
|
+
tree.addBinary("mul", Node.createValueNode("literal", "*", "*"));
|
|
206
|
+
|
|
207
|
+
const result = tree.commit();
|
|
208
|
+
const expected = Node.createNode("expression", "add", [
|
|
209
|
+
Node.createValueNode("literal", "a", "a"),
|
|
210
|
+
Node.createValueNode("literal", "+", "+"),
|
|
211
|
+
Node.createNode("expression", "mul", [
|
|
212
|
+
Node.createValueNode("literal", "b", "b"),
|
|
213
|
+
Node.createValueNode("literal", "*", "*"),
|
|
214
|
+
Node.createValueNode("literal", "c", "c"),
|
|
215
|
+
]),
|
|
216
|
+
]);
|
|
217
|
+
|
|
218
|
+
expect(result?.toString()).toBe("a+b*c");
|
|
219
|
+
expect(result?.toCycleFreeObject()).toEqual(expected.toCycleFreeObject());
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("add Partial Binary With Equal Precedence And Right Associated", () => {
|
|
223
|
+
const tree = new PrecedenceTree({
|
|
224
|
+
mul: 0,
|
|
225
|
+
add: 1,
|
|
226
|
+
bool: 2
|
|
227
|
+
}, { mul: Association.right });
|
|
228
|
+
|
|
229
|
+
tree.addAtom(Node.createValueNode("literal", "a", "a"));
|
|
230
|
+
tree.addBinary("add", Node.createValueNode("literal", "+", "+"));
|
|
231
|
+
tree.addAtom(Node.createValueNode("literal", "b", "b"));
|
|
232
|
+
tree.addBinary("mul", Node.createValueNode("literal", "*", "*"));
|
|
233
|
+
tree.addAtom(Node.createValueNode("literal", "c", "c"));
|
|
234
|
+
tree.addBinary("mul", Node.createValueNode("literal", "*", "*"));
|
|
235
|
+
|
|
236
|
+
const result = tree.commit();
|
|
237
|
+
const expected = Node.createNode("expression", "add", [
|
|
238
|
+
Node.createValueNode("literal", "a", "a"),
|
|
239
|
+
Node.createValueNode("literal", "+", "+"),
|
|
240
|
+
Node.createNode("expression", "mul", [
|
|
241
|
+
Node.createValueNode("literal", "b", "b"),
|
|
242
|
+
Node.createValueNode("literal", "*", "*"),
|
|
243
|
+
Node.createValueNode("literal", "c", "c"),
|
|
244
|
+
]),
|
|
245
|
+
]);
|
|
246
|
+
|
|
247
|
+
expect(result?.toString()).toBe("a+b*c");
|
|
248
|
+
expect(result?.toCycleFreeObject()).toEqual(expected.toCycleFreeObject());
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test("add Partial Binary With Greater Precedence", () => {
|
|
252
|
+
const tree = new PrecedenceTree({
|
|
253
|
+
mul: 0,
|
|
254
|
+
add: 1,
|
|
255
|
+
bool: 2
|
|
256
|
+
}, {});
|
|
257
|
+
|
|
258
|
+
tree.addAtom(Node.createValueNode("literal", "a", "a"));
|
|
259
|
+
tree.addBinary("add", Node.createValueNode("literal", "+", "+"));
|
|
260
|
+
tree.addAtom(Node.createValueNode("literal", "b", "b"));
|
|
261
|
+
tree.addBinary("mul", Node.createValueNode("literal", "*", "*"));
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
const result = tree.commit();
|
|
265
|
+
const expected = Node.createNode("expression", "add", [
|
|
266
|
+
Node.createValueNode("literal", "a", "a"),
|
|
267
|
+
Node.createValueNode("literal", "+", "+"),
|
|
268
|
+
Node.createValueNode("literal", "b", "b"),
|
|
269
|
+
]);
|
|
270
|
+
|
|
271
|
+
expect(result?.toString()).toBe("a+b");
|
|
272
|
+
expect(result?.toCycleFreeObject()).toEqual(expected.toCycleFreeObject());
|
|
273
|
+
});
|
|
162
274
|
});
|
|
@@ -13,9 +13,9 @@ export class PrecedenceTree {
|
|
|
13
13
|
private _binaryPlaceholder: Node;
|
|
14
14
|
private _binaryNode: Node | null;
|
|
15
15
|
private _atomNode: Node | null;
|
|
16
|
-
private _orphanedAtom: Node | null;
|
|
17
16
|
private _precedenceMap: Record<string, number>;
|
|
18
17
|
private _associationMap: Record<string, Association>;
|
|
18
|
+
private _revertBinary: () => void;
|
|
19
19
|
|
|
20
20
|
constructor(precedenceMap: Record<string, number> = {}, associationMap: Record<string, Association> = {}) {
|
|
21
21
|
this._prefixPlaceholder = Node.createNode("placeholder", "prefix-placeholder");
|
|
@@ -25,9 +25,9 @@ export class PrecedenceTree {
|
|
|
25
25
|
this._binaryPlaceholder = Node.createNode("placeholder", "binary-placeholder");
|
|
26
26
|
this._atomNode = null;
|
|
27
27
|
this._binaryNode = null;
|
|
28
|
-
this._orphanedAtom = null;
|
|
29
28
|
this._precedenceMap = precedenceMap;
|
|
30
29
|
this._associationMap = associationMap;
|
|
30
|
+
this._revertBinary = () => { };
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
addPrefix(name: string, ...prefix: Node[]) {
|
|
@@ -72,12 +72,17 @@ export class PrecedenceTree {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
this._binaryPlaceholder.remove();
|
|
75
|
-
this._orphanedAtom = lastAtomNode;
|
|
76
75
|
|
|
77
76
|
if (lastBinaryNode == null) {
|
|
78
77
|
const node = Node.createNode("expression", name, [lastAtomNode, ...delimiterNode, this._binaryPlaceholder]);
|
|
79
78
|
|
|
80
79
|
this._binaryNode = node;
|
|
80
|
+
|
|
81
|
+
this._revertBinary = () => {
|
|
82
|
+
lastAtomNode.remove();
|
|
83
|
+
this._binaryNode = lastAtomNode;
|
|
84
|
+
};
|
|
85
|
+
|
|
81
86
|
return;
|
|
82
87
|
}
|
|
83
88
|
|
|
@@ -86,6 +91,11 @@ export class PrecedenceTree {
|
|
|
86
91
|
|
|
87
92
|
lastBinaryNode.appendChild(node);
|
|
88
93
|
|
|
94
|
+
this._revertBinary = () => {
|
|
95
|
+
node.replaceWith(lastAtomNode);
|
|
96
|
+
this._binaryNode = lastBinaryNode;
|
|
97
|
+
};
|
|
98
|
+
|
|
89
99
|
this._binaryNode = node;
|
|
90
100
|
} else if (precedence === lastPrecendece) {
|
|
91
101
|
const node = Node.createNode("expression", name, []);
|
|
@@ -94,6 +104,13 @@ export class PrecedenceTree {
|
|
|
94
104
|
lastBinaryNode.appendChild(lastAtomNode);
|
|
95
105
|
|
|
96
106
|
node.append(lastBinaryNode, ...delimiterNode, this._binaryPlaceholder);
|
|
107
|
+
|
|
108
|
+
this._revertBinary = () => {
|
|
109
|
+
lastBinaryNode.remove();
|
|
110
|
+
node.replaceWith(lastBinaryNode);
|
|
111
|
+
this._binaryNode = lastBinaryNode;
|
|
112
|
+
};
|
|
113
|
+
|
|
97
114
|
this._binaryNode = node;
|
|
98
115
|
} else if (precedence > lastPrecendece) {
|
|
99
116
|
let ancestor = lastBinaryNode.parent;
|
|
@@ -115,6 +132,12 @@ export class PrecedenceTree {
|
|
|
115
132
|
root.replaceWith(node);
|
|
116
133
|
node.append(root, ...delimiterNode, this._binaryPlaceholder);
|
|
117
134
|
|
|
135
|
+
this._revertBinary = () => {
|
|
136
|
+
root.remove();
|
|
137
|
+
node.replaceWith(root);
|
|
138
|
+
this._binaryNode = root;
|
|
139
|
+
};
|
|
140
|
+
|
|
118
141
|
this._binaryNode = node;
|
|
119
142
|
|
|
120
143
|
|
|
@@ -122,6 +145,12 @@ export class PrecedenceTree {
|
|
|
122
145
|
const node = Node.createNode("expression", name, [lastAtomNode, ...delimiterNode, this._binaryPlaceholder]);
|
|
123
146
|
lastBinaryNode.appendChild(node);
|
|
124
147
|
|
|
148
|
+
this._revertBinary = () => {
|
|
149
|
+
lastAtomNode.remove();
|
|
150
|
+
node.replaceWith(lastAtomNode);
|
|
151
|
+
this._binaryNode = lastBinaryNode;
|
|
152
|
+
};
|
|
153
|
+
|
|
125
154
|
this._binaryNode = node;
|
|
126
155
|
}
|
|
127
156
|
|
|
@@ -171,7 +200,7 @@ export class PrecedenceTree {
|
|
|
171
200
|
this._atomNode = node;
|
|
172
201
|
}
|
|
173
202
|
|
|
174
|
-
hasAtom(){
|
|
203
|
+
hasAtom() {
|
|
175
204
|
return this._atomNode != null;
|
|
176
205
|
}
|
|
177
206
|
|
|
@@ -183,8 +212,8 @@ export class PrecedenceTree {
|
|
|
183
212
|
const atomNode = this._compileAtomNode();
|
|
184
213
|
|
|
185
214
|
if (atomNode == null) {
|
|
186
|
-
|
|
187
|
-
this.
|
|
215
|
+
this._revertBinary();
|
|
216
|
+
let root = this._binaryNode.findRoot();
|
|
188
217
|
this.reset();
|
|
189
218
|
return root;
|
|
190
219
|
} else {
|
|
@@ -199,7 +228,6 @@ export class PrecedenceTree {
|
|
|
199
228
|
private reset() {
|
|
200
229
|
this._prefixNode = null;
|
|
201
230
|
this._atomNode = null;
|
|
202
|
-
this._orphanedAtom = null;
|
|
203
231
|
this._postfixNode = null;
|
|
204
232
|
this._binaryNode = null;
|
|
205
233
|
}
|