clarity-pattern-parser 5.0.0 → 6.0.2
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 +328 -38
- package/TODO.md +63 -7
- package/dist/ast/Node.d.ts +8 -2
- package/dist/index.browser.js +520 -205
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.esm.js +519 -206
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +520 -205
- package/dist/index.js.map +1 -1
- package/dist/intellisense/AutoComplete.d.ts +34 -0
- package/dist/intellisense/Suggestion.d.ts +10 -0
- package/dist/intellisense/SuggestionOption.d.ts +4 -0
- package/dist/patterns/And.d.ts +8 -7
- package/dist/patterns/Cursor.d.ts +6 -4
- package/dist/patterns/CursorHistory.d.ts +2 -2
- package/dist/patterns/Literal.d.ts +8 -8
- package/dist/patterns/Not.d.ts +9 -5
- package/dist/patterns/Or.d.ts +8 -5
- package/dist/patterns/Pattern.d.ts +8 -4
- package/dist/patterns/Reference.d.ts +11 -7
- package/dist/patterns/Regex.d.ts +8 -8
- package/dist/patterns/Repeat.d.ts +8 -7
- package/package.json +1 -1
- package/src/ast/Node.test.ts +116 -0
- package/src/ast/Node.ts +71 -5
- package/src/index.ts +14 -3
- package/src/intellisense/AutoComplete.test.ts +168 -23
- package/src/intellisense/AutoComplete.ts +102 -21
- package/src/intellisense/Suggestion.ts +3 -4
- package/src/intellisense/javascript/Javascript.test.ts +86 -62
- package/src/intellisense/javascript/{expressionStatement.ts → assignment.ts} +7 -8
- package/src/intellisense/javascript/escapedCharacter.ts +0 -1
- package/src/intellisense/javascript/exponent.ts +0 -2
- package/src/intellisense/javascript/expression.ts +44 -26
- package/src/intellisense/javascript/fraction.ts +0 -2
- package/src/intellisense/javascript/infixOperator.ts +6 -2
- package/src/intellisense/javascript/keywords.ts +3 -0
- package/src/intellisense/javascript/objectAccess.ts +9 -0
- package/src/intellisense/javascript/objectLiteral.ts +3 -3
- package/src/intellisense/javascript/propertyAccess.ts +8 -3
- package/src/intellisense/javascript/stringLiteral.ts +16 -8
- package/src/patterns/And.test.ts +74 -50
- package/src/patterns/And.ts +72 -36
- package/src/patterns/Cursor.ts +17 -14
- package/src/patterns/CursorHistory.ts +8 -8
- package/src/patterns/Literal.test.ts +79 -38
- package/src/patterns/Literal.ts +34 -41
- package/src/patterns/Not.test.ts +99 -8
- package/src/patterns/Not.ts +58 -14
- package/src/patterns/Or.test.ts +128 -13
- package/src/patterns/Or.ts +46 -13
- package/src/patterns/Pattern.ts +8 -4
- package/src/patterns/Reference.test.ts +127 -28
- package/src/patterns/Reference.ts +62 -32
- package/src/patterns/Regex.test.ts +76 -35
- package/src/patterns/Regex.ts +35 -43
- package/src/patterns/Repeat.test.ts +72 -41
- package/src/patterns/Repeat.ts +55 -38
- package/src/patterns/getNextPattern.test.ts +0 -39
- package/src/patterns/getNextPattern.ts +0 -18
|
@@ -1,79 +1,160 @@
|
|
|
1
1
|
import { Cursor } from "../patterns/Cursor";
|
|
2
|
-
import { ParseError } from "../patterns/ParseError";
|
|
3
2
|
import { Pattern } from "../patterns/Pattern";
|
|
4
3
|
import { Suggestion } from "./Suggestion";
|
|
5
4
|
import { SuggestionOption } from "./SuggestionOption";
|
|
6
5
|
|
|
6
|
+
export interface AutoCompleteOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Allows for certain patterns to combine their tokens with the next tokens.
|
|
9
|
+
* Be very careful, this can explode to infinity pretty quick. Usually useful
|
|
10
|
+
* for dividers and spaces.
|
|
11
|
+
*/
|
|
12
|
+
greedyPatternNames?: string[];
|
|
13
|
+
/**
|
|
14
|
+
* Allows for custom suggestions for patterns. The key is the name of the pattern
|
|
15
|
+
* and the string array are the tokens suggested for that pattern.
|
|
16
|
+
*/
|
|
17
|
+
customTokens?: Record<string, string[]>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const defaultOptions = { greedyPatternNames: [], customTokens: {} };
|
|
21
|
+
|
|
7
22
|
export class AutoComplete {
|
|
8
23
|
private _pattern: Pattern;
|
|
24
|
+
private _options: AutoCompleteOptions;
|
|
9
25
|
private _cursor!: Cursor;
|
|
10
26
|
private _text: string;
|
|
11
27
|
|
|
12
|
-
constructor(pattern: Pattern) {
|
|
28
|
+
constructor(pattern: Pattern, options: AutoCompleteOptions = defaultOptions) {
|
|
13
29
|
this._pattern = pattern;
|
|
30
|
+
this._options = options;
|
|
14
31
|
this._text = "";
|
|
15
32
|
}
|
|
16
33
|
|
|
34
|
+
/**
|
|
35
|
+
* @deprecated Use suggestFor instead.
|
|
36
|
+
* @param text The text to suggest for.
|
|
37
|
+
*/
|
|
17
38
|
suggest(text: string): Suggestion {
|
|
39
|
+
return this.suggestFor(text);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
suggestFor(text: string): Suggestion {
|
|
18
43
|
if (text.length === 0) {
|
|
19
44
|
return {
|
|
20
45
|
isComplete: false,
|
|
21
|
-
options: this.
|
|
22
|
-
|
|
46
|
+
options: this._createSuggestionsFromRoot(),
|
|
47
|
+
errorAtIndex: 0,
|
|
23
48
|
cursor: null,
|
|
24
|
-
|
|
49
|
+
ast: null
|
|
25
50
|
}
|
|
26
51
|
}
|
|
27
52
|
|
|
28
53
|
this._text = text;
|
|
29
54
|
this._cursor = new Cursor(text);
|
|
30
|
-
this._pattern.parse(this._cursor);
|
|
55
|
+
const ast = this._pattern.parse(this._cursor);
|
|
31
56
|
|
|
32
57
|
const leafPattern = this._cursor.leafMatch.pattern;
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
58
|
+
const isComplete = ast?.value === text;
|
|
59
|
+
const options = this._createSuggestionsFromTokens();
|
|
60
|
+
|
|
61
|
+
let nextPatterns = [this._pattern];
|
|
62
|
+
let errorAtIndex = null;
|
|
63
|
+
|
|
64
|
+
if (leafPattern != null) {
|
|
65
|
+
nextPatterns = leafPattern.getNextPatterns();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (this._cursor.hasError && this._cursor.furthestError != null) {
|
|
69
|
+
errorAtIndex = this._cursor.furthestError.index;
|
|
70
|
+
|
|
71
|
+
errorAtIndex = options.reduce((errorAtIndex, option) =>
|
|
72
|
+
Math.max(errorAtIndex, option.startIndex),
|
|
73
|
+
errorAtIndex);
|
|
74
|
+
}
|
|
37
75
|
|
|
38
76
|
return {
|
|
39
77
|
isComplete: isComplete,
|
|
40
78
|
options: options,
|
|
41
|
-
|
|
79
|
+
errorAtIndex,
|
|
42
80
|
cursor: this._cursor,
|
|
43
|
-
|
|
81
|
+
ast,
|
|
44
82
|
}
|
|
45
83
|
}
|
|
46
84
|
|
|
47
|
-
private
|
|
85
|
+
private _createSuggestionsFromRoot(): SuggestionOption[] {
|
|
48
86
|
const suggestions: SuggestionOption[] = [];
|
|
49
87
|
const tokens = this._pattern.getTokens();
|
|
50
88
|
|
|
51
89
|
for (const token of tokens) {
|
|
52
|
-
suggestions.push(this.
|
|
90
|
+
suggestions.push(this._createSuggestion("", token));
|
|
53
91
|
}
|
|
54
92
|
|
|
55
93
|
return suggestions;
|
|
56
94
|
}
|
|
57
95
|
|
|
58
|
-
private
|
|
96
|
+
private _createSuggestionsFromTokens(): SuggestionOption[] {
|
|
59
97
|
const leafMatch = this._cursor.leafMatch;
|
|
60
98
|
|
|
61
99
|
if (!leafMatch.pattern) {
|
|
62
|
-
return this.
|
|
100
|
+
return this._createSuggestions(-1, this._getTokensForPattern(this._pattern));
|
|
63
101
|
}
|
|
64
102
|
|
|
65
103
|
const leafPattern = leafMatch.pattern;
|
|
66
104
|
const parent = leafMatch.pattern.parent;
|
|
67
105
|
|
|
68
106
|
if (parent !== null && leafMatch.node != null) {
|
|
69
|
-
const
|
|
70
|
-
|
|
107
|
+
const patterns = leafPattern.getNextPatterns();
|
|
108
|
+
|
|
109
|
+
const tokens = patterns.reduce((acc: string[], pattern) => {
|
|
110
|
+
acc.push(...this._getTokensForPattern(pattern));
|
|
111
|
+
return acc;
|
|
112
|
+
}, []);
|
|
113
|
+
|
|
114
|
+
return this._createSuggestions(leafMatch.node.lastIndex, tokens);
|
|
71
115
|
} else {
|
|
72
116
|
return [];
|
|
73
117
|
}
|
|
74
118
|
}
|
|
75
119
|
|
|
76
|
-
private
|
|
120
|
+
private _getTokensForPattern(pattern: Pattern) {
|
|
121
|
+
const augmentedTokens = this._getAugmentedTokens(pattern)
|
|
122
|
+
|
|
123
|
+
if (this._options.greedyPatternNames != null && this._options.greedyPatternNames.includes(pattern.name)) {
|
|
124
|
+
const nextPatterns = pattern.getNextPatterns();
|
|
125
|
+
const tokens: string[] = [];
|
|
126
|
+
|
|
127
|
+
const nextPatternTokens = nextPatterns.reduce((acc: string[], pattern) => {
|
|
128
|
+
acc.push(...this._getTokensForPattern(pattern));
|
|
129
|
+
return acc;
|
|
130
|
+
}, []);
|
|
131
|
+
|
|
132
|
+
for (let token of augmentedTokens) {
|
|
133
|
+
for (let nextPatternToken of nextPatternTokens) {
|
|
134
|
+
tokens.push(token + nextPatternToken);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return tokens;
|
|
139
|
+
} else {
|
|
140
|
+
return augmentedTokens;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private _getAugmentedTokens(pattern: Pattern) {
|
|
145
|
+
const customTokensMap: any = this._options.customTokens || {};
|
|
146
|
+
const leafPatterns = pattern.getPatterns();
|
|
147
|
+
const tokens: string[] = customTokensMap[pattern.name] || [];
|
|
148
|
+
|
|
149
|
+
leafPatterns.forEach(p => {
|
|
150
|
+
const augmentedTokens = customTokensMap[p.name] || [];
|
|
151
|
+
tokens.push(...p.getTokens(), ...augmentedTokens);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
return tokens;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private _createSuggestions(lastIndex: number, tokens: string[]): SuggestionOption[] {
|
|
77
158
|
let substring = lastIndex === -1 ? "" : this._cursor.getChars(0, lastIndex);
|
|
78
159
|
const suggestionStrings: string[] = [];
|
|
79
160
|
const options: SuggestionOption[] = [];
|
|
@@ -86,7 +167,7 @@ export class AutoComplete {
|
|
|
86
167
|
|
|
87
168
|
if (startsWith && !alreadyExist && !isSameAsText) {
|
|
88
169
|
suggestionStrings.push(suggestion);
|
|
89
|
-
options.push(this.
|
|
170
|
+
options.push(this._createSuggestion(this._cursor.text, suggestion));
|
|
90
171
|
}
|
|
91
172
|
}
|
|
92
173
|
|
|
@@ -96,7 +177,7 @@ export class AutoComplete {
|
|
|
96
177
|
return reducedOptions;
|
|
97
178
|
}
|
|
98
179
|
|
|
99
|
-
private
|
|
180
|
+
private _createSuggestion(fullText: string, suggestion: string): SuggestionOption {
|
|
100
181
|
const furthestMatch = findMatchIndex(suggestion, fullText);
|
|
101
182
|
const text = suggestion.slice(furthestMatch);
|
|
102
183
|
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
+
import { Node } from "../ast/Node";
|
|
1
2
|
import { Cursor } from "../patterns/Cursor";
|
|
2
|
-
import { Match } from "../patterns/CursorHistory";
|
|
3
|
-
import { ParseError } from "../patterns/ParseError";
|
|
4
3
|
import { Pattern } from "../patterns/Pattern";
|
|
5
4
|
import { SuggestionOption } from "./SuggestionOption";
|
|
6
5
|
|
|
7
6
|
export interface Suggestion {
|
|
8
7
|
isComplete: boolean;
|
|
9
8
|
options: SuggestionOption[];
|
|
10
|
-
|
|
9
|
+
errorAtIndex: number | null;
|
|
11
10
|
cursor: Cursor | null;
|
|
12
|
-
|
|
11
|
+
ast: Node | null;
|
|
13
12
|
}
|
|
@@ -1,202 +1,226 @@
|
|
|
1
|
+
import { Cursor } from "../../patterns/Cursor";
|
|
1
2
|
import { escapedCharacter } from "./escapedCharacter";
|
|
2
3
|
import { exponent } from "./exponent";
|
|
3
4
|
import { expression } from "./expression";
|
|
4
|
-
import {
|
|
5
|
+
import { assignment } from "./assignment";
|
|
5
6
|
import { infixOperator } from "./infixOperator";
|
|
6
7
|
import { integer } from "./integer";
|
|
7
8
|
import { name } from "./name";
|
|
8
9
|
import { parameters } from "./parameters";
|
|
9
10
|
import { prefixOperator } from "./prefixOperator";
|
|
11
|
+
import { objectAccess } from "./objectAccess";
|
|
10
12
|
|
|
11
13
|
describe("Ecmascript 3", () => {
|
|
12
14
|
test("Escaped Character", () => {
|
|
13
|
-
let result = escapedCharacter.
|
|
15
|
+
let result = escapedCharacter.exec(`\\"`);
|
|
14
16
|
expect(result.ast?.value).toBe(`\\"`)
|
|
15
17
|
|
|
16
|
-
result = escapedCharacter.
|
|
18
|
+
result = escapedCharacter.exec(`\\'`)
|
|
17
19
|
expect(result.ast?.value).toBe(`\\'`)
|
|
18
20
|
|
|
19
|
-
result = escapedCharacter.
|
|
21
|
+
result = escapedCharacter.exec(`\\\\`)
|
|
20
22
|
expect(result.ast?.value).toBe(`\\\\`)
|
|
21
23
|
|
|
22
|
-
result = escapedCharacter.
|
|
24
|
+
result = escapedCharacter.exec(`\\/`)
|
|
23
25
|
expect(result.ast?.value).toBe(`\\/`)
|
|
24
26
|
|
|
25
|
-
result = escapedCharacter.
|
|
27
|
+
result = escapedCharacter.exec(`\\f`)
|
|
26
28
|
expect(result.ast?.value).toBe(`\\f`)
|
|
27
29
|
|
|
28
|
-
result = escapedCharacter.
|
|
30
|
+
result = escapedCharacter.exec(`\\t`)
|
|
29
31
|
expect(result.ast?.value).toBe(`\\t`)
|
|
30
32
|
|
|
31
|
-
result = escapedCharacter.
|
|
33
|
+
result = escapedCharacter.exec(`\\u00E9`)
|
|
32
34
|
expect(result.ast?.value).toBe(`\\u00E9`)
|
|
33
35
|
});
|
|
34
36
|
|
|
35
37
|
test("Exponent", () => {
|
|
36
|
-
let result = exponent.
|
|
38
|
+
let result = exponent.exec("e+1");
|
|
37
39
|
expect(result.ast?.value).toBe("e+1")
|
|
38
40
|
|
|
39
|
-
result = exponent.
|
|
41
|
+
result = exponent.exec("e-1");
|
|
40
42
|
expect(result.ast?.value).toBe("e-1")
|
|
41
43
|
|
|
42
|
-
result = exponent.
|
|
44
|
+
result = exponent.exec("E+1");
|
|
43
45
|
expect(result.ast?.value).toBe("E+1")
|
|
44
46
|
|
|
45
|
-
result = exponent.
|
|
47
|
+
result = exponent.exec("E-1");
|
|
46
48
|
expect(result.ast?.value).toBe("E-1")
|
|
47
49
|
|
|
48
|
-
result = exponent.
|
|
50
|
+
result = exponent.exec("e+11");
|
|
49
51
|
expect(result.ast?.value).toBe("e+11")
|
|
50
52
|
|
|
51
|
-
result = exponent.
|
|
53
|
+
result = exponent.exec("11");
|
|
52
54
|
expect(result.ast).toBeNull()
|
|
53
55
|
});
|
|
54
56
|
|
|
55
57
|
test("Integer", () => {
|
|
56
|
-
let result = integer.
|
|
58
|
+
let result = integer.exec("0");
|
|
57
59
|
expect(result.ast?.value).toBe("0");
|
|
58
60
|
|
|
59
|
-
result = integer.
|
|
61
|
+
result = integer.exec("1");
|
|
60
62
|
expect(result.ast?.value).toBe("1");
|
|
61
63
|
|
|
62
|
-
result = integer.
|
|
64
|
+
result = integer.exec("100");
|
|
63
65
|
expect(result.ast?.value).toBe("100");
|
|
64
66
|
|
|
65
|
-
result = integer.
|
|
67
|
+
result = integer.exec(".1");
|
|
66
68
|
expect(result.ast).toBeNull();
|
|
67
69
|
});
|
|
68
70
|
|
|
69
71
|
test("Infix Operator", () => {
|
|
70
|
-
let result = infixOperator.
|
|
72
|
+
let result = infixOperator.exec("*");
|
|
71
73
|
expect(result.ast?.value).toBe("*");
|
|
72
74
|
|
|
73
|
-
result = infixOperator.
|
|
75
|
+
result = infixOperator.exec("/");
|
|
74
76
|
expect(result.ast?.value).toBe("/");
|
|
75
77
|
|
|
76
|
-
result = infixOperator.
|
|
78
|
+
result = infixOperator.exec("%");
|
|
77
79
|
expect(result.ast?.value).toBe("%");
|
|
78
80
|
|
|
79
|
-
result = infixOperator.
|
|
81
|
+
result = infixOperator.exec("+");
|
|
80
82
|
expect(result.ast?.value).toBe("+");
|
|
81
83
|
|
|
82
|
-
result = infixOperator.
|
|
84
|
+
result = infixOperator.exec("-");
|
|
83
85
|
expect(result.ast?.value).toBe("-");
|
|
84
86
|
|
|
85
|
-
result = infixOperator.
|
|
87
|
+
result = infixOperator.exec(">=");
|
|
86
88
|
expect(result.ast?.value).toBe(">=");
|
|
87
89
|
|
|
88
|
-
result = infixOperator.
|
|
90
|
+
result = infixOperator.exec("<=");
|
|
89
91
|
expect(result.ast?.value).toBe("<=");
|
|
90
92
|
|
|
91
|
-
result = infixOperator.
|
|
93
|
+
result = infixOperator.exec(">");
|
|
92
94
|
expect(result.ast?.value).toBe(">");
|
|
93
95
|
|
|
94
|
-
result = infixOperator.
|
|
96
|
+
result = infixOperator.exec("<");
|
|
95
97
|
expect(result.ast?.value).toBe("<");
|
|
96
98
|
|
|
97
|
-
result = infixOperator.
|
|
99
|
+
result = infixOperator.exec("===");
|
|
98
100
|
expect(result.ast?.value).toBe("===");
|
|
99
101
|
|
|
100
|
-
result = infixOperator.
|
|
102
|
+
result = infixOperator.exec("!==");
|
|
101
103
|
expect(result.ast?.value).toBe("!==");
|
|
102
104
|
|
|
103
|
-
result = infixOperator.
|
|
105
|
+
result = infixOperator.exec("||");
|
|
104
106
|
expect(result.ast?.value).toBe("||");
|
|
105
107
|
|
|
106
|
-
result = infixOperator.
|
|
108
|
+
result = infixOperator.exec("&&");
|
|
107
109
|
expect(result.ast?.value).toBe("&&");
|
|
108
110
|
|
|
109
|
-
result = infixOperator.
|
|
111
|
+
result = infixOperator.exec("bad");
|
|
110
112
|
expect(result.ast).toBeNull();
|
|
111
113
|
});
|
|
112
114
|
|
|
113
115
|
|
|
114
116
|
test("Name", () => {
|
|
115
|
-
let result = name.
|
|
117
|
+
let result = name.exec("p_0");
|
|
116
118
|
expect(result.ast?.value).toBe("p_0");
|
|
117
119
|
|
|
118
|
-
result = name.
|
|
120
|
+
result = name.exec("_0");
|
|
119
121
|
expect(result.ast?.value).toBe("_0");
|
|
120
122
|
|
|
121
|
-
result = name.
|
|
123
|
+
result = name.exec("0");
|
|
122
124
|
expect(result.ast).toBeNull();
|
|
123
125
|
|
|
124
|
-
result = name.
|
|
126
|
+
result = name.exec("_");
|
|
125
127
|
expect(result.ast?.value).toBe("_");
|
|
126
128
|
});
|
|
127
129
|
|
|
128
130
|
test("Parameters", () => {
|
|
129
|
-
let result = parameters.
|
|
131
|
+
let result = parameters.exec("(param1)");
|
|
130
132
|
expect(result.ast?.value).toBe("(param1)");
|
|
131
133
|
|
|
132
|
-
result = parameters.
|
|
134
|
+
result = parameters.exec("(param1, param2)");
|
|
133
135
|
expect(result.ast?.value).toBe("(param1, param2)");
|
|
134
136
|
|
|
135
|
-
result = parameters.
|
|
137
|
+
result = parameters.exec("(param1, param2,)");
|
|
136
138
|
expect(result.ast).toBeNull();
|
|
137
139
|
});
|
|
138
140
|
|
|
139
141
|
test("Prefix Operator", () => {
|
|
140
|
-
let result = prefixOperator.
|
|
142
|
+
let result = prefixOperator.exec("typeof ");
|
|
141
143
|
expect(result.ast?.value).toBe("typeof ");
|
|
142
144
|
|
|
143
|
-
result = prefixOperator.
|
|
145
|
+
result = prefixOperator.exec("+");
|
|
144
146
|
expect(result.ast?.value).toBe("+");
|
|
145
147
|
|
|
146
|
-
result = prefixOperator.
|
|
148
|
+
result = prefixOperator.exec("-");
|
|
147
149
|
expect(result.ast?.value).toBe("-");
|
|
148
150
|
|
|
149
|
-
result = prefixOperator.
|
|
151
|
+
result = prefixOperator.exec("!");
|
|
150
152
|
expect(result.ast?.value).toBe("!");
|
|
151
153
|
|
|
152
|
-
result = prefixOperator.
|
|
154
|
+
result = prefixOperator.exec("a");
|
|
153
155
|
expect(result.ast).toBeNull();
|
|
154
156
|
});
|
|
155
157
|
|
|
156
158
|
test("Object Literal", () => {
|
|
157
|
-
let result = expression.
|
|
159
|
+
let result = expression.exec(`{}`)
|
|
158
160
|
expect(result.ast?.value).toBe("{}");
|
|
159
161
|
|
|
160
|
-
result = expression.
|
|
162
|
+
result = expression.exec(`{prop:{}}`)
|
|
161
163
|
expect(result.ast?.value).toBe("{prop:{}}");
|
|
162
164
|
|
|
163
|
-
result = expression.
|
|
165
|
+
result = expression.exec(`{prop:"value"}`)
|
|
164
166
|
expect(result.ast?.value).toBe(`{prop:"value"}`);
|
|
165
167
|
|
|
166
|
-
result = expression.
|
|
168
|
+
result = expression.exec(`{prop:0.9}`)
|
|
167
169
|
expect(result.ast?.value).toBe(`{prop:0.9}`);
|
|
168
170
|
|
|
169
|
-
result = expression.
|
|
171
|
+
result = expression.exec(`{prop:1}`)
|
|
170
172
|
expect(result.ast?.value).toBe(`{prop:1}`);
|
|
171
173
|
|
|
172
|
-
result = expression.
|
|
174
|
+
result = expression.exec(`{"prop":1}`)
|
|
173
175
|
expect(result.ast?.value).toBe(`{"prop":1}`);
|
|
174
176
|
});
|
|
175
177
|
|
|
176
|
-
test("
|
|
177
|
-
|
|
178
|
+
test("Expression", () => {
|
|
179
|
+
|
|
180
|
+
let result = expression.exec("[]")
|
|
178
181
|
expect(result.ast?.value).toBe("[]");
|
|
179
182
|
|
|
180
|
-
result = expression.
|
|
183
|
+
result = expression.exec("[{}, 9, 0.9e-10, [1, 2]]")
|
|
181
184
|
expect(result.ast?.value).toBe("[{}, 9, 0.9e-10, [1, 2]]");
|
|
182
|
-
|
|
185
|
+
|
|
186
|
+
result = expression.exec(`"John"`);
|
|
187
|
+
expect(result.ast?.value).toBe(`"John"`)
|
|
188
|
+
|
|
189
|
+
result = expression.exec(`variableName.property`);
|
|
190
|
+
expect(result.ast?.value).toBe(`variableName.property`);
|
|
191
|
+
|
|
192
|
+
result = expression.exec(`{property: ""}`);
|
|
193
|
+
expect(result.ast?.value).toBe(`{property: ""}`);
|
|
194
|
+
|
|
195
|
+
const cursor = new Cursor(`name() == name.property === name2 ? {prop: name, blah: [ 0.9e-10 ]} : name`);
|
|
196
|
+
cursor.startRecording();
|
|
197
|
+
const ast = expression.parse(cursor);
|
|
198
|
+
})
|
|
183
199
|
|
|
184
200
|
test("Expression Statement", () => {
|
|
185
|
-
let result =
|
|
201
|
+
let result = assignment.exec(`name = "John"`);
|
|
186
202
|
expect(result.ast?.value).toBe(`name = "John"`);
|
|
187
203
|
|
|
188
|
-
result =
|
|
204
|
+
result = assignment.exec(`name = othername = "John"`)
|
|
189
205
|
expect(result.ast?.value).toBe(`name = othername = "John"`);
|
|
190
206
|
|
|
191
|
-
result =
|
|
207
|
+
result = assignment.exec(`name = othername.prop = "John"`)
|
|
192
208
|
expect(result.ast?.value).toBe(`name = othername.prop = "John"`);
|
|
193
209
|
|
|
194
|
-
result =
|
|
210
|
+
result = assignment.exec(`name = othername.prop += 2`)
|
|
195
211
|
expect(result.ast?.value).toBe(`name = othername.prop += 2`);
|
|
196
|
-
|
|
197
|
-
result =
|
|
198
|
-
expect(result.ast?.value).toBe(`name.prop().method(blah) = blah.prop()`);
|
|
199
|
-
|
|
212
|
+
|
|
213
|
+
result = assignment.exec(`name.prop().method(blah) = blah.prop() == ha ? first : second`)
|
|
214
|
+
expect(result.ast?.value).toBe(`name.prop().method(blah) = blah.prop() == ha ? first : second`);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
test("Object Access", () => {
|
|
219
|
+
let result = expression.exec("name.prop");
|
|
220
|
+
expect(result.ast?.value).toBe(`name.prop`);
|
|
221
|
+
|
|
222
|
+
result = expression.exec(`name.prop.anotherProp["Ha"][coolYo] === 1`);
|
|
223
|
+
expect(result.ast?.value).toBe(`name.prop.anotherProp["Ha"][coolYo] === 1`);
|
|
200
224
|
});
|
|
201
225
|
|
|
202
226
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { And } from "../../patterns/And";
|
|
2
2
|
import { Literal } from "../../patterns/Literal";
|
|
3
3
|
import { Or } from "../../patterns/Or";
|
|
4
|
-
import {
|
|
4
|
+
import { Reference } from "../../patterns/Reference";
|
|
5
5
|
import { expression } from "./expression";
|
|
6
6
|
import { optionalSpaces } from "./optionalSpaces";
|
|
7
7
|
|
|
@@ -16,14 +16,13 @@ const assignment = new And("assignment", [
|
|
|
16
16
|
optionalSpaces,
|
|
17
17
|
assignmentOperators,
|
|
18
18
|
optionalSpaces,
|
|
19
|
+
new Or("assignment-right-operand", [
|
|
20
|
+
new Reference("assignment"),
|
|
21
|
+
expression
|
|
22
|
+
]),
|
|
19
23
|
]);
|
|
20
24
|
|
|
21
|
-
const expressionStatement = new And("expressionStatement", [
|
|
22
|
-
new Repeat("assignments",
|
|
23
|
-
assignment),
|
|
24
|
-
optionalSpaces,
|
|
25
|
-
expression
|
|
26
|
-
]);
|
|
27
25
|
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
|
|
28
|
+
export { assignment }
|
|
@@ -6,8 +6,10 @@ import { Reference } from "../../patterns/Reference";
|
|
|
6
6
|
import { Repeat } from "../../patterns/Repeat";
|
|
7
7
|
import { infixOperator } from "./infixOperator";
|
|
8
8
|
import { invocation } from "./invocation";
|
|
9
|
+
import { nullKeyword } from "./keywords";
|
|
9
10
|
import { literal } from "./literal";
|
|
10
11
|
import { name } from "./name";
|
|
12
|
+
import { objectAccess } from "./objectAccess";
|
|
11
13
|
import { optionalSpaces } from "./optionalSpaces";
|
|
12
14
|
import { prefixOperator } from "./prefixOperator";
|
|
13
15
|
import { propertyAccess } from "./propertyAccess";
|
|
@@ -41,46 +43,62 @@ const prefixExpression = new And("prefix-expression", [
|
|
|
41
43
|
new Reference("expression")
|
|
42
44
|
]);
|
|
43
45
|
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
optionalSpaces,
|
|
47
|
-
new Reference("expression"),
|
|
48
|
-
], true);
|
|
49
|
-
|
|
50
|
-
const optionalTernary = new And("ternary", [
|
|
51
|
-
new Literal("question-mark", "?"),
|
|
52
|
-
optionalSpaces,
|
|
53
|
-
new Reference("expression"),
|
|
54
|
-
optionalSpaces,
|
|
55
|
-
new Literal("colon", ":"),
|
|
56
|
-
optionalSpaces,
|
|
57
|
-
new Reference("expression")
|
|
58
|
-
], true);
|
|
59
|
-
|
|
60
|
-
const optionalMemberAccesses = new Repeat("object-member-accesses",
|
|
61
|
-
new Or("object-member-access", [
|
|
46
|
+
const memberAccess = new Repeat("member-access",
|
|
47
|
+
new Or("member-access", [
|
|
62
48
|
invocation,
|
|
63
49
|
propertyAccess,
|
|
64
|
-
])
|
|
65
|
-
undefined, true
|
|
50
|
+
])
|
|
66
51
|
);
|
|
67
52
|
|
|
53
|
+
|
|
68
54
|
var variableName = name.clone("variable-name");
|
|
69
55
|
|
|
70
56
|
const expressions = new Or("expressions", [
|
|
71
57
|
newExpression,
|
|
72
58
|
deleteExpression,
|
|
73
|
-
groupExpression,
|
|
74
|
-
prefixExpression,
|
|
75
59
|
literal,
|
|
60
|
+
nullKeyword,
|
|
61
|
+
objectAccess,
|
|
76
62
|
variableName,
|
|
63
|
+
groupExpression,
|
|
64
|
+
prefixExpression
|
|
77
65
|
]);
|
|
78
66
|
|
|
79
|
-
const
|
|
67
|
+
const expressionBody = new And("expression-body", [
|
|
80
68
|
expressions,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
69
|
+
memberAccess.clone(undefined, true),
|
|
70
|
+
]);
|
|
71
|
+
|
|
72
|
+
const infixExpression = new And("infix-expression", [
|
|
73
|
+
expressionBody,
|
|
74
|
+
optionalSpaces,
|
|
75
|
+
infixOperator,
|
|
76
|
+
optionalSpaces,
|
|
77
|
+
new Or("infix-right-operand", [
|
|
78
|
+
new Reference("infix-expression"),
|
|
79
|
+
expressionBody,
|
|
80
|
+
])
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
const ternaryExpression = new And("ternary", [
|
|
84
|
+
new Or("ternary-condition", [
|
|
85
|
+
infixExpression,
|
|
86
|
+
expressionBody
|
|
87
|
+
]),
|
|
88
|
+
optionalSpaces,
|
|
89
|
+
new Literal("question-mark", "?"),
|
|
90
|
+
optionalSpaces,
|
|
91
|
+
new Reference("expression"),
|
|
92
|
+
optionalSpaces,
|
|
93
|
+
new Literal("colon", ":"),
|
|
94
|
+
optionalSpaces,
|
|
95
|
+
new Reference("expression")
|
|
96
|
+
]);
|
|
97
|
+
|
|
98
|
+
const expression = new Or("expression", [
|
|
99
|
+
ternaryExpression,
|
|
100
|
+
infixExpression,
|
|
101
|
+
expressionBody
|
|
84
102
|
]);
|
|
85
103
|
|
|
86
104
|
export { expression }
|