clarity-pattern-parser 10.1.25 → 10.2.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.
@@ -0,0 +1,51 @@
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 ExpressionPattern implements Pattern {
6
+ private _id;
7
+ private _type;
8
+ private _name;
9
+ private _parent;
10
+ private _firstIndex;
11
+ private _originalPatterns;
12
+ private _patterns;
13
+ private _unaryPatterns;
14
+ private _binaryPatterns;
15
+ private _recursivePatterns;
16
+ private _recursiveNames;
17
+ private _binaryAssociation;
18
+ private _precedenceMap;
19
+ private _binaryNames;
20
+ get id(): string;
21
+ get type(): string;
22
+ get name(): string;
23
+ get parent(): Pattern | null;
24
+ set parent(pattern: Pattern | null);
25
+ get children(): Pattern[];
26
+ get unaryPatterns(): readonly Pattern[];
27
+ get binaryPatterns(): readonly Pattern[];
28
+ get recursivePatterns(): readonly Pattern[];
29
+ constructor(name: string, patterns: Pattern[]);
30
+ private _organizePatterns;
31
+ private _isBinary;
32
+ private _isBinaryPattern;
33
+ private _extractDelimiter;
34
+ private _extractName;
35
+ private _isRecursive;
36
+ private _isRecursivePattern;
37
+ private _extractRecursiveTail;
38
+ parse(cursor: Cursor): Node | null;
39
+ private _tryToParse;
40
+ test(text: string): boolean;
41
+ exec(text: string, record?: boolean): ParseResult;
42
+ getTokens(): string[];
43
+ getTokensAfter(childReference: Pattern): string[];
44
+ getNextTokens(): string[];
45
+ getPatterns(): Pattern[];
46
+ getPatternsAfter(childReference: Pattern): Pattern[];
47
+ getNextPatterns(): Pattern[];
48
+ find(predicate: (p: Pattern) => boolean): Pattern | null;
49
+ clone(name?: string): Pattern;
50
+ isEqual(pattern: ExpressionPattern): boolean;
51
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clarity-pattern-parser",
3
- "version": "10.1.25",
3
+ "version": "10.2.0",
4
4
  "description": "Parsing Library for Typescript and Javascript.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.esm.js",
package/src/ast/Node.ts CHANGED
@@ -183,6 +183,17 @@ export class Node {
183
183
  return this.findAll(predicate)[0] || null;
184
184
  }
185
185
 
186
+ findRoot() {
187
+ let pattern: Node | null = this;
188
+
189
+ while (true) {
190
+ if (pattern.parent == null) {
191
+ return pattern;
192
+ }
193
+ pattern = pattern.parent;
194
+ }
195
+ }
196
+
186
197
  findAll(predicate: (node: Node) => boolean): Node[] {
187
198
  const matches: Node[] = [];
188
199
 
@@ -284,7 +295,7 @@ export class Node {
284
295
  if (this.children.length === 0) {
285
296
  length = this._value.length;
286
297
  } else {
287
- length = this.children.reduce((acc, c) => acc + c.normalize(acc + startIndex), startIndex);
298
+ length = this.children.reduce((acc, c) => acc + c.normalize(acc + startIndex), startIndex) - startIndex;
288
299
  }
289
300
 
290
301
  this._firstIndex = startIndex;
@@ -9,6 +9,7 @@ import { Repeat } from "../patterns/Repeat";
9
9
  import { Grammar } from "./Grammar";
10
10
  import { Optional } from "../patterns/Optional";
11
11
  import { Context } from "../patterns/Context";
12
+ import { patterns } from "./patterns";
12
13
 
13
14
  describe("Grammar", () => {
14
15
  test("Literal", () => {
@@ -569,4 +570,18 @@ describe("Grammar", () => {
569
570
  const result = fullname.exec("John Doe");
570
571
  expect(result?.ast?.value).toBe("John Doe");
571
572
  });
573
+
574
+ test("Expression Pattern", ()=>{
575
+ const {variables, expression} = patterns`
576
+ variables = "a" | "b" | "c"
577
+ ternary = expression + " ? " + expression + " : " + expression
578
+ expression = ternary | variables
579
+
580
+ bad-ternary = bad-expression + " ? " + bad-expression + " : " + bad-expression
581
+ bad-expression = bad-ternary | bad-ternary
582
+ `;
583
+ let result = expression.exec("a ? b : c");
584
+ debugger;
585
+ expect(result).toBe(result);
586
+ });
572
587
  });
@@ -11,6 +11,7 @@ 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
15
 
15
16
  let anonymousIndexId = 0;
16
17
 
@@ -248,11 +249,34 @@ export class Grammar {
248
249
  const patternNodes = node.children.filter(n => n.name !== "default-divider" && n.name !== "greedy-divider");
249
250
  const isGreedy = node.find(n => n.name === "greedy-divider") != null;
250
251
  const patterns = patternNodes.map(n => this._buildPattern(n));
251
- const or = new Options(name, patterns, isGreedy);
252
+ const hasRecursivePattern = patterns.some(p=>this._isRecursive(name, p));
253
+
254
+ if (hasRecursivePattern && !isGreedy){
255
+ try {
256
+ const expression = new ExpressionPattern(name, patterns);
257
+ return expression;
258
+ } catch{}
259
+ }
252
260
 
261
+ const or = new Options(name, patterns, isGreedy);
253
262
  return or;
254
263
  }
255
264
 
265
+ private _isRecursive(name: string, pattern: Pattern) {
266
+ if (pattern.type === "right-associated" && this._isRecursivePattern(name, pattern.children[0])) {
267
+ return true;
268
+ }
269
+
270
+ return this._isRecursivePattern(name, pattern);
271
+ }
272
+
273
+ 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;
278
+ }
279
+
256
280
  private _buildPattern(node: Node): Pattern {
257
281
  const type = node.name;
258
282
  const name = `anonymous-pattern-${anonymousIndexId++}`;
package/src/index.ts CHANGED
@@ -19,6 +19,7 @@ import { ParseResult } from "./patterns/ParseResult";
19
19
  import { grammar } from "./grammar/patterns/grammar";
20
20
  import { patterns } from "./grammar/patterns";
21
21
  import { Context } from "./patterns/Context";
22
+ import { ExpressionPattern } from "./patterns/ExpressionPattern";
22
23
 
23
24
  export {
24
25
  Node,
@@ -32,6 +33,7 @@ export {
32
33
  CursorHistory,
33
34
  Match,
34
35
  Context,
36
+ ExpressionPattern,
35
37
  Literal,
36
38
  Not,
37
39
  Options,
@@ -0,0 +1,132 @@
1
+ import { Options } from "./Options";
2
+ import { Literal } from './Literal';
3
+ import { ExpressionPattern } from './ExpressionPattern';
4
+ import { Reference } from "./Reference";
5
+ import { Sequence } from './Sequence';
6
+ import { Regex } from './Regex';
7
+ import { Optional } from "./Optional";
8
+ import { AutoComplete } from "../intellisense/AutoComplete";
9
+ import { RightAssociatedPattern } from "./RightAssociatedPattern";
10
+
11
+ function createExpressionPattern() {
12
+ const spaces = new Regex("spaces", "\\s+");
13
+ spaces.setTokens([" "]);
14
+
15
+ const optionalSpaces = new Optional("optional-spaces", spaces);
16
+
17
+ const variables = new Options("variables", [
18
+ new Literal("a", "a"),
19
+ new Literal("b", "b"),
20
+ new Literal("c", "c"),
21
+ new Literal("d", "d"),
22
+ new Literal("e", "e"),
23
+ ]);
24
+
25
+ const mulDivOperator = new Options("mult-div", [
26
+ new Literal("mult", " * "),
27
+ new Literal("div", " / "),
28
+ ]);
29
+
30
+ const addSubOperator = new Options("add-sub", [
31
+ new Literal("add", " + "),
32
+ new Literal("sub", " - "),
33
+ ]);
34
+
35
+ const boolOperator = new Options("and-or", [
36
+ new Literal("and", " && "),
37
+ new Literal("or", " || "),
38
+ ]);
39
+
40
+ const group = new Sequence("group", [
41
+ new Literal("open-paren", "("),
42
+ optionalSpaces,
43
+ new Reference("expression"),
44
+ optionalSpaces,
45
+ new Literal("close-paren", ")"),
46
+ ]);
47
+
48
+ const ternary = new Sequence("ternary", [
49
+ new Reference("expression"),
50
+ optionalSpaces,
51
+ new Literal("question-mark", "?"),
52
+ optionalSpaces,
53
+ new Reference("expression"),
54
+ optionalSpaces,
55
+ new Literal("colon", ":"),
56
+ optionalSpaces,
57
+ new Reference("expression"),
58
+ ]);
59
+
60
+ const multDivExpression = new Sequence("mult-div-expression", [
61
+ new Reference("expression"),
62
+ mulDivOperator,
63
+ new Reference("expression"),
64
+ ]);
65
+
66
+ const addSubExpression = new Sequence("add-sub-expression", [
67
+ new Reference("expression"),
68
+ addSubOperator,
69
+ new Reference("expression"),
70
+ ]);
71
+
72
+ const boolExpression = new Sequence("bool-expression", [
73
+ new Reference("expression"),
74
+ boolOperator,
75
+ new Reference("expression"),
76
+ ]);
77
+
78
+ const expression = new ExpressionPattern("expression", [
79
+ multDivExpression,
80
+ addSubExpression,
81
+ boolExpression,
82
+ ternary,
83
+ group,
84
+ variables,
85
+ ]);
86
+
87
+ return expression;
88
+ }
89
+
90
+ function createOptionsExpression() {
91
+ const a = new Literal("a", "a");
92
+ const b = new Literal("b", "b");
93
+ const c = new Literal("c", "c");
94
+
95
+ const expressionPattern = new ExpressionPattern("expression", [a, b, c]);
96
+ return expressionPattern;
97
+ }
98
+
99
+ describe("Expression Pattern", () => {
100
+ test("Single Expression", () => {
101
+ const expression = createExpressionPattern();
102
+ let result = expression.exec("a");
103
+ result = expression.exec("a + b");
104
+ result = expression.exec("a + b * c * d");
105
+ result = expression.exec("a + b * c || d + e");
106
+ result = expression.exec("(a + b) * (c + d)");
107
+ result = expression.exec("(a + b) * c + (d + e)");
108
+ result = expression.exec("a + b * c ? d : e");
109
+ result = expression.exec("a + b * (a + b * c ? d : e) ? d : e");
110
+ result = expression.exec("a + b * a + b * c ? d : e ? d : e");
111
+ result = expression.exec("a + b * ?");
112
+
113
+ expect(result).toBe(result);
114
+ });
115
+
116
+ test("Options like", ()=>{
117
+ const expression = createOptionsExpression();
118
+ const autoComplete = new AutoComplete(expression);
119
+ const suggestion = autoComplete.suggestFor("a");
120
+
121
+ expect(suggestion).toBe(suggestion);
122
+ });
123
+
124
+ test("Suggest", () => {
125
+ const expression = createExpressionPattern();
126
+
127
+ const autoComplete = new AutoComplete(expression);
128
+ const suggestion = autoComplete.suggestFor("a ? b ");
129
+
130
+ expect(suggestion).toBe(suggestion);
131
+ });
132
+ });