flowquery 1.0.0 → 1.0.1
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/.github/workflows/npm-publish.yml +2 -0
- package/.github/workflows/release.yml +18 -9
- package/dist/compute/runner.js +75 -0
- package/dist/compute/runner.js.map +1 -0
- package/dist/flowquery.min.js +1 -0
- package/dist/index.browser.js +119 -0
- package/dist/index.browser.js.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/index.node.js +123 -0
- package/dist/index.node.js.map +1 -0
- package/dist/io/command_line.js +102 -0
- package/dist/io/command_line.js.map +1 -0
- package/dist/parsing/alias.js +23 -0
- package/dist/parsing/alias.js.map +1 -0
- package/dist/parsing/alias_option.js +11 -0
- package/dist/parsing/alias_option.js.map +1 -0
- package/dist/parsing/ast_node.js +145 -0
- package/dist/parsing/ast_node.js.map +1 -0
- package/dist/parsing/base_parser.js +92 -0
- package/dist/parsing/base_parser.js.map +1 -0
- package/dist/parsing/components/csv.js +13 -0
- package/dist/parsing/components/csv.js.map +1 -0
- package/dist/parsing/components/from.js +16 -0
- package/dist/parsing/components/from.js.map +1 -0
- package/dist/parsing/components/headers.js +16 -0
- package/dist/parsing/components/headers.js.map +1 -0
- package/dist/parsing/components/json.js +13 -0
- package/dist/parsing/components/json.js.map +1 -0
- package/dist/parsing/components/null.js +13 -0
- package/dist/parsing/components/null.js.map +1 -0
- package/dist/parsing/components/post.js +13 -0
- package/dist/parsing/components/post.js.map +1 -0
- package/dist/parsing/components/text.js +13 -0
- package/dist/parsing/components/text.js.map +1 -0
- package/dist/parsing/context.js +47 -0
- package/dist/parsing/context.js.map +1 -0
- package/dist/parsing/data_structures/associative_array.js +45 -0
- package/dist/parsing/data_structures/associative_array.js.map +1 -0
- package/dist/parsing/data_structures/json_array.js +35 -0
- package/dist/parsing/data_structures/json_array.js.map +1 -0
- package/dist/parsing/data_structures/key_value_pair.js +41 -0
- package/dist/parsing/data_structures/key_value_pair.js.map +1 -0
- package/dist/parsing/data_structures/lookup.js +44 -0
- package/dist/parsing/data_structures/lookup.js.map +1 -0
- package/dist/parsing/data_structures/range_lookup.js +40 -0
- package/dist/parsing/data_structures/range_lookup.js.map +1 -0
- package/dist/parsing/expressions/expression.js +142 -0
- package/dist/parsing/expressions/expression.js.map +1 -0
- package/dist/parsing/expressions/f_string.js +29 -0
- package/dist/parsing/expressions/f_string.js.map +1 -0
- package/dist/parsing/expressions/identifier.js +26 -0
- package/dist/parsing/expressions/identifier.js.map +1 -0
- package/dist/parsing/expressions/number.js +41 -0
- package/dist/parsing/expressions/number.js.map +1 -0
- package/dist/parsing/expressions/operator.js +180 -0
- package/dist/parsing/expressions/operator.js.map +1 -0
- package/dist/parsing/expressions/reference.js +45 -0
- package/dist/parsing/expressions/reference.js.map +1 -0
- package/dist/parsing/expressions/string.js +34 -0
- package/dist/parsing/expressions/string.js.map +1 -0
- package/dist/parsing/functions/aggregate_function.js +58 -0
- package/dist/parsing/functions/aggregate_function.js.map +1 -0
- package/dist/parsing/functions/async_function.js +119 -0
- package/dist/parsing/functions/async_function.js.map +1 -0
- package/dist/parsing/functions/avg.js +43 -0
- package/dist/parsing/functions/avg.js.map +1 -0
- package/dist/parsing/functions/collect.js +52 -0
- package/dist/parsing/functions/collect.js.map +1 -0
- package/dist/parsing/functions/function.js +59 -0
- package/dist/parsing/functions/function.js.map +1 -0
- package/dist/parsing/functions/function_factory.js +259 -0
- package/dist/parsing/functions/function_factory.js.map +1 -0
- package/dist/parsing/functions/function_metadata.js +159 -0
- package/dist/parsing/functions/function_metadata.js.map +1 -0
- package/dist/parsing/functions/functions.js +47 -0
- package/dist/parsing/functions/functions.js.map +1 -0
- package/dist/parsing/functions/join.js +29 -0
- package/dist/parsing/functions/join.js.map +1 -0
- package/dist/parsing/functions/predicate_function.js +37 -0
- package/dist/parsing/functions/predicate_function.js.map +1 -0
- package/dist/parsing/functions/predicate_function_factory.js +19 -0
- package/dist/parsing/functions/predicate_function_factory.js.map +1 -0
- package/dist/parsing/functions/predicate_sum.js +33 -0
- package/dist/parsing/functions/predicate_sum.js.map +1 -0
- package/dist/parsing/functions/rand.js +17 -0
- package/dist/parsing/functions/rand.js.map +1 -0
- package/dist/parsing/functions/range.js +22 -0
- package/dist/parsing/functions/range.js.map +1 -0
- package/dist/parsing/functions/reducer_element.js +12 -0
- package/dist/parsing/functions/reducer_element.js.map +1 -0
- package/dist/parsing/functions/replace.js +23 -0
- package/dist/parsing/functions/replace.js.map +1 -0
- package/dist/parsing/functions/round.js +21 -0
- package/dist/parsing/functions/round.js.map +1 -0
- package/dist/parsing/functions/size.js +21 -0
- package/dist/parsing/functions/size.js.map +1 -0
- package/dist/parsing/functions/split.js +29 -0
- package/dist/parsing/functions/split.js.map +1 -0
- package/dist/parsing/functions/stringify.js +29 -0
- package/dist/parsing/functions/stringify.js.map +1 -0
- package/dist/parsing/functions/sum.js +38 -0
- package/dist/parsing/functions/sum.js.map +1 -0
- package/dist/parsing/functions/to_json.js +21 -0
- package/dist/parsing/functions/to_json.js.map +1 -0
- package/dist/parsing/functions/value_holder.js +16 -0
- package/dist/parsing/functions/value_holder.js.map +1 -0
- package/dist/parsing/logic/case.js +27 -0
- package/dist/parsing/logic/case.js.map +1 -0
- package/dist/parsing/logic/else.js +16 -0
- package/dist/parsing/logic/else.js.map +1 -0
- package/dist/parsing/logic/end.js +13 -0
- package/dist/parsing/logic/end.js.map +1 -0
- package/dist/parsing/logic/then.js +16 -0
- package/dist/parsing/logic/then.js.map +1 -0
- package/dist/parsing/logic/when.js +16 -0
- package/dist/parsing/logic/when.js.map +1 -0
- package/dist/parsing/operations/aggregated_return.js +35 -0
- package/dist/parsing/operations/aggregated_return.js.map +1 -0
- package/dist/parsing/operations/aggregated_with.js +41 -0
- package/dist/parsing/operations/aggregated_with.js.map +1 -0
- package/dist/parsing/operations/group_by.js +139 -0
- package/dist/parsing/operations/group_by.js.map +1 -0
- package/dist/parsing/operations/limit.js +38 -0
- package/dist/parsing/operations/limit.js.map +1 -0
- package/dist/parsing/operations/load.js +174 -0
- package/dist/parsing/operations/load.js.map +1 -0
- package/dist/parsing/operations/operation.js +81 -0
- package/dist/parsing/operations/operation.js.map +1 -0
- package/dist/parsing/operations/projection.js +21 -0
- package/dist/parsing/operations/projection.js.map +1 -0
- package/dist/parsing/operations/return.js +60 -0
- package/dist/parsing/operations/return.js.map +1 -0
- package/dist/parsing/operations/unwind.js +46 -0
- package/dist/parsing/operations/unwind.js.map +1 -0
- package/dist/parsing/operations/where.js +53 -0
- package/dist/parsing/operations/where.js.map +1 -0
- package/dist/parsing/operations/with.js +36 -0
- package/dist/parsing/operations/with.js.map +1 -0
- package/dist/parsing/parser.js +812 -0
- package/dist/parsing/parser.js.map +1 -0
- package/dist/parsing/token_to_node.js +121 -0
- package/dist/parsing/token_to_node.js.map +1 -0
- package/dist/tokenization/keyword.js +46 -0
- package/dist/tokenization/keyword.js.map +1 -0
- package/dist/tokenization/operator.js +28 -0
- package/dist/tokenization/operator.js.map +1 -0
- package/dist/tokenization/string_walker.js +165 -0
- package/dist/tokenization/string_walker.js.map +1 -0
- package/dist/tokenization/symbol.js +18 -0
- package/dist/tokenization/symbol.js.map +1 -0
- package/dist/tokenization/token.js +484 -0
- package/dist/tokenization/token.js.map +1 -0
- package/dist/tokenization/token_mapper.js +55 -0
- package/dist/tokenization/token_mapper.js.map +1 -0
- package/dist/tokenization/token_type.js +19 -0
- package/dist/tokenization/token_type.js.map +1 -0
- package/dist/tokenization/tokenizer.js +220 -0
- package/dist/tokenization/tokenizer.js.map +1 -0
- package/dist/tokenization/trie.js +111 -0
- package/dist/tokenization/trie.js.map +1 -0
- package/dist/utils/object_utils.js +19 -0
- package/dist/utils/object_utils.js.map +1 -0
- package/dist/utils/string_utils.js +110 -0
- package/dist/utils/string_utils.js.map +1 -0
- package/docs/flowquery.min.js +1 -1
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/package.json +21 -4
- package/src/compute/runner.ts +45 -0
- package/src/index.browser.ts +118 -0
- package/src/index.node.ts +141 -0
- package/src/parsing/functions/async_function.ts +95 -0
- package/src/parsing/functions/function_factory.ts +230 -1
- package/src/parsing/functions/function_metadata.ts +238 -0
- package/src/parsing/functions/functions.ts +43 -0
- package/src/parsing/operations/load.ts +51 -2
- package/src/parsing/parser.ts +46 -5
- package/tests/parsing/function_plugins.test.ts +369 -0
|
@@ -0,0 +1,812 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const return_1 = __importDefault(require("./operations/return"));
|
|
7
|
+
const expression_1 = __importDefault(require("./expressions/expression"));
|
|
8
|
+
const ast_node_1 = __importDefault(require("./ast_node"));
|
|
9
|
+
const base_parser_1 = __importDefault(require("./base_parser"));
|
|
10
|
+
const function_factory_1 = __importDefault(require("./functions/function_factory"));
|
|
11
|
+
const function_1 = __importDefault(require("./functions/function"));
|
|
12
|
+
const async_function_1 = __importDefault(require("./functions/async_function"));
|
|
13
|
+
const associative_array_1 = __importDefault(require("./data_structures/associative_array"));
|
|
14
|
+
const json_array_1 = __importDefault(require("./data_structures/json_array"));
|
|
15
|
+
const key_value_pair_1 = __importDefault(require("./data_structures/key_value_pair"));
|
|
16
|
+
const with_1 = __importDefault(require("./operations/with"));
|
|
17
|
+
const unwind_1 = __importDefault(require("./operations/unwind"));
|
|
18
|
+
const where_1 = __importDefault(require("./operations/where"));
|
|
19
|
+
const alias_option_1 = require("./alias_option");
|
|
20
|
+
const load_1 = __importDefault(require("./operations/load"));
|
|
21
|
+
const from_1 = __importDefault(require("./components/from"));
|
|
22
|
+
const alias_1 = __importDefault(require("./alias"));
|
|
23
|
+
const headers_1 = __importDefault(require("./components/headers"));
|
|
24
|
+
const case_1 = __importDefault(require("./logic/case"));
|
|
25
|
+
const when_1 = __importDefault(require("./logic/when"));
|
|
26
|
+
const else_1 = __importDefault(require("./logic/else"));
|
|
27
|
+
const then_1 = __importDefault(require("./logic/then"));
|
|
28
|
+
const lookup_1 = __importDefault(require("./data_structures/lookup"));
|
|
29
|
+
const operator_1 = require("./expressions/operator");
|
|
30
|
+
const reference_1 = __importDefault(require("./expressions/reference"));
|
|
31
|
+
const post_1 = __importDefault(require("./components/post"));
|
|
32
|
+
const aggregated_return_1 = __importDefault(require("./operations/aggregated_return"));
|
|
33
|
+
const context_1 = __importDefault(require("./context"));
|
|
34
|
+
const aggregate_function_1 = __importDefault(require("./functions/aggregate_function"));
|
|
35
|
+
const object_utils_1 = __importDefault(require("../utils/object_utils"));
|
|
36
|
+
const token_1 = __importDefault(require("../tokenization/token"));
|
|
37
|
+
const predicate_function_factory_1 = __importDefault(require("./functions/predicate_function_factory"));
|
|
38
|
+
const f_string_1 = __importDefault(require("./expressions/f_string"));
|
|
39
|
+
const string_1 = __importDefault(require("./expressions/string"));
|
|
40
|
+
const aggregated_with_1 = __importDefault(require("./operations/aggregated_with"));
|
|
41
|
+
const identifier_1 = __importDefault(require("./expressions/identifier"));
|
|
42
|
+
const limit_1 = __importDefault(require("./operations/limit"));
|
|
43
|
+
const range_lookup_1 = __importDefault(require("./data_structures/range_lookup"));
|
|
44
|
+
const null_1 = __importDefault(require("./components/null"));
|
|
45
|
+
/**
|
|
46
|
+
* Main parser for FlowQuery statements.
|
|
47
|
+
*
|
|
48
|
+
* Parses FlowQuery declarative query language statements into an Abstract Syntax Tree (AST).
|
|
49
|
+
* Supports operations like WITH, UNWIND, RETURN, LOAD, WHERE, and LIMIT, along with
|
|
50
|
+
* expressions, functions, data structures, and logical constructs.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* const parser = new Parser();
|
|
55
|
+
* const ast = parser.parse("unwind [1, 2, 3, 4, 5, 6] as num return num");
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
class Parser extends base_parser_1.default {
|
|
59
|
+
constructor() {
|
|
60
|
+
super(...arguments);
|
|
61
|
+
this.variables = new Map();
|
|
62
|
+
this.context = new context_1.default();
|
|
63
|
+
this._returns = 0;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Parses a FlowQuery statement into an Abstract Syntax Tree.
|
|
67
|
+
*
|
|
68
|
+
* @param statement - The FlowQuery statement to parse
|
|
69
|
+
* @returns The root AST node containing the parsed structure
|
|
70
|
+
* @throws {Error} If the statement is malformed or contains syntax errors
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* const ast = parser.parse("LOAD JSON FROM 'https://api.adviceslip.com/advice' AS data RETURN data");
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
parse(statement) {
|
|
78
|
+
this.tokenize(statement);
|
|
79
|
+
const root = new ast_node_1.default();
|
|
80
|
+
let previous = null;
|
|
81
|
+
let operation = null;
|
|
82
|
+
while (!this.token.isEOF()) {
|
|
83
|
+
if (root.childCount() > 0) {
|
|
84
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
this.skipWhitespaceAndComments();
|
|
88
|
+
}
|
|
89
|
+
operation = this.parseOperation();
|
|
90
|
+
if (operation === null) {
|
|
91
|
+
throw new Error('Expected one of WITH, UNWIND, RETURN, or LOAD');
|
|
92
|
+
}
|
|
93
|
+
if (this._returns > 1) {
|
|
94
|
+
throw new Error('Only one RETURN statement is allowed');
|
|
95
|
+
}
|
|
96
|
+
if (previous !== null) {
|
|
97
|
+
previous.addSibling(operation);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
root.addChild(operation);
|
|
101
|
+
}
|
|
102
|
+
const where = this.parseWhere();
|
|
103
|
+
if (where !== null) {
|
|
104
|
+
if (operation instanceof return_1.default) {
|
|
105
|
+
operation.where = where;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
operation.addSibling(where);
|
|
109
|
+
operation = where;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const limit = this.parseLimit();
|
|
113
|
+
if (limit !== null) {
|
|
114
|
+
operation.addSibling(limit);
|
|
115
|
+
operation = limit;
|
|
116
|
+
}
|
|
117
|
+
previous = operation;
|
|
118
|
+
}
|
|
119
|
+
if (!(operation instanceof return_1.default)) {
|
|
120
|
+
throw new Error('Last statement must be a RETURN or a WHERE statement');
|
|
121
|
+
}
|
|
122
|
+
return root;
|
|
123
|
+
}
|
|
124
|
+
parseOperation() {
|
|
125
|
+
return (this.parseWith() ||
|
|
126
|
+
this.parseUnwind() ||
|
|
127
|
+
this.parseReturn() ||
|
|
128
|
+
this.parseLoad());
|
|
129
|
+
}
|
|
130
|
+
parseWith() {
|
|
131
|
+
if (!this.token.isWith()) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
this.setNextToken();
|
|
135
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
136
|
+
const expressions = Array.from(this.parseExpressions(alias_option_1.AliasOption.REQUIRED));
|
|
137
|
+
if (expressions.length === 0) {
|
|
138
|
+
throw new Error('Expected expression');
|
|
139
|
+
}
|
|
140
|
+
if (expressions.some((expression) => expression.has_reducers())) {
|
|
141
|
+
return new aggregated_with_1.default(expressions);
|
|
142
|
+
}
|
|
143
|
+
return new with_1.default(expressions);
|
|
144
|
+
}
|
|
145
|
+
parseUnwind() {
|
|
146
|
+
if (!this.token.isUnwind()) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
this.setNextToken();
|
|
150
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
151
|
+
const expression = this.parseExpression();
|
|
152
|
+
if (expression === null) {
|
|
153
|
+
throw new Error('Expected expression');
|
|
154
|
+
}
|
|
155
|
+
if (!object_utils_1.default.isInstanceOfAny(expression.firstChild(), [json_array_1.default, function_1.default, reference_1.default, lookup_1.default, range_lookup_1.default])) {
|
|
156
|
+
throw new Error('Expected array, function, reference, or lookup.');
|
|
157
|
+
}
|
|
158
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
159
|
+
const alias = this.parseAlias();
|
|
160
|
+
if (alias !== null) {
|
|
161
|
+
expression.setAlias(alias.getAlias());
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
throw new Error('Expected alias');
|
|
165
|
+
}
|
|
166
|
+
const unwind = new unwind_1.default(expression);
|
|
167
|
+
this.variables.set(alias.getAlias(), unwind);
|
|
168
|
+
return unwind;
|
|
169
|
+
}
|
|
170
|
+
parseReturn() {
|
|
171
|
+
if (!this.token.isReturn()) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
this.setNextToken();
|
|
175
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
176
|
+
const expressions = Array.from(this.parseExpressions(alias_option_1.AliasOption.OPTIONAL));
|
|
177
|
+
if (expressions.length === 0) {
|
|
178
|
+
throw new Error('Expected expression');
|
|
179
|
+
}
|
|
180
|
+
if (expressions.some((expression) => expression.has_reducers())) {
|
|
181
|
+
return new aggregated_return_1.default(expressions);
|
|
182
|
+
}
|
|
183
|
+
this._returns++;
|
|
184
|
+
return new return_1.default(expressions);
|
|
185
|
+
}
|
|
186
|
+
parseWhere() {
|
|
187
|
+
if (!this.token.isWhere()) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
this.expectPreviousTokenToBeWhitespaceOrComment();
|
|
191
|
+
this.setNextToken();
|
|
192
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
193
|
+
const expression = this.parseExpression();
|
|
194
|
+
if (expression === null) {
|
|
195
|
+
throw new Error('Expected expression');
|
|
196
|
+
}
|
|
197
|
+
if (object_utils_1.default.isInstanceOfAny(expression.firstChild(), [json_array_1.default, associative_array_1.default])) {
|
|
198
|
+
throw new Error('Expected an expression which can be evaluated to a boolean');
|
|
199
|
+
}
|
|
200
|
+
return new where_1.default(expression);
|
|
201
|
+
}
|
|
202
|
+
parseLoad() {
|
|
203
|
+
if (!this.token.isLoad()) {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
const load = new load_1.default();
|
|
207
|
+
this.setNextToken();
|
|
208
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
209
|
+
if (!(this.token.isJSON() || this.token.isCSV() || this.token.isText())) {
|
|
210
|
+
throw new Error('Expected JSON, CSV, or TEXT');
|
|
211
|
+
}
|
|
212
|
+
load.addChild(this.token.node);
|
|
213
|
+
this.setNextToken();
|
|
214
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
215
|
+
if (!this.token.isFrom()) {
|
|
216
|
+
throw new Error('Expected FROM');
|
|
217
|
+
}
|
|
218
|
+
this.setNextToken();
|
|
219
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
220
|
+
const from = new from_1.default();
|
|
221
|
+
load.addChild(from);
|
|
222
|
+
// Check if the source is an async function
|
|
223
|
+
const asyncFunc = this.parseAsyncFunction();
|
|
224
|
+
if (asyncFunc !== null) {
|
|
225
|
+
from.addChild(asyncFunc);
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
const expression = this.parseExpression();
|
|
229
|
+
if (expression === null) {
|
|
230
|
+
throw new Error('Expected expression or async function');
|
|
231
|
+
}
|
|
232
|
+
from.addChild(expression);
|
|
233
|
+
}
|
|
234
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
235
|
+
if (this.token.isHeaders()) {
|
|
236
|
+
const headers = new headers_1.default();
|
|
237
|
+
this.setNextToken();
|
|
238
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
239
|
+
const header = this.parseExpression();
|
|
240
|
+
if (header === null) {
|
|
241
|
+
throw new Error('Expected expression');
|
|
242
|
+
}
|
|
243
|
+
headers.addChild(header);
|
|
244
|
+
load.addChild(headers);
|
|
245
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
246
|
+
}
|
|
247
|
+
if (this.token.isPost()) {
|
|
248
|
+
const post = new post_1.default();
|
|
249
|
+
this.setNextToken();
|
|
250
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
251
|
+
const payload = this.parseExpression();
|
|
252
|
+
if (payload === null) {
|
|
253
|
+
throw new Error('Expected expression');
|
|
254
|
+
}
|
|
255
|
+
post.addChild(payload);
|
|
256
|
+
load.addChild(post);
|
|
257
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
258
|
+
}
|
|
259
|
+
const alias = this.parseAlias();
|
|
260
|
+
if (alias !== null) {
|
|
261
|
+
load.addChild(alias);
|
|
262
|
+
this.variables.set(alias.getAlias(), load);
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
throw new Error('Expected alias');
|
|
266
|
+
}
|
|
267
|
+
return load;
|
|
268
|
+
}
|
|
269
|
+
parseLimit() {
|
|
270
|
+
this.skipWhitespaceAndComments();
|
|
271
|
+
if (!this.token.isLimit()) {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
this.expectPreviousTokenToBeWhitespaceOrComment();
|
|
275
|
+
this.setNextToken();
|
|
276
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
277
|
+
if (!this.token.isNumber()) {
|
|
278
|
+
throw new Error('Expected number');
|
|
279
|
+
}
|
|
280
|
+
const limit = new limit_1.default(parseInt(this.token.value || '0'));
|
|
281
|
+
this.setNextToken();
|
|
282
|
+
return limit;
|
|
283
|
+
}
|
|
284
|
+
*parseExpressions(alias_option = alias_option_1.AliasOption.NOT_ALLOWED) {
|
|
285
|
+
while (true) {
|
|
286
|
+
const expression = this.parseExpression();
|
|
287
|
+
if (expression !== null) {
|
|
288
|
+
const alias = this.parseAlias();
|
|
289
|
+
if (expression.firstChild() instanceof reference_1.default && alias === null) {
|
|
290
|
+
const reference = expression.firstChild();
|
|
291
|
+
expression.setAlias(reference.identifier);
|
|
292
|
+
this.variables.set(reference.identifier, expression);
|
|
293
|
+
}
|
|
294
|
+
else if (alias_option === alias_option_1.AliasOption.REQUIRED && alias === null && !(expression.firstChild() instanceof reference_1.default)) {
|
|
295
|
+
throw new Error('Alias required');
|
|
296
|
+
}
|
|
297
|
+
else if (alias_option === alias_option_1.AliasOption.NOT_ALLOWED && alias !== null) {
|
|
298
|
+
throw new Error('Alias not allowed');
|
|
299
|
+
}
|
|
300
|
+
else if ([alias_option_1.AliasOption.OPTIONAL, alias_option_1.AliasOption.REQUIRED].includes(alias_option) && alias !== null) {
|
|
301
|
+
expression.setAlias(alias.getAlias());
|
|
302
|
+
this.variables.set(alias.getAlias(), expression);
|
|
303
|
+
}
|
|
304
|
+
yield expression;
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
this.skipWhitespaceAndComments();
|
|
310
|
+
if (!this.token.isComma()) {
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
this.setNextToken();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
parseExpression() {
|
|
317
|
+
var _a, _b;
|
|
318
|
+
const expression = new expression_1.default();
|
|
319
|
+
while (true) {
|
|
320
|
+
this.skipWhitespaceAndComments();
|
|
321
|
+
if (this.token.isIdentifier() && !((_a = this.peek()) === null || _a === void 0 ? void 0 : _a.isLeftParenthesis())) {
|
|
322
|
+
const identifier = this.token.value || '';
|
|
323
|
+
const reference = new reference_1.default(identifier, this.variables.get(identifier));
|
|
324
|
+
this.setNextToken();
|
|
325
|
+
const lookup = this.parseLookup(reference);
|
|
326
|
+
expression.addNode(lookup);
|
|
327
|
+
}
|
|
328
|
+
else if (this.token.isIdentifier() && ((_b = this.peek()) === null || _b === void 0 ? void 0 : _b.isLeftParenthesis())) {
|
|
329
|
+
const func = this.parsePredicateFunction() || this.parseFunction();
|
|
330
|
+
if (func !== null) {
|
|
331
|
+
const lookup = this.parseLookup(func);
|
|
332
|
+
expression.addNode(lookup);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
else if (this.token.isOperand()) {
|
|
336
|
+
expression.addNode(this.token.node);
|
|
337
|
+
this.setNextToken();
|
|
338
|
+
}
|
|
339
|
+
else if (this.token.isFString()) {
|
|
340
|
+
const f_string = this.parseFString();
|
|
341
|
+
if (f_string === null) {
|
|
342
|
+
throw new Error('Expected f-string');
|
|
343
|
+
}
|
|
344
|
+
expression.addNode(f_string);
|
|
345
|
+
}
|
|
346
|
+
else if (this.token.isLeftParenthesis()) {
|
|
347
|
+
this.setNextToken();
|
|
348
|
+
const sub = this.parseExpression();
|
|
349
|
+
if (sub === null) {
|
|
350
|
+
throw new Error('Expected expression');
|
|
351
|
+
}
|
|
352
|
+
if (!this.token.isRightParenthesis()) {
|
|
353
|
+
throw new Error('Expected right parenthesis');
|
|
354
|
+
}
|
|
355
|
+
this.setNextToken();
|
|
356
|
+
const lookup = this.parseLookup(sub);
|
|
357
|
+
expression.addNode(lookup);
|
|
358
|
+
}
|
|
359
|
+
else if (this.token.isOpeningBrace() || this.token.isOpeningBracket()) {
|
|
360
|
+
const json = this.parseJSON();
|
|
361
|
+
if (json === null) {
|
|
362
|
+
throw new Error('Expected JSON object');
|
|
363
|
+
}
|
|
364
|
+
const lookup = this.parseLookup(json);
|
|
365
|
+
expression.addNode(lookup);
|
|
366
|
+
}
|
|
367
|
+
else if (this.token.isCase()) {
|
|
368
|
+
const _case = this.parseCase();
|
|
369
|
+
if (_case === null) {
|
|
370
|
+
throw new Error('Expected CASE statement');
|
|
371
|
+
}
|
|
372
|
+
expression.addNode(_case);
|
|
373
|
+
}
|
|
374
|
+
else if (this.token.isNot()) {
|
|
375
|
+
const not = new operator_1.Not();
|
|
376
|
+
this.setNextToken();
|
|
377
|
+
const sub = this.parseExpression();
|
|
378
|
+
if (sub === null) {
|
|
379
|
+
throw new Error('Expected expression');
|
|
380
|
+
}
|
|
381
|
+
not.addChild(sub);
|
|
382
|
+
expression.addNode(not);
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
if (expression.nodesAdded()) {
|
|
386
|
+
throw new Error('Expected operand or left parenthesis');
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
this.skipWhitespaceAndComments();
|
|
393
|
+
if (this.token.isOperator()) {
|
|
394
|
+
expression.addNode(this.token.node);
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
this.setNextToken();
|
|
400
|
+
}
|
|
401
|
+
if (expression.nodesAdded()) {
|
|
402
|
+
expression.finish();
|
|
403
|
+
return expression;
|
|
404
|
+
}
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
parseLookup(node) {
|
|
408
|
+
let variable = node;
|
|
409
|
+
let lookup = null;
|
|
410
|
+
while (true) {
|
|
411
|
+
if (this.token.isDot()) {
|
|
412
|
+
this.setNextToken();
|
|
413
|
+
if (!this.token.isIdentifier() && !this.token.isKeyword()) {
|
|
414
|
+
throw new Error('Expected identifier');
|
|
415
|
+
}
|
|
416
|
+
lookup = new lookup_1.default();
|
|
417
|
+
lookup.index = new identifier_1.default(this.token.value || '');
|
|
418
|
+
lookup.variable = variable;
|
|
419
|
+
this.setNextToken();
|
|
420
|
+
}
|
|
421
|
+
else if (this.token.isOpeningBracket()) {
|
|
422
|
+
this.setNextToken();
|
|
423
|
+
this.skipWhitespaceAndComments();
|
|
424
|
+
const index = this.parseExpression();
|
|
425
|
+
let to = null;
|
|
426
|
+
this.skipWhitespaceAndComments();
|
|
427
|
+
if (this.token.isColon()) {
|
|
428
|
+
this.setNextToken();
|
|
429
|
+
this.skipWhitespaceAndComments();
|
|
430
|
+
lookup = new range_lookup_1.default();
|
|
431
|
+
to = this.parseExpression();
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
if (index === null) {
|
|
435
|
+
throw new Error('Expected expression');
|
|
436
|
+
}
|
|
437
|
+
lookup = new lookup_1.default();
|
|
438
|
+
}
|
|
439
|
+
this.skipWhitespaceAndComments();
|
|
440
|
+
if (!this.token.isClosingBracket()) {
|
|
441
|
+
throw new Error('Expected closing bracket');
|
|
442
|
+
}
|
|
443
|
+
this.setNextToken();
|
|
444
|
+
if (lookup instanceof range_lookup_1.default) {
|
|
445
|
+
lookup.from = index || new null_1.default();
|
|
446
|
+
lookup.to = to || new null_1.default();
|
|
447
|
+
}
|
|
448
|
+
else if (lookup instanceof lookup_1.default && index !== null) {
|
|
449
|
+
lookup.index = index;
|
|
450
|
+
}
|
|
451
|
+
lookup.variable = variable;
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
variable = lookup || variable;
|
|
457
|
+
}
|
|
458
|
+
return variable;
|
|
459
|
+
}
|
|
460
|
+
parseCase() {
|
|
461
|
+
if (!this.token.isCase()) {
|
|
462
|
+
return null;
|
|
463
|
+
}
|
|
464
|
+
this.setNextToken();
|
|
465
|
+
const _case = new case_1.default();
|
|
466
|
+
let parts = 0;
|
|
467
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
468
|
+
while (true) {
|
|
469
|
+
const when = this.parseWhen();
|
|
470
|
+
if (when === null && parts === 0) {
|
|
471
|
+
throw new Error('Expected WHEN');
|
|
472
|
+
}
|
|
473
|
+
else if (when === null && parts > 0) {
|
|
474
|
+
break;
|
|
475
|
+
}
|
|
476
|
+
else if (when !== null) {
|
|
477
|
+
_case.addChild(when);
|
|
478
|
+
}
|
|
479
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
480
|
+
const then = this.parseThen();
|
|
481
|
+
if (then === null) {
|
|
482
|
+
throw new Error('Expected THEN');
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
_case.addChild(then);
|
|
486
|
+
}
|
|
487
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
488
|
+
parts++;
|
|
489
|
+
}
|
|
490
|
+
const _else = this.parseElse();
|
|
491
|
+
if (_else === null) {
|
|
492
|
+
throw new Error('Expected ELSE');
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
_case.addChild(_else);
|
|
496
|
+
}
|
|
497
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
498
|
+
if (!this.token.isEnd()) {
|
|
499
|
+
throw new Error('Expected END');
|
|
500
|
+
}
|
|
501
|
+
this.setNextToken();
|
|
502
|
+
return _case;
|
|
503
|
+
}
|
|
504
|
+
parseWhen() {
|
|
505
|
+
if (!this.token.isWhen()) {
|
|
506
|
+
return null;
|
|
507
|
+
}
|
|
508
|
+
this.setNextToken();
|
|
509
|
+
const when = new when_1.default();
|
|
510
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
511
|
+
const expression = this.parseExpression();
|
|
512
|
+
if (expression === null) {
|
|
513
|
+
throw new Error('Expected expression');
|
|
514
|
+
}
|
|
515
|
+
when.addChild(expression);
|
|
516
|
+
return when;
|
|
517
|
+
}
|
|
518
|
+
parseThen() {
|
|
519
|
+
if (!this.token.isThen()) {
|
|
520
|
+
return null;
|
|
521
|
+
}
|
|
522
|
+
this.setNextToken();
|
|
523
|
+
const then = new then_1.default();
|
|
524
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
525
|
+
const expression = this.parseExpression();
|
|
526
|
+
if (expression === null) {
|
|
527
|
+
throw new Error('Expected expression');
|
|
528
|
+
}
|
|
529
|
+
then.addChild(expression);
|
|
530
|
+
return then;
|
|
531
|
+
}
|
|
532
|
+
parseElse() {
|
|
533
|
+
if (!this.token.isElse()) {
|
|
534
|
+
return null;
|
|
535
|
+
}
|
|
536
|
+
this.setNextToken();
|
|
537
|
+
const _else = new else_1.default();
|
|
538
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
539
|
+
const expression = this.parseExpression();
|
|
540
|
+
if (expression === null) {
|
|
541
|
+
throw new Error('Expected expression');
|
|
542
|
+
}
|
|
543
|
+
_else.addChild(expression);
|
|
544
|
+
return _else;
|
|
545
|
+
}
|
|
546
|
+
parseAlias() {
|
|
547
|
+
this.skipWhitespaceAndComments();
|
|
548
|
+
if (!this.token.isAs()) {
|
|
549
|
+
return null;
|
|
550
|
+
}
|
|
551
|
+
this.expectPreviousTokenToBeWhitespaceOrComment();
|
|
552
|
+
this.setNextToken();
|
|
553
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
554
|
+
if ((!this.token.isIdentifier() && !this.token.isKeyword()) || this.token.value === null) {
|
|
555
|
+
throw new Error('Expected identifier');
|
|
556
|
+
}
|
|
557
|
+
const alias = new alias_1.default(this.token.value || '');
|
|
558
|
+
this.setNextToken();
|
|
559
|
+
return alias;
|
|
560
|
+
}
|
|
561
|
+
parseFunction() {
|
|
562
|
+
var _a;
|
|
563
|
+
if (!this.token.isIdentifier()) {
|
|
564
|
+
return null;
|
|
565
|
+
}
|
|
566
|
+
if (this.token.value === null) {
|
|
567
|
+
throw new Error('Expected identifier');
|
|
568
|
+
}
|
|
569
|
+
if (!((_a = this.peek()) === null || _a === void 0 ? void 0 : _a.isLeftParenthesis())) {
|
|
570
|
+
return null;
|
|
571
|
+
}
|
|
572
|
+
const func = function_factory_1.default.create(this.token.value);
|
|
573
|
+
if (func instanceof aggregate_function_1.default && this.context.containsType(aggregate_function_1.default)) {
|
|
574
|
+
throw new Error('Aggregate functions cannot be nested');
|
|
575
|
+
}
|
|
576
|
+
this.context.push(func);
|
|
577
|
+
this.setNextToken();
|
|
578
|
+
this.setNextToken();
|
|
579
|
+
this.skipWhitespaceAndComments();
|
|
580
|
+
if (this.token.isDistinct()) {
|
|
581
|
+
func.distinct = true;
|
|
582
|
+
this.setNextToken();
|
|
583
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
584
|
+
}
|
|
585
|
+
func.parameters = Array.from(this.parseExpressions(alias_option_1.AliasOption.NOT_ALLOWED));
|
|
586
|
+
this.skipWhitespaceAndComments();
|
|
587
|
+
if (!this.token.isRightParenthesis()) {
|
|
588
|
+
throw new Error('Expected right parenthesis');
|
|
589
|
+
}
|
|
590
|
+
this.setNextToken();
|
|
591
|
+
this.context.pop();
|
|
592
|
+
return func;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Parses an async function call for use in LOAD operations.
|
|
596
|
+
* Only matches if the identifier is registered as an async data provider.
|
|
597
|
+
*
|
|
598
|
+
* @returns An AsyncFunction node if a registered async function is found, otherwise null
|
|
599
|
+
*/
|
|
600
|
+
parseAsyncFunction() {
|
|
601
|
+
var _a;
|
|
602
|
+
if (!this.token.isIdentifier()) {
|
|
603
|
+
return null;
|
|
604
|
+
}
|
|
605
|
+
if (this.token.value === null) {
|
|
606
|
+
return null;
|
|
607
|
+
}
|
|
608
|
+
// Only parse as async function if it's registered as an async provider
|
|
609
|
+
if (!function_factory_1.default.isAsyncProvider(this.token.value)) {
|
|
610
|
+
return null;
|
|
611
|
+
}
|
|
612
|
+
if (!((_a = this.peek()) === null || _a === void 0 ? void 0 : _a.isLeftParenthesis())) {
|
|
613
|
+
return null;
|
|
614
|
+
}
|
|
615
|
+
const asyncFunc = new async_function_1.default(this.token.value);
|
|
616
|
+
this.setNextToken(); // skip function name
|
|
617
|
+
this.setNextToken(); // skip left parenthesis
|
|
618
|
+
this.skipWhitespaceAndComments();
|
|
619
|
+
asyncFunc.parameters = Array.from(this.parseExpressions(alias_option_1.AliasOption.NOT_ALLOWED));
|
|
620
|
+
this.skipWhitespaceAndComments();
|
|
621
|
+
if (!this.token.isRightParenthesis()) {
|
|
622
|
+
throw new Error('Expected right parenthesis');
|
|
623
|
+
}
|
|
624
|
+
this.setNextToken();
|
|
625
|
+
return asyncFunc;
|
|
626
|
+
}
|
|
627
|
+
parsePredicateFunction() {
|
|
628
|
+
if (!this.ahead([token_1.default.IDENTIFIER(""), token_1.default.LEFT_PARENTHESIS, token_1.default.IDENTIFIER(""), token_1.default.IN])) {
|
|
629
|
+
return null;
|
|
630
|
+
}
|
|
631
|
+
if (this.token.value === null) {
|
|
632
|
+
throw new Error('Expected identifier');
|
|
633
|
+
}
|
|
634
|
+
const func = predicate_function_factory_1.default.create(this.token.value);
|
|
635
|
+
this.setNextToken();
|
|
636
|
+
if (!this.token.isLeftParenthesis()) {
|
|
637
|
+
throw new Error('Expected left parenthesis');
|
|
638
|
+
}
|
|
639
|
+
this.setNextToken();
|
|
640
|
+
this.skipWhitespaceAndComments();
|
|
641
|
+
if (!this.token.isIdentifier()) {
|
|
642
|
+
throw new Error('Expected identifier');
|
|
643
|
+
}
|
|
644
|
+
const reference = new reference_1.default(this.token.value);
|
|
645
|
+
this.variables.set(reference.identifier, reference);
|
|
646
|
+
func.addChild(reference);
|
|
647
|
+
this.setNextToken();
|
|
648
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
649
|
+
if (!this.token.isIn()) {
|
|
650
|
+
throw new Error('Expected IN');
|
|
651
|
+
}
|
|
652
|
+
this.setNextToken();
|
|
653
|
+
this.expectAndSkipWhitespaceAndComments();
|
|
654
|
+
const expression = this.parseExpression();
|
|
655
|
+
if (expression === null) {
|
|
656
|
+
throw new Error('Expected expression');
|
|
657
|
+
}
|
|
658
|
+
if (!object_utils_1.default.isInstanceOfAny(expression.firstChild(), [json_array_1.default, reference_1.default, lookup_1.default, function_1.default])) {
|
|
659
|
+
throw new Error('Expected array or reference');
|
|
660
|
+
}
|
|
661
|
+
func.addChild(expression);
|
|
662
|
+
this.skipWhitespaceAndComments();
|
|
663
|
+
if (!this.token.isPipe()) {
|
|
664
|
+
throw new Error('Expected pipe');
|
|
665
|
+
}
|
|
666
|
+
this.setNextToken();
|
|
667
|
+
const _return = this.parseExpression();
|
|
668
|
+
if (_return === null) {
|
|
669
|
+
throw new Error('Expected expression');
|
|
670
|
+
}
|
|
671
|
+
func.addChild(_return);
|
|
672
|
+
const where = this.parseWhere();
|
|
673
|
+
if (where !== null) {
|
|
674
|
+
func.addChild(where);
|
|
675
|
+
}
|
|
676
|
+
this.skipWhitespaceAndComments();
|
|
677
|
+
if (!this.token.isRightParenthesis()) {
|
|
678
|
+
throw new Error('Expected right parenthesis');
|
|
679
|
+
}
|
|
680
|
+
this.setNextToken();
|
|
681
|
+
this.variables.delete(reference.identifier);
|
|
682
|
+
return func;
|
|
683
|
+
}
|
|
684
|
+
parseFString() {
|
|
685
|
+
if (!this.token.isFString()) {
|
|
686
|
+
return null;
|
|
687
|
+
}
|
|
688
|
+
const f_string = new f_string_1.default();
|
|
689
|
+
while (this.token.isFString()) {
|
|
690
|
+
if (this.token.value !== null) {
|
|
691
|
+
f_string.addChild(new string_1.default(this.token.value));
|
|
692
|
+
}
|
|
693
|
+
this.setNextToken();
|
|
694
|
+
if (this.token.isOpeningBrace()) {
|
|
695
|
+
this.setNextToken();
|
|
696
|
+
const expression = this.parseExpression();
|
|
697
|
+
if (expression === null) {
|
|
698
|
+
throw new Error('Expected expression');
|
|
699
|
+
}
|
|
700
|
+
f_string.addChild(expression);
|
|
701
|
+
if (!this.token.isClosingBrace()) {
|
|
702
|
+
throw new Error('Expected closing brace');
|
|
703
|
+
}
|
|
704
|
+
this.setNextToken();
|
|
705
|
+
}
|
|
706
|
+
else {
|
|
707
|
+
break;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
return f_string;
|
|
711
|
+
}
|
|
712
|
+
parseJSON() {
|
|
713
|
+
if (this.token.isOpeningBrace()) {
|
|
714
|
+
const array = this.parseAssociativeArray();
|
|
715
|
+
if (array === null) {
|
|
716
|
+
throw new Error('Expected associative array');
|
|
717
|
+
}
|
|
718
|
+
return array;
|
|
719
|
+
}
|
|
720
|
+
else if (this.token.isOpeningBracket()) {
|
|
721
|
+
const array = this.parseJSONArray();
|
|
722
|
+
if (array === null) {
|
|
723
|
+
throw new Error('Expected JSON array');
|
|
724
|
+
}
|
|
725
|
+
return array;
|
|
726
|
+
}
|
|
727
|
+
throw new Error('Expected opening brace or bracket');
|
|
728
|
+
}
|
|
729
|
+
parseAssociativeArray() {
|
|
730
|
+
if (!this.token.isOpeningBrace()) {
|
|
731
|
+
return null;
|
|
732
|
+
}
|
|
733
|
+
const array = new associative_array_1.default();
|
|
734
|
+
this.setNextToken();
|
|
735
|
+
while (true) {
|
|
736
|
+
this.skipWhitespaceAndComments();
|
|
737
|
+
if (this.token.isClosingBrace()) {
|
|
738
|
+
break;
|
|
739
|
+
}
|
|
740
|
+
if (!this.token.isIdentifier() && !this.token.isKeyword()) {
|
|
741
|
+
throw new Error('Expected identifier');
|
|
742
|
+
}
|
|
743
|
+
const key = this.token.value;
|
|
744
|
+
if (key === null) {
|
|
745
|
+
throw new Error('Expected string');
|
|
746
|
+
}
|
|
747
|
+
this.setNextToken();
|
|
748
|
+
this.skipWhitespaceAndComments();
|
|
749
|
+
if (!this.token.isColon()) {
|
|
750
|
+
throw new Error('Expected colon');
|
|
751
|
+
}
|
|
752
|
+
this.setNextToken();
|
|
753
|
+
this.skipWhitespaceAndComments();
|
|
754
|
+
const value = this.parseExpression();
|
|
755
|
+
if (value === null) {
|
|
756
|
+
throw new Error('Expected expression');
|
|
757
|
+
}
|
|
758
|
+
array.addKeyValue(new key_value_pair_1.default(key, value));
|
|
759
|
+
this.skipWhitespaceAndComments();
|
|
760
|
+
if (this.token.isComma()) {
|
|
761
|
+
this.setNextToken();
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
this.setNextToken();
|
|
765
|
+
return array;
|
|
766
|
+
}
|
|
767
|
+
parseJSONArray() {
|
|
768
|
+
if (!this.token.isOpeningBracket()) {
|
|
769
|
+
return null;
|
|
770
|
+
}
|
|
771
|
+
const array = new json_array_1.default();
|
|
772
|
+
this.setNextToken();
|
|
773
|
+
while (true) {
|
|
774
|
+
this.skipWhitespaceAndComments();
|
|
775
|
+
if (this.token.isClosingBracket()) {
|
|
776
|
+
break;
|
|
777
|
+
}
|
|
778
|
+
const value = this.parseExpression();
|
|
779
|
+
if (value === null) {
|
|
780
|
+
throw new Error('Expected expression');
|
|
781
|
+
}
|
|
782
|
+
array.addValue(value);
|
|
783
|
+
this.skipWhitespaceAndComments();
|
|
784
|
+
if (this.token.isComma()) {
|
|
785
|
+
this.setNextToken();
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
this.setNextToken();
|
|
789
|
+
return array;
|
|
790
|
+
}
|
|
791
|
+
expectAndSkipWhitespaceAndComments() {
|
|
792
|
+
const skipped = this.skipWhitespaceAndComments();
|
|
793
|
+
if (!skipped) {
|
|
794
|
+
throw new Error('Expected whitespace or comment');
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
skipWhitespaceAndComments() {
|
|
798
|
+
let skipped = this.previousToken.isWhitespaceOrComment();
|
|
799
|
+
while (this.token.isWhitespace() || this.token.isComment()) {
|
|
800
|
+
this.setNextToken();
|
|
801
|
+
skipped = true;
|
|
802
|
+
}
|
|
803
|
+
return skipped;
|
|
804
|
+
}
|
|
805
|
+
expectPreviousTokenToBeWhitespaceOrComment() {
|
|
806
|
+
if (!this.previousToken.isWhitespaceOrComment()) {
|
|
807
|
+
throw new Error('Expected whitespace or comment');
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
exports.default = Parser;
|
|
812
|
+
//# sourceMappingURL=parser.js.map
|