@ldclabs/kip-lang 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -2
- package/dist/ast.d.ts +54 -2
- package/dist/ast.d.ts.map +1 -1
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +30 -0
- package/dist/diagnostics.js.map +1 -1
- package/dist/formatter.d.ts.map +1 -1
- package/dist/formatter.js +112 -10
- package/dist/formatter.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +271 -33
- package/dist/parser.js.map +1 -1
- package/dist/token.d.ts +12 -0
- package/dist/token.d.ts.map +1 -1
- package/dist/token.js +26 -2
- package/dist/token.js.map +1 -1
- package/package.json +1 -1
package/dist/parser.js
CHANGED
|
@@ -49,14 +49,20 @@ class Parser {
|
|
|
49
49
|
return this.parseFindStatement();
|
|
50
50
|
case TokenType.Upsert:
|
|
51
51
|
return this.parseUpsertStatement();
|
|
52
|
+
case TokenType.Update:
|
|
53
|
+
return this.parseUpdateStatement();
|
|
54
|
+
case TokenType.Merge:
|
|
55
|
+
return this.parseMergeStatement();
|
|
52
56
|
case TokenType.Delete:
|
|
53
57
|
return this.parseDeleteStatement();
|
|
54
58
|
case TokenType.Describe:
|
|
55
59
|
return this.parseDescribeStatement();
|
|
56
60
|
case TokenType.Search:
|
|
57
61
|
return this.parseSearchStatement();
|
|
62
|
+
case TokenType.Export:
|
|
63
|
+
return this.parseExportStatement();
|
|
58
64
|
default:
|
|
59
|
-
this.error(`Unexpected token '${tok.value}', expected a statement keyword (FIND, UPSERT, DELETE, DESCRIBE, SEARCH)`, tok);
|
|
65
|
+
this.error(`Unexpected token '${tok.value}', expected a statement keyword (FIND, UPSERT, UPDATE, MERGE, DELETE, DESCRIBE, SEARCH, EXPORT)`, tok);
|
|
60
66
|
this.advance();
|
|
61
67
|
return null;
|
|
62
68
|
}
|
|
@@ -151,6 +157,10 @@ class Parser {
|
|
|
151
157
|
const handle = this.expectVariable();
|
|
152
158
|
this.expect(TokenType.LBrace);
|
|
153
159
|
const matcher = this.parseConceptMatcher();
|
|
160
|
+
let expectVersion;
|
|
161
|
+
if (this.check(TokenType.Expect)) {
|
|
162
|
+
expectVersion = this.parseExpectVersion();
|
|
163
|
+
}
|
|
154
164
|
let setAttributes;
|
|
155
165
|
let setPropositions;
|
|
156
166
|
let metadata;
|
|
@@ -197,6 +207,7 @@ class Parser {
|
|
|
197
207
|
kind: 'ConceptBlock',
|
|
198
208
|
handle,
|
|
199
209
|
matcher,
|
|
210
|
+
expectVersion,
|
|
200
211
|
setAttributes,
|
|
201
212
|
setPropositions,
|
|
202
213
|
metadata,
|
|
@@ -214,6 +225,10 @@ class Parser {
|
|
|
214
225
|
}
|
|
215
226
|
this.expect(TokenType.LBrace);
|
|
216
227
|
const proposition = this.parsePropositionPatternBody(undefined);
|
|
228
|
+
let expectVersion;
|
|
229
|
+
if (this.check(TokenType.Expect)) {
|
|
230
|
+
expectVersion = this.parseExpectVersion();
|
|
231
|
+
}
|
|
217
232
|
let setAttributes;
|
|
218
233
|
let metadata;
|
|
219
234
|
this.skipComments();
|
|
@@ -250,6 +265,7 @@ class Parser {
|
|
|
250
265
|
subject: proposition.subject,
|
|
251
266
|
predicate: proposition.predicate,
|
|
252
267
|
object: proposition.object,
|
|
268
|
+
expectVersion,
|
|
253
269
|
setAttributes,
|
|
254
270
|
metadata,
|
|
255
271
|
range: { start, end: this.currentPos() },
|
|
@@ -257,6 +273,74 @@ class Parser {
|
|
|
257
273
|
};
|
|
258
274
|
}
|
|
259
275
|
// ────────────────────────────────────────────────────────────────────
|
|
276
|
+
// UPDATE
|
|
277
|
+
// ────────────────────────────────────────────────────────────────────
|
|
278
|
+
parseUpdateStatement() {
|
|
279
|
+
const start = this.currentPos();
|
|
280
|
+
const comments = this.collectLeadingComments();
|
|
281
|
+
this.expect(TokenType.Update);
|
|
282
|
+
const target = this.expectVariable();
|
|
283
|
+
let setAttributes;
|
|
284
|
+
let setMetadata;
|
|
285
|
+
this.skipComments();
|
|
286
|
+
while (this.check(TokenType.Set) && !this.isAtEnd()) {
|
|
287
|
+
const setStart = this.currentPos();
|
|
288
|
+
this.advance();
|
|
289
|
+
if (this.check(TokenType.Attributes)) {
|
|
290
|
+
this.advance();
|
|
291
|
+
setAttributes = this.parseSetAttributesBody(setStart);
|
|
292
|
+
}
|
|
293
|
+
else if (this.check(TokenType.Metadata)) {
|
|
294
|
+
this.advance();
|
|
295
|
+
setMetadata = this.parseSetMetadataBody(setStart);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
this.error(`Expected ATTRIBUTES or METADATA after SET in UPDATE statement`, this.current());
|
|
299
|
+
this.advance();
|
|
300
|
+
}
|
|
301
|
+
this.skipComments();
|
|
302
|
+
}
|
|
303
|
+
if (!setAttributes && !setMetadata) {
|
|
304
|
+
this.error(`Expected SET ATTRIBUTES or SET METADATA in UPDATE statement`, this.current());
|
|
305
|
+
}
|
|
306
|
+
const where = this.parseWhereClause();
|
|
307
|
+
let limit;
|
|
308
|
+
if (this.check(TokenType.Limit)) {
|
|
309
|
+
limit = this.parseLimitClause();
|
|
310
|
+
}
|
|
311
|
+
return {
|
|
312
|
+
kind: 'UpdateStatement',
|
|
313
|
+
target,
|
|
314
|
+
setAttributes,
|
|
315
|
+
setMetadata,
|
|
316
|
+
where,
|
|
317
|
+
limit,
|
|
318
|
+
range: { start, end: this.currentPos() },
|
|
319
|
+
leadingComments: comments.length > 0 ? comments : undefined
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
// ────────────────────────────────────────────────────────────────────
|
|
323
|
+
// MERGE
|
|
324
|
+
// ────────────────────────────────────────────────────────────────────
|
|
325
|
+
parseMergeStatement() {
|
|
326
|
+
const start = this.currentPos();
|
|
327
|
+
const comments = this.collectLeadingComments();
|
|
328
|
+
this.expect(TokenType.Merge);
|
|
329
|
+
this.expect(TokenType.Concept);
|
|
330
|
+
const source = this.expectVariable();
|
|
331
|
+
this.expect(TokenType.Into);
|
|
332
|
+
const target = this.expectVariable();
|
|
333
|
+
const where = this.parseWhereClause();
|
|
334
|
+
return {
|
|
335
|
+
kind: 'MergeStatement',
|
|
336
|
+
source,
|
|
337
|
+
target,
|
|
338
|
+
where,
|
|
339
|
+
range: { start, end: this.currentPos() },
|
|
340
|
+
leadingComments: comments.length > 0 ? comments : undefined
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
// ────────────────────────────────────────────────────────────────────
|
|
260
344
|
// DELETE
|
|
261
345
|
// ────────────────────────────────────────────────────────────────────
|
|
262
346
|
parseDeleteStatement() {
|
|
@@ -338,6 +422,7 @@ class Parser {
|
|
|
338
422
|
this.expect(TokenType.Describe);
|
|
339
423
|
let describeType;
|
|
340
424
|
let typeName;
|
|
425
|
+
let typeNameValue;
|
|
341
426
|
let limit;
|
|
342
427
|
let cursor;
|
|
343
428
|
if (this.check(TokenType.Primer)) {
|
|
@@ -357,7 +442,11 @@ class Parser {
|
|
|
357
442
|
else if (this.check(TokenType.Type)) {
|
|
358
443
|
describeType = 'CONCEPT_TYPE';
|
|
359
444
|
this.advance();
|
|
360
|
-
|
|
445
|
+
typeNameValue = this.parseStringOrParameterValue('DESCRIBE CONCEPT TYPE');
|
|
446
|
+
typeName =
|
|
447
|
+
typeNameValue.kind === 'StringLiteral'
|
|
448
|
+
? typeNameValue.parsed
|
|
449
|
+
: typeNameValue.name;
|
|
361
450
|
}
|
|
362
451
|
else {
|
|
363
452
|
this.error(`Expected TYPE or TYPES after DESCRIBE CONCEPT`, this.current());
|
|
@@ -373,7 +462,11 @@ class Parser {
|
|
|
373
462
|
else if (this.check(TokenType.Type)) {
|
|
374
463
|
describeType = 'PROPOSITION_TYPE';
|
|
375
464
|
this.advance();
|
|
376
|
-
|
|
465
|
+
typeNameValue = this.parseStringOrParameterValue('DESCRIBE PROPOSITION TYPE');
|
|
466
|
+
typeName =
|
|
467
|
+
typeNameValue.kind === 'StringLiteral'
|
|
468
|
+
? typeNameValue.parsed
|
|
469
|
+
: typeNameValue.name;
|
|
377
470
|
}
|
|
378
471
|
else {
|
|
379
472
|
this.error(`Expected TYPE or TYPES after DESCRIBE PROPOSITION`, this.current());
|
|
@@ -394,6 +487,7 @@ class Parser {
|
|
|
394
487
|
kind: 'DescribeStatement',
|
|
395
488
|
describeType,
|
|
396
489
|
typeName,
|
|
490
|
+
typeNameValue,
|
|
397
491
|
limit,
|
|
398
492
|
cursor,
|
|
399
493
|
range: { start, end: this.currentPos() },
|
|
@@ -424,18 +518,35 @@ class Parser {
|
|
|
424
518
|
const term = termValue.kind === 'StringLiteral' ? termValue.parsed : termValue.name;
|
|
425
519
|
let withType;
|
|
426
520
|
let withTypeValue;
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
withTypeValue = this.parseStringOrParameterValue('SEARCH WITH TYPE');
|
|
431
|
-
withType =
|
|
432
|
-
withTypeValue.kind === 'StringLiteral'
|
|
433
|
-
? withTypeValue.parsed
|
|
434
|
-
: withTypeValue.name;
|
|
435
|
-
}
|
|
521
|
+
let mode;
|
|
522
|
+
let modeValue;
|
|
523
|
+
let threshold;
|
|
436
524
|
let limit;
|
|
437
|
-
|
|
438
|
-
|
|
525
|
+
while (!this.isAtEnd()) {
|
|
526
|
+
if (this.check(TokenType.With)) {
|
|
527
|
+
this.advance();
|
|
528
|
+
this.expect(TokenType.Type);
|
|
529
|
+
withTypeValue = this.parseStringOrParameterValue('SEARCH WITH TYPE');
|
|
530
|
+
withType =
|
|
531
|
+
withTypeValue.kind === 'StringLiteral'
|
|
532
|
+
? withTypeValue.parsed
|
|
533
|
+
: withTypeValue.name;
|
|
534
|
+
}
|
|
535
|
+
else if (this.check(TokenType.Mode)) {
|
|
536
|
+
this.advance();
|
|
537
|
+
modeValue = this.parseStringOrParameterValue('SEARCH MODE');
|
|
538
|
+
mode =
|
|
539
|
+
modeValue.kind === 'StringLiteral' ? modeValue.parsed : modeValue.name;
|
|
540
|
+
}
|
|
541
|
+
else if (this.check(TokenType.Threshold)) {
|
|
542
|
+
threshold = this.parseThresholdClause();
|
|
543
|
+
}
|
|
544
|
+
else if (this.check(TokenType.Limit)) {
|
|
545
|
+
limit = this.parseLimitClause();
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
548
|
+
break;
|
|
549
|
+
}
|
|
439
550
|
}
|
|
440
551
|
return {
|
|
441
552
|
kind: 'SearchStatement',
|
|
@@ -444,6 +555,31 @@ class Parser {
|
|
|
444
555
|
termValue,
|
|
445
556
|
withType,
|
|
446
557
|
withTypeValue,
|
|
558
|
+
mode,
|
|
559
|
+
modeValue,
|
|
560
|
+
threshold,
|
|
561
|
+
limit,
|
|
562
|
+
range: { start, end: this.currentPos() },
|
|
563
|
+
leadingComments: comments.length > 0 ? comments : undefined
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
// ────────────────────────────────────────────────────────────────────
|
|
567
|
+
// EXPORT
|
|
568
|
+
// ────────────────────────────────────────────────────────────────────
|
|
569
|
+
parseExportStatement() {
|
|
570
|
+
const start = this.currentPos();
|
|
571
|
+
const comments = this.collectLeadingComments();
|
|
572
|
+
this.expect(TokenType.Export);
|
|
573
|
+
const target = this.expectVariable();
|
|
574
|
+
const where = this.parseWhereClause();
|
|
575
|
+
let limit;
|
|
576
|
+
if (this.check(TokenType.Limit)) {
|
|
577
|
+
limit = this.parseLimitClause();
|
|
578
|
+
}
|
|
579
|
+
return {
|
|
580
|
+
kind: 'ExportStatement',
|
|
581
|
+
target,
|
|
582
|
+
where,
|
|
447
583
|
limit,
|
|
448
584
|
range: { start, end: this.currentPos() },
|
|
449
585
|
leadingComments: comments.length > 0 ? comments : undefined
|
|
@@ -617,6 +753,31 @@ class Parser {
|
|
|
617
753
|
}
|
|
618
754
|
parsePredicateExpr() {
|
|
619
755
|
const start = this.currentPos();
|
|
756
|
+
if (this.check(TokenType.Variable)) {
|
|
757
|
+
const pred = this.parsePredicateVariable();
|
|
758
|
+
if (this.check(TokenType.LBrace)) {
|
|
759
|
+
this.error(`Predicate variables cannot use hop ranges; use a quoted predicate literal for path traversal`, this.current());
|
|
760
|
+
this.parseHopRange();
|
|
761
|
+
}
|
|
762
|
+
if (this.check(TokenType.Pipe)) {
|
|
763
|
+
this.error(`Predicate variables cannot be used in predicate alternations`, this.current());
|
|
764
|
+
while (this.match(TokenType.Pipe)) {
|
|
765
|
+
if (this.check(TokenType.String)) {
|
|
766
|
+
this.parsePredicateLiteral();
|
|
767
|
+
}
|
|
768
|
+
else if (this.check(TokenType.Variable)) {
|
|
769
|
+
this.parsePredicateVariable();
|
|
770
|
+
}
|
|
771
|
+
else {
|
|
772
|
+
break;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
return {
|
|
777
|
+
...pred,
|
|
778
|
+
range: { start, end: this.currentPos() }
|
|
779
|
+
};
|
|
780
|
+
}
|
|
620
781
|
const first = this.parsePredicateLiteral();
|
|
621
782
|
// Check for alternation: "pred1" | "pred2"
|
|
622
783
|
if (this.check(TokenType.Pipe)) {
|
|
@@ -632,6 +793,15 @@ class Parser {
|
|
|
632
793
|
}
|
|
633
794
|
return first;
|
|
634
795
|
}
|
|
796
|
+
parsePredicateVariable() {
|
|
797
|
+
const start = this.currentPos();
|
|
798
|
+
const name = this.expectVariable();
|
|
799
|
+
return {
|
|
800
|
+
kind: 'PredicateVariable',
|
|
801
|
+
name,
|
|
802
|
+
range: { start, end: this.currentPos() }
|
|
803
|
+
};
|
|
804
|
+
}
|
|
635
805
|
parsePredicateLiteral() {
|
|
636
806
|
const start = this.currentPos();
|
|
637
807
|
const value = this.expectStringValue();
|
|
@@ -736,6 +906,16 @@ class Parser {
|
|
|
736
906
|
range: { start, end: this.currentPos() }
|
|
737
907
|
};
|
|
738
908
|
}
|
|
909
|
+
parseSetMetadataBody(start) {
|
|
910
|
+
this.expect(TokenType.LBrace);
|
|
911
|
+
const entries = this.parseObjectEntries();
|
|
912
|
+
this.expect(TokenType.RBrace);
|
|
913
|
+
return {
|
|
914
|
+
kind: 'SetMetadata',
|
|
915
|
+
entries,
|
|
916
|
+
range: { start, end: this.currentPos() }
|
|
917
|
+
};
|
|
918
|
+
}
|
|
739
919
|
parseSetPropositionsBody(start) {
|
|
740
920
|
this.expect(TokenType.LBrace);
|
|
741
921
|
const items = [];
|
|
@@ -831,6 +1011,17 @@ class Parser {
|
|
|
831
1011
|
range: { start, end: this.currentPos() }
|
|
832
1012
|
};
|
|
833
1013
|
}
|
|
1014
|
+
parseExpectVersion() {
|
|
1015
|
+
const start = this.currentPos();
|
|
1016
|
+
this.expect(TokenType.Expect);
|
|
1017
|
+
this.expect(TokenType.Version);
|
|
1018
|
+
const value = this.parseNumberOrParameterValue('EXPECT VERSION');
|
|
1019
|
+
return {
|
|
1020
|
+
kind: 'ExpectVersion',
|
|
1021
|
+
value,
|
|
1022
|
+
range: { start, end: this.currentPos() }
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
834
1025
|
// ────────────────────────────────────────────────────────────────────
|
|
835
1026
|
// ORDER BY, LIMIT, CURSOR
|
|
836
1027
|
// ────────────────────────────────────────────────────────────────────
|
|
@@ -838,6 +1029,22 @@ class Parser {
|
|
|
838
1029
|
const start = this.currentPos();
|
|
839
1030
|
this.expect(TokenType.Order);
|
|
840
1031
|
this.expect(TokenType.By);
|
|
1032
|
+
const keys = [];
|
|
1033
|
+
keys.push(this.parseOrderByKey());
|
|
1034
|
+
while (this.match(TokenType.Comma)) {
|
|
1035
|
+
keys.push(this.parseOrderByKey());
|
|
1036
|
+
}
|
|
1037
|
+
const first = keys[0];
|
|
1038
|
+
return {
|
|
1039
|
+
kind: 'OrderByClause',
|
|
1040
|
+
keys,
|
|
1041
|
+
expression: first.expression,
|
|
1042
|
+
direction: first.direction,
|
|
1043
|
+
range: { start, end: this.currentPos() }
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
parseOrderByKey() {
|
|
1047
|
+
const start = this.currentPos();
|
|
841
1048
|
const expression = this.parseExpression();
|
|
842
1049
|
let direction = 'ASC';
|
|
843
1050
|
if (this.check(TokenType.Asc)) {
|
|
@@ -849,45 +1056,59 @@ class Parser {
|
|
|
849
1056
|
direction = 'DESC';
|
|
850
1057
|
}
|
|
851
1058
|
return {
|
|
852
|
-
kind: '
|
|
1059
|
+
kind: 'OrderByKey',
|
|
853
1060
|
expression,
|
|
854
1061
|
direction,
|
|
855
1062
|
range: { start, end: this.currentPos() }
|
|
856
1063
|
};
|
|
857
1064
|
}
|
|
858
|
-
|
|
1065
|
+
parseThresholdClause() {
|
|
859
1066
|
const start = this.currentPos();
|
|
860
|
-
this.expect(TokenType.
|
|
1067
|
+
this.expect(TokenType.Threshold);
|
|
1068
|
+
const value = this.parseNumberOrParameterValue('THRESHOLD');
|
|
1069
|
+
return {
|
|
1070
|
+
kind: 'ThresholdClause',
|
|
1071
|
+
value,
|
|
1072
|
+
range: { start, end: this.currentPos() }
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1075
|
+
parseNumberOrParameterValue(context) {
|
|
861
1076
|
const tok = this.current();
|
|
1077
|
+
const start = this.currentPos();
|
|
862
1078
|
let value;
|
|
863
1079
|
if (tok.type === TokenType.Number) {
|
|
864
1080
|
value = {
|
|
865
1081
|
kind: 'NumberLiteral',
|
|
866
1082
|
value: Number(tok.value),
|
|
867
1083
|
raw: tok.value,
|
|
868
|
-
range: { start
|
|
1084
|
+
range: { start, end: start }
|
|
869
1085
|
};
|
|
870
1086
|
this.advance();
|
|
871
1087
|
value.range.end = this.currentPos();
|
|
1088
|
+
return value;
|
|
872
1089
|
}
|
|
873
|
-
|
|
1090
|
+
if (tok.type === TokenType.Parameter) {
|
|
874
1091
|
value = {
|
|
875
1092
|
kind: 'ParameterRef',
|
|
876
1093
|
name: tok.value,
|
|
877
|
-
range: { start
|
|
1094
|
+
range: { start, end: start }
|
|
878
1095
|
};
|
|
879
1096
|
this.advance();
|
|
880
1097
|
value.range.end = this.currentPos();
|
|
1098
|
+
return value;
|
|
881
1099
|
}
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
1100
|
+
this.error(`Expected number or parameter after ${context}`, tok);
|
|
1101
|
+
return {
|
|
1102
|
+
kind: 'NumberLiteral',
|
|
1103
|
+
value: 0,
|
|
1104
|
+
raw: '0',
|
|
1105
|
+
range: { start, end: start }
|
|
1106
|
+
};
|
|
1107
|
+
}
|
|
1108
|
+
parseLimitClause() {
|
|
1109
|
+
const start = this.currentPos();
|
|
1110
|
+
this.expect(TokenType.Limit);
|
|
1111
|
+
const value = this.parseNumberOrParameterValue('LIMIT');
|
|
891
1112
|
return {
|
|
892
1113
|
kind: 'LimitClause',
|
|
893
1114
|
value,
|
|
@@ -1215,9 +1436,14 @@ class Parser {
|
|
|
1215
1436
|
value,
|
|
1216
1437
|
range: { start: entryStart, end: this.currentPos() }
|
|
1217
1438
|
});
|
|
1218
|
-
// Optional comma
|
|
1219
|
-
this.match(TokenType.Comma);
|
|
1220
1439
|
this.skipComments();
|
|
1440
|
+
if (this.check(TokenType.RBrace))
|
|
1441
|
+
break;
|
|
1442
|
+
if (this.match(TokenType.Comma)) {
|
|
1443
|
+
this.skipComments();
|
|
1444
|
+
continue;
|
|
1445
|
+
}
|
|
1446
|
+
this.error(`Expected ',' or '}' after object entry`, this.current());
|
|
1221
1447
|
}
|
|
1222
1448
|
return entries;
|
|
1223
1449
|
}
|
|
@@ -1351,7 +1577,11 @@ class Parser {
|
|
|
1351
1577
|
type === TokenType.Regex ||
|
|
1352
1578
|
type === TokenType.In ||
|
|
1353
1579
|
type === TokenType.IsNull ||
|
|
1354
|
-
type === TokenType.IsNotNull
|
|
1580
|
+
type === TokenType.IsNotNull ||
|
|
1581
|
+
type === TokenType.Add ||
|
|
1582
|
+
type === TokenType.Mul ||
|
|
1583
|
+
type === TokenType.Clamp ||
|
|
1584
|
+
type === TokenType.Coalesce);
|
|
1355
1585
|
}
|
|
1356
1586
|
/** Keywords that can also serve as property names in dot notation or object keys */
|
|
1357
1587
|
isNonAmbiguousKeyword(type) {
|
|
@@ -1370,7 +1600,12 @@ class Parser {
|
|
|
1370
1600
|
type === TokenType.By ||
|
|
1371
1601
|
type === TokenType.Order ||
|
|
1372
1602
|
type === TokenType.Set ||
|
|
1373
|
-
type === TokenType.With
|
|
1603
|
+
type === TokenType.With ||
|
|
1604
|
+
type === TokenType.Into ||
|
|
1605
|
+
type === TokenType.Expect ||
|
|
1606
|
+
type === TokenType.Version ||
|
|
1607
|
+
type === TokenType.Mode ||
|
|
1608
|
+
type === TokenType.Threshold);
|
|
1374
1609
|
}
|
|
1375
1610
|
unescapeString(raw) {
|
|
1376
1611
|
if (raw.startsWith('"') && raw.endsWith('"')) {
|
|
@@ -1415,9 +1650,12 @@ class Parser {
|
|
|
1415
1650
|
const stmtStarters = new Set([
|
|
1416
1651
|
TokenType.Find,
|
|
1417
1652
|
TokenType.Upsert,
|
|
1653
|
+
TokenType.Update,
|
|
1654
|
+
TokenType.Merge,
|
|
1418
1655
|
TokenType.Delete,
|
|
1419
1656
|
TokenType.Describe,
|
|
1420
1657
|
TokenType.Search,
|
|
1658
|
+
TokenType.Export,
|
|
1421
1659
|
TokenType.EOF
|
|
1422
1660
|
]);
|
|
1423
1661
|
while (!this.isAtEnd() && !stmtStarters.has(this.current().type)) {
|