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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clarity-pattern-parser",
3
- "version": "11.0.2",
3
+ "version": "11.0.4",
4
4
  "description": "Parsing Library for Typescript and Javascript.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.esm.js",
@@ -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
  });
@@ -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 => this._buildPattern(n));
252
- const hasRecursivePattern = patterns.some(p=>this._isRecursive(name, p));
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
- if (hasRecursivePattern && !isGreedy){
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
- return pattern.type === "sequence" &&
275
- pattern.children[0].type === "reference" &&
276
- pattern.children[0].name === name &&
277
- pattern.children.length > 2;
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 Options("options-patterns", [patternName, anonymousPattern]);
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
- let root = this._binaryPlaceholder.findRoot();
187
- this._binaryPlaceholder.parent?.replaceWith(this._orphanedAtom as Node);
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
  }
@@ -12,8 +12,6 @@ export class RightAssociatedPattern implements Pattern {
12
12
  private _parent: Pattern | null;
13
13
  private _children: Pattern[];
14
14
 
15
- shouldCompactAst = false;
16
-
17
15
  get id(): string {
18
16
  return this._id;
19
17
  }