@sap/cds-compiler 5.2.0 → 5.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/CHANGELOG.md +32 -0
- package/bin/cdsc.js +5 -0
- package/bin/cdshi.js +8 -8
- package/doc/CHANGELOG_BETA.md +9 -4
- package/lib/api/validate.js +5 -0
- package/lib/base/message-registry.js +25 -1
- package/lib/base/messages.js +1 -1
- package/lib/base/model.js +0 -1
- package/lib/compiler/assert-consistency.js +2 -2
- package/lib/compiler/builtins.js +1 -1
- package/lib/compiler/checks.js +25 -6
- package/lib/compiler/define.js +24 -28
- package/lib/compiler/extend.js +11 -13
- package/lib/compiler/generate.js +3 -3
- package/lib/compiler/populate.js +13 -7
- package/lib/compiler/propagator.js +2 -2
- package/lib/compiler/resolve.js +58 -60
- package/lib/compiler/shared.js +5 -5
- package/lib/compiler/tweak-assocs.js +247 -34
- package/lib/compiler/utils.js +40 -32
- package/lib/compiler/xpr-rewrite.js +44 -58
- package/lib/edm/annotations/genericTranslation.js +4 -4
- package/lib/edm/csn2edm.js +2 -2
- package/lib/edm/edm.js +46 -21
- package/lib/edm/edmInboundChecks.js +0 -1
- package/lib/edm/edmPreprocessor.js +40 -27
- package/lib/edm/edmUtils.js +1 -1
- package/lib/gen/BaseParser.js +180 -122
- package/lib/gen/CdlParser.js +2226 -2170
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +3820 -3777
- package/lib/inspect/inspectPropagation.js +1 -1
- package/lib/json/from-csn.js +5 -3
- package/lib/json/to-csn.js +7 -10
- package/lib/language/antlrParser.js +38 -4
- package/lib/language/errorStrategy.js +1 -1
- package/lib/language/genericAntlrParser.js +4 -4
- package/lib/language/multiLineStringParser.js +1 -1
- package/lib/main.d.ts +23 -0
- package/lib/model/cloneCsn.js +22 -13
- package/lib/optionProcessor.js +7 -7
- package/lib/parsers/AstBuildingParser.js +155 -37
- package/lib/parsers/CdlGrammar.g4 +154 -81
- package/lib/parsers/Lexer.js +20 -10
- package/lib/render/toCdl.js +23 -18
- package/lib/transform/addTenantFields.js +4 -4
- package/lib/transform/forRelationalDB.js +7 -6
- package/lib/utils/moduleResolve.js +1 -1
- package/package.json +1 -1
- package/share/messages/redirected-to-complex.md +6 -3
|
@@ -42,9 +42,9 @@ tokens{ // reserved words
|
|
|
42
42
|
start returns[ source = new XsnSource( 'cdl' ) ]
|
|
43
43
|
:
|
|
44
44
|
(
|
|
45
|
-
( <cond=
|
|
45
|
+
( <cond=namespaceRestriction> namespaceDeclaration[ $source ]
|
|
46
46
|
| usingDeclaration[ $source ]
|
|
47
|
-
| artifactDefOrExtend[ $source ] <setCondition=
|
|
47
|
+
| artifactDefOrExtend[ $source ] <setCondition=namespaceRestriction>
|
|
48
48
|
)
|
|
49
49
|
( ';' | <exitLoop> | <repeatLoop=afterBrace> { this.noAssignmentInSameLine(); } )
|
|
50
50
|
)*
|
|
@@ -53,7 +53,8 @@ start returns[ source = new XsnSource( 'cdl' ) ]
|
|
|
53
53
|
|
|
54
54
|
artifactsBlock[ art, start = undefined ]
|
|
55
55
|
:
|
|
56
|
-
'{'
|
|
56
|
+
'{'<setCondition=vocabularyRestriction>
|
|
57
|
+
{ $art.artifacts = this.createDict( $start ); $art.extensions = []; }
|
|
57
58
|
(
|
|
58
59
|
artifactDefOrExtend[ $art ]
|
|
59
60
|
( ';' | <exitLoop> | <repeatLoop=afterBrace> { this.noAssignmentInSameLine(); } )
|
|
@@ -70,7 +71,7 @@ artifactDefOrExtend[ outer ] locals[ art = new XsnArtifact() ]
|
|
|
70
71
|
DEFINE?
|
|
71
72
|
( serviceDef[ $art, $outer ]
|
|
72
73
|
| contextDef[ $art, $outer ]
|
|
73
|
-
| annotationDef[ $art, $outer ]
|
|
74
|
+
| <cond=vocabularyRestriction>annotationDef[ $art, $outer ]
|
|
74
75
|
| typeDef[ $art, $outer ]
|
|
75
76
|
| aspectDef[ $art, $outer ]
|
|
76
77
|
| entityDef[ $art, $outer ]
|
|
@@ -79,9 +80,8 @@ artifactDefOrExtend[ outer ] locals[ art = new XsnArtifact() ]
|
|
|
79
80
|
| actionMainDef[ $art, $outer ]
|
|
80
81
|
| functionMainDef[ $art, $outer ]
|
|
81
82
|
)
|
|
82
|
-
// TODO: condition to disable ANNOTATE/EXTEND in EXTEND … WITH DEFINITION
|
|
83
83
|
|
|
|
84
|
-
EXTEND { $art.kind = 'extend'; }
|
|
84
|
+
<cond=extensionRestriction> EXTEND { $art.kind = 'extend'; }
|
|
85
85
|
( extendArtifact[ $art, $outer ]
|
|
86
86
|
| extendService[ $art, $outer ]
|
|
87
87
|
// Non-streamlined Syntax; we would neither add new clauses to them, nor
|
|
@@ -92,7 +92,7 @@ artifactDefOrExtend[ outer ] locals[ art = new XsnArtifact() ]
|
|
|
92
92
|
| <hide> extendProjection[ $art, $outer ]
|
|
93
93
|
)
|
|
94
94
|
|
|
|
95
|
-
ANNOTATE annotateArtifact[ $art, $outer ]
|
|
95
|
+
<cond=extensionRestriction> ANNOTATE annotateArtifact[ $art, $outer ]
|
|
96
96
|
)
|
|
97
97
|
;
|
|
98
98
|
|
|
@@ -384,16 +384,16 @@ paramDef[ outer ] locals[ art = new XsnArtifact() ]
|
|
|
384
384
|
elementsBlock[ $art ]
|
|
385
385
|
nullability[ $art ]?
|
|
386
386
|
|
|
|
387
|
-
':'
|
|
387
|
+
':'
|
|
388
388
|
typeExpression[ $art ] // was elementType, with NOT? NULL / DEFAULT
|
|
389
|
-
{ this.docComment( $art ); } annoAssignStd[ $art ]*
|
|
390
389
|
)
|
|
391
390
|
;
|
|
392
391
|
|
|
393
392
|
returnsSpec[ outer ] locals[ art = new XsnArtifact() ]
|
|
394
393
|
@finally{ this.attachLocation( $art ); }
|
|
395
394
|
:
|
|
396
|
-
RETURNS
|
|
395
|
+
RETURNS<setCondition=elementRestriction>
|
|
396
|
+
{ $art.kind = 'param'; $outer.returns = $art; }
|
|
397
397
|
{ this.docComment( $art ); } annoAssignStd[ $art ]*
|
|
398
398
|
typeExpression[ $art ]
|
|
399
399
|
;
|
|
@@ -428,18 +428,22 @@ elementDef[ outer, art = undefined ]
|
|
|
428
428
|
elementsBlock[ $art ]
|
|
429
429
|
nullability[ $art ]?
|
|
430
430
|
|
|
|
431
|
-
':'
|
|
431
|
+
':'<setCondition=elementRestriction>
|
|
432
432
|
typeExpression[ $art ] // was elementType, with NOT? NULL / DEFAULT
|
|
433
|
-
|
|
433
|
+
|
|
|
434
|
+
// <setCondition=elementRestriction> // TODO TOOL: allow this
|
|
435
|
+
{ this.elementRestriction(); }<always> // workaround
|
|
436
|
+
)
|
|
434
437
|
(
|
|
435
|
-
|
|
436
|
-
|
|
438
|
+
<cond=calcOrDefaultRestriction> '='
|
|
439
|
+
// TODO TOOL: add to "expected set" if failing here? Or have some "do not
|
|
440
|
+
// consider for rule exit if condition failure on `=`"?
|
|
437
441
|
expr=expression { $art.value = $expr; }
|
|
438
442
|
( STORED { $art.value.stored = this.valueWithLocation( true ); } )?
|
|
439
443
|
// TODO: why have `stored` as property of the value?
|
|
444
|
+
{ this.docComment( $art ); } // TODO: also restricted
|
|
445
|
+
( <cond=elementRestriction> annoAssignStd[ $art ] )*
|
|
440
446
|
)?
|
|
441
|
-
{ this.docComment( $art ); }
|
|
442
|
-
( <cond=allowFinalAnnoAssign> annoAssignStd[ $art ] )*
|
|
443
447
|
;
|
|
444
448
|
|
|
445
449
|
enumSymbolsBlock[ art ]
|
|
@@ -583,7 +587,7 @@ extendArtifact[ art, outer ]
|
|
|
583
587
|
|
|
|
584
588
|
typeNamedArgsList[ $art ]
|
|
585
589
|
|
|
|
586
|
-
COLUMNS selectItemsList[ $art,
|
|
590
|
+
COLUMNS selectItemsList[ $art, this.lb() ]
|
|
587
591
|
|
|
|
588
592
|
DEFINITIONS artifactsBlock[ $art, this.lb() ]
|
|
589
593
|
)?
|
|
@@ -789,20 +793,7 @@ elementDefOrExtend[ outer ] locals[ art = new XsnArtifact() ]
|
|
|
789
793
|
|
|
790
794
|
// Type expressions -------------------------------------------------------------
|
|
791
795
|
|
|
792
|
-
//
|
|
793
|
-
// - elementType: full stuff + enum + localized + null + default ( + calc ), managed-compo
|
|
794
|
-
// - in type def: typeSpecSemi: elementsBlock, : elementsBlock, assoc, localized
|
|
795
|
-
// - param def = default + typeSpec: elementsBlock + :typeSpecCont (no assoc!)
|
|
796
|
-
// - returns = typeSpecCont: elementsBlock + null, typeArray, typeOf (+ enum), ref+null+enum,
|
|
797
|
-
// - typeArray: +enum + null + typeof
|
|
798
|
-
|
|
799
|
-
// - select item: redirected to + type of / localized, ref, assoc (published assoc)
|
|
800
|
-
// - mixin: only assoc
|
|
801
|
-
// - cast: just refoptargs
|
|
802
|
-
// - extend: just the type args
|
|
803
|
-
|
|
804
|
-
// -> typeExpression, typeForColumn, typeForMixin, typeRefOptArgs
|
|
805
|
-
|
|
796
|
+
// For `type` and `annotation` definitions:
|
|
806
797
|
typeOrIncludesSpec[ art ]
|
|
807
798
|
:
|
|
808
799
|
elementsBlock[ $art ]
|
|
@@ -815,11 +806,15 @@ typeOrIncludesSpec[ art ]
|
|
|
815
806
|
<priority>
|
|
816
807
|
ref=simplePath { $art.type = $ref; }
|
|
817
808
|
(
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
809
|
+
// <default> does not work here
|
|
810
|
+
typeRefOptArgs[ $art ]<atAltStart>
|
|
811
|
+
( typeExpression[ $art ]<atAltStart>
|
|
812
|
+
| { this.docComment( $art ); }
|
|
813
|
+
)
|
|
814
|
+
|
|
|
815
|
+
typeExpression[ $art ]<atAltStart>
|
|
816
|
+
|
|
|
817
|
+
{ this.docComment( $art ); }
|
|
823
818
|
|
|
|
824
819
|
{ $art.includes = [ $art.type ]; delete $art.type; }
|
|
825
820
|
(
|
|
@@ -835,36 +830,82 @@ typeOrIncludesSpec[ art ]
|
|
|
835
830
|
)
|
|
836
831
|
;
|
|
837
832
|
|
|
833
|
+
// Type expression (after the `:`) and “final” annotation assignment. Type
|
|
834
|
+
// expressions include `null`/`not null` and `default`, the latter is forbidden in
|
|
835
|
+
// the `returns` type.
|
|
836
|
+
//
|
|
837
|
+
// If used in a definition with additional clauses (currently just `= expr` for
|
|
838
|
+
// elements), these clauses must be guarded with <cond=…>.
|
|
839
|
+
//
|
|
840
|
+
// No annotation assignments are allowed after element and enum blocks, because
|
|
841
|
+
// these would conflict with the optional `;` after those blocks. To lower the
|
|
842
|
+
// impact with enums, the “final” annotation assignments are actually moved before
|
|
843
|
+
// the keyword `enum` (only allowed if not after `many`/`array of`).
|
|
844
|
+
//
|
|
845
|
+
// This rule is not used when the type expression is restricted: CDL-style cast in
|
|
846
|
+
// `select` items, `cast` function, `mixin` definition.
|
|
847
|
+
|
|
838
848
|
typeExpression[ art ]
|
|
849
|
+
// TODO: really introduce <exitRule>
|
|
839
850
|
:
|
|
840
851
|
elementsBlock[ $art ]
|
|
841
852
|
nullability[ $art ]?
|
|
842
853
|
|
|
|
843
854
|
( typeRefOptArgs[ $art ] | typeTypeOf[ $art ] )
|
|
855
|
+
(<altRuleStart>)
|
|
844
856
|
nullability[ $art ]?
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
857
|
+
// <setCondition=calcOrDefaultRestriction> // TODO TOOL: allow this
|
|
858
|
+
{ this.calcOrDefaultRestriction(); }<always> // workaround
|
|
859
|
+
(
|
|
860
|
+
nullabilityAndDefault[ $art ]
|
|
861
|
+
{ this.docComment( $art ); } annoAssignStd[ $art ]*
|
|
862
|
+
|
|
|
863
|
+
enumSymbolsBlock[ $art ]
|
|
864
|
+
nullabilityAndDefault[ $art ]?
|
|
865
|
+
|
|
|
866
|
+
{ this.docComment( $art ); } annoAssignStd[ $art ]+
|
|
867
|
+
( enumSymbolsBlock[ $art ]
|
|
868
|
+
// <setCondition=calcOrDefaultRestriction> // TODO TOOL: allow this
|
|
869
|
+
{ this.calcOrDefaultRestriction(); }<always> // workaround
|
|
870
|
+
nullabilityAndDefault[ $art ]?
|
|
871
|
+
)?
|
|
872
|
+
|
|
|
873
|
+
{ this.docComment( $art ); }
|
|
874
|
+
)
|
|
848
875
|
|
|
|
849
|
-
LOCALIZED
|
|
850
|
-
|
|
851
|
-
|
|
876
|
+
LOCALIZED
|
|
877
|
+
{ $art.localized = this.valueWithLocation( true ); }
|
|
878
|
+
typeRefOptArgs[ $art ] // TODO: why no TYPE OF ?
|
|
879
|
+
// <setCondition=calcOrDefaultRestriction> // TODO TOOL: allow this
|
|
880
|
+
{ this.calcOrDefaultRestriction(); }<always> // workaround
|
|
852
881
|
nullabilityAndDefault[ $art ]?
|
|
882
|
+
{ this.docComment( $art ); } annoAssignStd[ $art ]*
|
|
853
883
|
|
|
|
854
884
|
assoc=ASSOCIATION cardinality[ $art ]? TO card=ONE/MANY?
|
|
855
885
|
target=simplePath { this.setAssocAndComposition( $art, $assoc, $card, $target ); }
|
|
886
|
+
// final anno assignments allowed also with fkeys (also in ANTLR-based parser)
|
|
887
|
+
// <prepare=calcOrDefaultRestriction,arg=true> // TODO TOOL: allow this
|
|
888
|
+
{ this.calcOrDefaultRestriction(false,true); }<always> // workaround
|
|
889
|
+
|
|
856
890
|
( ON cond=condition { $art.on = $cond; }
|
|
857
|
-
| foreignKeysBlock[ $art ]?
|
|
891
|
+
| foreignKeysBlock[ $art ]?
|
|
892
|
+
nullabilityAndDefault[ $art ]?
|
|
893
|
+
// scalar default - hm..., what about calc expression?
|
|
858
894
|
)
|
|
895
|
+
{ this.docComment( $art ); } annoAssignStd[ $art ]*
|
|
859
896
|
|
|
|
860
897
|
assoc=COMPOSITION cardinality[ $art ]? OF card=ONE/MANY?
|
|
861
898
|
(
|
|
862
899
|
target=simplePath { this.setAssocAndComposition( $art, $assoc, $card, $target ); }
|
|
900
|
+
// final anno assignments allowed also with fkeys (also in ANTLR-based parser) - TODO: really?
|
|
901
|
+
// <prepare=calcOrDefaultRestriction,arg=true> // TODO TOOL: allow this
|
|
902
|
+
{ this.calcOrDefaultRestriction(false,true); }<always> // workaround
|
|
863
903
|
( ON cond=condition { $art.on = $cond; }
|
|
864
|
-
| foreignKeysBlock[ $art ]?
|
|
904
|
+
| foreignKeysBlock[ $art ]?
|
|
905
|
+
nullabilityAndDefault[ $art ]?
|
|
865
906
|
)
|
|
907
|
+
{ this.docComment( $art ); } annoAssignStd[ $art ]*
|
|
866
908
|
|
|
|
867
|
-
// TODO: really do SyntaxOnly/GrammarAmbiguities/CompositionOfMany.cds ?
|
|
868
909
|
{ $target = {}; this.setAssocAndComposition( $art, $assoc, $card, $target ); }
|
|
869
910
|
elementsBlock[ $target ]
|
|
870
911
|
{ $target.location = $target.elements[Symbol.for('cds.$location')]; }
|
|
@@ -879,9 +920,11 @@ typeExpression[ art ]
|
|
|
879
920
|
|
|
|
880
921
|
( typeRefOptArgs[ $art.items ] | typeTypeOf[ $art.items ] )
|
|
881
922
|
nullability[ $art.items ]?
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
923
|
+
( enumSymbolsBlock[ $art.items ]
|
|
924
|
+
nullability[ $art.items ]? // TODO: only with enum
|
|
925
|
+
|
|
|
926
|
+
{ this.docComment( $art ); } annoAssignStd[ $art ]*
|
|
927
|
+
)
|
|
885
928
|
)
|
|
886
929
|
;
|
|
887
930
|
|
|
@@ -1000,9 +1043,12 @@ targetCardinality[ card, atAlt = false ]
|
|
|
1000
1043
|
nullabilityAndDefault[ art ]
|
|
1001
1044
|
:
|
|
1002
1045
|
nullability[ $art ]
|
|
1003
|
-
( DEFAULT expr=expression
|
|
1046
|
+
( <cond=calcOrDefaultRestriction> DEFAULT expr=expression
|
|
1047
|
+
{ $art.default = $expr; }
|
|
1048
|
+
)?
|
|
1004
1049
|
|
|
|
1005
|
-
DEFAULT expr=expression
|
|
1050
|
+
<cond=calcOrDefaultRestriction> DEFAULT expr=expression
|
|
1051
|
+
{ $art.default = $expr; }
|
|
1006
1052
|
nullability[ $art ]?
|
|
1007
1053
|
// TODO TOOL: when `followUnion` does not contain `Id`, `RuleEnd_` does not
|
|
1008
1054
|
// need to induce prediction (here for `default`).
|
|
@@ -1161,7 +1207,7 @@ tableOrQueryParens returns[ default expr ]
|
|
|
1161
1207
|
{ $expr = this.taggedIfQuery( $expr ); $expr.name = this.fragileAlias(); }
|
|
1162
1208
|
|
|
|
1163
1209
|
// <setCondition=setPrecInCallingRule> // TODO TOOL: allow this
|
|
1164
|
-
{ this.setPrecInCallingRule(); } // workaround
|
|
1210
|
+
{ this.setPrecInCallingRule(); }<always> // workaround
|
|
1165
1211
|
)
|
|
1166
1212
|
; // change #10799 for ANTLR-based parser
|
|
1167
1213
|
|
|
@@ -1194,10 +1240,15 @@ fromRefWithOptAlias returns[ default expr = { path: [] } ]
|
|
|
1194
1240
|
} }
|
|
1195
1241
|
fromPath[ $expr, 'ref']
|
|
1196
1242
|
)?
|
|
1197
|
-
(
|
|
1198
|
-
|
|
1243
|
+
(
|
|
1244
|
+
AS Id['FromAlias'] { $expr.name = this.identAst(); }
|
|
1245
|
+
|
|
|
1246
|
+
<hide, cond=tableAlias>
|
|
1247
|
+
Id_restricted['FromAlias']
|
|
1199
1248
|
{ $expr.name = this.fragileAlias(); }
|
|
1200
|
-
|
|
|
1249
|
+
|
|
|
1250
|
+
<default=fallback>
|
|
1251
|
+
{ this.classifyImplicitName( $expr.scope ? 'FromElemImplicit' : 'FromImplicit', $expr ); }
|
|
1201
1252
|
)
|
|
1202
1253
|
;
|
|
1203
1254
|
|
|
@@ -1288,9 +1339,24 @@ excludingClause[ query ]
|
|
|
1288
1339
|
{ this.finalizeDictOrArray( $query.excludingDict ); }
|
|
1289
1340
|
;
|
|
1290
1341
|
|
|
1291
|
-
selectItemsList[ query,
|
|
1342
|
+
selectItemsList[ query, start = undefined ]
|
|
1343
|
+
:
|
|
1344
|
+
'{'<setCondition=notInExpandInline>
|
|
1345
|
+
{ $query.columns = this.createArray( $start ); }
|
|
1346
|
+
(
|
|
1347
|
+
( '*' { $query.columns.push( this.valueWithLocation() ); }
|
|
1348
|
+
| selectItemDef[ $query.columns ]
|
|
1349
|
+
)
|
|
1350
|
+
( ',' | <exitLoop> )
|
|
1351
|
+
)*
|
|
1352
|
+
'}'<setCondition=afterBrace>
|
|
1353
|
+
{ this.finalizeDictOrArray( $query.columns ); }
|
|
1354
|
+
;
|
|
1355
|
+
|
|
1356
|
+
nestedSelectItemsList[ query, clause ]
|
|
1292
1357
|
:
|
|
1293
|
-
'{'
|
|
1358
|
+
'{'<setCondition=inExpandInline>
|
|
1359
|
+
{ $query[$clause] = this.createArray(); }
|
|
1294
1360
|
(
|
|
1295
1361
|
( '*' { $query[$clause].push( this.valueWithLocation() ); }
|
|
1296
1362
|
| selectItemDef[ $query[$clause] ]
|
|
@@ -1306,32 +1372,34 @@ selectItemDef[ columns ] locals[ art = new XsnArtifact(), alias ]
|
|
|
1306
1372
|
:
|
|
1307
1373
|
{ $columns.push( $art ); } // TODO: probably too early
|
|
1308
1374
|
{ this.docComment( $art ); } annoAssignCol[ $art ]*
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
(
|
|
1375
|
+
( <cond=notInExpandInline> VIRTUAL
|
|
1376
|
+
{ $art.virtual = this.valueWithLocation( true ); } )?
|
|
1377
|
+
( <cond=notInExpandInline> KEY
|
|
1378
|
+
{ $art.key = this.valueWithLocation( true ); } )?
|
|
1312
1379
|
(
|
|
1313
1380
|
expr=expression { $art.value = $expr; }
|
|
1314
1381
|
( as=AS Id['ItemAlias'] { $art.name = this.identAst(); }
|
|
1315
1382
|
| Id_restricted['ItemAlias'] { $art.name = this.fragileAlias( true ); }
|
|
1316
1383
|
| { $alias = this.classifyImplicitName( 'ItemImplicit', $expr ); }
|
|
1317
1384
|
)
|
|
1318
|
-
// TODO: <cond> for expand/inline only
|
|
1385
|
+
// TODO: <cond> instead `reportExpandInline` for "expand/inline only w/ ref"
|
|
1319
1386
|
(
|
|
1320
1387
|
{ this.reportExpandInline( $art, false ); }
|
|
1321
|
-
|
|
1388
|
+
nestedSelectItemsList[ $art, 'expand' ]
|
|
1322
1389
|
excludingClause[ $art ]?
|
|
1323
1390
|
|
|
|
1324
|
-
'.'
|
|
1325
|
-
{
|
|
1391
|
+
'.'
|
|
1392
|
+
{ this.reportExpandInline( $art, $as || true ); }
|
|
1393
|
+
{ if ($alias) $alias.token.parsedAs = $alias.parsedAs; }
|
|
1326
1394
|
(
|
|
1327
|
-
|
|
1395
|
+
nestedSelectItemsList[ $art, 'inline' ]
|
|
1328
1396
|
excludingClause[ $art ]?
|
|
1329
1397
|
|
|
|
1330
1398
|
'*' { $art.inline = [ this.valueWithLocation() ]; }
|
|
1331
1399
|
)
|
|
1332
1400
|
)?
|
|
1333
1401
|
|
|
|
1334
|
-
|
|
1402
|
+
nestedSelectItemsList[ $art, 'expand' ]
|
|
1335
1403
|
excludingClause[ $art ]?
|
|
1336
1404
|
AS Id['ItemAlias'] { $art.name = this.identAst(); }
|
|
1337
1405
|
)
|
|
@@ -1442,7 +1510,7 @@ expression returns[ default expr ]
|
|
|
1442
1510
|
(
|
|
1443
1511
|
Id_all['paramref']
|
|
1444
1512
|
{ $expr = { path: [ this.identAst() ], location: this.startLocation(), scope: 'param' }; }
|
|
1445
|
-
(
|
|
1513
|
+
( valuePath[ ...$ ]<atAltStart>
|
|
1446
1514
|
{ $expr = this.valuePathAst( $expr ); }
|
|
1447
1515
|
| { this.attachLocation( $expr ); }
|
|
1448
1516
|
)
|
|
@@ -1597,6 +1665,7 @@ castFunction returns[ default expr = {} ]
|
|
|
1597
1665
|
;
|
|
1598
1666
|
|
|
1599
1667
|
argumentsAndFilter[ pathStep ]
|
|
1668
|
+
// TODO: what about valuePath with EXISTS, after `:` etc (also in ANTLR-based parser)?
|
|
1600
1669
|
options{ minTokensMatched = 1 }
|
|
1601
1670
|
:
|
|
1602
1671
|
(
|
|
@@ -1606,7 +1675,6 @@ options{ minTokensMatched = 1 }
|
|
|
1606
1675
|
// TOOL? at least msg)
|
|
1607
1676
|
(
|
|
1608
1677
|
<default=fallback> // TODO TOOL: allow in loop
|
|
1609
|
-
{ ; } // TODO TOOL: we need an idle action here, for <default>
|
|
1610
1678
|
(
|
|
1611
1679
|
expr=funcExpression { $pathStep.args.push( $expr ); }
|
|
1612
1680
|
(
|
|
@@ -1623,6 +1691,9 @@ options{ minTokensMatched = 1 }
|
|
|
1623
1691
|
)?
|
|
1624
1692
|
)?
|
|
1625
1693
|
|
|
|
1694
|
+
// TODO: if we want perfect CC and error recovery, `isNamedArg` would work
|
|
1695
|
+
// like keyword prediction and also do something similar to the (future)
|
|
1696
|
+
// "identifier confirmation prediction" (consider argument `(par ‡ : 42)`
|
|
1626
1697
|
<cond=isNamedArg> id=Id_all['paramname']
|
|
1627
1698
|
(
|
|
1628
1699
|
':' { $pathStep.args = this.createDict( $open ); $pathStep.$syntax = ':'; }
|
|
@@ -1679,11 +1750,11 @@ funcExpression returns[ default expr ] locals[ args ]
|
|
|
1679
1750
|
)*
|
|
1680
1751
|
;
|
|
1681
1752
|
|
|
1682
|
-
GenericExpr
|
|
1753
|
+
GenericExpr
|
|
1683
1754
|
: Id_all | '*' ;
|
|
1684
|
-
GenericIntro
|
|
1755
|
+
GenericIntro
|
|
1685
1756
|
: Id_all ;
|
|
1686
|
-
GenericSeparator
|
|
1757
|
+
GenericSeparator
|
|
1687
1758
|
: Id_all ;
|
|
1688
1759
|
|
|
1689
1760
|
overClause[ outer ] locals[ over = [] ]
|
|
@@ -1791,7 +1862,7 @@ literalValue returns[ default expr = {} ]
|
|
|
1791
1862
|
annoAssignStd[ art ]
|
|
1792
1863
|
@finally{ this.docComment( $art ); }
|
|
1793
1864
|
:
|
|
1794
|
-
'@'<setCondition=
|
|
1865
|
+
'@'<setCondition=annoInSameLine> { this.reportUnexpectedSpace(); }
|
|
1795
1866
|
( annoAssignParen[ ...$ ]
|
|
1796
1867
|
| annoAssignBase[ ...$ ]
|
|
1797
1868
|
)
|
|
@@ -1809,16 +1880,16 @@ annoAssignCol[ art ]
|
|
|
1809
1880
|
annoAssignMid[ art ]
|
|
1810
1881
|
@finally{ this.docComment( $art ); }
|
|
1811
1882
|
:
|
|
1812
|
-
'@'<setCondition=
|
|
1883
|
+
'@'<setCondition=annoInSameLine> { this.reportUnexpectedSpace(); }
|
|
1813
1884
|
( annoAssignParen[ ...$ ]
|
|
1814
|
-
| name=annoNamePath
|
|
1885
|
+
| name=annoNamePath // !
|
|
1815
1886
|
{ this.assignAnnotation( $art, {}, $name ); this.warnIfColonFollows( $name ); }
|
|
1816
1887
|
)
|
|
1817
1888
|
;
|
|
1818
1889
|
|
|
1819
1890
|
annoAssignParen[ art ]
|
|
1820
1891
|
:
|
|
1821
|
-
'('<setCondition=
|
|
1892
|
+
'('<setCondition=annoInSameLine>
|
|
1822
1893
|
( annoAssignBase[ $art ]
|
|
1823
1894
|
( ',' | <exitLoop> )
|
|
1824
1895
|
)*
|
|
@@ -1829,7 +1900,7 @@ annoAssignBase[ art ] locals[ value = {} ]
|
|
|
1829
1900
|
@finally{ this.assignAnnotation( $art, $value, $name || {} ); }
|
|
1830
1901
|
:
|
|
1831
1902
|
name=annoNamePath
|
|
1832
|
-
( <cond=
|
|
1903
|
+
( <cond=annoInSameLine> ':' value=annoValue )?
|
|
1833
1904
|
;
|
|
1834
1905
|
|
|
1835
1906
|
annoNamePath[ category = 'anno' ] returns[ default name = new XsnName() ]
|
|
@@ -1844,7 +1915,7 @@ annoNamePath[ category = 'anno' ] returns[ default name = new XsnName() ]
|
|
|
1844
1915
|
Id_all[ $category ] { $name.path.push( this.identAstWithPrefix( $at ) ); }
|
|
1845
1916
|
)
|
|
1846
1917
|
)*
|
|
1847
|
-
( <cond=
|
|
1918
|
+
( <cond=annoInSameLine> annoPathVariant[ $name ] )?
|
|
1848
1919
|
;
|
|
1849
1920
|
|
|
1850
1921
|
annoPath[ nameOrRef, category = 'annoref' ]
|
|
@@ -1878,7 +1949,7 @@ annoStructValue returns[ default value = {} ] locals[ name = new XsnName() ]
|
|
|
1878
1949
|
@finally{ $value.name = $name; }
|
|
1879
1950
|
:
|
|
1880
1951
|
annoPath[ $name, 'name' ] { this.attachLocation( $name ); }
|
|
1881
|
-
( ':'
|
|
1952
|
+
( ':'
|
|
1882
1953
|
$value=annoValue
|
|
1883
1954
|
|
|
|
1884
1955
|
{ this.attachLocation( $value ); }
|
|
@@ -1895,13 +1966,15 @@ annoValue returns[ default value = {} ]
|
|
|
1895
1966
|
|
|
|
1896
1967
|
annoPath[ $value, 'annoref' ]
|
|
1897
1968
|
|
|
|
1898
|
-
'{'
|
|
1969
|
+
'{'
|
|
1899
1970
|
{
|
|
1900
|
-
if (this.
|
|
1971
|
+
if (!this.dynamic_.arrayAnno) $value.$flatten = [];
|
|
1901
1972
|
else { $value.struct = Object.create(null); $value.literal = 'struct'; }
|
|
1902
1973
|
}
|
|
1903
1974
|
(
|
|
1904
1975
|
// TODO: complain about empty loop if top-level as before
|
|
1976
|
+
// TOOL TODO → allow `<cond=…> '}'` below where the condition rejects `}`
|
|
1977
|
+
// after `{` if top-level
|
|
1905
1978
|
sub=annoStructValue
|
|
1906
1979
|
{
|
|
1907
1980
|
if ($value.$flatten) $value.$flatten.push( $sub );
|
|
@@ -1911,13 +1984,13 @@ annoValue returns[ default value = {} ]
|
|
|
1911
1984
|
)*
|
|
1912
1985
|
'}' // Do NOT use <setCondition=afterBrace> here!
|
|
1913
1986
|
|
|
|
1914
|
-
'['<setCondition=
|
|
1987
|
+
'['<setCondition=ellipsisRestriction>
|
|
1915
1988
|
{ $value.val = []; $value.literal = 'array' }
|
|
1916
1989
|
// no need for createArray() here, $value.location is set above
|
|
1917
1990
|
(
|
|
1918
1991
|
( sub=annoValue { $value.val.push( $sub ) }
|
|
1919
1992
|
|
|
|
1920
|
-
ellipsis='...'
|
|
1993
|
+
<cond=ellipsisRestriction> ellipsis='...'
|
|
1921
1994
|
( UP TO upTo=annoValue | { $upTo = undefined; } )
|
|
1922
1995
|
{ $value.val.push( { literal: 'token', val: '...', location: $ellipsis.location, upTo: $upTo } ); }
|
|
1923
1996
|
)
|
package/lib/parsers/Lexer.js
CHANGED
|
@@ -42,9 +42,9 @@ class Token {
|
|
|
42
42
|
text;
|
|
43
43
|
keyword;
|
|
44
44
|
location;
|
|
45
|
-
|
|
45
|
+
parsedAs;
|
|
46
46
|
get isIdentifier() { // compatibility method
|
|
47
|
-
return this.
|
|
47
|
+
return this.parsedAs !== 'keyword' && this.parsedAs !== 'token' && this.parsedAs;
|
|
48
48
|
}
|
|
49
49
|
get tokenIndex() {
|
|
50
50
|
return this.location.tokenIndex;
|
|
@@ -92,7 +92,7 @@ class Lexer {
|
|
|
92
92
|
endLine: line,
|
|
93
93
|
endCol: col + text.length,
|
|
94
94
|
// remark: end positions of multi-line tokens must be set by function
|
|
95
|
-
tokenIndex: parser.tokens.length,
|
|
95
|
+
tokenIndex: parser.tokens.length + parser.docComments.length + parser.comments.length,
|
|
96
96
|
};
|
|
97
97
|
let keyword;
|
|
98
98
|
if (typeof type !== 'function' ||
|
|
@@ -103,7 +103,7 @@ class Lexer {
|
|
|
103
103
|
text,
|
|
104
104
|
keyword,
|
|
105
105
|
location: this.location,
|
|
106
|
-
|
|
106
|
+
parsedAs: undefined,
|
|
107
107
|
} );
|
|
108
108
|
}
|
|
109
109
|
}
|
|
@@ -116,7 +116,7 @@ class Lexer {
|
|
|
116
116
|
col: endCol,
|
|
117
117
|
endLine: line,
|
|
118
118
|
endCol,
|
|
119
|
-
tokenIndex: parser.tokens.length,
|
|
119
|
+
tokenIndex: parser.tokens.length + parser.docComments.length + parser.comments.length,
|
|
120
120
|
};
|
|
121
121
|
parser.tokens.push( {
|
|
122
122
|
__proto__: Token.prototype,
|
|
@@ -124,7 +124,7 @@ class Lexer {
|
|
|
124
124
|
text: '',
|
|
125
125
|
keyword: false,
|
|
126
126
|
location,
|
|
127
|
-
|
|
127
|
+
parsedAs: undefined,
|
|
128
128
|
} );
|
|
129
129
|
}
|
|
130
130
|
}
|
|
@@ -141,14 +141,24 @@ function comment( text, lexer, parser, beg ) {
|
|
|
141
141
|
}
|
|
142
142
|
else if (text === '/*' && lexer.input.charAt( rulesRegexp.lastIndex ) === '*' &&
|
|
143
143
|
rulesRegexp.lastIndex + 2 < re.lastIndex) { // not just `/**/`
|
|
144
|
-
lexer.location.tokenIndex = parser.docComments.length;
|
|
145
144
|
parser.docComments.push( {
|
|
146
145
|
__proto__: Token.prototype,
|
|
147
146
|
type: 'DocComment',
|
|
148
147
|
text: lexer.input.substring( beg, re.lastIndex ),
|
|
149
148
|
keyword: false,
|
|
150
149
|
location: lexer.location,
|
|
151
|
-
|
|
150
|
+
parsedAs: undefined,
|
|
151
|
+
} );
|
|
152
|
+
adaptEndLocation( lexer, re.lastIndex ); // also works after push ?
|
|
153
|
+
}
|
|
154
|
+
else { // TODO: only attach with option `attachTokens` ?
|
|
155
|
+
parser.comments.push( {
|
|
156
|
+
__proto__: Token.prototype,
|
|
157
|
+
type: 'Comment',
|
|
158
|
+
text: lexer.input.substring( beg, re.lastIndex ),
|
|
159
|
+
keyword: false,
|
|
160
|
+
location: lexer.location,
|
|
161
|
+
parsedAs: undefined,
|
|
152
162
|
} );
|
|
153
163
|
adaptEndLocation( lexer, re.lastIndex ); // also works after push ?
|
|
154
164
|
}
|
|
@@ -187,7 +197,7 @@ function string( text, lexer, parser, beg ) {
|
|
|
187
197
|
multi: 'The multi-line string literal must end with $(NEWCODE)',
|
|
188
198
|
} );
|
|
189
199
|
keyword = 0;
|
|
190
|
-
// TODO: set
|
|
200
|
+
// TODO: set parsedAs to 0 → no further error if string is not expected?
|
|
191
201
|
prefix = null; // no combination with date/time/…
|
|
192
202
|
}
|
|
193
203
|
adaptEndLocation( lexer, (rulesRegexp.lastIndex = lastIndex || lexer.input.length) );
|
|
@@ -221,7 +231,7 @@ function ident( text, lexer, parser, beg ) {
|
|
|
221
231
|
ident: 'The delimited id must end with $(NEWCODE) before the end of line',
|
|
222
232
|
} );
|
|
223
233
|
keyword = 0;
|
|
224
|
-
// TODO: set
|
|
234
|
+
// TODO: set parsedAs to 0 → no further error if string is not expected?
|
|
225
235
|
}
|
|
226
236
|
adaptEndLocation( lexer, (rulesRegexp.lastIndex = lastIndex || lexer.input.length) );
|
|
227
237
|
return [ 'Id', lexer.input.substring( beg, rulesRegexp.lastIndex ), keyword ];
|