clarity-pattern-parser 4.0.3 → 6.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 +466 -1
- package/TODO.md +76 -2
- package/dist/ast/Node.d.ts +49 -11
- package/dist/ast/Visitor.d.ts +31 -31
- package/dist/index.browser.js +1513 -1495
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +17 -17
- package/dist/index.esm.js +1480 -1459
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1481 -1463
- package/dist/index.js.map +1 -1
- package/dist/intellisense/AutoComplete.d.ts +28 -0
- package/dist/intellisense/Suggestion.d.ts +11 -0
- package/dist/intellisense/SuggestionOption.d.ts +4 -0
- package/dist/patterns/And.d.ts +37 -24
- package/dist/patterns/Cursor.d.ts +37 -0
- package/dist/patterns/CursorHistory.d.ts +30 -0
- package/dist/patterns/Literal.d.ts +35 -19
- package/dist/patterns/Not.d.ts +29 -11
- package/dist/patterns/Or.d.ts +33 -22
- package/dist/patterns/ParseError.d.ts +6 -8
- package/dist/patterns/ParseResult.d.ts +6 -0
- package/dist/patterns/Pattern.d.ts +20 -26
- package/dist/patterns/Reference.d.ts +34 -12
- package/dist/patterns/Regex.d.ts +41 -21
- package/dist/patterns/Repeat.d.ts +38 -20
- package/dist/patterns/clonePatterns.d.ts +2 -0
- package/dist/patterns/filterOutNull.d.ts +2 -0
- package/dist/patterns/findPattern.d.ts +2 -0
- package/dist/patterns/getNextPattern.d.ts +2 -0
- package/jest.config.js +2 -1
- package/package.json +4 -5
- package/rollup.config.js +1 -1
- package/src/ast/Node.test.ts +364 -0
- package/src/ast/Node.ts +237 -23
- package/src/index.ts +25 -27
- package/src/intellisense/AutoComplete.test.ts +150 -0
- package/src/intellisense/AutoComplete.ts +200 -0
- package/src/intellisense/Suggestion.ts +12 -0
- package/src/intellisense/SuggestionOption.ts +4 -0
- package/src/{tests/cssPatterns → intellisense/css}/cssValue.ts +1 -1
- package/src/{tests/cssPatterns → intellisense/css}/divider.ts +2 -1
- package/src/intellisense/css/hex.ts +6 -0
- package/src/{tests/cssPatterns → intellisense/css}/method.ts +8 -9
- package/src/intellisense/css/name.ts +5 -0
- package/src/{tests/javascriptPatterns → intellisense/css}/number.ts +3 -3
- package/src/intellisense/css/spaces.ts +6 -0
- package/src/intellisense/css/unit.ts +10 -0
- package/src/{tests/cssPatterns → intellisense/css}/value.ts +1 -1
- package/src/{tests/cssPatterns → intellisense/css}/values.ts +1 -1
- package/src/intellisense/javascript/Javascript.test.ts +203 -0
- package/src/intellisense/javascript/arrayLiteral.ts +25 -0
- package/src/intellisense/javascript/deleteStatement.ts +14 -0
- package/src/intellisense/javascript/escapedCharacter.ts +49 -0
- package/src/intellisense/javascript/exponent.ts +24 -0
- package/src/intellisense/javascript/expression.ts +87 -0
- package/src/intellisense/javascript/expressionStatement.ts +29 -0
- package/src/intellisense/javascript/fraction.ts +11 -0
- package/src/intellisense/javascript/infixOperator.ts +36 -0
- package/src/intellisense/javascript/integer.ts +7 -0
- package/src/intellisense/javascript/invocation.ts +28 -0
- package/src/intellisense/javascript/literal.ts +14 -0
- package/src/intellisense/javascript/name.ts +3 -0
- package/src/intellisense/javascript/numberLiteral.ts +10 -0
- package/src/intellisense/javascript/objectLiteral.ts +30 -0
- package/src/intellisense/javascript/optionalSpaces.ts +3 -0
- package/src/intellisense/javascript/parameters.ts +20 -0
- package/src/intellisense/javascript/prefixOperator.ts +13 -0
- package/src/intellisense/javascript/propertyAccess.ts +23 -0
- package/src/intellisense/javascript/stringLiteral.ts +28 -0
- package/src/patterns/And.test.ts +310 -0
- package/src/patterns/And.ts +244 -119
- package/src/patterns/Cursor.test.ts +93 -0
- package/src/patterns/Cursor.ts +133 -0
- package/src/patterns/CursorHistory.test.ts +54 -0
- package/src/patterns/CursorHistory.ts +95 -0
- package/src/patterns/Literal.test.ts +166 -0
- package/src/patterns/Literal.ts +141 -62
- package/src/patterns/Not.test.ts +168 -0
- package/src/patterns/Not.ts +113 -32
- package/src/patterns/Or.test.ts +209 -0
- package/src/patterns/Or.ts +128 -97
- package/src/patterns/ParseError.ts +3 -7
- package/src/patterns/ParseResult.ts +7 -0
- package/src/patterns/Pattern.ts +21 -150
- package/src/patterns/Reference.test.ts +193 -0
- package/src/patterns/Reference.ts +114 -88
- package/src/patterns/Regex.test.ts +133 -0
- package/src/patterns/Regex.ts +117 -60
- package/src/patterns/Repeat.test.ts +218 -0
- package/src/patterns/Repeat.ts +220 -103
- package/src/patterns/clonePatterns.ts +5 -0
- package/src/patterns/filterOutNull.ts +13 -0
- package/src/patterns/findPattern.ts +25 -0
- package/src/Cursor.ts +0 -141
- package/src/CursorHistory.ts +0 -146
- package/src/TextSuggester.ts +0 -317
- package/src/ast/Visitor.ts +0 -271
- package/src/patterns/LookAhead.ts +0 -32
- package/src/patterns/Recursive.ts +0 -92
- package/src/tests/And.test.ts +0 -180
- package/src/tests/ComplexExamples.test.ts +0 -86
- package/src/tests/CssPatterns.test.ts +0 -90
- package/src/tests/CursorHistory.test.ts +0 -107
- package/src/tests/Cusor.test.ts +0 -174
- package/src/tests/HtmlPatterns.test.ts +0 -34
- package/src/tests/Literal.test.ts +0 -79
- package/src/tests/LookAhead.test.ts +0 -44
- package/src/tests/Not.test.ts +0 -51
- package/src/tests/Or.test.ts +0 -113
- package/src/tests/Pattern.test.ts +0 -290
- package/src/tests/Recursive.test.ts +0 -64
- package/src/tests/Reference.test.ts +0 -16
- package/src/tests/Repeat.test.ts +0 -75
- package/src/tests/SpeedTest.test.ts +0 -31
- package/src/tests/TextSuggester.test.ts +0 -297
- package/src/tests/Visitor.test.ts +0 -331
- package/src/tests/cssPatterns/hex.ts +0 -5
- package/src/tests/cssPatterns/name.ts +0 -5
- package/src/tests/cssPatterns/number.ts +0 -8
- package/src/tests/cssPatterns/spaces.ts +0 -5
- package/src/tests/cssPatterns/unit.ts +0 -8
- package/src/tests/htmlPatterns/element.ts +0 -49
- package/src/tests/javascriptPatterns/boolean.ts +0 -10
- package/src/tests/javascriptPatterns/json.ts +0 -67
- package/src/tests/javascriptPatterns/name.ts +0 -5
- package/src/tests/javascriptPatterns/objectLiteral.ts +0 -40
- package/src/tests/javascriptPatterns/string.ts +0 -84
- package/src/tests/javascriptPatterns/unit.ts +0 -8
- package/src/tests/javascriptPatterns/whitespace.ts +0 -44
- package/src/tests/naturalLanguage/filter.ts +0 -37
- package/src/tests/patterns/sentence.ts +0 -37
- /package/src/{tests/cssPatterns → intellisense/css}/optionalSpaces.ts +0 -0
package/src/patterns/Or.ts
CHANGED
|
@@ -1,132 +1,163 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
this.
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
private assertArguments() {
|
|
20
|
-
if (this._children.length < 2) {
|
|
21
|
-
throw new Error(
|
|
22
|
-
"Invalid Argument: OrValue needs to have more than one value pattern."
|
|
23
|
-
);
|
|
24
|
-
}
|
|
1
|
+
import { Node } from "../ast/Node";
|
|
2
|
+
import { Cursor } from "./Cursor";
|
|
3
|
+
import { Pattern } from "./Pattern";
|
|
4
|
+
import { clonePatterns } from "./clonePatterns";
|
|
5
|
+
import { findPattern } from "./findPattern";
|
|
6
|
+
|
|
7
|
+
export class Or implements Pattern {
|
|
8
|
+
private _type: string;
|
|
9
|
+
private _name: string;
|
|
10
|
+
private _parent: Pattern | null;
|
|
11
|
+
private _children: Pattern[];
|
|
12
|
+
private _isOptional: boolean;
|
|
13
|
+
private _firstIndex: number;
|
|
14
|
+
|
|
15
|
+
get type(): string {
|
|
16
|
+
return this._type;
|
|
17
|
+
}
|
|
25
18
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
19
|
+
get name(): string {
|
|
20
|
+
return this._name;
|
|
21
|
+
}
|
|
29
22
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
get parent(): Pattern | null {
|
|
24
|
+
return this._parent;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
set parent(pattern: Pattern | null) {
|
|
28
|
+
this._parent = pattern;
|
|
33
29
|
}
|
|
34
30
|
|
|
35
|
-
|
|
36
|
-
this.
|
|
37
|
-
this.errors = [];
|
|
38
|
-
this.node = null;
|
|
39
|
-
this.cursor = cursor;
|
|
40
|
-
this.mark = cursor.mark();
|
|
31
|
+
get children(): Pattern[] {
|
|
32
|
+
return this._children;
|
|
41
33
|
}
|
|
42
34
|
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
get isOptional(): boolean {
|
|
36
|
+
return this._isOptional;
|
|
37
|
+
}
|
|
45
38
|
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
constructor(name: string, options: Pattern[], isOptional: boolean = false) {
|
|
40
|
+
if (options.length === 0) {
|
|
41
|
+
throw new Error("Need at least one pattern with an 'or' pattern.");
|
|
48
42
|
}
|
|
49
|
-
|
|
43
|
+
|
|
44
|
+
const children = clonePatterns(options, false);
|
|
45
|
+
this._assignChildrenToParent(children);
|
|
46
|
+
|
|
47
|
+
this._type = "or";
|
|
48
|
+
this._name = name;
|
|
49
|
+
this._parent = null;
|
|
50
|
+
this._children = children;
|
|
51
|
+
this._isOptional = isOptional;
|
|
52
|
+
this._firstIndex = 0;
|
|
50
53
|
}
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
private _assignChildrenToParent(children: Pattern[]): void {
|
|
56
|
+
for (const child of children) {
|
|
57
|
+
child.parent = this;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
test(text: string) {
|
|
62
|
+
const cursor = new Cursor(text);
|
|
63
|
+
const ast = this.parse(cursor);
|
|
55
64
|
|
|
56
|
-
return
|
|
65
|
+
return ast?.value === text;
|
|
57
66
|
}
|
|
58
67
|
|
|
59
|
-
|
|
60
|
-
const cursor =
|
|
68
|
+
exec(text: string) {
|
|
69
|
+
const cursor = new Cursor(text);
|
|
70
|
+
const ast = this.parse(cursor);
|
|
61
71
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
72
|
+
return {
|
|
73
|
+
ast: ast?.value === text ? ast : null,
|
|
74
|
+
cursor
|
|
75
|
+
};
|
|
76
|
+
}
|
|
66
77
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
parse(cursor: Cursor): Node | null {
|
|
79
|
+
this._firstIndex = cursor.index;
|
|
80
|
+
|
|
81
|
+
const node = this._tryToParse(cursor);
|
|
82
|
+
|
|
83
|
+
if (node != null) {
|
|
84
|
+
cursor.resolveError();
|
|
85
|
+
return node
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!this._isOptional) {
|
|
89
|
+
cursor.recordErrorAt(this._firstIndex, this)
|
|
90
|
+
return null;
|
|
76
91
|
}
|
|
92
|
+
|
|
93
|
+
cursor.resolveError();
|
|
94
|
+
cursor.moveTo(this._firstIndex);
|
|
95
|
+
return null;
|
|
77
96
|
}
|
|
78
97
|
|
|
79
|
-
private
|
|
80
|
-
const
|
|
81
|
-
|
|
98
|
+
private _tryToParse(cursor: Cursor): Node | null {
|
|
99
|
+
for (const pattern of this._children) {
|
|
100
|
+
cursor.moveTo(this._firstIndex);
|
|
101
|
+
const result = pattern.parse(cursor);
|
|
82
102
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
cursor.resolveError();
|
|
86
|
-
cursor.moveToMark(this.mark);
|
|
87
|
-
return false;
|
|
88
|
-
} else {
|
|
89
|
-
if (this._isOptional) {
|
|
90
|
-
cursor.resolveError();
|
|
91
|
-
cursor.moveToMark(this.mark);
|
|
103
|
+
if (!cursor.hasError) {
|
|
104
|
+
return result;
|
|
92
105
|
}
|
|
93
|
-
|
|
94
|
-
|
|
106
|
+
|
|
107
|
+
cursor.resolveError();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return null
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
getTokens(): string[] {
|
|
114
|
+
const tokens: string[] = [];
|
|
115
|
+
|
|
116
|
+
for (const child of this._children) {
|
|
117
|
+
tokens.push(...child.getTokens());
|
|
95
118
|
}
|
|
119
|
+
|
|
120
|
+
return tokens;
|
|
96
121
|
}
|
|
97
122
|
|
|
98
|
-
|
|
99
|
-
|
|
123
|
+
getTokensAfter(_childReference: Pattern): string[] {
|
|
124
|
+
if (this._parent === null) {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
100
127
|
|
|
101
|
-
this.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
[
|
|
107
|
-
|
|
108
|
-
);
|
|
128
|
+
return this._parent.getTokensAfter(this);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
getNextTokens(): string[] {
|
|
132
|
+
if (this._parent == null) {
|
|
133
|
+
return []
|
|
134
|
+
}
|
|
109
135
|
|
|
110
|
-
|
|
111
|
-
cursor.addMatch(this, this.node);
|
|
136
|
+
return this._parent.getTokensAfter(this);
|
|
112
137
|
}
|
|
113
138
|
|
|
114
|
-
|
|
115
|
-
if (
|
|
116
|
-
|
|
139
|
+
getPatternsAfter(_childReference: Pattern): Pattern[] {
|
|
140
|
+
if (this._parent === null) {
|
|
141
|
+
return [];
|
|
117
142
|
}
|
|
118
143
|
|
|
119
|
-
|
|
120
|
-
|
|
144
|
+
return this._parent.getPatternsAfter(this)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
getNextPatterns(): Pattern[] {
|
|
148
|
+
if (this.parent == null) {
|
|
149
|
+
return [];
|
|
121
150
|
}
|
|
122
151
|
|
|
123
|
-
return
|
|
152
|
+
return this.parent.getPatternsAfter(this)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
findPattern(predicate: (p: Pattern) => boolean): Pattern | null {
|
|
156
|
+
return findPattern(this, predicate);
|
|
124
157
|
}
|
|
125
158
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
[]
|
|
130
|
-
);
|
|
159
|
+
clone(name = this._name, isOptional = this._isOptional): Pattern {
|
|
160
|
+
const or = new Or(name, this._children, isOptional);
|
|
161
|
+
return or;
|
|
131
162
|
}
|
|
132
163
|
}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import Pattern from "./Pattern";
|
|
1
|
+
import { Pattern } from "./Pattern";
|
|
2
2
|
|
|
3
|
-
export
|
|
4
|
-
public message: string;
|
|
5
|
-
public name: string;
|
|
3
|
+
export class ParseError {
|
|
6
4
|
public index: number;
|
|
7
5
|
public pattern: Pattern;
|
|
8
6
|
|
|
9
|
-
constructor(
|
|
10
|
-
this.name = "ParseError";
|
|
11
|
-
this.message = message;
|
|
7
|
+
constructor(index: number, pattern: Pattern) {
|
|
12
8
|
this.index = index;
|
|
13
9
|
this.pattern = pattern;
|
|
14
10
|
}
|
package/src/patterns/Pattern.ts
CHANGED
|
@@ -1,151 +1,22 @@
|
|
|
1
|
-
import Cursor from "
|
|
2
|
-
import Node from "../ast/Node";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
this._name = name;
|
|
23
|
-
this._children = [];
|
|
24
|
-
this._parent = null;
|
|
25
|
-
this._isOptional = isOptional;
|
|
26
|
-
this.children = children;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
abstract parse(cursor: Cursor): Node | null;
|
|
30
|
-
|
|
31
|
-
exec(text: string) {
|
|
32
|
-
const cursor = new Cursor(text);
|
|
33
|
-
const node = this.parse(cursor);
|
|
34
|
-
|
|
35
|
-
if (cursor.didSuccessfullyParse()) {
|
|
36
|
-
return node;
|
|
37
|
-
} else {
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
test(text: string) {
|
|
43
|
-
return this.exec(text) != null;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
get name() {
|
|
47
|
-
return this._name;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
get type() {
|
|
51
|
-
return this._type;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
get parent() {
|
|
55
|
-
return this._parent;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
set parent(value: Pattern | null) {
|
|
59
|
-
this._parent = value;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
get children() {
|
|
63
|
-
return this._children;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
set children(value) {
|
|
67
|
-
this._children = value;
|
|
68
|
-
this.cloneChildren();
|
|
69
|
-
this.assignAsParent();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
abstract clone(name?: string): Pattern;
|
|
73
|
-
abstract getTokens(): string[];
|
|
74
|
-
|
|
75
|
-
getTokenValue(): string | null {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
getNextTokens(): string[] {
|
|
80
|
-
const parent = this._parent;
|
|
81
|
-
|
|
82
|
-
if (parent != null) {
|
|
83
|
-
const siblings = parent.children;
|
|
84
|
-
const index = siblings.findIndex((c) => c === this);
|
|
85
|
-
const nextSibling = siblings[index + 1];
|
|
86
|
-
|
|
87
|
-
// I don't like this, so I think we need to rethink this.
|
|
88
|
-
if (parent.type.indexOf("repeat") === 0) {
|
|
89
|
-
const tokens = parent.getNextTokens();
|
|
90
|
-
if (index === 0 && siblings.length > 1) {
|
|
91
|
-
return nextSibling.getTokens().concat(tokens);
|
|
92
|
-
} else if (index === 1) {
|
|
93
|
-
return siblings[0].getTokens();
|
|
94
|
-
} else {
|
|
95
|
-
return this.getTokens().concat(tokens);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Another thing I don't like.
|
|
100
|
-
if (
|
|
101
|
-
this._parent?.type?.indexOf("and") === 0 &&
|
|
102
|
-
nextSibling != null &&
|
|
103
|
-
nextSibling.isOptional
|
|
104
|
-
) {
|
|
105
|
-
let tokens: string[] = [];
|
|
106
|
-
|
|
107
|
-
for (let x = index + 1; x < siblings.length; x++) {
|
|
108
|
-
const child = siblings[x];
|
|
109
|
-
|
|
110
|
-
if (child.isOptional) {
|
|
111
|
-
tokens = tokens.concat(child.getTokens());
|
|
112
|
-
} else {
|
|
113
|
-
tokens = tokens.concat(child.getTokens());
|
|
114
|
-
break;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (x === siblings.length - 1) {
|
|
118
|
-
tokens = tokens.concat(this._parent.getNextTokens());
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return tokens;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// If you are an or you have already qualified.
|
|
126
|
-
if (parent.type.indexOf("or") === 0) {
|
|
127
|
-
return parent.getNextTokens();
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (nextSibling != null) {
|
|
131
|
-
return nextSibling.getTokens();
|
|
132
|
-
} else {
|
|
133
|
-
return parent.getNextTokens();
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return [];
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
private cloneChildren() {
|
|
141
|
-
this._children = this._children.map((pattern) => {
|
|
142
|
-
return pattern.clone();
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
Object.freeze(this._children);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
private assignAsParent() {
|
|
149
|
-
this._children.forEach((child) => (child.parent = this));
|
|
150
|
-
}
|
|
1
|
+
import { Cursor } from "./Cursor";
|
|
2
|
+
import { Node } from "../ast/Node";
|
|
3
|
+
import { ParseResult } from "./ParseResult"
|
|
4
|
+
|
|
5
|
+
export interface Pattern {
|
|
6
|
+
type: string;
|
|
7
|
+
name: string;
|
|
8
|
+
parent: Pattern | null;
|
|
9
|
+
children: Pattern[];
|
|
10
|
+
isOptional: boolean;
|
|
11
|
+
|
|
12
|
+
parse(cursor: Cursor): Node | null;
|
|
13
|
+
exec(text: string): ParseResult;
|
|
14
|
+
test(text: string): boolean;
|
|
15
|
+
clone(name?: string, isOptional?: boolean): Pattern;
|
|
16
|
+
getTokens(): string[];
|
|
17
|
+
getTokensAfter(childReference: Pattern): string[];
|
|
18
|
+
getPatternsAfter(childReference: Pattern): Pattern[];
|
|
19
|
+
getNextPatterns(): Pattern[];
|
|
20
|
+
getNextTokens(): string[];
|
|
21
|
+
findPattern(predicate: (p: Pattern) => boolean): Pattern | null;
|
|
151
22
|
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { Node } from "../ast/Node";
|
|
2
|
+
import { And } from "./And";
|
|
3
|
+
import { Cursor } from "./Cursor";
|
|
4
|
+
import { findPattern } from "./findPattern";
|
|
5
|
+
import { Literal } from "./Literal";
|
|
6
|
+
import { Or } from "./Or";
|
|
7
|
+
import { Pattern } from "./Pattern";
|
|
8
|
+
import { Reference } from "./Reference";
|
|
9
|
+
import { Regex } from "./Regex";
|
|
10
|
+
import { Repeat } from "./Repeat";
|
|
11
|
+
|
|
12
|
+
function createValuePattern() {
|
|
13
|
+
const number = new Regex("number", "\\d+");
|
|
14
|
+
number.setTokens(["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]);
|
|
15
|
+
|
|
16
|
+
const openBracket = new Literal("open-bracket", "[");
|
|
17
|
+
const closeBracket = new Literal("close-bracket", "]");
|
|
18
|
+
const divider = new Regex("divider", "\\s*,\\s+");
|
|
19
|
+
divider.setTokens([", "]);
|
|
20
|
+
|
|
21
|
+
const valueRef = new Reference("value");
|
|
22
|
+
const values = new Repeat("values", valueRef, divider);
|
|
23
|
+
const array = new And("array", [openBracket, values, closeBracket]);
|
|
24
|
+
const value = new Or("value", [number, array]);
|
|
25
|
+
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe("Reference", () => {
|
|
30
|
+
test("One Deep Successful Parse", () => {
|
|
31
|
+
const value = createValuePattern();
|
|
32
|
+
const cursor = new Cursor("[1, 2]");
|
|
33
|
+
const result = value.parse(cursor);
|
|
34
|
+
|
|
35
|
+
const expected = new Node("and", "array", 0, 5, [
|
|
36
|
+
new Node("literal", "open-bracket", 0, 0, [], "["),
|
|
37
|
+
new Node("repeat", "values", 1, 4, [
|
|
38
|
+
new Node("regex", "number", 1, 1, [], "1"),
|
|
39
|
+
new Node("regex", "divider", 2, 3, [], ", "),
|
|
40
|
+
new Node("regex", "number", 4, 4, [], "2")
|
|
41
|
+
]),
|
|
42
|
+
new Node("literal", "close-bracket", 5, 5, [], "]"),
|
|
43
|
+
])
|
|
44
|
+
|
|
45
|
+
expect(result).toEqual(expected);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("No Reference Pattern", () => {
|
|
49
|
+
const ref = new Reference("bad-reference");
|
|
50
|
+
|
|
51
|
+
expect(() => {
|
|
52
|
+
ref.parse(new Cursor("text"))
|
|
53
|
+
}).toThrowError()
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("Get Tokens", () => {
|
|
57
|
+
const value = createValuePattern();
|
|
58
|
+
const ref = findPattern(value, (p) => p.type === "reference");
|
|
59
|
+
const tokens = ref?.getTokens();
|
|
60
|
+
const expected = [
|
|
61
|
+
"1",
|
|
62
|
+
"2",
|
|
63
|
+
"3",
|
|
64
|
+
"4",
|
|
65
|
+
"5",
|
|
66
|
+
"6",
|
|
67
|
+
"7",
|
|
68
|
+
"8",
|
|
69
|
+
"9",
|
|
70
|
+
"0",
|
|
71
|
+
"["
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
expect(tokens).toEqual(expected);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("Get Tokens After With No Parent", () => {
|
|
78
|
+
const ref = new Reference("bad-reference");
|
|
79
|
+
const tokens = ref.getTokensAfter(new Literal("bogus", "bogus"))
|
|
80
|
+
|
|
81
|
+
expect(tokens).toEqual([]);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("Properties", () => {
|
|
85
|
+
const ref = new Reference("ref");
|
|
86
|
+
|
|
87
|
+
expect(ref.type).toBe("reference");
|
|
88
|
+
expect(ref.name).toBe("ref");
|
|
89
|
+
expect(ref.isOptional).toBeFalsy();
|
|
90
|
+
expect(ref.parent).toBe(null)
|
|
91
|
+
expect(ref.children).toEqual([])
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("Exec", () => {
|
|
95
|
+
const value = createValuePattern();
|
|
96
|
+
const reference = findPattern(value, p => p.type === "reference") as Reference
|
|
97
|
+
const { ast: result } = reference.exec("B");
|
|
98
|
+
expect(result).toBeNull()
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("Test With Match", () => {
|
|
102
|
+
const value = createValuePattern();
|
|
103
|
+
const reference = findPattern(value, p => p.type === "reference") as Reference
|
|
104
|
+
const result = reference.test("[1]");
|
|
105
|
+
expect(result).toBeTruthy()
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("Test No Match", () => {
|
|
109
|
+
const value = createValuePattern();
|
|
110
|
+
const reference = findPattern(value, p => p.type === "reference") as Reference
|
|
111
|
+
const result = reference.test("B");
|
|
112
|
+
expect(result).toBeFalsy()
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("Find Pattern", () => {
|
|
116
|
+
const value = createValuePattern();
|
|
117
|
+
const reference = value.findPattern(p => p.type === "reference") as Pattern;
|
|
118
|
+
|
|
119
|
+
const pattern = reference?.findPattern(p => p.name === "Nada");
|
|
120
|
+
|
|
121
|
+
expect(pattern).toBe(null);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
test("Get Next Tokens", () => {
|
|
126
|
+
const value = createValuePattern();
|
|
127
|
+
const reference = value.findPattern(p => p.type === "reference") as Pattern;
|
|
128
|
+
const tokens = reference.getNextTokens();
|
|
129
|
+
|
|
130
|
+
expect(tokens).toEqual([", ", "]"]);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("Get Next Tokens With Null Parent", () => {
|
|
134
|
+
const reference = new Reference("ref-name");
|
|
135
|
+
const tokens = reference.getNextTokens();
|
|
136
|
+
|
|
137
|
+
expect(tokens).toEqual([])
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("Get Tokens After", () => {
|
|
141
|
+
const value = createValuePattern();
|
|
142
|
+
const reference = value.findPattern(p => p.type === "reference") as Pattern;
|
|
143
|
+
const tokens = reference.getTokensAfter(new Literal("bogus", "Bogus"));
|
|
144
|
+
|
|
145
|
+
expect(tokens).toEqual([", ", "]"]);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("Get Tokens After With Null Parent", () => {
|
|
149
|
+
const reference = new Reference("ref-name");
|
|
150
|
+
const tokens = reference.getTokensAfter(new Literal("bogus", "Bogus"));
|
|
151
|
+
|
|
152
|
+
expect(tokens).toEqual([])
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("Get Patterns After", () => {
|
|
156
|
+
const value = createValuePattern();
|
|
157
|
+
const reference = value.findPattern(p => p.type === "reference") as Pattern;
|
|
158
|
+
const patterns = reference.getPatternsAfter(new Literal("bogus", "Bogus"));
|
|
159
|
+
|
|
160
|
+
expect(patterns.length).toEqual(2);
|
|
161
|
+
expect(patterns[0].type).toEqual("regex");
|
|
162
|
+
expect(patterns[0].name).toEqual("divider");
|
|
163
|
+
expect(patterns[1].type).toEqual("literal");
|
|
164
|
+
expect(patterns[1].name).toEqual("close-bracket");
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test("Get Patterns After With Null Parent", () => {
|
|
168
|
+
const reference = new Reference("ref-name");
|
|
169
|
+
const patterns = reference.getPatternsAfter(new Literal("bogus", "Bogus"));
|
|
170
|
+
|
|
171
|
+
expect(patterns).toEqual([])
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("Get Next Patterns", () => {
|
|
175
|
+
const value = createValuePattern();
|
|
176
|
+
const reference = value.findPattern(p => p.type === "reference") as Pattern;
|
|
177
|
+
const patterns = reference.getNextPatterns();
|
|
178
|
+
|
|
179
|
+
expect(patterns.length).toEqual(2);
|
|
180
|
+
expect(patterns[0].type).toEqual("regex");
|
|
181
|
+
expect(patterns[0].name).toEqual("divider");
|
|
182
|
+
expect(patterns[1].type).toEqual("literal");
|
|
183
|
+
expect(patterns[1].name).toEqual("close-bracket");
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test("Get Next Patterns With Null Parent", () => {
|
|
187
|
+
const reference = new Reference("ref-name");
|
|
188
|
+
const patterns = reference.getNextPatterns();
|
|
189
|
+
|
|
190
|
+
expect(patterns).toEqual([])
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
});
|