@sap/cds-compiler 3.5.2 → 3.6.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 +63 -1
- package/bin/cdsc.js +14 -6
- package/doc/CHANGELOG_ARCHIVE.md +10 -10
- package/doc/CHANGELOG_DEPRECATED.md +2 -2
- package/lib/api/main.js +32 -55
- package/lib/api/options.js +1 -0
- package/lib/api/validate.js +5 -0
- package/lib/base/message-registry.js +104 -32
- package/lib/base/messages.js +277 -212
- package/lib/base/model.js +33 -22
- package/lib/base/optionProcessorHelper.js +9 -2
- package/lib/base/shuffle.js +50 -0
- package/lib/checks/actionsFunctions.js +37 -20
- package/lib/checks/foreignKeys.js +13 -6
- package/lib/checks/nonexpandableStructured.js +1 -2
- package/lib/checks/onConditions.js +21 -19
- package/lib/checks/parameters.js +1 -1
- package/lib/checks/queryNoDbArtifacts.js +2 -0
- package/lib/checks/types.js +16 -22
- package/lib/compiler/assert-consistency.js +31 -28
- package/lib/compiler/builtins.js +20 -4
- package/lib/compiler/checks.js +72 -63
- package/lib/compiler/define.js +396 -314
- package/lib/compiler/extend.js +55 -49
- package/lib/compiler/index.js +5 -0
- package/lib/compiler/populate.js +28 -11
- package/lib/compiler/propagator.js +2 -1
- package/lib/compiler/resolve.js +29 -20
- package/lib/compiler/shared.js +15 -10
- package/lib/compiler/utils.js +7 -7
- package/lib/edm/annotations/genericTranslation.js +51 -46
- package/lib/edm/annotations/preprocessAnnotations.js +39 -42
- package/lib/edm/csn2edm.js +69 -21
- package/lib/edm/edm.js +2 -2
- package/lib/edm/edmInboundChecks.js +6 -8
- package/lib/edm/edmPreprocessor.js +88 -80
- package/lib/edm/edmUtils.js +6 -15
- package/lib/gen/Dictionary.json +81 -13
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +2 -1
- package/lib/gen/languageParser.js +4680 -4484
- package/lib/inspect/inspectModelStatistics.js +2 -1
- package/lib/inspect/inspectPropagation.js +2 -1
- package/lib/json/from-csn.js +131 -78
- package/lib/json/to-csn.js +39 -23
- package/lib/language/antlrParser.js +0 -3
- package/lib/language/docCommentParser.js +7 -3
- package/lib/language/errorStrategy.js +3 -2
- package/lib/language/genericAntlrParser.js +96 -41
- package/lib/language/language.g4 +112 -128
- package/lib/language/multiLineStringParser.js +2 -1
- package/lib/main.d.ts +115 -2
- package/lib/main.js +16 -3
- package/lib/model/csnRefs.js +3 -3
- package/lib/model/csnUtils.js +109 -179
- package/lib/model/enrichCsn.js +13 -8
- package/lib/model/revealInternalProperties.js +4 -3
- package/lib/optionProcessor.js +23 -3
- package/lib/render/manageConstraints.js +11 -15
- package/lib/render/toCdl.js +144 -47
- package/lib/render/toHdbcds.js +22 -22
- package/lib/render/toRename.js +3 -4
- package/lib/render/toSql.js +29 -20
- package/lib/render/utils/delta.js +3 -1
- package/lib/render/utils/sql.js +3 -16
- package/lib/transform/db/associations.js +6 -6
- package/lib/transform/db/cdsPersistence.js +3 -3
- package/lib/transform/db/constraints.js +8 -8
- package/lib/transform/db/expansion.js +4 -4
- package/lib/transform/db/flattening.js +12 -15
- package/lib/transform/db/temporal.js +4 -3
- package/lib/transform/db/transformExists.js +2 -1
- package/lib/transform/draft/db.js +7 -7
- package/lib/transform/forOdataNew.js +15 -4
- package/lib/transform/forRelationalDB.js +53 -39
- package/lib/transform/odata/toFinalBaseType.js +106 -82
- package/lib/transform/odata/typesExposure.js +26 -17
- package/lib/transform/odata/utils.js +1 -1
- package/lib/transform/parseExpr.js +1 -1
- package/lib/transform/transformUtilsNew.js +33 -10
- package/lib/transform/translateAssocsToJoins.js +8 -7
- package/lib/transform/universalCsn/coreComputed.js +7 -5
- package/lib/transform/universalCsn/universalCsnEnricher.js +12 -4
- package/lib/utils/timetrace.js +2 -2
- package/package.json +1 -2
package/lib/language/language.g4
CHANGED
|
@@ -113,6 +113,10 @@
|
|
|
113
113
|
//
|
|
114
114
|
// * If you want to set a property starting with '$' like $syntax, use
|
|
115
115
|
// obj['$'+'syntax'] as the ANTLR tool would replace $syntax by $ctx.syntax
|
|
116
|
+
//
|
|
117
|
+
// * If you want to use Unicode characters, move the corresponding code to
|
|
118
|
+
// ./genericAntlrParser.js; ANTLR or the TypeScript wrapper might destroy
|
|
119
|
+
// Unicode characters on certain operating systems.
|
|
116
120
|
|
|
117
121
|
grammar language;
|
|
118
122
|
options {
|
|
@@ -219,8 +223,8 @@ artifactDefOrExtend[ outer, defOnly = false ] locals[ art = {} ] // cannot use `
|
|
|
219
223
|
annotationAssignment_ll1[ $art ]*
|
|
220
224
|
(
|
|
221
225
|
DEFINE?
|
|
222
|
-
( serviceDef[ $art, $outer, defOnly ]
|
|
223
|
-
| contextDef[ $art, $outer, defOnly ]
|
|
226
|
+
( serviceDef[ $art, $outer, $defOnly ]
|
|
227
|
+
| contextDef[ $art, $outer, $defOnly ]
|
|
224
228
|
| entityDef[ $art, $outer ]
|
|
225
229
|
| typeDef[ $art, $outer ]
|
|
226
230
|
| aspectDef[ $art, $outer ]
|
|
@@ -231,10 +235,7 @@ artifactDefOrExtend[ outer, defOnly = false ] locals[ art = {} ] // cannot use `
|
|
|
231
235
|
)
|
|
232
236
|
|
|
|
233
237
|
extend=EXTEND
|
|
234
|
-
{
|
|
235
|
-
this.error( 'syntax-extend-context', $extend,
|
|
236
|
-
{ code: 'EXTEND artifact', meta: defOnly },
|
|
237
|
-
'No $(CODE) within $(META) extensions' );
|
|
238
|
+
{ this.reportUnexpectedExtension( $defOnly, $extend );
|
|
238
239
|
if (!$outer.extensions) $outer.extensions = [];
|
|
239
240
|
}
|
|
240
241
|
// #ATN: EXTEND art, while CONTEXT, ENTITY etc are not reserved
|
|
@@ -248,10 +249,7 @@ artifactDefOrExtend[ outer, defOnly = false ] locals[ art = {} ] // cannot use `
|
|
|
248
249
|
)
|
|
249
250
|
|
|
|
250
251
|
annotate=ANNOTATE
|
|
251
|
-
{
|
|
252
|
-
this.error( 'syntax-extend-context', $annotate,
|
|
253
|
-
{ code: 'ANNOTATE artifact', meta: defOnly },
|
|
254
|
-
'No $(CODE) within $(META) extensions' );
|
|
252
|
+
{ this.reportUnexpectedExtension( $defOnly, $annotate );
|
|
255
253
|
if (!$outer.extensions) $outer.extensions = [];
|
|
256
254
|
this.meltKeywordToIdentifier();
|
|
257
255
|
}
|
|
@@ -515,8 +513,10 @@ actionFunctionDef[ outer ] locals[ art = {} ]
|
|
|
515
513
|
parameterDef[ outer ] locals[ art = {} ]
|
|
516
514
|
@after { this.attachLocation( $art ); }
|
|
517
515
|
:
|
|
518
|
-
{ this.docComment( $art ); }
|
|
519
|
-
annotationAssignment_ll1[ $art ]
|
|
516
|
+
{ this.meltKeywordToIdentifier();; this.docComment( $art ); }
|
|
517
|
+
( annotationAssignment_ll1[ $art ]
|
|
518
|
+
{ this.meltKeywordToIdentifier(); }
|
|
519
|
+
)*
|
|
520
520
|
name=ident['Param']
|
|
521
521
|
{ this.addDef( $art, $outer, 'params', 'param', $name.id );
|
|
522
522
|
this.docComment( $art ); }
|
|
@@ -532,12 +532,17 @@ parameterListDef[ art ]
|
|
|
532
532
|
'(' { $art.params = this.createDict(); }
|
|
533
533
|
// also empty param list (we might do some hacking later to allow reserved words)
|
|
534
534
|
// see annotationAssignment_paren
|
|
535
|
-
|
|
535
|
+
{
|
|
536
|
+
if (this.isStraightBefore(')')) {
|
|
537
|
+
this.matchWildcard(); // we know it is the ')' - we do not reach the final match
|
|
538
|
+
this.finalizeDictOrArray( $art.params );
|
|
539
|
+
return $ctx;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
parameterDef[ $art ]
|
|
543
|
+
( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
|
|
536
544
|
parameterDef[ $art ]
|
|
537
|
-
|
|
538
|
-
parameterDef[ $art ]
|
|
539
|
-
)*
|
|
540
|
-
)?
|
|
545
|
+
)*
|
|
541
546
|
')' { this.finalizeDictOrArray( $art.params ); }
|
|
542
547
|
;
|
|
543
548
|
|
|
@@ -572,7 +577,7 @@ elementDef[ outer ] locals[ $art = {} ]
|
|
|
572
577
|
elementDefInner[ $art, $outer, false ]
|
|
573
578
|
;
|
|
574
579
|
|
|
575
|
-
elementDefInner[ art, outer,
|
|
580
|
+
elementDefInner[ art, outer, mightBeEnum ]
|
|
576
581
|
@after{ this.attachLocation( $art ); }
|
|
577
582
|
:
|
|
578
583
|
// VIRTUAL is keyword, except if before the following tokens texts:
|
|
@@ -587,13 +592,11 @@ elementDefInner[ art, outer, allowEq ]
|
|
|
587
592
|
}
|
|
588
593
|
)?
|
|
589
594
|
{ this.setLocalToken( 'ELEMENT', 'ELEMENT', /^[:{@=}]$/ ); }
|
|
590
|
-
ELEMENT?
|
|
595
|
+
( ELEMENT { $mightBeEnum = false; } )? // auto-recognizable at other places
|
|
591
596
|
name=ident['Element']
|
|
592
597
|
{ this.addDef( $art, $outer, 'elements', 'element', $name.id );
|
|
593
598
|
this.docComment( $art ); }
|
|
594
599
|
annotationAssignment_fix[ $art ]*
|
|
595
|
-
// TODO: we can think of making the typeSpec optional and do checks instead:
|
|
596
|
-
// type optional with '=', type required otherwise
|
|
597
600
|
(
|
|
598
601
|
typeStruct[ $art ]
|
|
599
602
|
( nullability[ $art ]
|
|
@@ -602,15 +605,14 @@ elementDefInner[ art, outer, allowEq ]
|
|
|
602
605
|
)
|
|
603
606
|
|
|
|
604
607
|
':'
|
|
605
|
-
elementType[ $art ]
|
|
606
|
-
|
|
|
607
|
-
//
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
if (
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
$art.value = $e.expr;
|
|
608
|
+
elementType[ $art, $mightBeEnum ]
|
|
609
|
+
|
|
|
610
|
+
'=' e=expression // SQL has syntax variant using AS - we DO NOT
|
|
611
|
+
{ $art.value = $e.expr;
|
|
612
|
+
// this.setIntroLocation( eq ); -- future
|
|
613
|
+
if ($mightBeEnum && ($e.expr.val !== undefined || $e.expr.sym !== undefined) &&
|
|
614
|
+
!$virtual && !$key && !$masked && !$art.elements && !$art.type)
|
|
615
|
+
$art['$'+'syntax'] = 'enum';
|
|
614
616
|
}
|
|
615
617
|
{ this.docComment( $art ); }
|
|
616
618
|
annotationAssignment_ll1[ $art ]* // for enum symbol def via EXTEND
|
|
@@ -632,11 +634,11 @@ elementType[ art ] // TODO: split this monster rule
|
|
|
632
634
|
typeStruct[ $art.target, true ] optionalSemi
|
|
633
635
|
|
|
|
634
636
|
one=ONE
|
|
635
|
-
{ this.setMaxCardinality( $art,
|
|
637
|
+
{ this.setMaxCardinality( $art, this.numberLiteral( $one, null, '1' ) ); }
|
|
636
638
|
typeCompoStruct[ $art.target ] optionalSemi
|
|
637
639
|
|
|
|
638
640
|
many=MANY
|
|
639
|
-
{ this.setMaxCardinality( $art,
|
|
641
|
+
{ this.setMaxCardinality( $art, { literal: 'string', val: '*' }, $many ); }
|
|
640
642
|
typeCompoStruct[ $art.target ] optionalSemi
|
|
641
643
|
|
|
|
642
644
|
// we do not support `Composition of many { e }` - ambiguity ad-hoc target versus foreign keys!
|
|
@@ -657,15 +659,10 @@ elementType[ art ] // TODO: split this monster rule
|
|
|
657
659
|
nullability[ $art.items ]?
|
|
658
660
|
| // #ATN: typeRefOptArgs/typeTypeOf can start with TYPE
|
|
659
661
|
( typeTypeOf[ $art.items ] | typeRefOptArgs[ $art.items ] )
|
|
660
|
-
nullability[ $art.items ]?
|
|
662
|
+
nullability[ $art.items ]?
|
|
661
663
|
{ this.docComment( $art ); }
|
|
662
664
|
annotationAssignment_ll1[ $art ]*
|
|
663
665
|
(
|
|
664
|
-
{ if ($art.items.notNull) {
|
|
665
|
-
this.message( 'syntax-unexpected-null', $art.items.notNull.location,
|
|
666
|
-
{ keyword: $art.items.notNull.val ? 'not null' : 'null' } );
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
666
|
ENUM '{' { $art.items.enum = this.createDict(); }
|
|
670
667
|
enumSymbolDef[ $art.items ]*
|
|
671
668
|
'}' { this.finalizeDictOrArray( $art.items.enum ); }
|
|
@@ -676,6 +673,7 @@ elementType[ art ] // TODO: split this monster rule
|
|
|
676
673
|
|
|
|
677
674
|
l=LOCALIZED { $art.localized = this.valueWithTokenLocation( true, $l ); }
|
|
678
675
|
typeRefOptArgs[ $art ]
|
|
676
|
+
optInvisibleNullability[ $art ]
|
|
679
677
|
{ this.docComment( $art ); }
|
|
680
678
|
annotationAssignment_ll1[ $art ]*
|
|
681
679
|
( elementProperties[ $art ]
|
|
@@ -685,6 +683,7 @@ elementType[ art ] // TODO: split this monster rule
|
|
|
685
683
|
requiredSemi
|
|
686
684
|
|
|
|
687
685
|
typeTypeOf[ $art ] // Note: Same as the typeRefOptArgs rule below
|
|
686
|
+
optInvisibleNullability[ $art ]
|
|
688
687
|
{ this.docComment( $art ); }
|
|
689
688
|
annotationAssignment_ll1[ $art ]*
|
|
690
689
|
(
|
|
@@ -700,6 +699,7 @@ elementType[ art ] // TODO: split this monster rule
|
|
|
700
699
|
requiredSemi // also req after foreign key spec
|
|
701
700
|
|
|
|
702
701
|
typeRefOptArgs[ $art ] // Note: Same as the typeTypeOf rule above
|
|
702
|
+
optInvisibleNullability[ $art ]
|
|
703
703
|
{ this.docComment( $art ); }
|
|
704
704
|
annotationAssignment_ll1[ $art ]*
|
|
705
705
|
(
|
|
@@ -717,15 +717,13 @@ elementType[ art ] // TODO: split this monster rule
|
|
|
717
717
|
|
|
718
718
|
elementProperties[ elem ]
|
|
719
719
|
:
|
|
720
|
+
defaultValue[ $elem ]
|
|
721
|
+
nullability[ $elem ]? // placement accoring to SQL spec
|
|
722
|
+
|
|
|
720
723
|
nullability[ $elem ]
|
|
721
724
|
defaultValue[ $elem ]?
|
|
722
725
|
|
|
|
723
|
-
|
|
724
|
-
nullability[ $elem ]?
|
|
725
|
-
|
|
|
726
|
-
eq='='
|
|
727
|
-
{ this.error( 'syntax-unsupported-calc-elem', $eq ); }
|
|
728
|
-
e=expression { $elem.value = $e.expr; }
|
|
726
|
+
'=' e=expression { $elem.value = $e.expr; }
|
|
729
727
|
;
|
|
730
728
|
|
|
731
729
|
defaultValue[ art ] locals[ elem, elements = {} ]
|
|
@@ -756,7 +754,7 @@ extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
|
|
|
756
754
|
(
|
|
757
755
|
// all the alternatives from `extendWithOptElementsOrType` --------------
|
|
758
756
|
'{' { $art.elements = this.createDict(); }
|
|
759
|
-
elementDefOrExtend[ $art ]*
|
|
757
|
+
elementDefOrExtend[ $art, true ]*
|
|
760
758
|
'}' { this.finalizeDictOrArray( $art.elements ); }
|
|
761
759
|
{ this.checkExtensionDict( $art.elements ); }
|
|
762
760
|
optionalSemi
|
|
@@ -786,7 +784,7 @@ extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
|
|
|
786
784
|
|
|
|
787
785
|
DEFINITIONS
|
|
788
786
|
'{' { $art.artifacts = this.createDict(); }
|
|
789
|
-
artifactDefOrExtend[ $art,
|
|
787
|
+
artifactDefOrExtend[ $art, 'definitions' ]*
|
|
790
788
|
'}' { this.finalizeDictOrArray( $art.artifacts ); }
|
|
791
789
|
optionalSemi
|
|
792
790
|
|
|
|
@@ -817,7 +815,7 @@ extendService[ art, outer ] locals[ name = {} ]
|
|
|
817
815
|
simplePath[ $name, 'Service' ]
|
|
818
816
|
{ $art.name = $name; this.addItem( $art, $outer, 'extensions', 'extend' ); }
|
|
819
817
|
( WITH { this.noSemicolonHere(); } )?
|
|
820
|
-
optArtifactsBlock[ art, '
|
|
818
|
+
optArtifactsBlock[ art, 'service' ]
|
|
821
819
|
;
|
|
822
820
|
|
|
823
821
|
extendContext[ art, outer ] locals[ name = {} ]
|
|
@@ -827,7 +825,7 @@ extendContext[ art, outer ] locals[ name = {} ]
|
|
|
827
825
|
simplePath[ $name, 'Context' ]
|
|
828
826
|
{ $art.name = $name; this.addItem( $art, $outer, 'extensions', 'extend' ); }
|
|
829
827
|
( WITH { this.noSemicolonHere(); } )?
|
|
830
|
-
optArtifactsBlock[ art, '
|
|
828
|
+
optArtifactsBlock[ art, 'context' ]
|
|
831
829
|
;
|
|
832
830
|
|
|
833
831
|
extendEntityOrAspect[ art, outer ] locals[ name = {} ]
|
|
@@ -924,12 +922,12 @@ extendType[ art, outer ] locals[ name = {} ]
|
|
|
924
922
|
annotationAssignment_ll1[ $art ]*
|
|
925
923
|
(
|
|
926
924
|
'{' { $art.elements = this.createDict(); }
|
|
927
|
-
elementDefOrExtend[ $art ]*
|
|
925
|
+
elementDefOrExtend[ $art, true ]*
|
|
928
926
|
'}' { this.finalizeDictOrArray( $art.elements ); }
|
|
929
927
|
{ this.checkExtensionDict( $art.elements ); }
|
|
930
928
|
optionalSemi
|
|
931
929
|
|
|
|
932
|
-
// extend type
|
|
930
|
+
// extend type Art with (length: 10);
|
|
933
931
|
typeNamedArgList[ $art ]
|
|
934
932
|
requiredSemi
|
|
935
933
|
|
|
|
@@ -949,7 +947,7 @@ extendWithOptElementsOrType[ art ]
|
|
|
949
947
|
annotationAssignment_ll1[ $art ]*
|
|
950
948
|
(
|
|
951
949
|
'{' { $art.elements = this.createDict(); }
|
|
952
|
-
elementDefOrExtend[ $art ]*
|
|
950
|
+
elementDefOrExtend[ $art, true ]*
|
|
953
951
|
'}' { this.finalizeDictOrArray( $art.elements ); }
|
|
954
952
|
{ this.checkExtensionDict( $art.elements ); }
|
|
955
953
|
optionalSemi
|
|
@@ -979,7 +977,7 @@ extendWithOptElementsNoWith[ art ]
|
|
|
979
977
|
annotationAssignment_ll1[ $art ]*
|
|
980
978
|
(
|
|
981
979
|
'{' { $art.elements = this.createDict(); }
|
|
982
|
-
elementDefOrExtend[ $art ]*
|
|
980
|
+
elementDefOrExtend[ $art, true ]*
|
|
983
981
|
'}' { this.finalizeDictOrArray( $art.elements ); }
|
|
984
982
|
{ this.checkExtensionDict( $art.elements ); }
|
|
985
983
|
optionalSemi
|
|
@@ -990,7 +988,7 @@ extendWithOptElementsNoWith[ art ]
|
|
|
990
988
|
|
|
991
989
|
// For `extend … with elements` or `extend entity … with`, `extend aspect … with`,
|
|
992
990
|
// i.e. definitions in { … } are never enums
|
|
993
|
-
elementDefOrExtend[ outer ] locals[ art = {} ]
|
|
991
|
+
elementDefOrExtend[ outer, mightBeEnum = false ] locals[ art = {} ]
|
|
994
992
|
@after { /* #ATN 1 */ } // if ($art) this.attachLocation( $art ); }
|
|
995
993
|
:
|
|
996
994
|
{ $art.location = this.startLocation();; this.docComment( $art ); }
|
|
@@ -1000,7 +998,7 @@ elementDefOrExtend[ outer ] locals[ art = {} ]
|
|
|
1000
998
|
EXTEND
|
|
1001
999
|
extendElement[ $art, $outer ]
|
|
1002
1000
|
|
|
|
1003
|
-
elementDefInner[ $art, $outer,
|
|
1001
|
+
elementDefInner[ $art, $outer, $mightBeEnum ]
|
|
1004
1002
|
)
|
|
1005
1003
|
;
|
|
1006
1004
|
|
|
@@ -1158,6 +1156,7 @@ typeSpec[ art ] // for parameterDef
|
|
|
1158
1156
|
ENUM '{' { $art.enum = this.createDict(); }
|
|
1159
1157
|
enumSymbolDef[ $art ]*
|
|
1160
1158
|
'}' { this.finalizeDictOrArray( $art.enum ); }
|
|
1159
|
+
nullability[ $art ]?
|
|
1161
1160
|
)?
|
|
1162
1161
|
// TODO: no LOCALIZED ?
|
|
1163
1162
|
| typeRefOptArgs[ $art ]
|
|
@@ -1166,6 +1165,7 @@ typeSpec[ art ] // for parameterDef
|
|
|
1166
1165
|
ENUM '{' { $art.enum = this.createDict(); }
|
|
1167
1166
|
enumSymbolDef[ $art ]*
|
|
1168
1167
|
'}' { this.finalizeDictOrArray( $art.enum ); }
|
|
1168
|
+
nullability[ $art ]?
|
|
1169
1169
|
)?
|
|
1170
1170
|
)
|
|
1171
1171
|
;
|
|
@@ -1184,6 +1184,7 @@ returnTypeSpec[ art ]
|
|
|
1184
1184
|
ENUM '{' { $art.returns.enum = this.createDict(); }
|
|
1185
1185
|
enumSymbolDef[ $art.returns ]*
|
|
1186
1186
|
'}' { this.finalizeDictOrArray( $art.returns.enum ); }
|
|
1187
|
+
nullability[ $art.returns ]?
|
|
1187
1188
|
)?
|
|
1188
1189
|
// TODO: no LOCALIZED ?
|
|
1189
1190
|
| typeRefOptArgs[ $art.returns ]
|
|
@@ -1192,6 +1193,7 @@ returnTypeSpec[ art ]
|
|
|
1192
1193
|
ENUM '{' { $art.returns.enum = this.createDict(); }
|
|
1193
1194
|
enumSymbolDef[ $art.returns ]*
|
|
1194
1195
|
'}' { this.finalizeDictOrArray( $art.returns.enum ); }
|
|
1196
|
+
nullability[ $art.returns ]?
|
|
1195
1197
|
)?
|
|
1196
1198
|
)
|
|
1197
1199
|
|
|
@@ -1235,21 +1237,11 @@ typeSpecSemi[ art ] // with 'includes', for type and annotation defs
|
|
|
1235
1237
|
( typeStruct[ $art.items ]
|
|
1236
1238
|
nullability[ $art.items ]?
|
|
1237
1239
|
optionalSemi
|
|
1238
|
-
| typeTypeOf[ $art.items ]
|
|
1240
|
+
| ( typeTypeOf[ $art.items ] | typeRefOptArgs[ $art.items ] )
|
|
1239
1241
|
nullability[ $art.items ]?
|
|
1240
1242
|
{ this.docComment( $art ); }
|
|
1241
1243
|
annotationAssignment_ll1[ $art ]*
|
|
1242
|
-
requiredSemi
|
|
1243
|
-
| typeRefOptArgs[ $art.items ]
|
|
1244
|
-
nullability[ $art.items ]? // only if not followed by `enum`
|
|
1245
|
-
{ this.docComment( $art ); }
|
|
1246
|
-
annotationAssignment_ll1[ $art ]*
|
|
1247
1244
|
(
|
|
1248
|
-
{ if ($art.items.notNull) {
|
|
1249
|
-
this.message( 'syntax-unexpected-null', $art.items.notNull.location,
|
|
1250
|
-
{ keyword: $art.items.notNull.val ? 'not null' : 'null' } );
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
1245
|
ENUM '{' { $art.items.enum = this.createDict(); }
|
|
1254
1246
|
enumSymbolDef[ $art.items ]*
|
|
1255
1247
|
'}' { this.finalizeDictOrArray( $art.items.enum ); }
|
|
@@ -1348,6 +1340,7 @@ typeArray[ art ]
|
|
|
1348
1340
|
ENUM '{' { $art.items.enum = this.createDict(); }
|
|
1349
1341
|
enumSymbolDef[ $art.items ]*
|
|
1350
1342
|
'}' { this.finalizeDictOrArray( $art.items.enum ); }
|
|
1343
|
+
nullability[ $art.items ]?
|
|
1351
1344
|
)?
|
|
1352
1345
|
| typeRefOptArgs[ $art.items ]
|
|
1353
1346
|
nullability[ $art.items ]?
|
|
@@ -1355,6 +1348,7 @@ typeArray[ art ]
|
|
|
1355
1348
|
ENUM '{' { $art.items.enum = this.createDict(); }
|
|
1356
1349
|
enumSymbolDef[ $art.items ]*
|
|
1357
1350
|
'}' { this.finalizeDictOrArray( $art.items.enum ); }
|
|
1351
|
+
nullability[ $art.items ]?
|
|
1358
1352
|
)?
|
|
1359
1353
|
)
|
|
1360
1354
|
;
|
|
@@ -1423,14 +1417,14 @@ typeAssociationElementCont[ art ] // including Composition
|
|
|
1423
1417
|
typeToOne[ art ]
|
|
1424
1418
|
:
|
|
1425
1419
|
one=ONE
|
|
1426
|
-
{ this.setMaxCardinality( $art,
|
|
1420
|
+
{ this.setMaxCardinality( $art, this.numberLiteral( $one, null, '1' ) ); }
|
|
1427
1421
|
simplePath[ $art.target, 'artref' ]
|
|
1428
1422
|
;
|
|
1429
1423
|
|
|
1430
1424
|
typeToMany[ art ]
|
|
1431
1425
|
:
|
|
1432
1426
|
many=MANY
|
|
1433
|
-
{ this.setMaxCardinality( $art,
|
|
1427
|
+
{ this.setMaxCardinality( $art, { literal: 'string', val: '*' }, $many ); }
|
|
1434
1428
|
simplePath[ $art.target, 'artref' ]
|
|
1435
1429
|
;
|
|
1436
1430
|
|
|
@@ -1467,13 +1461,18 @@ cardinality[ art ] locals[ card = {} ]
|
|
|
1467
1461
|
']'
|
|
1468
1462
|
;
|
|
1469
1463
|
|
|
1464
|
+
// TO be used when NOT and NULL are already in the lookahead set:
|
|
1465
|
+
optInvisibleNullability[ art ]
|
|
1466
|
+
: { this.setLocalTokenForId( 1, { 'NOT': 'HelperToken1', 'NULL': 'HelperToken2' } ); }
|
|
1467
|
+
( n1=HelperToken1 n2=NULL { this.setNullability( $art, $n1, $n2 ); }
|
|
1468
|
+
| n1=HelperToken2 { this.setNullability( $art, $n1, null ); }
|
|
1469
|
+
)?
|
|
1470
|
+
;
|
|
1471
|
+
|
|
1470
1472
|
nullability[ art ]
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
|
1475
|
-
n2=NULL
|
|
1476
|
-
{ $art.notNull = this.valueWithTokenLocation( false, $n2 ); }
|
|
1473
|
+
@after{ this.setNullability( $art, $n1, $n2 ); }
|
|
1474
|
+
: n1=NOT n2=NULL
|
|
1475
|
+
| n1=NULL
|
|
1477
1476
|
;
|
|
1478
1477
|
|
|
1479
1478
|
foreignKey[ outer ] locals[ art = {}, elem = {} ]
|
|
@@ -1806,29 +1805,16 @@ projectionExclusion[ outer ] locals[ art = {} ]
|
|
|
1806
1805
|
// Actually, this is a subset if elementDefInner...
|
|
1807
1806
|
// TODO: the corresponding restrictions must also be checked in the core
|
|
1808
1807
|
// compiler, as the mixin element could come via CSN
|
|
1809
|
-
mixinElementDef[ outer ] locals[ art = {} ]
|
|
1810
|
-
@after { /* #ATN
|
|
1808
|
+
mixinElementDef[ outer ] locals[ art = { target: {} } ]
|
|
1809
|
+
@after { /* #ATN 1 */ this.attachLocation($art); }
|
|
1811
1810
|
:
|
|
1812
|
-
name=ident['Mixin']
|
|
1813
|
-
|
|
1814
|
-
(
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
// #ATN: path could start with MANY or ONE - make sure a token follows in same rule!
|
|
1820
|
-
( typeToMany[ $art ] | typeToOne[ $art ] | simplePath[ $art.target, 'artref' ] )
|
|
1821
|
-
typeAssociationCont[ $art ]?
|
|
1822
|
-
|
|
|
1823
|
-
typeRefOptArgs[ $art ]
|
|
1824
|
-
( as='=' expression
|
|
1825
|
-
{ this.error( 'syntax-unsupported-calc-elem', $as ); }
|
|
1826
|
-
)?
|
|
1827
|
-
)
|
|
1828
|
-
|
|
|
1829
|
-
as='=' expression
|
|
1830
|
-
{ this.error( 'syntax-unsupported-calc-elem', $as ); }
|
|
1831
|
-
)
|
|
1811
|
+
name=ident['Mixin'] ':'
|
|
1812
|
+
typeAssociationBase[ $art, false ]
|
|
1813
|
+
{ if ($art.type) this.addDef( $art, $outer, 'mixin', 'mixin', $name.id ); }
|
|
1814
|
+
// #ATN: path could start with MANY or ONE - make sure a token follows in same rule!
|
|
1815
|
+
( typeToMany[ $art ] | typeToOne[ $art ] | simplePath[ $art.target, 'artref' ] )
|
|
1816
|
+
// TODO CC: exclude every token other than ON
|
|
1817
|
+
typeAssociationCont[ $art ]? // better error reporting than simply `ON condition`
|
|
1832
1818
|
requiredSemi
|
|
1833
1819
|
;
|
|
1834
1820
|
|
|
@@ -1866,7 +1852,6 @@ selectItemDefBody[ art, outer ] locals[ assoc ]
|
|
|
1866
1852
|
{ this.reportExpandInline( $art, false ); }
|
|
1867
1853
|
selectItemInlineList[ $art, 'expand' ]
|
|
1868
1854
|
excludingClause[ $art ]?
|
|
1869
|
-
// TODO: we might alternatively allow AS here
|
|
1870
1855
|
|
|
|
1871
1856
|
{ this.reportExpandInline( $art, $as || this._input.LT(-1) ); }
|
|
1872
1857
|
DOTbeforeBRACE // ...orASTERISK
|
|
@@ -2056,7 +2041,7 @@ conditionEOF returns [ cond ]
|
|
|
2056
2041
|
;
|
|
2057
2042
|
|
|
2058
2043
|
condition returns [ cond ] locals[ args = [] ]
|
|
2059
|
-
@after{ $cond = this.argsExpression( $args ); }
|
|
2044
|
+
@after{ $cond = this.argsExpression( $args, true ); }
|
|
2060
2045
|
:
|
|
2061
2046
|
c1=conditionAnd { $args.push($c1.cond); }
|
|
2062
2047
|
(
|
|
@@ -2066,7 +2051,7 @@ condition returns [ cond ] locals[ args = [] ]
|
|
|
2066
2051
|
;
|
|
2067
2052
|
|
|
2068
2053
|
conditionAnd returns [ cond ] locals[ args = [] ]
|
|
2069
|
-
@after{ $cond = this.argsExpression( $args,
|
|
2054
|
+
@after{ $cond = this.argsExpression( $args, 'and' ); } // 'and' used by A2J and checks
|
|
2070
2055
|
:
|
|
2071
2056
|
c1=conditionTerm { $args.push($c1.cond); }
|
|
2072
2057
|
(
|
|
@@ -2077,7 +2062,7 @@ conditionAnd returns [ cond ] locals[ args = [] ]
|
|
|
2077
2062
|
|
|
2078
2063
|
// Note: New operators need to be added to functionExpressionOperatorsRequireParentheses[] in toCdl.js.
|
|
2079
2064
|
conditionTerm returns [ cond ] locals[ args = [] ]
|
|
2080
|
-
@after{ $cond = this.argsExpression( $args,
|
|
2065
|
+
@after{ $cond = this.argsExpression( $args, '=' ); }// op: '=' (not nary) used by A2J and checks
|
|
2081
2066
|
:
|
|
2082
2067
|
nt=NOT { this.pushXprToken( $args ); }
|
|
2083
2068
|
ct=conditionTerm { $args.push( $ct.cond ); }
|
|
@@ -2133,7 +2118,7 @@ predicate[ args ]
|
|
|
2133
2118
|
;
|
|
2134
2119
|
|
|
2135
2120
|
expression returns [ expr ] locals [ args = [] ]
|
|
2136
|
-
@after{ $expr = this.argsExpression( $args ); }
|
|
2121
|
+
@after{ $expr = this.argsExpression( $args, true ); }
|
|
2137
2122
|
:
|
|
2138
2123
|
e1=expressionSum { $args.push( $e1.expr ); }
|
|
2139
2124
|
(
|
|
@@ -2143,7 +2128,7 @@ expression returns [ expr ] locals [ args = [] ]
|
|
|
2143
2128
|
;
|
|
2144
2129
|
|
|
2145
2130
|
expressionSum returns [ expr ] locals [ args = [] ]
|
|
2146
|
-
@after{ $expr = this.argsExpression( $args ); }
|
|
2131
|
+
@after{ $expr = this.argsExpression( $args, true ); }
|
|
2147
2132
|
:
|
|
2148
2133
|
e1=expressionFactor { $args.push( $e1.expr ); }
|
|
2149
2134
|
(
|
|
@@ -2153,7 +2138,7 @@ expressionSum returns [ expr ] locals [ args = [] ]
|
|
|
2153
2138
|
;
|
|
2154
2139
|
|
|
2155
2140
|
expressionFactor returns [ expr ] locals [ args = [] ]
|
|
2156
|
-
@after{ $expr = this.argsExpression( $args ); }
|
|
2141
|
+
@after{ $expr = this.argsExpression( $args, true ); }
|
|
2157
2142
|
:
|
|
2158
2143
|
e1=expressionTerm { $args.push( $e1.expr ); }
|
|
2159
2144
|
(
|
|
@@ -2163,7 +2148,7 @@ expressionFactor returns [ expr ] locals [ args = [] ]
|
|
|
2163
2148
|
;
|
|
2164
2149
|
|
|
2165
2150
|
expressionTerm returns [ expr ] locals [ args = [] ]
|
|
2166
|
-
@after{ /* #ATN 1 */ $expr = this.argsExpression( $args ); }
|
|
2151
|
+
@after{ /* #ATN 1 */ $expr = this.argsExpression( $args, false ); }
|
|
2167
2152
|
:
|
|
2168
2153
|
( '+' | '-' ) { this.pushXprToken( $args ); }
|
|
2169
2154
|
e1=expressionTerm // prefix op or part of the number
|
|
@@ -2210,12 +2195,13 @@ expressionTerm returns [ expr ] locals [ args = [] ]
|
|
|
2210
2195
|
{ $args[0].suffix.push( this.surroundByParens( $over.over, $open, $close ) ); }
|
|
2211
2196
|
)?
|
|
2212
2197
|
|
|
|
2213
|
-
':'
|
|
2198
|
+
colon=':' { this.reportUnexpectedSpace( $colon ); }
|
|
2214
2199
|
(
|
|
2215
2200
|
vp=valuePath[ 'paramref', this.startLocation() ]
|
|
2216
2201
|
{{ const par = $vp.qp;; par.scope = 'param';; $args.push( par ); }}
|
|
2217
2202
|
|
|
|
2218
2203
|
pp=Number
|
|
2204
|
+
// TODO: no extra XSN property `param` for this, re-use `val`
|
|
2219
2205
|
{ $args.push( { param: this.numberLiteral( $pp ), scope: 'param' } );
|
|
2220
2206
|
this.csnParseOnly( 'syntax-unsupported-param', [ $pp ], { '#': 'positional', code: ':' + $pp.text } );
|
|
2221
2207
|
}
|
|
@@ -2224,6 +2210,7 @@ expressionTerm returns [ expr ] locals [ args = [] ]
|
|
|
2224
2210
|
qm= '?' // is automatically not mentioned as CC candidate
|
|
2225
2211
|
// if we have an HideAlternatives here, we would block it to use it in
|
|
2226
2212
|
// parallel to an expression (would produce adaptivePredict() otherwise)
|
|
2213
|
+
// TODO: no extra XSN property `param` for this, re-use `val`
|
|
2227
2214
|
{ $args.push( { param: this.valueWithTokenLocation( '?', $qm ), scope: 'param' } );
|
|
2228
2215
|
this.csnParseOnly( 'syntax-unsupported-param', [ $qm ], { '#': 'dynamic', code: '?' } );
|
|
2229
2216
|
}
|
|
@@ -2315,7 +2302,7 @@ pathArguments[ pathStep, considerSpecial ]
|
|
|
2315
2302
|
// For code completion, we need to handle generic tokens directly after the
|
|
2316
2303
|
// '('. To avoid invalidating an assoc `trim` to an entity with parameter
|
|
2317
2304
|
// `leading` (ok, a bit constructed), we do not do it with named parameters.
|
|
2318
|
-
{ if (!this.setLocalTokenForId( { ':': 'HelperToken1', '=>': 'HelperToken2' } ))
|
|
2305
|
+
{ if (!this.setLocalTokenForId( 2, { ':': 'HelperToken1', '=>': 'HelperToken2' } ))
|
|
2319
2306
|
this.prepareGenericKeywords( $considerSpecial ); }
|
|
2320
2307
|
(
|
|
2321
2308
|
{ $pathStep.args = this.createDict(); $pathStep['$'+'syntax'] = ':'; }
|
|
@@ -2366,7 +2353,7 @@ namedExpression[ pathStep, id ]
|
|
|
2366
2353
|
|
|
2367
2354
|
funcExpression[ pathStep, considerSpecial ] locals[ args = [] ]
|
|
2368
2355
|
@init { this.prepareGenericKeywords( $considerSpecial ); }
|
|
2369
|
-
@after{ $pathStep.args.push( this.argsExpression( $args,
|
|
2356
|
+
@after{ $pathStep.args.push( this.argsExpression( $args, false ) ); }
|
|
2370
2357
|
:
|
|
2371
2358
|
(
|
|
2372
2359
|
expr=expression
|
|
@@ -2417,9 +2404,8 @@ funcExpression[ pathStep, considerSpecial ] locals[ args = [] ]
|
|
|
2417
2404
|
;
|
|
2418
2405
|
|
|
2419
2406
|
overClause returns[ over ] locals[ args = [] ]
|
|
2420
|
-
@after{ $over = this.argsExpression( $args ); }
|
|
2407
|
+
@after{ $over = this.argsExpression( $args, false ); }
|
|
2421
2408
|
:
|
|
2422
|
-
// TODO: empty really allowed?
|
|
2423
2409
|
( PARTITION { this.pushXprToken( $args ); } BY { this.pushXprToken( $args ); }
|
|
2424
2410
|
pb=partitionByClause { $args.push( $pb.expr ); }
|
|
2425
2411
|
)?
|
|
@@ -2432,7 +2418,7 @@ overClause returns[ over ] locals[ args = [] ]
|
|
|
2432
2418
|
;
|
|
2433
2419
|
|
|
2434
2420
|
partitionByClause returns [ expr ] locals[ args = [] ]
|
|
2435
|
-
@after{ $expr = this.argsExpression( $args ); }
|
|
2421
|
+
@after{ $expr = this.argsExpression( $args, false ); }
|
|
2436
2422
|
:
|
|
2437
2423
|
e1=expression { $args.push( $e1.expr ); }
|
|
2438
2424
|
( ',' { this.pushXprToken( $args ); }
|
|
@@ -2442,7 +2428,7 @@ partitionByClause returns [ expr ] locals[ args = [] ]
|
|
|
2442
2428
|
|
|
2443
2429
|
// ORDER BY clause in generic functions, e.g. `first_value(id order by name)`
|
|
2444
2430
|
funcOrderByClause[ args ] returns[ expr ]
|
|
2445
|
-
@after{ $expr = this.argsExpression( args,
|
|
2431
|
+
@after{ $expr = this.argsExpression( $args, false, $args[0]?.location ); }
|
|
2446
2432
|
:
|
|
2447
2433
|
ORDER { this.pushXprToken( $args ); } BY { this.pushXprToken( $args ); }
|
|
2448
2434
|
ob=exprOrderByClause { $args.push( $ob.expr ); }
|
|
@@ -2450,7 +2436,7 @@ funcOrderByClause[ args ] returns[ expr ]
|
|
|
2450
2436
|
|
|
2451
2437
|
// ORDER BY clause in generic functions or OVER clause
|
|
2452
2438
|
exprOrderByClause returns[ expr ] locals[ args = [] ]
|
|
2453
|
-
@after{ $expr = this.argsExpression( $args ); }
|
|
2439
|
+
@after{ $expr = this.argsExpression( $args, false ); }
|
|
2454
2440
|
:
|
|
2455
2441
|
orderBySpecInExpr[ $args ]
|
|
2456
2442
|
( ',' { this.pushXprToken( $args ); } orderBySpecInExpr[ $args ] )*
|
|
@@ -2468,7 +2454,7 @@ orderBySpecInExpr[ args ]
|
|
|
2468
2454
|
;
|
|
2469
2455
|
|
|
2470
2456
|
windowFrameClause returns[ wf ] locals[ args = [] ]
|
|
2471
|
-
@after{ $wf = this.argsExpression( $args ); }
|
|
2457
|
+
@after{ $wf = this.argsExpression( $args, false ); }
|
|
2472
2458
|
:
|
|
2473
2459
|
(
|
|
2474
2460
|
windowFrameStartSpec[ $args ]
|
|
@@ -2517,7 +2503,7 @@ optionalCardinality[ pathStep ]
|
|
|
2517
2503
|
:
|
|
2518
2504
|
// Make sure to test second token to allow expressions starting with Number
|
|
2519
2505
|
// without introducing WHERE - that would be @options{k=2}. The code
|
|
2520
|
-
// completion just produces `:`after having inserted a Number - TODO.
|
|
2506
|
+
// completion just produces `:` after having inserted a Number - TODO.
|
|
2521
2507
|
{ if (this._input.LT(2).text !== ':') return $ctx; }
|
|
2522
2508
|
( trgMax=Number ':'
|
|
2523
2509
|
{ if ($pathStep) $pathStep.cardinality = { targetMax: this.numberLiteral( $trgMax ), location: this.startLocation() }; }
|
|
@@ -2547,7 +2533,7 @@ optionalWhereForFilter
|
|
|
2547
2533
|
// - "atn": at the beginning of a column definition
|
|
2548
2534
|
//
|
|
2549
2535
|
// want to let the ambiguity in select items (solution: "either" possibility)
|
|
2550
|
-
//
|
|
2536
|
+
//
|
|
2551
2537
|
// entity E @Anno: Base { … }; // Base is include (chosen w/ warning) or @Anno value?
|
|
2552
2538
|
// entity V(p) as select from E { // either: anno value "ref p", select item -x
|
|
2553
2539
|
// @anno :p - x as x; // or: anno value true, select item :p-x
|
|
@@ -2561,7 +2547,7 @@ annotationAssignment_fix[ art ] locals[ assignment ]
|
|
|
2561
2547
|
this.docComment( $art );
|
|
2562
2548
|
}
|
|
2563
2549
|
} :
|
|
2564
|
-
'@'
|
|
2550
|
+
at='@' { this.reportUnexpectedSpace( $at ); }
|
|
2565
2551
|
(
|
|
2566
2552
|
annotationAssignment_paren[ $art ]
|
|
2567
2553
|
|
|
|
@@ -2579,7 +2565,7 @@ annotationAssignment_ll1[ art ] locals[ assignment ]
|
|
|
2579
2565
|
this.docComment( $art );
|
|
2580
2566
|
}
|
|
2581
2567
|
} :
|
|
2582
|
-
'@'
|
|
2568
|
+
at='@' { this.reportUnexpectedSpace( $at ); }
|
|
2583
2569
|
(
|
|
2584
2570
|
annotationAssignment_paren[ $art ]
|
|
2585
2571
|
|
|
|
@@ -2601,7 +2587,7 @@ annotationAssignment_atn[ art ] locals[ assignment ]
|
|
|
2601
2587
|
this.docComment( $art );
|
|
2602
2588
|
}
|
|
2603
2589
|
} :
|
|
2604
|
-
'@'
|
|
2590
|
+
at='@' { this.reportUnexpectedSpace( $at ); }
|
|
2605
2591
|
(
|
|
2606
2592
|
annotationAssignment_paren[ $art ]
|
|
2607
2593
|
|
|
|
@@ -2612,7 +2598,8 @@ annotationAssignment_atn[ art ] locals[ assignment ]
|
|
|
2612
2598
|
// -> used to introduce variant name if and only if in same line as previous token
|
|
2613
2599
|
{ this.setLocalToken( '#', 'HelperToken1', null, true ); }
|
|
2614
2600
|
(
|
|
2615
|
-
HelperToken1
|
|
2601
|
+
hash=HelperToken1
|
|
2602
|
+
{ this.meltKeywordToIdentifier();; this.reportUnexpectedSpace( $hash ); }
|
|
2616
2603
|
variant=ident['variant'] { $assignment.name.variant = $variant.id; }
|
|
2617
2604
|
)?
|
|
2618
2605
|
// ':' is in the follow set of this rule, as it is used in rule "selectItemDef"
|
|
@@ -2624,10 +2611,11 @@ annotationAssignment_atn[ art ] locals[ assignment ]
|
|
|
2624
2611
|
(
|
|
2625
2612
|
val=annoValueBase[ $assignment ]
|
|
2626
2613
|
|
|
|
2627
|
-
|
|
2614
|
+
atv='@'? annotationPath[ $assignment, 'ref', $atv ]
|
|
2628
2615
|
{ this.setLocalToken( '#', 'HelperToken1', null, true ); } // see above
|
|
2629
2616
|
(
|
|
2630
|
-
HelperToken1
|
|
2617
|
+
hash=HelperToken1
|
|
2618
|
+
{ this.meltKeywordToIdentifier();; this.reportUnexpectedSpace( $hash ); }
|
|
2631
2619
|
variant=ident['variant'] { $assignment.variant = $variant.id; }
|
|
2632
2620
|
)?
|
|
2633
2621
|
)
|
|
@@ -2638,15 +2626,10 @@ annotationAssignment_atn[ art ] locals[ assignment ]
|
|
|
2638
2626
|
annotationAssignment_paren[ art ]
|
|
2639
2627
|
:
|
|
2640
2628
|
'('
|
|
2641
|
-
// allow completely useless `@()
|
|
2629
|
+
// allow completely useless `@()`; no warning anymore - who cares?
|
|
2642
2630
|
{
|
|
2643
2631
|
this.meltKeywordToIdentifier();
|
|
2644
2632
|
if (this.isStraightBefore(')')) {
|
|
2645
|
-
// TODO: or should we simple accept this without warning? (but still no CC)
|
|
2646
|
-
this.warning( 'syntax-unexpected-right-paren',
|
|
2647
|
-
this.tokenLocation( this.getCurrentToken() ),
|
|
2648
|
-
{ offending: "')'", expecting: ['Identifier'], code: '@()' },
|
|
2649
|
-
'Unexpected $(OFFENDING), expecting $(EXPECTING); ignoring $(CODE)' );
|
|
2650
2633
|
this.matchWildcard(); // we know it is the ')' - we do not reach the final match
|
|
2651
2634
|
return $ctx;
|
|
2652
2635
|
}
|
|
@@ -2695,7 +2678,7 @@ annotationPathVariant[ art ] locals[ variant = {} ]
|
|
|
2695
2678
|
@after { this.attachLocation($art); }
|
|
2696
2679
|
:
|
|
2697
2680
|
// TODO: warning for space after '#'
|
|
2698
|
-
'#' { this.meltKeywordToIdentifier(); }
|
|
2681
|
+
hash='#' { this.meltKeywordToIdentifier();; this.reportUnexpectedSpace( $hash ); }
|
|
2699
2682
|
simplePath[ $variant, 'variant' ] { $art.variant = $variant; }
|
|
2700
2683
|
;
|
|
2701
2684
|
|
|
@@ -2832,7 +2815,8 @@ literalValue returns[ val ] locals[ tok ]
|
|
|
2832
2815
|
@init{ $tok = this.getCurrentToken(); }
|
|
2833
2816
|
@after { this.attachLocation($val); }
|
|
2834
2817
|
:
|
|
2835
|
-
'#'
|
|
2818
|
+
hash='#' { this.meltKeywordToIdentifier();; this.reportUnexpectedSpace( $hash ); }
|
|
2819
|
+
name=ident['enumref'] // TODO v4: remove from this rule (not in enum!)
|
|
2836
2820
|
{ $val = { literal: 'enum', sym: $name.id } }
|
|
2837
2821
|
|
|
|
2838
2822
|
NULL
|