clarity-pattern-parser 10.1.13 → 10.1.15
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 +26 -44
- package/dist/index.browser.js.map +1 -1
- package/dist/index.esm.js +26 -44
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +26 -44
- package/dist/index.js.map +1 -1
- package/dist/patterns/Options.d.ts +1 -1
- package/dist/patterns/Sequence.d.ts +1 -0
- package/package.json +1 -1
- package/src/grammar/ComplexGrammar.test.ts +16 -0
- package/src/grammar/Grammar.test.ts +3 -0
- package/src/intellisense/AutoComplete.test.ts +28 -1
- package/src/intellisense/AutoComplete.ts +14 -11
- package/src/intellisense/javascript/Javascript.test.ts +1 -3
- package/src/patterns/Options.ts +13 -23
- package/src/patterns/Sequence.ts +20 -7
- package/src/patterns/DepthCache.ts +0 -26
|
@@ -22,7 +22,7 @@ export declare class Options implements Pattern {
|
|
|
22
22
|
exec(text: string, record?: boolean): ParseResult;
|
|
23
23
|
parse(cursor: Cursor): Node | null;
|
|
24
24
|
private _tryToParse;
|
|
25
|
-
private
|
|
25
|
+
private _isBeyondRecursiveDepth;
|
|
26
26
|
getTokens(): string[];
|
|
27
27
|
getTokensAfter(_childReference: Pattern): string[];
|
|
28
28
|
getNextTokens(): string[];
|
package/package.json
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { patterns } from "./patterns";
|
|
2
|
+
|
|
3
|
+
describe("Complex Grammar Tests", () => {
|
|
4
|
+
test("Nested", () => {
|
|
5
|
+
const { expression } = patterns`
|
|
6
|
+
integer = /[0-9]+/
|
|
7
|
+
variable = /[A-Za-z][A-Za-z0-9]*/
|
|
8
|
+
space = /\\s+/
|
|
9
|
+
or-expression = expression + space? + "||" + space? + expression
|
|
10
|
+
mult-expression = expression + space? + "*" + space? + expression
|
|
11
|
+
expression = or-expression | mult-expression | integer | variable
|
|
12
|
+
`;
|
|
13
|
+
const result = expression.exec("a * b || c");
|
|
14
|
+
expect(result.ast?.toString()).toBe("a * b || c");
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -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 "..";
|
|
12
13
|
|
|
13
14
|
describe("Grammar", () => {
|
|
14
15
|
test("Literal", () => {
|
|
@@ -569,4 +570,6 @@ describe("Grammar", () => {
|
|
|
569
570
|
const result = fullname.exec("John Doe");
|
|
570
571
|
expect(result?.ast?.value).toBe("John Doe");
|
|
571
572
|
});
|
|
573
|
+
|
|
574
|
+
|
|
572
575
|
});
|
|
@@ -490,4 +490,31 @@ describe("AutoComplete", () => {
|
|
|
490
490
|
expect(results.options).toEqual(expected);
|
|
491
491
|
});
|
|
492
492
|
|
|
493
|
-
|
|
493
|
+
test("Furthest Error", () => {
|
|
494
|
+
const branchOne = new Sequence("branch-1", [
|
|
495
|
+
new Literal("space-1-1", " "),
|
|
496
|
+
new Literal("space-1-2", " "),
|
|
497
|
+
new Options('branch-1-options', [
|
|
498
|
+
new Literal("AA", "AA"),
|
|
499
|
+
new Literal("AB", "AB"),
|
|
500
|
+
])
|
|
501
|
+
]);
|
|
502
|
+
const branchTwo = new Sequence("branch-2", [
|
|
503
|
+
new Literal("space-2-1", " "),
|
|
504
|
+
new Literal("space-2-2", " "),
|
|
505
|
+
new Options('branch-2-options', [
|
|
506
|
+
new Literal("BA", "BA"),
|
|
507
|
+
new Literal("BB", "BB")
|
|
508
|
+
])
|
|
509
|
+
]);
|
|
510
|
+
const eitherBranch = new Options("either-branch", [branchOne, branchTwo]);
|
|
511
|
+
|
|
512
|
+
const autoComplete = new AutoComplete(eitherBranch);
|
|
513
|
+
const results = autoComplete.suggestFor(" B");
|
|
514
|
+
const expected = [
|
|
515
|
+
{ startIndex: 3, text: "A" },
|
|
516
|
+
{ startIndex: 3, text: "B" },
|
|
517
|
+
];
|
|
518
|
+
expect(results.options).toEqual(expected);
|
|
519
|
+
})
|
|
520
|
+
});
|
|
@@ -76,9 +76,10 @@ export class AutoComplete {
|
|
|
76
76
|
errorAtIndex = this._cursor.furthestError.endIndex;
|
|
77
77
|
error = this._cursor.furthestError;
|
|
78
78
|
|
|
79
|
-
errorAtIndex = options.reduce(
|
|
80
|
-
Math.max(errorAtIndex, option.startIndex),
|
|
81
|
-
errorAtIndex
|
|
79
|
+
errorAtIndex = options.reduce(
|
|
80
|
+
(errorAtIndex, option) => Math.max(errorAtIndex, option.startIndex),
|
|
81
|
+
errorAtIndex
|
|
82
|
+
);
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
return {
|
|
@@ -98,17 +99,19 @@ export class AutoComplete {
|
|
|
98
99
|
|
|
99
100
|
private _getAllOptions() {
|
|
100
101
|
const errorMatches = this._getOptionsFromErrors();
|
|
101
|
-
const
|
|
102
|
-
const finalResults: SuggestionOption[] = [];
|
|
102
|
+
const validLeafMatches = this._cursor.leafMatches.filter(v => v.node?.lastIndex === this._cursor.getLastIndex())
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
const leafMatchSuggestions = validLeafMatches.map((m) => this._createSuggestionsFromMatch(m)).flat();
|
|
105
|
+
const uniqueResults: SuggestionOption[] = [];
|
|
106
|
+
|
|
107
|
+
[...leafMatchSuggestions, ...errorMatches].forEach(m=>{
|
|
108
|
+
const index = uniqueResults.findIndex(f => m.text === f.text);
|
|
106
109
|
if (index === -1){
|
|
107
|
-
|
|
110
|
+
uniqueResults.push(m);
|
|
108
111
|
}
|
|
109
112
|
});
|
|
110
113
|
|
|
111
|
-
return
|
|
114
|
+
return uniqueResults;
|
|
112
115
|
}
|
|
113
116
|
|
|
114
117
|
private _getOptionsFromErrors() {
|
|
@@ -118,9 +121,9 @@ export class AutoComplete {
|
|
|
118
121
|
const tokens = this._getTokensForPattern(e.pattern);
|
|
119
122
|
const adjustedTokens = tokens.map(t => t.slice(e.endIndex - e.startIndex));
|
|
120
123
|
return this._createSuggestions(e.endIndex, adjustedTokens);
|
|
121
|
-
});
|
|
124
|
+
}).flat();
|
|
122
125
|
|
|
123
|
-
return suggestions
|
|
126
|
+
return suggestions;
|
|
124
127
|
}
|
|
125
128
|
|
|
126
129
|
private _createSuggestionsFromRoot(): SuggestionOption[] {
|
package/src/patterns/Options.ts
CHANGED
|
@@ -4,13 +4,10 @@ import { Pattern } from "./Pattern";
|
|
|
4
4
|
import { clonePatterns } from "./clonePatterns";
|
|
5
5
|
import { findPattern } from "./findPattern";
|
|
6
6
|
import { ParseResult } from "./ParseResult";
|
|
7
|
-
import { DepthCache } from './DepthCache';
|
|
8
7
|
|
|
9
8
|
/*
|
|
10
9
|
The following is created to reduce the overhead of recursion check.
|
|
11
10
|
*/
|
|
12
|
-
|
|
13
|
-
const depthCache = new DepthCache();
|
|
14
11
|
let idIndex = 0;
|
|
15
12
|
|
|
16
13
|
export class Options implements Pattern {
|
|
@@ -90,13 +87,9 @@ export class Options implements Pattern {
|
|
|
90
87
|
|
|
91
88
|
parse(cursor: Cursor): Node | null {
|
|
92
89
|
// This is a cache to help with speed
|
|
93
|
-
this._firstIndex = cursor.index;
|
|
94
|
-
depthCache.incrementDepth(this._id, this._firstIndex);
|
|
95
|
-
|
|
96
90
|
this._firstIndex = cursor.index;
|
|
97
91
|
const node = this._tryToParse(cursor);
|
|
98
92
|
|
|
99
|
-
depthCache.decrementDepth(this._id, this._firstIndex);
|
|
100
93
|
|
|
101
94
|
if (node != null) {
|
|
102
95
|
cursor.moveTo(node.lastIndex);
|
|
@@ -108,19 +101,11 @@ export class Options implements Pattern {
|
|
|
108
101
|
return null;
|
|
109
102
|
}
|
|
110
103
|
|
|
111
|
-
|
|
112
|
-
|
|
113
104
|
private _tryToParse(cursor: Cursor): Node | null {
|
|
114
|
-
|
|
115
|
-
let children = this._children;
|
|
105
|
+
let children = this.children;
|
|
116
106
|
|
|
117
|
-
if (
|
|
118
|
-
children =
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (depthCache.getDepth(this._id, this._firstIndex) > 2) {
|
|
122
|
-
cursor.recordErrorAt(this._firstIndex, this._firstIndex, this);
|
|
123
|
-
return null;
|
|
107
|
+
if (this._isBeyondRecursiveDepth()) {
|
|
108
|
+
children = children.slice().reverse();
|
|
124
109
|
}
|
|
125
110
|
|
|
126
111
|
const results: (Node | null)[] = [];
|
|
@@ -148,18 +133,23 @@ export class Options implements Pattern {
|
|
|
148
133
|
return nonNullResults[0] || null;
|
|
149
134
|
}
|
|
150
135
|
|
|
151
|
-
private
|
|
152
|
-
let
|
|
153
|
-
let pattern = this
|
|
136
|
+
private _isBeyondRecursiveDepth() {
|
|
137
|
+
let depth = 0;
|
|
138
|
+
let pattern: Pattern | null = this;
|
|
154
139
|
|
|
155
140
|
while (pattern != null) {
|
|
156
141
|
if (pattern.id === this.id) {
|
|
157
|
-
|
|
142
|
+
depth++;
|
|
158
143
|
}
|
|
144
|
+
|
|
145
|
+
if (depth >= this.children.length) {
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
|
|
159
149
|
pattern = pattern.parent;
|
|
160
150
|
}
|
|
161
151
|
|
|
162
|
-
return
|
|
152
|
+
return false;
|
|
163
153
|
}
|
|
164
154
|
|
|
165
155
|
getTokens(): string[] {
|
package/src/patterns/Sequence.ts
CHANGED
|
@@ -4,9 +4,7 @@ import { Node } from "../ast/Node";
|
|
|
4
4
|
import { clonePatterns } from "./clonePatterns";
|
|
5
5
|
import { filterOutNull } from "./filterOutNull";
|
|
6
6
|
import { findPattern } from "./findPattern";
|
|
7
|
-
import { DepthCache } from "./DepthCache";
|
|
8
7
|
|
|
9
|
-
const depthCache = new DepthCache();
|
|
10
8
|
let idIndex = 0;
|
|
11
9
|
|
|
12
10
|
export class Sequence implements Pattern {
|
|
@@ -87,12 +85,8 @@ export class Sequence implements Pattern {
|
|
|
87
85
|
parse(cursor: Cursor): Node | null {
|
|
88
86
|
// This is a cache to help with speed
|
|
89
87
|
this._firstIndex = cursor.index;
|
|
90
|
-
depthCache.incrementDepth(this._id, this._firstIndex);
|
|
91
|
-
|
|
92
88
|
this._nodes = [];
|
|
93
|
-
|
|
94
89
|
const passed = this.tryToParse(cursor);
|
|
95
|
-
depthCache.decrementDepth(this._id, this._firstIndex);
|
|
96
90
|
|
|
97
91
|
if (passed) {
|
|
98
92
|
const node = this.createNode(cursor);
|
|
@@ -108,7 +102,7 @@ export class Sequence implements Pattern {
|
|
|
108
102
|
}
|
|
109
103
|
|
|
110
104
|
private tryToParse(cursor: Cursor): boolean {
|
|
111
|
-
if (
|
|
105
|
+
if (this._isBeyondRecursiveDepth()) {
|
|
112
106
|
cursor.recordErrorAt(this._firstIndex, this._firstIndex, this);
|
|
113
107
|
return false;
|
|
114
108
|
}
|
|
@@ -173,6 +167,25 @@ export class Sequence implements Pattern {
|
|
|
173
167
|
return passed;
|
|
174
168
|
}
|
|
175
169
|
|
|
170
|
+
private _isBeyondRecursiveDepth() {
|
|
171
|
+
let depth = 0;
|
|
172
|
+
let pattern: Pattern | null = this;
|
|
173
|
+
|
|
174
|
+
while (pattern != null) {
|
|
175
|
+
if (pattern.id === this.id && this._firstIndex === (pattern as Sequence)._firstIndex) {
|
|
176
|
+
depth++;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (depth > 1) {
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
pattern = pattern.parent;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
|
|
176
189
|
private getLastValidNode(): Node | null {
|
|
177
190
|
const nodes = filterOutNull(this._nodes);
|
|
178
191
|
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export class DepthCache {
|
|
2
|
-
private _depthMap: Record<string, Record<number, number>> = {};
|
|
3
|
-
|
|
4
|
-
getDepth(name: string, cursorIndex: number) {
|
|
5
|
-
if (this._depthMap[name] == null) {
|
|
6
|
-
this._depthMap[name] = {};
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
if (this._depthMap[name][cursorIndex] == null) {
|
|
10
|
-
this._depthMap[name][cursorIndex] = 0;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return this._depthMap[name][cursorIndex];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
incrementDepth(name: string, cursorIndex: number) {
|
|
18
|
-
const depth = this.getDepth(name, cursorIndex);
|
|
19
|
-
this._depthMap[name][cursorIndex] = depth + 1;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
decrementDepth(name: string, cursorIndex: number) {
|
|
23
|
-
const depth = this.getDepth(name, cursorIndex);
|
|
24
|
-
this._depthMap[name][cursorIndex] = depth - 1;
|
|
25
|
-
}
|
|
26
|
-
}
|