@aeriajs/compiler 0.0.61 → 0.0.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ast.d.ts +1 -0
- package/dist/ast.js +4 -6
- package/dist/codegen/generateContracts.js +15 -19
- package/dist/codegen/generateExports.js +5 -9
- package/dist/codegen/generateJSCollections.js +13 -17
- package/dist/codegen/generateTSCollections.js +13 -17
- package/dist/codegen/index.js +4 -20
- package/dist/codegen/utils.js +25 -37
- package/dist/codegen.js +8 -45
- package/dist/compile.js +19 -58
- package/dist/diagnostic.js +1 -5
- package/dist/guards.js +3 -41
- package/dist/index.js +7 -23
- package/dist/lexer.js +48 -52
- package/dist/parser.js +267 -297
- package/dist/semantic.js +31 -68
- package/dist/token.js +1 -4
- package/dist/types.js +1 -2
- package/dist/utils.js +1 -4
- package/package.json +6 -9
- package/dist/ast.mjs +0 -24
- package/dist/codegen/generateContracts.mjs +0 -85
- package/dist/codegen/generateExports.mjs +0 -42
- package/dist/codegen/generateJSCollections.mjs +0 -103
- package/dist/codegen/generateTSCollections.mjs +0 -114
- package/dist/codegen/index.mjs +0 -5
- package/dist/codegen/utils.mjs +0 -161
- package/dist/codegen.mjs +0 -54
- package/dist/compile.mjs +0 -69
- package/dist/diagnostic.mjs +0 -18
- package/dist/guards.mjs +0 -8
- package/dist/index.mjs +0 -8
- package/dist/lexer.mjs +0 -375
- package/dist/parser.mjs +0 -1297
- package/dist/semantic.mjs +0 -202
- package/dist/token.mjs +0 -24
- package/dist/types.mjs +0 -1
- package/dist/utils.mjs +0 -12
package/dist/parser.js
CHANGED
|
@@ -1,69 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.parse = exports.memoTable = exports.locationMap = void 0;
|
|
37
|
-
const types_1 = require("@aeriajs/types");
|
|
38
|
-
const core_1 = require("@phosphor-icons/core");
|
|
39
|
-
const AST = __importStar(require("./ast.js"));
|
|
40
|
-
const guards = __importStar(require("./guards.js"));
|
|
41
|
-
const lexer = __importStar(require("./lexer.js"));
|
|
42
|
-
const token_js_1 = require("./token.js");
|
|
43
|
-
const diagnostic_js_1 = require("./diagnostic.js");
|
|
44
|
-
const utils_js_1 = require("./utils.js");
|
|
1
|
+
import { DESCRIPTION_PRESETS, LAYOUT_NAMES, PROPERTY_ARRAY_ELEMENTS, PROPERTY_FORMATS, PROPERTY_INPUT_ELEMENTS, PROPERTY_INPUT_TYPES } from '@aeriajs/types';
|
|
2
|
+
import { icons } from '@phosphor-icons/core';
|
|
3
|
+
import * as AST from './ast.js';
|
|
4
|
+
import * as guards from './guards.js';
|
|
5
|
+
import * as lexer from './lexer.js';
|
|
6
|
+
import { TokenType } from './token.js';
|
|
7
|
+
import { Diagnostic } from './diagnostic.js';
|
|
8
|
+
import { DEFAULT_EXPORT_SYMBOLS } from './utils.js';
|
|
45
9
|
const MAX_ERROR_MESSAGE_ITEMS = 20;
|
|
46
|
-
const ICON_NAMES =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
defaultExportSymbols:
|
|
10
|
+
const ICON_NAMES = icons.map((icon) => icon.name);
|
|
11
|
+
export const locationMap = new WeakMap();
|
|
12
|
+
export const memoTable = {
|
|
13
|
+
defaultExportSymbols: DEFAULT_EXPORT_SYMBOLS,
|
|
50
14
|
};
|
|
51
15
|
const isFileProperty = (property) => {
|
|
52
16
|
return property.$ref === 'File';
|
|
53
17
|
};
|
|
54
18
|
const checkForValidRoles = (roles, symbols) => {
|
|
55
|
-
if (
|
|
19
|
+
if (memoTable.roles) {
|
|
56
20
|
for (const [i, role] of roles.entries()) {
|
|
57
21
|
const symbol = symbols[i];
|
|
58
|
-
if (!
|
|
59
|
-
const location =
|
|
60
|
-
throw new
|
|
22
|
+
if (!memoTable.roles.includes(role)) {
|
|
23
|
+
const location = locationMap.get(symbol);
|
|
24
|
+
throw new Diagnostic(`invalid role "${role}"`, location);
|
|
61
25
|
}
|
|
62
26
|
}
|
|
63
27
|
}
|
|
64
28
|
return roles;
|
|
65
29
|
};
|
|
66
|
-
const parse = (tokens) => {
|
|
30
|
+
export const parse = (tokens) => {
|
|
67
31
|
let index = 0;
|
|
68
32
|
const ast = {
|
|
69
33
|
kind: 'program',
|
|
@@ -77,28 +41,28 @@ const parse = (tokens) => {
|
|
|
77
41
|
const next = () => {
|
|
78
42
|
const token = tokens[index + 1];
|
|
79
43
|
if (!token) {
|
|
80
|
-
throw new
|
|
44
|
+
throw new Diagnostic('unexpected EOF', current().location);
|
|
81
45
|
}
|
|
82
46
|
return token;
|
|
83
47
|
};
|
|
84
48
|
const previous = () => {
|
|
85
49
|
const token = tokens[index - 1];
|
|
86
50
|
if (!token) {
|
|
87
|
-
throw new
|
|
51
|
+
throw new Diagnostic('invalid position');
|
|
88
52
|
}
|
|
89
53
|
return token;
|
|
90
54
|
};
|
|
91
55
|
const current = () => {
|
|
92
56
|
const token = tokens[index];
|
|
93
57
|
if (!token) {
|
|
94
|
-
throw new
|
|
58
|
+
throw new Diagnostic('unexpected EOF', previous().location);
|
|
95
59
|
}
|
|
96
60
|
return token;
|
|
97
61
|
};
|
|
98
62
|
const foldBrackets = () => {
|
|
99
|
-
if (match(
|
|
63
|
+
if (match(TokenType.LeftBracket)) {
|
|
100
64
|
advance();
|
|
101
|
-
while (!match(
|
|
65
|
+
while (!match(TokenType.RightBracket)) {
|
|
102
66
|
foldBrackets();
|
|
103
67
|
advance();
|
|
104
68
|
}
|
|
@@ -131,14 +95,14 @@ const parse = (tokens) => {
|
|
|
131
95
|
if (Array.isArray(value) && value.length > MAX_ERROR_MESSAGE_ITEMS) {
|
|
132
96
|
expectedValue += ' | ...';
|
|
133
97
|
}
|
|
134
|
-
throw new
|
|
98
|
+
throw new Diagnostic(expectedValue
|
|
135
99
|
? `expected ${expected} with value ${expectedValue} but found ${token.type} with value "${token.value}" instead`
|
|
136
100
|
: `expected ${expected} but found ${token.type} instead`, token.location);
|
|
137
101
|
};
|
|
138
102
|
const recover = (keywords) => {
|
|
139
103
|
let token;
|
|
140
104
|
while (token = tokens[++index]) {
|
|
141
|
-
if (token.type ===
|
|
105
|
+
if (token.type === TokenType.Keyword && keywords.includes(token.value)) {
|
|
142
106
|
break;
|
|
143
107
|
}
|
|
144
108
|
}
|
|
@@ -146,9 +110,9 @@ const parse = (tokens) => {
|
|
|
146
110
|
const parseArray = (types) => {
|
|
147
111
|
const array = [];
|
|
148
112
|
const symbols = [];
|
|
149
|
-
const { location: openingLocation } = consume(
|
|
150
|
-
if (match(
|
|
151
|
-
consume(
|
|
113
|
+
const { location: openingLocation } = consume(TokenType.LeftSquareBracket);
|
|
114
|
+
if (match(TokenType.RightSquareBracket)) {
|
|
115
|
+
consume(TokenType.RightSquareBracket);
|
|
152
116
|
return {
|
|
153
117
|
value: [],
|
|
154
118
|
symbols: [],
|
|
@@ -162,19 +126,19 @@ const parse = (tokens) => {
|
|
|
162
126
|
}
|
|
163
127
|
}
|
|
164
128
|
if (!type) {
|
|
165
|
-
throw new
|
|
129
|
+
throw new Diagnostic(`array got an invalid type, accepted ones are: ${types.join(' | ')}`, openingLocation);
|
|
166
130
|
}
|
|
167
|
-
while (!match(
|
|
131
|
+
while (!match(TokenType.RightSquareBracket)) {
|
|
168
132
|
const { value, location } = consume(type);
|
|
169
133
|
const elemSymbol = Symbol();
|
|
170
134
|
array.push(value);
|
|
171
135
|
symbols.push(elemSymbol);
|
|
172
|
-
|
|
173
|
-
if (match(
|
|
174
|
-
consume(
|
|
136
|
+
locationMap.set(elemSymbol, location);
|
|
137
|
+
if (match(TokenType.Comma)) {
|
|
138
|
+
consume(TokenType.Comma);
|
|
175
139
|
}
|
|
176
140
|
}
|
|
177
|
-
consume(
|
|
141
|
+
consume(TokenType.RightSquareBracket);
|
|
178
142
|
return {
|
|
179
143
|
value: array,
|
|
180
144
|
symbols,
|
|
@@ -183,18 +147,18 @@ const parse = (tokens) => {
|
|
|
183
147
|
const parseArrayBlock = (value) => {
|
|
184
148
|
const array = [];
|
|
185
149
|
const symbols = [];
|
|
186
|
-
consume(
|
|
187
|
-
while (!match(
|
|
188
|
-
const { value: identifier, location } = consume(
|
|
150
|
+
consume(TokenType.LeftBracket);
|
|
151
|
+
while (!match(TokenType.RightBracket)) {
|
|
152
|
+
const { value: identifier, location } = consume(TokenType.Identifier, value);
|
|
189
153
|
const elemSymbol = Symbol();
|
|
190
154
|
array.push(identifier);
|
|
191
155
|
symbols.push(elemSymbol);
|
|
192
|
-
|
|
193
|
-
if (match(
|
|
194
|
-
consume(
|
|
156
|
+
locationMap.set(elemSymbol, location);
|
|
157
|
+
if (match(TokenType.Comma)) {
|
|
158
|
+
consume(TokenType.Comma);
|
|
195
159
|
}
|
|
196
160
|
}
|
|
197
|
-
consume(
|
|
161
|
+
consume(TokenType.RightBracket);
|
|
198
162
|
return {
|
|
199
163
|
value: array,
|
|
200
164
|
symbols,
|
|
@@ -204,23 +168,23 @@ const parse = (tokens) => {
|
|
|
204
168
|
const array = {};
|
|
205
169
|
const symbols = [];
|
|
206
170
|
let hasAttributes = false;
|
|
207
|
-
consume(
|
|
208
|
-
while (!match(
|
|
209
|
-
const { value: identifier, location } = consume(
|
|
171
|
+
consume(TokenType.LeftBracket);
|
|
172
|
+
while (!match(TokenType.RightBracket)) {
|
|
173
|
+
const { value: identifier, location } = consume(TokenType.Identifier);
|
|
210
174
|
array[identifier] = true;
|
|
211
175
|
const elemSymbol = Symbol();
|
|
212
176
|
symbols.push(elemSymbol);
|
|
213
|
-
|
|
214
|
-
if (match(
|
|
177
|
+
locationMap.set(elemSymbol, location);
|
|
178
|
+
if (match(TokenType.AttributeName)) {
|
|
215
179
|
hasAttributes = true;
|
|
216
180
|
}
|
|
217
|
-
while (match(
|
|
181
|
+
while (match(TokenType.AttributeName)) {
|
|
218
182
|
array[identifier] = {};
|
|
219
|
-
const { value: attributeName } = consume(
|
|
183
|
+
const { value: attributeName } = consume(TokenType.AttributeName, allowedAttributes);
|
|
220
184
|
cb(attributeName, array, identifier);
|
|
221
185
|
}
|
|
222
186
|
}
|
|
223
|
-
consume(
|
|
187
|
+
consume(TokenType.RightBracket);
|
|
224
188
|
const value = hasAttributes
|
|
225
189
|
? array
|
|
226
190
|
: Object.keys(array);
|
|
@@ -231,16 +195,16 @@ const parse = (tokens) => {
|
|
|
231
195
|
};
|
|
232
196
|
const parsePropertyAttributeValue = (attributeName, property, location) => {
|
|
233
197
|
const consumeBoolean = () => {
|
|
234
|
-
if (match(
|
|
235
|
-
const { value } = consume(
|
|
198
|
+
if (match(TokenType.Boolean)) {
|
|
199
|
+
const { value } = consume(TokenType.Boolean);
|
|
236
200
|
return value;
|
|
237
201
|
}
|
|
238
202
|
return true;
|
|
239
203
|
};
|
|
240
204
|
if ('enum' in property && attributeName === 'values') {
|
|
241
205
|
property.enum = parseArray([
|
|
242
|
-
|
|
243
|
-
|
|
206
|
+
TokenType.QuotedString,
|
|
207
|
+
TokenType.Number,
|
|
244
208
|
]).value;
|
|
245
209
|
return;
|
|
246
210
|
}
|
|
@@ -248,27 +212,27 @@ const parse = (tokens) => {
|
|
|
248
212
|
const token = current();
|
|
249
213
|
advance();
|
|
250
214
|
switch (token.type) {
|
|
251
|
-
case
|
|
252
|
-
case
|
|
253
|
-
case
|
|
254
|
-
case
|
|
215
|
+
case TokenType.Number:
|
|
216
|
+
case TokenType.Boolean:
|
|
217
|
+
case TokenType.Null:
|
|
218
|
+
case TokenType.QuotedString: {
|
|
255
219
|
property.const = token.value;
|
|
256
220
|
return;
|
|
257
221
|
}
|
|
258
222
|
default: {
|
|
259
|
-
throw new
|
|
223
|
+
throw new Diagnostic(`const received invalid value: "${token.value}"`, location);
|
|
260
224
|
}
|
|
261
225
|
}
|
|
262
226
|
}
|
|
263
227
|
switch (attributeName) {
|
|
264
228
|
case 'icon': {
|
|
265
|
-
const { value } = consume(
|
|
229
|
+
const { value } = consume(TokenType.QuotedString, ICON_NAMES);
|
|
266
230
|
property[attributeName] = value;
|
|
267
231
|
return;
|
|
268
232
|
}
|
|
269
233
|
case 'hint':
|
|
270
234
|
case 'description': {
|
|
271
|
-
const { value } = consume(
|
|
235
|
+
const { value } = consume(TokenType.QuotedString);
|
|
272
236
|
property[attributeName] = value;
|
|
273
237
|
return;
|
|
274
238
|
}
|
|
@@ -289,11 +253,11 @@ const parse = (tokens) => {
|
|
|
289
253
|
case 'form':
|
|
290
254
|
case 'populate':
|
|
291
255
|
case 'indexes': {
|
|
292
|
-
property[attributeName] = parseArray([
|
|
256
|
+
property[attributeName] = parseArray([TokenType.Identifier]).value;
|
|
293
257
|
return;
|
|
294
258
|
}
|
|
295
259
|
case 'populateDepth': {
|
|
296
|
-
const { value } = consume(
|
|
260
|
+
const { value } = consume(TokenType.Number);
|
|
297
261
|
property[attributeName] = value;
|
|
298
262
|
return;
|
|
299
263
|
}
|
|
@@ -310,7 +274,7 @@ const parse = (tokens) => {
|
|
|
310
274
|
switch (attributeName) {
|
|
311
275
|
case 'extensions':
|
|
312
276
|
case 'accept': {
|
|
313
|
-
property[attributeName] = parseArray([
|
|
277
|
+
property[attributeName] = parseArray([TokenType.QuotedString]).value;
|
|
314
278
|
return;
|
|
315
279
|
}
|
|
316
280
|
}
|
|
@@ -321,44 +285,44 @@ const parse = (tokens) => {
|
|
|
321
285
|
case 'string': {
|
|
322
286
|
switch (attributeName) {
|
|
323
287
|
case 'format': {
|
|
324
|
-
const { value } = consume(
|
|
288
|
+
const { value } = consume(TokenType.QuotedString, PROPERTY_FORMATS);
|
|
325
289
|
property[attributeName] = value;
|
|
326
290
|
return;
|
|
327
291
|
}
|
|
328
292
|
case 'mask': {
|
|
329
|
-
if (match(
|
|
330
|
-
property[attributeName] = parseArray([
|
|
293
|
+
if (match(TokenType.LeftSquareBracket)) {
|
|
294
|
+
property[attributeName] = parseArray([TokenType.QuotedString]).value;
|
|
331
295
|
return;
|
|
332
296
|
}
|
|
333
297
|
else {
|
|
334
|
-
const { value } = consume(
|
|
298
|
+
const { value } = consume(TokenType.QuotedString);
|
|
335
299
|
property[attributeName] = value;
|
|
336
300
|
return;
|
|
337
301
|
}
|
|
338
302
|
}
|
|
339
303
|
case 'maskedValue': {
|
|
340
|
-
const { value } = consume(
|
|
304
|
+
const { value } = consume(TokenType.Boolean);
|
|
341
305
|
property[attributeName] = value;
|
|
342
306
|
return;
|
|
343
307
|
}
|
|
344
308
|
case 'minLength':
|
|
345
309
|
case 'maxLength': {
|
|
346
|
-
const { value } = consume(
|
|
310
|
+
const { value } = consume(TokenType.Number);
|
|
347
311
|
property[attributeName] = value;
|
|
348
312
|
return;
|
|
349
313
|
}
|
|
350
314
|
case 'inputType': {
|
|
351
|
-
const { value } = consume(
|
|
315
|
+
const { value } = consume(TokenType.QuotedString, PROPERTY_INPUT_TYPES);
|
|
352
316
|
property[attributeName] = value;
|
|
353
317
|
return;
|
|
354
318
|
}
|
|
355
319
|
case 'element': {
|
|
356
|
-
const { value } = consume(
|
|
320
|
+
const { value } = consume(TokenType.QuotedString, PROPERTY_INPUT_ELEMENTS);
|
|
357
321
|
property[attributeName] = value;
|
|
358
322
|
return;
|
|
359
323
|
}
|
|
360
324
|
case 'placeholder': {
|
|
361
|
-
const { value } = consume(
|
|
325
|
+
const { value } = consume(TokenType.QuotedString);
|
|
362
326
|
property[attributeName] = value;
|
|
363
327
|
return;
|
|
364
328
|
}
|
|
@@ -372,12 +336,12 @@ const parse = (tokens) => {
|
|
|
372
336
|
case 'exclusiveMaximum':
|
|
373
337
|
case 'minimum':
|
|
374
338
|
case 'maximum': {
|
|
375
|
-
const { value } = consume(
|
|
339
|
+
const { value } = consume(TokenType.Number);
|
|
376
340
|
property[attributeName] = value;
|
|
377
341
|
return;
|
|
378
342
|
}
|
|
379
343
|
case 'placeholder': {
|
|
380
|
-
const { value } = consume(
|
|
344
|
+
const { value } = consume(TokenType.QuotedString);
|
|
381
345
|
property[attributeName] = value;
|
|
382
346
|
return;
|
|
383
347
|
}
|
|
@@ -387,12 +351,12 @@ const parse = (tokens) => {
|
|
|
387
351
|
case 'array': {
|
|
388
352
|
switch (attributeName) {
|
|
389
353
|
case 'uniqueItems': {
|
|
390
|
-
const { value } = consume(
|
|
354
|
+
const { value } = consume(TokenType.Boolean);
|
|
391
355
|
property[attributeName] = value;
|
|
392
356
|
return;
|
|
393
357
|
}
|
|
394
358
|
case 'element': {
|
|
395
|
-
const { value } = consume(
|
|
359
|
+
const { value } = consume(TokenType.QuotedString, PROPERTY_ARRAY_ELEMENTS);
|
|
396
360
|
property[attributeName] = value;
|
|
397
361
|
return;
|
|
398
362
|
}
|
|
@@ -400,7 +364,7 @@ const parse = (tokens) => {
|
|
|
400
364
|
}
|
|
401
365
|
}
|
|
402
366
|
}
|
|
403
|
-
throw new
|
|
367
|
+
throw new Diagnostic(`invalid attribute name "${attributeName}"`, location);
|
|
404
368
|
};
|
|
405
369
|
const parsePropertyType = (options = {
|
|
406
370
|
allowModifiers: false,
|
|
@@ -413,24 +377,24 @@ const parse = (tokens) => {
|
|
|
413
377
|
if (options.allowModifiers) {
|
|
414
378
|
const nextToken = next();
|
|
415
379
|
const currentTokenValue = current().value;
|
|
416
|
-
if (match(
|
|
417
|
-
modifierToken = consume(
|
|
380
|
+
if (match(TokenType.Identifier) && typeof currentTokenValue === 'string' && guards.isValidPropertyModifier(currentTokenValue) && (nextToken.type === TokenType.LeftBracket || nextToken.type === TokenType.LeftSquareBracket || nextToken.type === TokenType.Identifier)) {
|
|
381
|
+
modifierToken = consume(TokenType.Identifier);
|
|
418
382
|
}
|
|
419
383
|
}
|
|
420
|
-
if (match(
|
|
421
|
-
consume(
|
|
384
|
+
if (match(TokenType.LeftSquareBracket)) {
|
|
385
|
+
consume(TokenType.LeftSquareBracket);
|
|
422
386
|
const arrayProperty = {
|
|
423
387
|
type: 'array',
|
|
424
388
|
};
|
|
425
|
-
while (!match(
|
|
389
|
+
while (!match(TokenType.RightSquareBracket)) {
|
|
426
390
|
const attributeSymbol = Symbol();
|
|
427
391
|
arrayProperty[AST.LOCATION_SYMBOL] ??= {
|
|
428
392
|
type: typeSymbol,
|
|
429
393
|
attributes: {},
|
|
430
394
|
arrays: {},
|
|
431
395
|
};
|
|
432
|
-
if (match(
|
|
433
|
-
const { value: rangeSeparator } = consume(
|
|
396
|
+
if (match(TokenType.Range)) {
|
|
397
|
+
const { value: rangeSeparator } = consume(TokenType.Range);
|
|
434
398
|
let attributeName;
|
|
435
399
|
const minItems = rangeSeparator[0];
|
|
436
400
|
if (!isNaN(minItems)) {
|
|
@@ -446,34 +410,34 @@ const parse = (tokens) => {
|
|
|
446
410
|
}
|
|
447
411
|
continue;
|
|
448
412
|
}
|
|
449
|
-
const { value: attributeName, location } = consume(
|
|
450
|
-
if (match(
|
|
451
|
-
consume(
|
|
452
|
-
|
|
413
|
+
const { value: attributeName, location } = consume(TokenType.AttributeName);
|
|
414
|
+
if (match(TokenType.LeftParens)) {
|
|
415
|
+
consume(TokenType.LeftParens);
|
|
416
|
+
locationMap.set(attributeSymbol, next().location);
|
|
453
417
|
arrayProperty[AST.LOCATION_SYMBOL].attributes[attributeName] = attributeSymbol;
|
|
454
418
|
parsePropertyAttributeValue(attributeName, arrayProperty, location);
|
|
455
|
-
consume(
|
|
419
|
+
consume(TokenType.RightParens);
|
|
456
420
|
}
|
|
457
421
|
else {
|
|
458
422
|
parsePropertyAttributeValue(attributeName, arrayProperty, location);
|
|
459
423
|
}
|
|
460
424
|
}
|
|
461
|
-
consume(
|
|
425
|
+
consume(TokenType.RightSquareBracket);
|
|
462
426
|
const { property: items, nestedProperties } = parsePropertyType(options);
|
|
463
427
|
property = {
|
|
464
428
|
...arrayProperty,
|
|
465
429
|
items,
|
|
466
430
|
};
|
|
467
|
-
|
|
431
|
+
locationMap.set(typeSymbol, current().location);
|
|
468
432
|
return {
|
|
469
433
|
kind: 'property',
|
|
470
434
|
property,
|
|
471
435
|
nestedProperties,
|
|
472
436
|
};
|
|
473
437
|
}
|
|
474
|
-
|
|
475
|
-
if (match(
|
|
476
|
-
consume(
|
|
438
|
+
locationMap.set(typeSymbol, current().location);
|
|
439
|
+
if (match(TokenType.LeftBracket)) {
|
|
440
|
+
consume(TokenType.LeftBracket);
|
|
477
441
|
property = {
|
|
478
442
|
type: 'object',
|
|
479
443
|
properties: {},
|
|
@@ -483,8 +447,8 @@ const parse = (tokens) => {
|
|
|
483
447
|
arrays: {},
|
|
484
448
|
},
|
|
485
449
|
};
|
|
486
|
-
while (!match(
|
|
487
|
-
const { value: keyword, location } = consume(
|
|
450
|
+
while (!match(TokenType.RightBracket)) {
|
|
451
|
+
const { value: keyword, location } = consume(TokenType.Keyword, lexer.COLLECTION_KEYWORDS);
|
|
488
452
|
switch (keyword) {
|
|
489
453
|
case 'writable':
|
|
490
454
|
case 'required': {
|
|
@@ -498,8 +462,8 @@ const parse = (tokens) => {
|
|
|
498
462
|
break;
|
|
499
463
|
}
|
|
500
464
|
case 'additionalProperties': {
|
|
501
|
-
if (match(
|
|
502
|
-
nestedAdditionalProperties = consume(
|
|
465
|
+
if (match(TokenType.Boolean)) {
|
|
466
|
+
nestedAdditionalProperties = consume(TokenType.Boolean).value;
|
|
503
467
|
}
|
|
504
468
|
else {
|
|
505
469
|
nestedAdditionalProperties = parsePropertyType();
|
|
@@ -507,13 +471,13 @@ const parse = (tokens) => {
|
|
|
507
471
|
break;
|
|
508
472
|
}
|
|
509
473
|
default:
|
|
510
|
-
throw new
|
|
474
|
+
throw new Diagnostic(`invalid keyword "${keyword}"`, location);
|
|
511
475
|
}
|
|
512
476
|
}
|
|
513
|
-
consume(
|
|
477
|
+
consume(TokenType.RightBracket);
|
|
514
478
|
}
|
|
515
479
|
else {
|
|
516
|
-
const { value: identifier } = consume(
|
|
480
|
+
const { value: identifier } = consume(TokenType.Identifier);
|
|
517
481
|
if (guards.isNativePropertyType(identifier)) {
|
|
518
482
|
switch (identifier) {
|
|
519
483
|
case 'enum': {
|
|
@@ -542,6 +506,13 @@ const parse = (tokens) => {
|
|
|
542
506
|
};
|
|
543
507
|
break;
|
|
544
508
|
}
|
|
509
|
+
case 'objectid': {
|
|
510
|
+
property = {
|
|
511
|
+
type: 'string',
|
|
512
|
+
format: 'objectid',
|
|
513
|
+
};
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
545
516
|
default:
|
|
546
517
|
property = {
|
|
547
518
|
type: AST.PropertyType[identifier],
|
|
@@ -559,12 +530,12 @@ const parse = (tokens) => {
|
|
|
559
530
|
};
|
|
560
531
|
}
|
|
561
532
|
}
|
|
562
|
-
while (match(
|
|
563
|
-
const { value: attributeName, location } = consume(
|
|
564
|
-
if (match(
|
|
565
|
-
consume(
|
|
533
|
+
while (match(TokenType.AttributeName)) {
|
|
534
|
+
const { value: attributeName, location } = consume(TokenType.AttributeName);
|
|
535
|
+
if (match(TokenType.LeftParens)) {
|
|
536
|
+
consume(TokenType.LeftParens);
|
|
566
537
|
const attributeSymbol = Symbol();
|
|
567
|
-
|
|
538
|
+
locationMap.set(attributeSymbol, next().location);
|
|
568
539
|
property[AST.LOCATION_SYMBOL] ??= {
|
|
569
540
|
type: typeSymbol,
|
|
570
541
|
attributes: {},
|
|
@@ -572,7 +543,7 @@ const parse = (tokens) => {
|
|
|
572
543
|
};
|
|
573
544
|
property[AST.LOCATION_SYMBOL].attributes[attributeName] = attributeSymbol;
|
|
574
545
|
parsePropertyAttributeValue(attributeName, property, location);
|
|
575
|
-
consume(
|
|
546
|
+
consume(TokenType.RightParens);
|
|
576
547
|
}
|
|
577
548
|
else {
|
|
578
549
|
parsePropertyAttributeValue(attributeName, property, location);
|
|
@@ -592,31 +563,31 @@ const parse = (tokens) => {
|
|
|
592
563
|
const parsePropertiesBlock = (options = {
|
|
593
564
|
allowModifiers: false,
|
|
594
565
|
}) => {
|
|
595
|
-
consume(
|
|
566
|
+
consume(TokenType.LeftBracket);
|
|
596
567
|
const properties = {};
|
|
597
|
-
while (!match(
|
|
568
|
+
while (!match(TokenType.RightBracket)) {
|
|
598
569
|
try {
|
|
599
|
-
const { value: propName } = consume(
|
|
570
|
+
const { value: propName } = consume(TokenType.Identifier);
|
|
600
571
|
properties[propName] = parsePropertyType(options);
|
|
601
|
-
if (match(
|
|
602
|
-
consume(
|
|
572
|
+
if (match(TokenType.Comma)) {
|
|
573
|
+
consume(TokenType.Comma);
|
|
603
574
|
}
|
|
604
575
|
}
|
|
605
576
|
catch (err) {
|
|
606
|
-
if (err instanceof
|
|
577
|
+
if (err instanceof Diagnostic) {
|
|
607
578
|
errors.push(err);
|
|
608
579
|
recoverLoop: for (;;) {
|
|
609
580
|
switch (current().type) {
|
|
610
|
-
case
|
|
611
|
-
case
|
|
581
|
+
case TokenType.RightBracket:
|
|
582
|
+
case TokenType.Identifier: {
|
|
612
583
|
break recoverLoop;
|
|
613
584
|
}
|
|
614
585
|
}
|
|
615
|
-
while (match(
|
|
586
|
+
while (match(TokenType.AttributeName)) {
|
|
616
587
|
advance();
|
|
617
|
-
if (match(
|
|
588
|
+
if (match(TokenType.LeftParens)) {
|
|
618
589
|
advance();
|
|
619
|
-
while (!match(
|
|
590
|
+
while (!match(TokenType.RightParens)) {
|
|
620
591
|
advance();
|
|
621
592
|
}
|
|
622
593
|
}
|
|
@@ -629,19 +600,19 @@ const parse = (tokens) => {
|
|
|
629
600
|
throw err;
|
|
630
601
|
}
|
|
631
602
|
}
|
|
632
|
-
consume(
|
|
603
|
+
consume(TokenType.RightBracket);
|
|
633
604
|
return properties;
|
|
634
605
|
};
|
|
635
606
|
const parseMultiplePropertyTypes = (options = {
|
|
636
607
|
allowModifiers: false,
|
|
637
608
|
}) => {
|
|
638
|
-
if (match(
|
|
639
|
-
consume(
|
|
609
|
+
if (match(TokenType.Pipe)) {
|
|
610
|
+
consume(TokenType.Pipe);
|
|
640
611
|
const properties = [];
|
|
641
612
|
while (index < tokens.length) {
|
|
642
613
|
properties.push(parsePropertyType(options));
|
|
643
|
-
if (match(
|
|
644
|
-
consume(
|
|
614
|
+
if (match(TokenType.Pipe)) {
|
|
615
|
+
consume(TokenType.Pipe);
|
|
645
616
|
}
|
|
646
617
|
else {
|
|
647
618
|
break;
|
|
@@ -654,15 +625,15 @@ const parse = (tokens) => {
|
|
|
654
625
|
const parseAccessCondition = (options = {
|
|
655
626
|
arrayBlock: false,
|
|
656
627
|
}) => {
|
|
657
|
-
if (match(
|
|
658
|
-
const { value } = consume(
|
|
628
|
+
if (match(TokenType.Boolean)) {
|
|
629
|
+
const { value } = consume(TokenType.Boolean);
|
|
659
630
|
return value;
|
|
660
631
|
}
|
|
661
|
-
else if (match(
|
|
632
|
+
else if (match(TokenType.QuotedString, [
|
|
662
633
|
'unauthenticated',
|
|
663
634
|
'unauthenticated-only',
|
|
664
635
|
])) {
|
|
665
|
-
const { value } = consume(
|
|
636
|
+
const { value } = consume(TokenType.QuotedString, [
|
|
666
637
|
'unauthenticated',
|
|
667
638
|
'unauthenticated-only',
|
|
668
639
|
]);
|
|
@@ -671,13 +642,13 @@ const parse = (tokens) => {
|
|
|
671
642
|
else {
|
|
672
643
|
const { value, symbols } = options.arrayBlock
|
|
673
644
|
? parseArrayBlock()
|
|
674
|
-
: parseArray([
|
|
645
|
+
: parseArray([TokenType.QuotedString]);
|
|
675
646
|
return checkForValidRoles(value, symbols);
|
|
676
647
|
}
|
|
677
648
|
};
|
|
678
649
|
const parseCollection = () => {
|
|
679
|
-
consume(
|
|
680
|
-
const { value: name } = consume(
|
|
650
|
+
consume(TokenType.Keyword, 'collection');
|
|
651
|
+
const { value: name } = consume(TokenType.Identifier);
|
|
681
652
|
const node = {
|
|
682
653
|
kind: 'collection',
|
|
683
654
|
name,
|
|
@@ -686,22 +657,22 @@ const parse = (tokens) => {
|
|
|
686
657
|
arrays: {},
|
|
687
658
|
},
|
|
688
659
|
};
|
|
689
|
-
if (match(
|
|
690
|
-
consume(
|
|
691
|
-
const { value: packageName } = match(
|
|
692
|
-
? consume(
|
|
693
|
-
: consume(
|
|
694
|
-
consume(
|
|
695
|
-
const { value: symbolName } = consume(
|
|
660
|
+
if (match(TokenType.Keyword, 'extends')) {
|
|
661
|
+
consume(TokenType.Keyword);
|
|
662
|
+
const { value: packageName } = match(TokenType.QuotedString)
|
|
663
|
+
? consume(TokenType.QuotedString)
|
|
664
|
+
: consume(TokenType.Identifier);
|
|
665
|
+
consume(TokenType.Dot);
|
|
666
|
+
const { value: symbolName } = consume(TokenType.Identifier);
|
|
696
667
|
node.extends = {
|
|
697
668
|
packageName,
|
|
698
669
|
importPath: packageName,
|
|
699
670
|
symbolName: symbolName[0].toLowerCase() + symbolName.slice(1),
|
|
700
671
|
};
|
|
701
672
|
}
|
|
702
|
-
consume(
|
|
703
|
-
while (!match(
|
|
704
|
-
const { value: keyword } = consume(
|
|
673
|
+
consume(TokenType.LeftBracket);
|
|
674
|
+
while (!match(TokenType.RightBracket)) {
|
|
675
|
+
const { value: keyword } = consume(TokenType.Keyword, lexer.COLLECTION_KEYWORDS);
|
|
705
676
|
try {
|
|
706
677
|
switch (keyword) {
|
|
707
678
|
case 'middlewares': {
|
|
@@ -709,11 +680,11 @@ const parse = (tokens) => {
|
|
|
709
680
|
break;
|
|
710
681
|
}
|
|
711
682
|
case 'owned': {
|
|
712
|
-
if (match(
|
|
713
|
-
node.owned = consume(
|
|
683
|
+
if (match(TokenType.Boolean)) {
|
|
684
|
+
node.owned = consume(TokenType.Boolean).value;
|
|
714
685
|
}
|
|
715
686
|
else {
|
|
716
|
-
node.owned = consume(
|
|
687
|
+
node.owned = consume(TokenType.QuotedString, [
|
|
717
688
|
'always',
|
|
718
689
|
'on-write',
|
|
719
690
|
]).value;
|
|
@@ -721,7 +692,7 @@ const parse = (tokens) => {
|
|
|
721
692
|
break;
|
|
722
693
|
}
|
|
723
694
|
case 'icon': {
|
|
724
|
-
const { value } = consume(
|
|
695
|
+
const { value } = consume(TokenType.QuotedString, ICON_NAMES);
|
|
725
696
|
node[keyword] = value;
|
|
726
697
|
break;
|
|
727
698
|
}
|
|
@@ -756,7 +727,7 @@ const parse = (tokens) => {
|
|
|
756
727
|
break;
|
|
757
728
|
}
|
|
758
729
|
case 'presets': {
|
|
759
|
-
const { value, symbols } = parseArrayBlock(
|
|
730
|
+
const { value, symbols } = parseArrayBlock(DESCRIPTION_PRESETS);
|
|
760
731
|
node[keyword] = value;
|
|
761
732
|
node[AST.LOCATION_SYMBOL].arrays[keyword] = symbols;
|
|
762
733
|
break;
|
|
@@ -789,7 +760,7 @@ const parse = (tokens) => {
|
|
|
789
760
|
}
|
|
790
761
|
}
|
|
791
762
|
catch (err) {
|
|
792
|
-
if (err instanceof
|
|
763
|
+
if (err instanceof Diagnostic) {
|
|
793
764
|
errors.push(err);
|
|
794
765
|
recover(lexer.COLLECTION_KEYWORDS);
|
|
795
766
|
continue;
|
|
@@ -797,19 +768,19 @@ const parse = (tokens) => {
|
|
|
797
768
|
throw err;
|
|
798
769
|
}
|
|
799
770
|
}
|
|
800
|
-
consume(
|
|
771
|
+
consume(TokenType.RightBracket);
|
|
801
772
|
return node;
|
|
802
773
|
};
|
|
803
774
|
const parseContract = () => {
|
|
804
|
-
consume(
|
|
805
|
-
const { value: name } = consume(
|
|
806
|
-
consume(
|
|
775
|
+
consume(TokenType.Keyword, 'contract');
|
|
776
|
+
const { value: name } = consume(TokenType.Identifier);
|
|
777
|
+
consume(TokenType.LeftBracket);
|
|
807
778
|
const node = {
|
|
808
779
|
kind: 'contract',
|
|
809
780
|
name,
|
|
810
781
|
};
|
|
811
|
-
while (!match(
|
|
812
|
-
const { value: keyword } = consume(
|
|
782
|
+
while (!match(TokenType.RightBracket)) {
|
|
783
|
+
const { value: keyword } = consume(TokenType.Keyword, lexer.CONTRACT_KEYWORDS);
|
|
813
784
|
switch (keyword) {
|
|
814
785
|
case 'roles': {
|
|
815
786
|
node.roles = parseAccessCondition({
|
|
@@ -837,39 +808,39 @@ const parse = (tokens) => {
|
|
|
837
808
|
}
|
|
838
809
|
}
|
|
839
810
|
}
|
|
840
|
-
consume(
|
|
811
|
+
consume(TokenType.RightBracket);
|
|
841
812
|
return node;
|
|
842
813
|
};
|
|
843
814
|
const parseFunctionsBlock = () => {
|
|
844
|
-
consume(
|
|
815
|
+
consume(TokenType.LeftBracket);
|
|
845
816
|
const functions = [];
|
|
846
817
|
const functionSets = [];
|
|
847
|
-
while (!match(
|
|
818
|
+
while (!match(TokenType.RightBracket)) {
|
|
848
819
|
try {
|
|
849
|
-
if (match(
|
|
850
|
-
const { value: macroName } = consume(
|
|
820
|
+
if (match(TokenType.MacroName)) {
|
|
821
|
+
const { value: macroName } = consume(TokenType.MacroName, ['include']);
|
|
851
822
|
switch (macroName) {
|
|
852
823
|
case 'include': {
|
|
853
|
-
const { value: functionSetName, location } = consume(
|
|
824
|
+
const { value: functionSetName, location } = consume(TokenType.Identifier);
|
|
854
825
|
const functionSetSymbol = Symbol();
|
|
855
|
-
|
|
826
|
+
locationMap.set(functionSetSymbol, location);
|
|
856
827
|
functionSets.push([
|
|
857
828
|
functionSetName,
|
|
858
829
|
functionSetSymbol,
|
|
859
830
|
]);
|
|
860
|
-
consume(
|
|
831
|
+
consume(TokenType.RightParens);
|
|
861
832
|
break;
|
|
862
833
|
}
|
|
863
834
|
}
|
|
864
835
|
continue;
|
|
865
836
|
}
|
|
866
837
|
let functionNode;
|
|
867
|
-
if (current().type ===
|
|
868
|
-
const { value: packageName } = match(
|
|
869
|
-
? consume(
|
|
870
|
-
: consume(
|
|
871
|
-
consume(
|
|
872
|
-
const { value: symbolName } = consume(
|
|
838
|
+
if (current().type === TokenType.Identifier && next().type === TokenType.Dot) {
|
|
839
|
+
const { value: packageName } = match(TokenType.QuotedString)
|
|
840
|
+
? consume(TokenType.QuotedString)
|
|
841
|
+
: consume(TokenType.Identifier);
|
|
842
|
+
consume(TokenType.Dot);
|
|
843
|
+
const { value: symbolName } = consume(TokenType.Identifier);
|
|
873
844
|
functionNode = {
|
|
874
845
|
kind: 'function',
|
|
875
846
|
name: symbolName,
|
|
@@ -881,10 +852,10 @@ const parse = (tokens) => {
|
|
|
881
852
|
};
|
|
882
853
|
}
|
|
883
854
|
else {
|
|
884
|
-
const { value: functionName } = consume(
|
|
855
|
+
const { value: functionName } = consume(TokenType.Identifier);
|
|
885
856
|
let exportSymbol;
|
|
886
|
-
if (
|
|
887
|
-
const packageName =
|
|
857
|
+
if (memoTable.defaultExportSymbols && functionName in memoTable.defaultExportSymbols) {
|
|
858
|
+
const packageName = memoTable.defaultExportSymbols[functionName];
|
|
888
859
|
exportSymbol = {
|
|
889
860
|
packageName,
|
|
890
861
|
importPath: packageName,
|
|
@@ -898,12 +869,12 @@ const parse = (tokens) => {
|
|
|
898
869
|
};
|
|
899
870
|
}
|
|
900
871
|
functions.push(functionNode);
|
|
901
|
-
while (match(
|
|
902
|
-
consume(
|
|
903
|
-
if (match(
|
|
904
|
-
consume(
|
|
872
|
+
while (match(TokenType.AttributeName, 'expose')) {
|
|
873
|
+
consume(TokenType.AttributeName, 'expose');
|
|
874
|
+
if (match(TokenType.LeftParens)) {
|
|
875
|
+
consume(TokenType.LeftParens);
|
|
905
876
|
functionNode.accessCondition = parseAccessCondition();
|
|
906
|
-
consume(
|
|
877
|
+
consume(TokenType.RightParens);
|
|
907
878
|
}
|
|
908
879
|
else {
|
|
909
880
|
functionNode.accessCondition = true;
|
|
@@ -911,10 +882,10 @@ const parse = (tokens) => {
|
|
|
911
882
|
}
|
|
912
883
|
}
|
|
913
884
|
catch (err) {
|
|
914
|
-
if (err instanceof
|
|
885
|
+
if (err instanceof Diagnostic) {
|
|
915
886
|
let token;
|
|
916
887
|
while (token = tokens[++index]) {
|
|
917
|
-
if (token.type ===
|
|
888
|
+
if (token.type === TokenType.Identifier || token.type === TokenType.RightBracket) {
|
|
918
889
|
break;
|
|
919
890
|
}
|
|
920
891
|
}
|
|
@@ -924,15 +895,15 @@ const parse = (tokens) => {
|
|
|
924
895
|
throw err;
|
|
925
896
|
}
|
|
926
897
|
}
|
|
927
|
-
consume(
|
|
898
|
+
consume(TokenType.RightBracket);
|
|
928
899
|
return {
|
|
929
900
|
functions,
|
|
930
901
|
functionSets,
|
|
931
902
|
};
|
|
932
903
|
};
|
|
933
904
|
const parseFunctionSet = () => {
|
|
934
|
-
consume(
|
|
935
|
-
const { value: name } = consume(
|
|
905
|
+
consume(TokenType.Keyword, 'functionset');
|
|
906
|
+
const { value: name } = consume(TokenType.Identifier);
|
|
936
907
|
const { functions, functionSets } = parseFunctionsBlock();
|
|
937
908
|
const node = {
|
|
938
909
|
kind: 'functionset',
|
|
@@ -944,10 +915,10 @@ const parse = (tokens) => {
|
|
|
944
915
|
};
|
|
945
916
|
const parseActionsBlock = () => {
|
|
946
917
|
const actions = {};
|
|
947
|
-
consume(
|
|
948
|
-
while (!match(
|
|
949
|
-
const { value: actionName } = consume(
|
|
950
|
-
consume(
|
|
918
|
+
consume(TokenType.LeftBracket);
|
|
919
|
+
while (!match(TokenType.RightBracket)) {
|
|
920
|
+
const { value: actionName } = consume(TokenType.Identifier);
|
|
921
|
+
consume(TokenType.LeftBracket);
|
|
951
922
|
const baseSlots = {};
|
|
952
923
|
const slots = {
|
|
953
924
|
route: {
|
|
@@ -959,28 +930,28 @@ const parse = (tokens) => {
|
|
|
959
930
|
event: {},
|
|
960
931
|
};
|
|
961
932
|
let actionType;
|
|
962
|
-
while (!match(
|
|
963
|
-
const { value: keyword } = consume(
|
|
933
|
+
while (!match(TokenType.RightBracket)) {
|
|
934
|
+
const { value: keyword } = consume(TokenType.Keyword, lexer.COLLECTION_ACTIONS_KEYWORDS);
|
|
964
935
|
switch (keyword) {
|
|
965
936
|
case 'icon': {
|
|
966
|
-
const { value } = consume(
|
|
937
|
+
const { value } = consume(TokenType.QuotedString, ICON_NAMES);
|
|
967
938
|
baseSlots[keyword] = value;
|
|
968
939
|
break;
|
|
969
940
|
}
|
|
970
941
|
case 'label': {
|
|
971
|
-
const { value } = consume(
|
|
942
|
+
const { value } = consume(TokenType.QuotedString);
|
|
972
943
|
baseSlots[keyword] = value;
|
|
973
944
|
break;
|
|
974
945
|
}
|
|
975
946
|
case 'ask':
|
|
976
947
|
case 'button':
|
|
977
948
|
case 'translate': {
|
|
978
|
-
const { value } = consume(
|
|
949
|
+
const { value } = consume(TokenType.Boolean);
|
|
979
950
|
baseSlots[keyword] = value;
|
|
980
951
|
break;
|
|
981
952
|
}
|
|
982
953
|
case 'roles': {
|
|
983
|
-
const { value, symbols } = parseArray([
|
|
954
|
+
const { value, symbols } = parseArray([TokenType.Identifier]);
|
|
984
955
|
const roles = checkForValidRoles(value, symbols);
|
|
985
956
|
baseSlots[keyword] = roles;
|
|
986
957
|
break;
|
|
@@ -991,7 +962,7 @@ const parse = (tokens) => {
|
|
|
991
962
|
break;
|
|
992
963
|
}
|
|
993
964
|
case 'route': {
|
|
994
|
-
const { value } = consume(
|
|
965
|
+
const { value } = consume(TokenType.QuotedString);
|
|
995
966
|
actionType = 'route';
|
|
996
967
|
slots.route.route.name = value;
|
|
997
968
|
break;
|
|
@@ -999,28 +970,28 @@ const parse = (tokens) => {
|
|
|
999
970
|
case 'setItem':
|
|
1000
971
|
case 'fetchItem':
|
|
1001
972
|
case 'clearItem': {
|
|
1002
|
-
const { value } = consume(
|
|
973
|
+
const { value } = consume(TokenType.Boolean);
|
|
1003
974
|
slots.route.route[keyword] = value;
|
|
1004
975
|
break;
|
|
1005
976
|
}
|
|
1006
977
|
case 'function': {
|
|
1007
|
-
const { value } = consume(
|
|
978
|
+
const { value } = consume(TokenType.QuotedString);
|
|
1008
979
|
actionType = 'function';
|
|
1009
980
|
slots.function.function = value;
|
|
1010
981
|
break;
|
|
1011
982
|
}
|
|
1012
983
|
case 'effect': {
|
|
1013
|
-
const { value } = consume(
|
|
984
|
+
const { value } = consume(TokenType.QuotedString);
|
|
1014
985
|
slots.function.effect = value;
|
|
1015
986
|
break;
|
|
1016
987
|
}
|
|
1017
988
|
case 'selection': {
|
|
1018
|
-
const { value } = consume(
|
|
989
|
+
const { value } = consume(TokenType.Boolean);
|
|
1019
990
|
slots.function.selection = value;
|
|
1020
991
|
break;
|
|
1021
992
|
}
|
|
1022
993
|
case 'event': {
|
|
1023
|
-
const { value } = consume(
|
|
994
|
+
const { value } = consume(TokenType.QuotedString);
|
|
1024
995
|
actionType = 'event';
|
|
1025
996
|
slots.event.event = value;
|
|
1026
997
|
break;
|
|
@@ -1036,17 +1007,17 @@ const parse = (tokens) => {
|
|
|
1036
1007
|
else {
|
|
1037
1008
|
actions[actionName] = baseSlots;
|
|
1038
1009
|
}
|
|
1039
|
-
consume(
|
|
1010
|
+
consume(TokenType.RightBracket);
|
|
1040
1011
|
}
|
|
1041
|
-
consume(
|
|
1012
|
+
consume(TokenType.RightBracket);
|
|
1042
1013
|
return actions;
|
|
1043
1014
|
};
|
|
1044
1015
|
const parseSearchBlock = () => {
|
|
1045
1016
|
const searchSlots = {};
|
|
1046
|
-
const { location } = consume(
|
|
1017
|
+
const { location } = consume(TokenType.LeftBracket);
|
|
1047
1018
|
let indexesSymbols;
|
|
1048
|
-
while (!match(
|
|
1049
|
-
const { value: keyword } = consume(
|
|
1019
|
+
while (!match(TokenType.RightBracket)) {
|
|
1020
|
+
const { value: keyword } = consume(TokenType.Keyword, lexer.COLLECTION_SEARCH_KEYWORDS);
|
|
1050
1021
|
switch (keyword) {
|
|
1051
1022
|
case 'indexes': {
|
|
1052
1023
|
const { value, symbols } = parseArrayBlock();
|
|
@@ -1055,12 +1026,12 @@ const parse = (tokens) => {
|
|
|
1055
1026
|
break;
|
|
1056
1027
|
}
|
|
1057
1028
|
case 'placeholder': {
|
|
1058
|
-
const { value } = consume(
|
|
1029
|
+
const { value } = consume(TokenType.QuotedString);
|
|
1059
1030
|
searchSlots[keyword] = value;
|
|
1060
1031
|
break;
|
|
1061
1032
|
}
|
|
1062
1033
|
case 'exactMatches': {
|
|
1063
|
-
const { value } = consume(
|
|
1034
|
+
const { value } = consume(TokenType.Boolean);
|
|
1064
1035
|
searchSlots[keyword] = value;
|
|
1065
1036
|
break;
|
|
1066
1037
|
}
|
|
@@ -1068,9 +1039,9 @@ const parse = (tokens) => {
|
|
|
1068
1039
|
}
|
|
1069
1040
|
const { indexes } = searchSlots;
|
|
1070
1041
|
if (!indexes) {
|
|
1071
|
-
throw new
|
|
1042
|
+
throw new Diagnostic('"indexes" option is required', location);
|
|
1072
1043
|
}
|
|
1073
|
-
consume(
|
|
1044
|
+
consume(TokenType.RightBracket);
|
|
1074
1045
|
const options = {
|
|
1075
1046
|
...searchSlots,
|
|
1076
1047
|
indexes,
|
|
@@ -1084,62 +1055,62 @@ const parse = (tokens) => {
|
|
|
1084
1055
|
let name;
|
|
1085
1056
|
const options = {};
|
|
1086
1057
|
const optionsSymbols = {};
|
|
1087
|
-
const { location } = consume(
|
|
1088
|
-
while (!match(
|
|
1089
|
-
const { value: keyword } = consume(
|
|
1058
|
+
const { location } = consume(TokenType.LeftBracket);
|
|
1059
|
+
while (!match(TokenType.RightBracket)) {
|
|
1060
|
+
const { value: keyword } = consume(TokenType.Keyword, lexer.COLLECTION_LAYOUT_KEYWORDS);
|
|
1090
1061
|
switch (keyword) {
|
|
1091
1062
|
case 'name': {
|
|
1092
|
-
name = consume(
|
|
1063
|
+
name = consume(TokenType.QuotedString, LAYOUT_NAMES).value;
|
|
1093
1064
|
break;
|
|
1094
1065
|
}
|
|
1095
1066
|
case 'options':
|
|
1096
1067
|
{
|
|
1097
|
-
consume(
|
|
1098
|
-
while (!match(
|
|
1099
|
-
const { value: optionsKeyword } = consume(
|
|
1068
|
+
consume(TokenType.LeftBracket);
|
|
1069
|
+
while (!match(TokenType.RightBracket)) {
|
|
1070
|
+
const { value: optionsKeyword } = consume(TokenType.Keyword, lexer.COLLECTION_LAYOUT_OPTIONS_KEYWORDS);
|
|
1100
1071
|
switch (optionsKeyword) {
|
|
1101
1072
|
case 'active':
|
|
1102
1073
|
case 'title':
|
|
1103
1074
|
case 'picture':
|
|
1104
1075
|
case 'badge': {
|
|
1105
|
-
const { value, location } = consume(
|
|
1076
|
+
const { value, location } = consume(TokenType.Identifier);
|
|
1106
1077
|
const symbol = Symbol();
|
|
1107
1078
|
options[optionsKeyword] = value;
|
|
1108
1079
|
optionsSymbols[optionsKeyword] = symbol;
|
|
1109
|
-
|
|
1080
|
+
locationMap.set(symbol, location);
|
|
1110
1081
|
break;
|
|
1111
1082
|
}
|
|
1112
1083
|
case 'information': {
|
|
1113
|
-
if (match(
|
|
1084
|
+
if (match(TokenType.LeftBracket)) {
|
|
1114
1085
|
const { value, symbols } = parseArrayBlock();
|
|
1115
1086
|
options[optionsKeyword] = value;
|
|
1116
1087
|
optionsSymbols[optionsKeyword] = symbols;
|
|
1117
1088
|
}
|
|
1118
1089
|
else {
|
|
1119
|
-
const { value, location } = consume(
|
|
1090
|
+
const { value, location } = consume(TokenType.Identifier);
|
|
1120
1091
|
const symbol = Symbol();
|
|
1121
1092
|
options[optionsKeyword] = value;
|
|
1122
1093
|
optionsSymbols[optionsKeyword] = symbol;
|
|
1123
|
-
|
|
1094
|
+
locationMap.set(symbol, location);
|
|
1124
1095
|
}
|
|
1125
1096
|
break;
|
|
1126
1097
|
}
|
|
1127
1098
|
case 'translateBadge': {
|
|
1128
|
-
const { value } = consume(
|
|
1099
|
+
const { value } = consume(TokenType.Boolean);
|
|
1129
1100
|
options[optionsKeyword] = value;
|
|
1130
1101
|
break;
|
|
1131
1102
|
}
|
|
1132
1103
|
}
|
|
1133
1104
|
}
|
|
1134
1105
|
}
|
|
1135
|
-
consume(
|
|
1106
|
+
consume(TokenType.RightBracket);
|
|
1136
1107
|
break;
|
|
1137
1108
|
}
|
|
1138
1109
|
}
|
|
1139
1110
|
if (!name) {
|
|
1140
|
-
throw new
|
|
1111
|
+
throw new Diagnostic('layout must have a "name" property', location);
|
|
1141
1112
|
}
|
|
1142
|
-
consume(
|
|
1113
|
+
consume(TokenType.RightBracket);
|
|
1143
1114
|
return {
|
|
1144
1115
|
kind: 'layout',
|
|
1145
1116
|
name,
|
|
@@ -1158,24 +1129,24 @@ const parse = (tokens) => {
|
|
|
1158
1129
|
fields: {},
|
|
1159
1130
|
},
|
|
1160
1131
|
};
|
|
1161
|
-
consume(
|
|
1162
|
-
while (!match(
|
|
1163
|
-
const { value: keyword, location: keywordLocation } = consume(
|
|
1132
|
+
consume(TokenType.LeftBracket);
|
|
1133
|
+
while (!match(TokenType.RightBracket)) {
|
|
1134
|
+
const { value: keyword, location: keywordLocation } = consume(TokenType.Keyword, lexer.COLLECTION_FORM_LAYOUT_KEYWORDS);
|
|
1164
1135
|
switch (keyword) {
|
|
1165
1136
|
case 'fields': {
|
|
1166
|
-
consume(
|
|
1167
|
-
while (!match(
|
|
1168
|
-
const { value: identifier, location: identifierLocation } = consume(
|
|
1137
|
+
consume(TokenType.LeftBracket);
|
|
1138
|
+
while (!match(TokenType.RightBracket)) {
|
|
1139
|
+
const { value: identifier, location: identifierLocation } = consume(TokenType.Identifier);
|
|
1169
1140
|
const identifierSymbol = Symbol();
|
|
1170
|
-
|
|
1141
|
+
locationMap.set(identifierSymbol, identifierLocation);
|
|
1171
1142
|
fields[identifier] ??= {};
|
|
1172
1143
|
node[AST.LOCATION_SYMBOL].fields[identifier] = {
|
|
1173
1144
|
name: identifierSymbol,
|
|
1174
1145
|
field: {},
|
|
1175
1146
|
};
|
|
1176
|
-
consume(
|
|
1177
|
-
while (!match(
|
|
1178
|
-
const { value: keyword, location: keywordLocation } = consume(
|
|
1147
|
+
consume(TokenType.LeftBracket);
|
|
1148
|
+
while (!match(TokenType.RightBracket)) {
|
|
1149
|
+
const { value: keyword, location: keywordLocation } = consume(TokenType.Keyword, lexer.COLLECTION_FORM_LAYOUT_KEYWORDS);
|
|
1179
1150
|
switch (keyword) {
|
|
1180
1151
|
case 'if': {
|
|
1181
1152
|
const ifTerms = [];
|
|
@@ -1185,47 +1156,47 @@ const parse = (tokens) => {
|
|
|
1185
1156
|
}
|
|
1186
1157
|
case 'span':
|
|
1187
1158
|
case 'verticalSpacing': {
|
|
1188
|
-
fields[identifier].span = consume(
|
|
1159
|
+
fields[identifier].span = consume(TokenType.Number).value;
|
|
1189
1160
|
break;
|
|
1190
1161
|
}
|
|
1191
1162
|
case 'separator': {
|
|
1192
|
-
fields[identifier].separator = match(
|
|
1193
|
-
? consume(
|
|
1194
|
-
: consume(
|
|
1163
|
+
fields[identifier].separator = match(TokenType.Boolean)
|
|
1164
|
+
? consume(TokenType.Boolean).value
|
|
1165
|
+
: consume(TokenType.QuotedString, [
|
|
1195
1166
|
'top',
|
|
1196
1167
|
'bottom',
|
|
1197
1168
|
]).value;
|
|
1198
1169
|
break;
|
|
1199
1170
|
}
|
|
1200
1171
|
default: {
|
|
1201
|
-
throw new
|
|
1172
|
+
throw new Diagnostic(`invalid keyword "${keyword}"`, keywordLocation);
|
|
1202
1173
|
}
|
|
1203
1174
|
}
|
|
1204
1175
|
}
|
|
1205
|
-
consume(
|
|
1176
|
+
consume(TokenType.RightBracket);
|
|
1206
1177
|
}
|
|
1207
|
-
consume(
|
|
1178
|
+
consume(TokenType.RightBracket);
|
|
1208
1179
|
break;
|
|
1209
1180
|
}
|
|
1210
1181
|
default: {
|
|
1211
|
-
throw new
|
|
1182
|
+
throw new Diagnostic(`invalid keyword "${keyword}"`, keywordLocation);
|
|
1212
1183
|
}
|
|
1213
1184
|
}
|
|
1214
1185
|
}
|
|
1215
|
-
consume(
|
|
1186
|
+
consume(TokenType.RightBracket);
|
|
1216
1187
|
return node;
|
|
1217
1188
|
};
|
|
1218
1189
|
const parseCondition = (symbols = []) => {
|
|
1219
|
-
if (match(
|
|
1220
|
-
consume(
|
|
1190
|
+
if (match(TokenType.LeftParens)) {
|
|
1191
|
+
consume(TokenType.LeftParens);
|
|
1221
1192
|
let operatorType, newOp = operatorType;
|
|
1222
1193
|
const conditions = [];
|
|
1223
|
-
while (!match(
|
|
1194
|
+
while (!match(TokenType.RightParens)) {
|
|
1224
1195
|
conditions.push(parseCondition(symbols));
|
|
1225
|
-
if (match(
|
|
1196
|
+
if (match(TokenType.RightParens)) {
|
|
1226
1197
|
break;
|
|
1227
1198
|
}
|
|
1228
|
-
const { value: operatorSymbol, location } = consume(
|
|
1199
|
+
const { value: operatorSymbol, location } = consume(TokenType.Operator);
|
|
1229
1200
|
switch (operatorSymbol) {
|
|
1230
1201
|
case '&&':
|
|
1231
1202
|
newOp = 'and';
|
|
@@ -1234,15 +1205,15 @@ const parse = (tokens) => {
|
|
|
1234
1205
|
newOp = 'or';
|
|
1235
1206
|
break;
|
|
1236
1207
|
default: {
|
|
1237
|
-
throw new
|
|
1208
|
+
throw new Diagnostic(`unsupported operator: "${operatorSymbol}"`, location);
|
|
1238
1209
|
}
|
|
1239
1210
|
}
|
|
1240
1211
|
if (operatorType && operatorType !== newOp) {
|
|
1241
|
-
throw new
|
|
1212
|
+
throw new Diagnostic('having "and" or "or" in the same expression is not supported, please use parenthesis', location);
|
|
1242
1213
|
}
|
|
1243
1214
|
operatorType = newOp;
|
|
1244
1215
|
}
|
|
1245
|
-
consume(
|
|
1216
|
+
consume(TokenType.RightParens);
|
|
1246
1217
|
switch (operatorType) {
|
|
1247
1218
|
case 'and': {
|
|
1248
1219
|
return {
|
|
@@ -1259,34 +1230,34 @@ const parse = (tokens) => {
|
|
|
1259
1230
|
}
|
|
1260
1231
|
}
|
|
1261
1232
|
}
|
|
1262
|
-
if (match(
|
|
1263
|
-
consume(
|
|
1233
|
+
if (match(TokenType.Operator, '!')) {
|
|
1234
|
+
consume(TokenType.Operator);
|
|
1264
1235
|
return {
|
|
1265
1236
|
not: parseCondition(symbols),
|
|
1266
1237
|
};
|
|
1267
1238
|
}
|
|
1268
|
-
const { value: term1, location: term1Location } = consume(
|
|
1239
|
+
const { value: term1, location: term1Location } = consume(TokenType.Identifier);
|
|
1269
1240
|
const term1Symbol = Symbol();
|
|
1270
|
-
|
|
1241
|
+
locationMap.set(term1Symbol, term1Location);
|
|
1271
1242
|
symbols.push([
|
|
1272
1243
|
term1,
|
|
1273
1244
|
term1Symbol,
|
|
1274
1245
|
]);
|
|
1275
|
-
if (!match(
|
|
1246
|
+
if (!match(TokenType.Operator, lexer.FINAL_OPERATORS)) {
|
|
1276
1247
|
return {
|
|
1277
1248
|
operator: 'truthy',
|
|
1278
1249
|
term1,
|
|
1279
1250
|
};
|
|
1280
1251
|
}
|
|
1281
|
-
const { value: operatorSymbol, location } = consume(
|
|
1252
|
+
const { value: operatorSymbol, location } = consume(TokenType.Operator);
|
|
1282
1253
|
let term2;
|
|
1283
|
-
if (match(
|
|
1254
|
+
if (match(TokenType.LeftParens)) {
|
|
1284
1255
|
term2 = parseCondition(symbols);
|
|
1285
1256
|
}
|
|
1286
|
-
else if (match(
|
|
1257
|
+
else if (match(TokenType.LeftSquareBracket)) {
|
|
1287
1258
|
term2 = parseArray([
|
|
1288
|
-
|
|
1289
|
-
|
|
1259
|
+
TokenType.QuotedString,
|
|
1260
|
+
TokenType.Number,
|
|
1290
1261
|
]).value;
|
|
1291
1262
|
}
|
|
1292
1263
|
else {
|
|
@@ -1314,7 +1285,7 @@ const parse = (tokens) => {
|
|
|
1314
1285
|
operator = 'lt';
|
|
1315
1286
|
break;
|
|
1316
1287
|
default: {
|
|
1317
|
-
throw new
|
|
1288
|
+
throw new Diagnostic(`unsupported operator: "${operatorSymbol}"`, location);
|
|
1318
1289
|
}
|
|
1319
1290
|
}
|
|
1320
1291
|
return {
|
|
@@ -1332,7 +1303,7 @@ const parse = (tokens) => {
|
|
|
1332
1303
|
if (collection.name === 'User') {
|
|
1333
1304
|
const { properties } = collection;
|
|
1334
1305
|
if ('roles' in properties && 'items' in properties.roles.property && 'enum' in properties.roles.property.items) {
|
|
1335
|
-
|
|
1306
|
+
memoTable.roles = properties.roles.property.items.enum;
|
|
1336
1307
|
}
|
|
1337
1308
|
}
|
|
1338
1309
|
ast.collections.push(collection);
|
|
@@ -1347,11 +1318,11 @@ const parse = (tokens) => {
|
|
|
1347
1318
|
break;
|
|
1348
1319
|
}
|
|
1349
1320
|
default:
|
|
1350
|
-
throw new
|
|
1321
|
+
throw new Diagnostic(`invalid declaration type: "${declType}"`, location);
|
|
1351
1322
|
}
|
|
1352
1323
|
}
|
|
1353
1324
|
catch (err) {
|
|
1354
|
-
if (err instanceof
|
|
1325
|
+
if (err instanceof Diagnostic) {
|
|
1355
1326
|
errors.push(err);
|
|
1356
1327
|
recover(lexer.TOPLEVEL_KEYWORDS);
|
|
1357
1328
|
continue;
|
|
@@ -1364,4 +1335,3 @@ const parse = (tokens) => {
|
|
|
1364
1335
|
errors,
|
|
1365
1336
|
};
|
|
1366
1337
|
};
|
|
1367
|
-
exports.parse = parse;
|