@sap/cds-compiler 2.4.4 → 2.10.2
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 +241 -1
- package/bin/.eslintrc.json +17 -0
- package/bin/cds_update_identifiers.js +8 -7
- package/bin/cdsc.js +180 -132
- package/bin/cdshi.js +18 -11
- package/bin/cdsse.js +38 -32
- package/bin/cdsv2m.js +8 -7
- package/doc/CHANGELOG_BETA.md +36 -1
- package/lib/api/main.js +81 -100
- package/lib/api/options.js +17 -11
- package/lib/api/validate.js +12 -8
- package/lib/backends.js +0 -81
- package/lib/base/keywords.js +32 -2
- package/lib/base/location.js +2 -2
- package/lib/base/message-registry.js +66 -4
- package/lib/base/messages.js +84 -27
- package/lib/base/model.js +2 -61
- package/lib/checks/arrayOfs.js +0 -1
- package/lib/checks/defaultValues.js +27 -2
- package/lib/checks/elements.js +1 -6
- package/lib/checks/enricher.js +8 -2
- package/lib/checks/foreignKeys.js +0 -6
- package/lib/checks/managedWithoutKeys.js +17 -0
- package/lib/checks/nonexpandableStructured.js +38 -0
- package/lib/checks/onConditions.js +9 -45
- package/lib/checks/queryNoDbArtifacts.js +27 -9
- package/lib/checks/selectItems.js +25 -2
- package/lib/checks/types.js +26 -2
- package/lib/checks/unknownMagic.js +38 -0
- package/lib/checks/utils.js +61 -0
- package/lib/checks/validator.js +66 -13
- package/lib/compiler/assert-consistency.js +24 -12
- package/lib/compiler/builtins.js +2 -0
- package/lib/compiler/checks.js +6 -4
- package/lib/compiler/definer.js +101 -39
- package/lib/compiler/index.js +88 -59
- package/lib/compiler/resolver.js +455 -209
- package/lib/compiler/shared.js +57 -33
- package/lib/edm/annotations/genericTranslation.js +183 -187
- package/lib/edm/csn2edm.js +128 -99
- package/lib/edm/edm.js +18 -21
- package/lib/edm/edmPreprocessor.js +361 -127
- package/lib/edm/edmUtils.js +103 -33
- package/lib/gen/Dictionary.json +74 -28
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +18 -4
- package/lib/gen/language.tokens +124 -118
- package/lib/gen/languageLexer.interp +13 -1
- package/lib/gen/languageLexer.js +870 -839
- package/lib/gen/languageLexer.tokens +116 -111
- package/lib/gen/languageParser.js +5894 -5614
- package/lib/json/from-csn.js +152 -67
- package/lib/json/to-csn.js +334 -135
- package/lib/language/antlrParser.js +4 -3
- package/lib/language/errorStrategy.js +1 -0
- package/lib/language/genericAntlrParser.js +24 -14
- package/lib/language/language.g4 +188 -128
- package/lib/main.d.ts +435 -0
- package/lib/main.js +31 -7
- package/lib/model/api.js +78 -0
- package/lib/model/csnRefs.js +463 -187
- package/lib/model/csnUtils.js +280 -136
- package/lib/model/enrichCsn.js +75 -4
- package/lib/model/revealInternalProperties.js +2 -1
- package/lib/modelCompare/compare.js +70 -25
- package/lib/optionProcessor.js +13 -10
- package/lib/render/.eslintrc.json +4 -1
- package/lib/render/DuplicateChecker.js +8 -5
- package/lib/render/toCdl.js +123 -40
- package/lib/render/toHdbcds.js +156 -65
- package/lib/render/toSql.js +87 -11
- package/lib/render/utils/common.js +55 -9
- package/lib/render/utils/sql.js +3 -3
- package/lib/sql-identifier.js +6 -1
- package/lib/transform/{sql → db}/.eslintrc.json +0 -0
- package/lib/transform/{sql → db}/assertUnique.js +7 -8
- package/lib/transform/{sql → db}/constraints.js +35 -20
- package/lib/transform/db/draft.js +353 -0
- package/lib/transform/db/expansion.js +582 -0
- package/lib/transform/db/flattening.js +325 -0
- package/lib/transform/{sql → db}/groupByOrderBy.js +8 -16
- package/lib/transform/{sql → db}/helpers.js +0 -0
- package/lib/transform/{sql → db}/transformExists.js +256 -60
- package/lib/transform/forHanaNew.js +216 -765
- package/lib/transform/forOdataNew.js +60 -56
- package/lib/transform/localized.js +48 -26
- package/lib/transform/odata/attachPath.js +19 -4
- package/lib/transform/odata/expandStructKeysInAssociations.js +2 -2
- package/lib/transform/odata/generateForeignKeyElements.js +13 -12
- package/lib/transform/odata/referenceFlattener.js +60 -36
- package/lib/transform/odata/sortByAssociationDependency.js +4 -4
- package/lib/transform/odata/structuralPath.js +76 -0
- package/lib/transform/odata/structureFlattener.js +21 -22
- package/lib/transform/odata/toFinalBaseType.js +5 -5
- package/lib/transform/odata/typesExposure.js +27 -17
- package/lib/transform/odata/utils.js +2 -2
- package/lib/transform/transformUtilsNew.js +141 -77
- package/lib/transform/translateAssocsToJoins.js +17 -14
- package/lib/transform/universalCsnEnricher.js +67 -0
- package/lib/utils/file.js +0 -11
- package/lib/utils/moduleResolve.js +6 -8
- package/lib/utils/timetrace.js +6 -1
- package/package.json +2 -1
- package/lib/base/deepCopy.js +0 -66
- package/lib/json/walker.js +0 -26
- package/lib/utils/string.js +0 -17
package/lib/language/language.g4
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
// allow integers at certain places), one token type for non-quoted and
|
|
21
21
|
// quoted identifiers.
|
|
22
22
|
//
|
|
23
|
-
// * Keep the number of keywords as small as
|
|
23
|
+
// * Keep the number of keywords as small as possible. Thus, built-ins is a
|
|
24
24
|
// topic for the semantic analysis, not the grammar. Examples: no keywords
|
|
25
25
|
// for built-in types or built-in SQL functions. This also avoids noise in
|
|
26
26
|
// the grammar and a huge/slow generated parser.
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
// is not enough for a decision), write a comment starting with `#ATN:`
|
|
44
44
|
// which describes the ambiguity. Additionally, put a comment `/* #ATN n
|
|
45
45
|
// */` INSIDE an (`@after`) action of a rule if the corresponding function
|
|
46
|
-
// in '../gen/
|
|
46
|
+
// in '../gen/languageParser.js' contains `n` occurrences of
|
|
47
47
|
// `adaptivePredict` calls. This is checked in 'test/testCompiler.js',
|
|
48
48
|
// which also counts the total number of `adaptivePredict` occurrences.
|
|
49
49
|
// └─────────────────────────────────────────────────────────────────────────┘
|
|
@@ -55,6 +55,10 @@
|
|
|
55
55
|
// good idea anyway to avoid calls to `adaptivePredict`, see the rules
|
|
56
56
|
// starting with `annotationAssignment_`.
|
|
57
57
|
//
|
|
58
|
+
// * Factoring out a sub rule into a named rule influences the error recovery:
|
|
59
|
+
// the parser tries to consume all tokens which are neither in the follow
|
|
60
|
+
// set of loops and named rules. So be careful.
|
|
61
|
+
//
|
|
58
62
|
// * Do not use actions in the lexer. Examples: de-quote string literals not
|
|
59
63
|
// in the lexer, but in the parser; do not throw errors, but produce error
|
|
60
64
|
// tokens if necessary.
|
|
@@ -106,6 +110,9 @@
|
|
|
106
110
|
//
|
|
107
111
|
// * The ANTLR error "missing attribute access on rule reference c in $c" can
|
|
108
112
|
// be solved with using $ctx.c instead of $c
|
|
113
|
+
//
|
|
114
|
+
// * If you want to set a property starting with '$' like $syntax, use
|
|
115
|
+
// obj['$'+'syntax'] as the ANTLR tool would replace $syntax by $ctx.syntax
|
|
109
116
|
|
|
110
117
|
grammar language;
|
|
111
118
|
options {
|
|
@@ -114,6 +121,7 @@ options {
|
|
|
114
121
|
}
|
|
115
122
|
tokens {
|
|
116
123
|
VIRTUAL, // used with setLocalToken()
|
|
124
|
+
OVER, // used with setLocalTokenIfBefore()
|
|
117
125
|
HelperToken1, // used with setLocalToken(), does not appear in messages
|
|
118
126
|
HelperToken2, // used with setLocalToken(), does not appear in messages
|
|
119
127
|
HideAlternatives, // hide alternative tokens (no token seq!)
|
|
@@ -491,17 +499,7 @@ projectionSpec returns[ query ] locals[ src ]
|
|
|
491
499
|
)?
|
|
492
500
|
( AS aliasName=ident['FromAlias'] { $src.name = $aliasName.id } )?
|
|
493
501
|
bracedSelectItemListDef[ $query ]?
|
|
494
|
-
|
|
495
|
-
// syntax is less than ideal - EXCLUDING is only useful for `*` - with
|
|
496
|
-
// this syntax, people wonder what happens with explicit select items
|
|
497
|
-
EXCLUDING
|
|
498
|
-
'{'
|
|
499
|
-
projectionExclusion[ $query ]
|
|
500
|
-
( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
|
|
501
|
-
projectionExclusion[ $query ]
|
|
502
|
-
)*
|
|
503
|
-
'}'
|
|
504
|
-
)?
|
|
502
|
+
excludingClause[ $query ]?
|
|
505
503
|
;
|
|
506
504
|
|
|
507
505
|
projectionClauses[ query ]
|
|
@@ -518,6 +516,18 @@ projectionClauses[ query ]
|
|
|
518
516
|
( lc=limitClause[ $query ] { $query = $lc.query; } ) ?
|
|
519
517
|
;
|
|
520
518
|
|
|
519
|
+
excludingClause[ query ]
|
|
520
|
+
:
|
|
521
|
+
// syntax is less than ideal - EXCLUDING is only useful for `*` - with
|
|
522
|
+
// this syntax, people wonder what happens with explicit select items
|
|
523
|
+
EXCLUDING '{'
|
|
524
|
+
projectionExclusion[ $query ]
|
|
525
|
+
( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
|
|
526
|
+
projectionExclusion[ $query ]
|
|
527
|
+
)*
|
|
528
|
+
'}'
|
|
529
|
+
;
|
|
530
|
+
|
|
521
531
|
projectionExclusion[ outer ] locals[ art ]
|
|
522
532
|
@after { this.attachLocation($art); }
|
|
523
533
|
:
|
|
@@ -816,7 +826,7 @@ annotateArtifact[ outer, loc, annos ] locals[ art, name = {} ]
|
|
|
816
826
|
)*
|
|
817
827
|
')'
|
|
818
828
|
(
|
|
819
|
-
RETURNS '{'
|
|
829
|
+
RETURNS '{' { $art['$'+'syntax'] = 'returns'; }
|
|
820
830
|
annotateElement[ $art ]*
|
|
821
831
|
'}'
|
|
822
832
|
optionalSemi
|
|
@@ -824,7 +834,7 @@ annotateArtifact[ outer, loc, annos ] locals[ art, name = {} ]
|
|
|
824
834
|
requiredSemi
|
|
825
835
|
)
|
|
826
836
|
|
|
|
827
|
-
RETURNS '{'
|
|
837
|
+
RETURNS '{' { $art['$'+'syntax'] = 'returns'; }
|
|
828
838
|
annotateElement[ $art ]*
|
|
829
839
|
'}'
|
|
830
840
|
optionalSemi
|
|
@@ -906,11 +916,12 @@ enumSymbolDef[ outer ] locals[ art, annos = [] ]
|
|
|
906
916
|
{ this.excludeExpected( ['Boolean', 'QuotedLiteral', "'#'", 'NULL'] ); }
|
|
907
917
|
(
|
|
908
918
|
val=literalValue
|
|
909
|
-
{ $art.value = $val.val;
|
|
919
|
+
{ $art.value = $val.val; }
|
|
910
920
|
|
|
|
911
921
|
( plus='+' | min='-' ) num=Number
|
|
912
922
|
{ $art.value = this.numberLiteral( $num, $plus||$min ); }
|
|
913
923
|
)
|
|
924
|
+
{ this.docComment( $annos ); }
|
|
914
925
|
annotationAssignment_ll1[ $annos ]*
|
|
915
926
|
)?
|
|
916
927
|
requiredSemi
|
|
@@ -1121,13 +1132,7 @@ bracedSelectItemListDef[ query ]
|
|
|
1121
1132
|
'{'
|
|
1122
1133
|
{ if (!$query.columns) $query.columns = []; } // set it early to avoid "wildcard" errors
|
|
1123
1134
|
(
|
|
1124
|
-
|
|
1125
|
-
{
|
|
1126
|
-
$query.columns = [ this.tokenLocation( $star, undefined, '*' ) ];
|
|
1127
|
-
}
|
|
1128
|
-
|
|
|
1129
|
-
selectItemDef[ $query.columns ]
|
|
1130
|
-
)
|
|
1135
|
+
selectItemDef[ $query.columns ]
|
|
1131
1136
|
( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
|
|
1132
1137
|
selectItemDef[ $query.columns ]
|
|
1133
1138
|
)*
|
|
@@ -1135,45 +1140,62 @@ bracedSelectItemListDef[ query ]
|
|
|
1135
1140
|
'}'
|
|
1136
1141
|
;
|
|
1137
1142
|
|
|
1138
|
-
selectItemDef[ outer ] locals[
|
|
1139
|
-
@after{
|
|
1143
|
+
selectItemDef[ outer ] locals[ annos = [] ]
|
|
1144
|
+
@after{ if ($ctx.art) this.attachLocation($art.art); }
|
|
1140
1145
|
:
|
|
1146
|
+
star='*'
|
|
1147
|
+
{ $outer.push( this.tokenLocation( $star, undefined, '*' ) ); }
|
|
1148
|
+
|
|
|
1141
1149
|
{ this.docComment( $annos ); }
|
|
1142
1150
|
annotationAssignment_atn[ $annos ]*
|
|
1143
|
-
// NEW: `VIRTUAL foo` - was `virtual AS foo` before
|
|
1144
1151
|
// VIRTUAL is keyword, except if before the following tokens texts:
|
|
1145
1152
|
{ this.setLocalToken( 'VIRTUAL', 'VIRTUAL', /^([,.:\[@]|as)$/i ) ; } // not '{'
|
|
1146
1153
|
virtual=VIRTUAL?
|
|
1147
1154
|
key=KEY?
|
|
1155
|
+
art=selectItemDefBody[ $outer, $annos ]
|
|
1156
|
+
{
|
|
1157
|
+
if ($virtual) $art.art.virtual = this.tokenLocation( $virtual, undefined, true );
|
|
1158
|
+
if ($key) $art.art.key = this.tokenLocation( $key, undefined, true );
|
|
1159
|
+
}
|
|
1160
|
+
;
|
|
1161
|
+
|
|
1162
|
+
selectItemDefBody[ outer, annos ] returns[ art = {} ]
|
|
1163
|
+
@after{ /* #ATN 1 */ this.attachLocation($art); }
|
|
1164
|
+
:
|
|
1148
1165
|
(
|
|
1149
1166
|
e=expression
|
|
1167
|
+
// we cannot use 'condition' instead, as long as we allow aliases without
|
|
1168
|
+
// AS (using rule 'ident' instead of 'identNoKeyword') -> ambiguities
|
|
1150
1169
|
{
|
|
1151
|
-
$art = this.addItem( $outer, null, null, $annos,
|
|
1152
|
-
{ value: $e.expr, key: $key, virtual: $virtual } );
|
|
1170
|
+
$art = this.addItem( $outer, null, null, $annos, { value: $e.expr } );
|
|
1153
1171
|
}
|
|
1154
1172
|
( AS n1=ident['Item'] { $art.name = $n1.id }
|
|
1155
|
-
| n2=ident['Item'] { this.fragileAlias( $n2.id, true )
|
|
1173
|
+
| n2=ident['Item'] { $art.name = this.fragileAlias( $n2.id, true ); }
|
|
1156
1174
|
| { if (this.getCurrentToken().text !== '.') this.classifyImplicitName( 'Item', $e.expr ); }
|
|
1157
1175
|
)
|
|
1158
1176
|
{ if ($art.value && !$art.value.path) this.excludeExpected( ["'.'", "'{'"] ); }
|
|
1159
1177
|
(
|
|
1160
1178
|
{ if ($art.value && !$art.value.path) this.reportExpandInline( 'expand' ); }
|
|
1161
1179
|
selectItemInlineList[ $art, 'expand' ]
|
|
1180
|
+
excludingClause[ $art ]?
|
|
1162
1181
|
// TODO: we might alternatively allow AS here
|
|
1163
1182
|
|
|
|
1164
1183
|
// TODO: complain if AS has been used - or in definer?
|
|
1165
1184
|
{ if ($art.value && !$art.value.path) this.reportExpandInline( 'inline' ); }
|
|
1166
|
-
DOTbeforeBRACE
|
|
1185
|
+
DOTbeforeBRACE // ...orASTERISK
|
|
1186
|
+
(
|
|
1187
|
+
selectItemInlineList[ $art, 'inline' ]
|
|
1188
|
+
excludingClause[ $art ]?
|
|
1189
|
+
|
|
|
1190
|
+
star='*'
|
|
1191
|
+
{ $art.inline = [ this.tokenLocation( $star, undefined, '*' ) ]; }
|
|
1192
|
+
)
|
|
1167
1193
|
)?
|
|
1168
1194
|
|
|
|
1169
|
-
{
|
|
1170
|
-
$art = this.addItem( $outer, null, null, $annos, { key: $key, virtual: $virtual } );
|
|
1171
|
-
}
|
|
1195
|
+
{ $art = this.addItem( $outer, null, null, $annos ); }
|
|
1172
1196
|
selectItemInlineList[ $art, 'expand' ]
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
| n2=ident['Item'] { this.fragileAlias( $n2.id, true );; $art.name = $n2.id }
|
|
1176
|
-
)
|
|
1197
|
+
excludingClause[ $art ]?
|
|
1198
|
+
AS n1=ident['Item'] { $art.name = $n1.id }
|
|
1177
1199
|
)
|
|
1178
1200
|
{ this.docComment( $annos ); }
|
|
1179
1201
|
annotationAssignment_fix[ $annos ]*
|
|
@@ -1198,6 +1220,30 @@ selectItemDef[ outer ] locals[ art = {}, annos = [], item = {} ] // AnnotatedQLS
|
|
|
1198
1220
|
)?
|
|
1199
1221
|
;
|
|
1200
1222
|
|
|
1223
|
+
selectItemInlineList[ art, clause ]
|
|
1224
|
+
:
|
|
1225
|
+
'{'
|
|
1226
|
+
{ $art[$clause] = []; }
|
|
1227
|
+
(
|
|
1228
|
+
selectItemInlineDef[ $art[$clause] ]
|
|
1229
|
+
( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
|
|
1230
|
+
selectItemInlineDef[ $art[$clause] ]
|
|
1231
|
+
)*
|
|
1232
|
+
)?
|
|
1233
|
+
'}'
|
|
1234
|
+
;
|
|
1235
|
+
|
|
1236
|
+
selectItemInlineDef[ outer ] locals[ annos = [] ]
|
|
1237
|
+
@after{ if ($ctx.art) this.attachLocation($art.art); }
|
|
1238
|
+
:
|
|
1239
|
+
star='*'
|
|
1240
|
+
{ $outer.push( this.tokenLocation( $star, undefined, '*' ) ); }
|
|
1241
|
+
|
|
|
1242
|
+
{ this.docComment( $annos ); }
|
|
1243
|
+
annotationAssignment_atn[ $annos ]*
|
|
1244
|
+
art=selectItemDefBody[ $outer, $annos ]
|
|
1245
|
+
;
|
|
1246
|
+
|
|
1201
1247
|
parameterListDef[ art ]
|
|
1202
1248
|
:
|
|
1203
1249
|
'('
|
|
@@ -1222,6 +1268,8 @@ parameterDef[ outer ] locals[ art, annos = [] ]
|
|
|
1222
1268
|
this.docComment( $annos ); }
|
|
1223
1269
|
annotationAssignment_fix[ $annos ]*
|
|
1224
1270
|
typeSpec[ $art ]
|
|
1271
|
+
( DEFAULT expr=expression { $art.default = $expr.expr; } )?
|
|
1272
|
+
{ this.docComment( $annos ); }
|
|
1225
1273
|
annotationAssignment_ll1[ $annos ]*
|
|
1226
1274
|
;
|
|
1227
1275
|
|
|
@@ -1365,6 +1413,8 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
|
|
|
1365
1413
|
|
|
|
1366
1414
|
':'
|
|
1367
1415
|
// #ATN: typeRefOptArgs can start with ARRAY or MANY or ASSOCIATION or TYPE or LOCALIZED
|
|
1416
|
+
// Nevertheless, MANY '{' is handled by local token rewrite:
|
|
1417
|
+
{ this.setLocalToken( 'MANY', 'HelperToken1', /^[^\{]/ ); }
|
|
1368
1418
|
(
|
|
1369
1419
|
typeStruct[ $art ]
|
|
1370
1420
|
optionalSemi
|
|
@@ -1374,6 +1424,12 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
|
|
|
1374
1424
|
( typeToMany[ $art ] | typeToOne[ $art ] | simplePath[ $art.target, 'artref' ] )
|
|
1375
1425
|
typeAssociationCont[ $art ]?
|
|
1376
1426
|
requiredSemi // and if its the ';'...
|
|
1427
|
+
|
|
|
1428
|
+
many=HelperToken1 // rewritten MANY before '{'
|
|
1429
|
+
{ $art.items = { location: this.tokenLocation( $many ) };}
|
|
1430
|
+
typeStruct[ $art.items ]
|
|
1431
|
+
nullability[ $art.items ]?
|
|
1432
|
+
optionalSemi
|
|
1377
1433
|
|
|
|
1378
1434
|
(
|
|
1379
1435
|
array=ARRAY of=OF
|
|
@@ -1413,6 +1469,7 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
|
|
|
1413
1469
|
annotationAssignment_ll1[ $annos ]*
|
|
1414
1470
|
requiredSemi
|
|
1415
1471
|
|
|
|
1472
|
+
// alt lookahead includes MANY '{'
|
|
1416
1473
|
{ $art.type = {}; }
|
|
1417
1474
|
simplePath[ $art.type, 'artref' ]
|
|
1418
1475
|
(
|
|
@@ -1420,8 +1477,20 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
|
|
|
1420
1477
|
head=Number
|
|
1421
1478
|
{ $art['$'+'typeArgs'] = [ this.numberLiteral( $head ) ]; }
|
|
1422
1479
|
( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
|
|
1423
|
-
|
|
1424
|
-
|
|
1480
|
+
(
|
|
1481
|
+
v=VARIABLE
|
|
1482
|
+
{ $art['$'+'typeArgs'].push(
|
|
1483
|
+
{ literal: 'string', val: 'variable', location: this.tokenLocation($v) } );
|
|
1484
|
+
}
|
|
1485
|
+
|
|
|
1486
|
+
f=FLOATING
|
|
1487
|
+
{ $art['$'+'typeArgs'].push(
|
|
1488
|
+
{ literal: 'string', val: 'floating', location: this.tokenLocation($f) } );
|
|
1489
|
+
}
|
|
1490
|
+
|
|
|
1491
|
+
tail=Number
|
|
1492
|
+
{ $art['$'+'typeArgs'].push( this.numberLiteral( $tail ) ); }
|
|
1493
|
+
)
|
|
1425
1494
|
)*
|
|
1426
1495
|
')'
|
|
1427
1496
|
{ this.docComment( $annos ); }
|
|
@@ -1645,8 +1714,20 @@ typeRefOptArgs[ art ]
|
|
|
1645
1714
|
head=Number
|
|
1646
1715
|
{ $art['$'+'typeArgs'] = [ this.numberLiteral( $head ) ]; }
|
|
1647
1716
|
( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
|
|
1648
|
-
|
|
1649
|
-
|
|
1717
|
+
(
|
|
1718
|
+
v=VARIABLE
|
|
1719
|
+
{ $art['$'+'typeArgs'].push(
|
|
1720
|
+
{ literal: 'string', val: 'variable', location: this.tokenLocation($v) } );
|
|
1721
|
+
}
|
|
1722
|
+
|
|
|
1723
|
+
f=FLOATING
|
|
1724
|
+
{ $art['$'+'typeArgs'].push(
|
|
1725
|
+
{ literal: 'string', val: 'floating', location: this.tokenLocation($f) } );
|
|
1726
|
+
}
|
|
1727
|
+
|
|
|
1728
|
+
tail=Number
|
|
1729
|
+
{ $art['$'+'typeArgs'].push( this.numberLiteral( $tail ) ); }
|
|
1730
|
+
)
|
|
1650
1731
|
)*
|
|
1651
1732
|
')'
|
|
1652
1733
|
|
|
|
@@ -1681,6 +1762,30 @@ orderByClause[ inQuery ] returns [ query ]
|
|
|
1681
1762
|
( ',' obn=orderBySpec { $query.orderBy.push( $obn.ob ); } )*
|
|
1682
1763
|
;
|
|
1683
1764
|
|
|
1765
|
+
overOrderByClause returns [ expr ]
|
|
1766
|
+
:
|
|
1767
|
+
o=ORDER b=BY { $expr = { op: this.tokenLocation($o, $b, 'orderBy' ) , args: [] }}
|
|
1768
|
+
ob1=orderBySpec { $expr.args.push( $ob1.ob ); }
|
|
1769
|
+
( ',' obn=orderBySpec { $expr.args.push( $obn.ob ); } )*
|
|
1770
|
+
;
|
|
1771
|
+
|
|
1772
|
+
partitionByClause returns [ expr ]
|
|
1773
|
+
:
|
|
1774
|
+
p=PARTITION b=BY { $expr = { op: this.tokenLocation($p, $b, 'partitionBy' ) , args: [] }}
|
|
1775
|
+
e1=expression { $expr.args.push( $e1.expr ); }
|
|
1776
|
+
( ',' en=expression { $expr.args.push( $en.expr ); } )*
|
|
1777
|
+
;
|
|
1778
|
+
|
|
1779
|
+
overClause returns [ over ]
|
|
1780
|
+
@after { this.attachLocation($over); }
|
|
1781
|
+
:
|
|
1782
|
+
o=OVER { $over = { op: this.tokenLocation( $o, null, 'over' ) , args: [] } }
|
|
1783
|
+
'('
|
|
1784
|
+
( pb=partitionByClause { $over.args.push( $pb.expr ); } )?
|
|
1785
|
+
( ob=overOrderByClause { $over.args.push( $ob.expr ); } )?
|
|
1786
|
+
')'
|
|
1787
|
+
;
|
|
1788
|
+
|
|
1684
1789
|
limitClause[ inQuery ] returns [ query ]
|
|
1685
1790
|
:
|
|
1686
1791
|
limkw=LIMIT { $query = this.unaryOpForParens( $inQuery, '$'+'query' ); }
|
|
@@ -1733,29 +1838,13 @@ queryPrimary returns[ query = {} ]
|
|
|
1733
1838
|
{ $query.quantifier = this.tokenLocation( $ad, undefined, $ad.text.toLowerCase() ); }
|
|
1734
1839
|
)?
|
|
1735
1840
|
bracedSelectItemListDef[ $query ]?
|
|
1736
|
-
|
|
1737
|
-
// syntax is less than ideal - EXCLUDING is only useful for `*` - with
|
|
1738
|
-
// this syntax, people wonder what happens with explicit select items
|
|
1739
|
-
EXCLUDING
|
|
1740
|
-
'{'
|
|
1741
|
-
projectionExclusion[ $query ]
|
|
1742
|
-
( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
|
|
1743
|
-
projectionExclusion[ $query ]
|
|
1744
|
-
)*
|
|
1745
|
-
'}'
|
|
1746
|
-
)?
|
|
1841
|
+
excludingClause[ $query ]?
|
|
1747
1842
|
|
|
|
1748
1843
|
( ad=( ALL | DISTINCT ) // TODO: or directly after SELECT ?
|
|
1749
1844
|
{ $query.quantifier = this.tokenLocation( $ad, undefined, $ad.text.toLowerCase() ); }
|
|
1750
1845
|
)?
|
|
1751
1846
|
{ $query.columns = []; } // set it early to avoid "wildcard" errors
|
|
1752
|
-
|
|
1753
|
-
{
|
|
1754
|
-
$query.columns = [ this.tokenLocation( $star, undefined, '*' ) ];
|
|
1755
|
-
}
|
|
1756
|
-
|
|
|
1757
|
-
selectItemDef[ $query.columns ]
|
|
1758
|
-
)
|
|
1847
|
+
selectItemDef[ $query.columns ]
|
|
1759
1848
|
( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
|
|
1760
1849
|
selectItemDef[ $query.columns ]
|
|
1761
1850
|
)*
|
|
@@ -1855,7 +1944,7 @@ tableTerm returns [ table ]
|
|
|
1855
1944
|
fromPath[ $table, 'ref']
|
|
1856
1945
|
)?
|
|
1857
1946
|
( AS n1=ident['FromAlias'] { $table.name = $n1.id }
|
|
1858
|
-
| n2=identNoKeyword['FromAlias'] { this.fragileAlias( $n2.id )
|
|
1947
|
+
| n2=identNoKeyword['FromAlias'] { $table.name = this.fragileAlias( $n2.id ); }
|
|
1859
1948
|
// if we would use rule `ident`, we would either had to make all JOIN
|
|
1860
1949
|
// kinds reserved or introduce ATN
|
|
1861
1950
|
)?
|
|
@@ -1865,11 +1954,9 @@ tableTerm returns [ table ]
|
|
|
1865
1954
|
// left-paren, but queryExpression has SELECT after initial left-parens
|
|
1866
1955
|
(
|
|
1867
1956
|
qe=queryExpression close=')'
|
|
1868
|
-
|
|
1869
|
-
// just use surroundByParens(), remove unaryOpForParens()
|
|
1870
|
-
{ $table = { query: this.unaryOpForParens( $qe.query ); } }
|
|
1957
|
+
{ $table = this.surroundByParens( $qe.query, $open, $close, true ); }
|
|
1871
1958
|
( AS a1=ident['FromAlias'] { $table.name = $a1.id } // for defining table aliass
|
|
1872
|
-
| a2=identNoKeyword['FromAlias'] { this.fragileAlias( $a2.id, true )
|
|
1959
|
+
| a2=identNoKeyword['FromAlias'] { $table.name = this.fragileAlias( $a2.id, true ); }
|
|
1873
1960
|
// not using ident` to have a similar behavior to above
|
|
1874
1961
|
)
|
|
1875
1962
|
|
|
|
@@ -1915,7 +2002,7 @@ fromPath[ qp, idkind ]
|
|
|
1915
2002
|
condition returns [ cond ] locals [ args = [], orl = [] ]
|
|
1916
2003
|
@after{
|
|
1917
2004
|
$cond = ($args.length == 1)
|
|
1918
|
-
? $args[0]
|
|
2005
|
+
? this.attachLocation( $args[0] )
|
|
1919
2006
|
: this.attachLocation({ op: $orl[0], args: $args });
|
|
1920
2007
|
}
|
|
1921
2008
|
:
|
|
@@ -1946,7 +2033,7 @@ conditionTerm returns [ cond ]
|
|
|
1946
2033
|
(
|
|
1947
2034
|
open='(' qe=queryExpression close=')'
|
|
1948
2035
|
{ $cond = { op: this.tokenLocation( $ex, undefined, 'exists' ),
|
|
1949
|
-
args: [
|
|
2036
|
+
args: [ this.surroundByParens( $qe.query, $open, $close, true ) ] }; }
|
|
1950
2037
|
|
|
|
1951
2038
|
qm=( HideAlternatives | '?' )
|
|
1952
2039
|
{ $cond = { op: this.tokenLocation( $ex, undefined, 'exists' ), args: [
|
|
@@ -2076,6 +2163,10 @@ expressionTerm returns [ expr ] locals [ op, args = [] ]
|
|
|
2076
2163
|
this.notSupportedYet( $ne ); }
|
|
2077
2164
|
|
|
|
2078
2165
|
vp=valuePath[ 'ref', null ] { $expr = this.valuePathAst( $vp.qp ); }
|
|
2166
|
+
{ this.setLocalTokenIfBefore( 'OVER', 'OVER', /^\($/i ); }
|
|
2167
|
+
(
|
|
2168
|
+
over=overClause { $expr.suffix = [ $over.over ] }
|
|
2169
|
+
)?
|
|
2079
2170
|
|
|
|
2080
2171
|
':'
|
|
2081
2172
|
( vp=valuePath[ 'paramref', this.startLocation() ]
|
|
@@ -2095,7 +2186,8 @@ expressionTerm returns [ expr ] locals [ op, args = [] ]
|
|
|
2095
2186
|
// #ATN: The following alternative is not LL1, because both can start with
|
|
2096
2187
|
// left-paren, but queryExpression has SELECT after initial left-parens
|
|
2097
2188
|
(
|
|
2098
|
-
qe=queryExpression close=')'
|
|
2189
|
+
qe=queryExpression close=')'
|
|
2190
|
+
{ $expr = this.surroundByParens( $qe.query, $open, $close, true ); }
|
|
2099
2191
|
|
|
|
2100
2192
|
c1=condition { $expr = [ $c1.cond ]; }
|
|
2101
2193
|
( ',' { if ($expr.length > 1 && this.isStraightBefore(')')) break; } // allow ',' before ')'
|
|
@@ -2275,7 +2367,7 @@ optionalCardinality[ pathStep ]
|
|
|
2275
2367
|
// completion just produces `:`after having inserted a Number - TODO.
|
|
2276
2368
|
{ if (this._input.LT(2).text !== ':') return $ctx; }
|
|
2277
2369
|
( trgMax=Number ':'
|
|
2278
|
-
{ if ($pathStep) $pathStep.cardinality = { targetMax: this.numberLiteral( $trgMax ) } }
|
|
2370
|
+
{ if ($pathStep) $pathStep.cardinality = { targetMax: this.numberLiteral( $trgMax ), location: this.startLocation() }; }
|
|
2279
2371
|
)
|
|
2280
2372
|
;
|
|
2281
2373
|
|
|
@@ -2294,65 +2386,9 @@ optionalWhereForFilter
|
|
|
2294
2386
|
WHERE
|
|
2295
2387
|
;
|
|
2296
2388
|
|
|
2297
|
-
selectItemInlineList[ art, clause ]
|
|
2298
|
-
:
|
|
2299
|
-
'{'
|
|
2300
|
-
{ $art[$clause] = []; }
|
|
2301
|
-
(
|
|
2302
|
-
( star='*' // TODO: allow everywhere
|
|
2303
|
-
{ $art[$clause].push( this.tokenLocation( $star, undefined, '*' ) ); }
|
|
2304
|
-
|
|
|
2305
|
-
selectItemInlineDef[ $art[$clause] ]
|
|
2306
|
-
)
|
|
2307
|
-
( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
|
|
2308
|
-
selectItemInlineDef[ $art[$clause] ]
|
|
2309
|
-
)*
|
|
2310
|
-
)?
|
|
2311
|
-
'}'
|
|
2312
|
-
;
|
|
2313
|
-
|
|
2314
|
-
selectItemInlineDef[ outer ] locals[ art = {}, alias, annos = [] ] // AnnotatedQLSelectItem
|
|
2315
|
-
@after{ this.attachLocation($art); }
|
|
2316
|
-
:
|
|
2317
|
-
{ this.docComment( $annos ); }
|
|
2318
|
-
annotationAssignment_atn[ $annos ]*
|
|
2319
|
-
(
|
|
2320
|
-
vp=valuePath[ 'ref', null ] // TODO: make sure that no function is used
|
|
2321
|
-
{ $art = this.addItem( $outer, null, null, $annos, { value: this.valuePathAst( $vp.qp ) }); }
|
|
2322
|
-
( AS n1=ident['Item'] { $art.name = $n1.id }
|
|
2323
|
-
| n2=ident['Item'] { this.fragileAlias( $n2.id, true );; $art.name = $n2.id }
|
|
2324
|
-
| { this.classifyImplicitName( 'Item', $vp.qp ); }
|
|
2325
|
-
)
|
|
2326
|
-
(
|
|
2327
|
-
selectItemInlineList[ $art, 'expand' ]
|
|
2328
|
-
|
|
|
2329
|
-
DOTbeforeBRACE selectItemInlineSpec[ $art ]
|
|
2330
|
-
)?
|
|
2331
|
-
{ this.docComment( $annos ); }
|
|
2332
|
-
annotationAssignment_fix[ $annos ]*
|
|
2333
|
-
|
|
|
2334
|
-
{
|
|
2335
|
-
$art = this.addItem( $outer, null, null, $annos, {} );
|
|
2336
|
-
}
|
|
2337
|
-
selectItemInlineList[ $art, 'expand' ]
|
|
2338
|
-
// TODO: use extra rule for expand with expressions
|
|
2339
|
-
( AS n1=ident['Item'] { $art.name = $n1.id }
|
|
2340
|
-
| n2=ident['Item'] { this.fragileAlias( $n2.id, true );; $art.name = $n2.id }
|
|
2341
|
-
)
|
|
2342
|
-
)
|
|
2343
|
-
;
|
|
2344
|
-
|
|
2345
|
-
selectItemInlineSpec[ outer ]
|
|
2346
|
-
:
|
|
2347
|
-
selectItemInlineList[ $outer, 'inline' ]
|
|
2348
|
-
|
|
|
2349
|
-
star='*'
|
|
2350
|
-
{ $outer.inline = [ this.tokenLocation( $star, undefined, '*' ) ]; }
|
|
2351
|
-
;
|
|
2352
|
-
|
|
2353
2389
|
// Simple paths and values ---------------------------------------------------
|
|
2354
2390
|
|
|
2355
|
-
annoValueBase returns[ val ]
|
|
2391
|
+
annoValueBase returns[ val ] locals [ hasEllipsis=0 ]
|
|
2356
2392
|
@after { this.attachLocation($val); }
|
|
2357
2393
|
:
|
|
2358
2394
|
{ $val = { literal: 'struct', location: this.startLocation() }; }
|
|
@@ -2371,10 +2407,28 @@ annoValueBase returns[ val ]
|
|
|
2371
2407
|
{ $val = { literal: 'array', location: this.startLocation(), val: [] }; }
|
|
2372
2408
|
'['
|
|
2373
2409
|
(
|
|
2374
|
-
|
|
2410
|
+
(
|
|
2411
|
+
head=arrayValue { $val.val.push( $head.val ); }
|
|
2412
|
+
|
|
|
2413
|
+
e='...'
|
|
2414
|
+
{
|
|
2415
|
+
$val.val.push( { literal: 'token', val: '...', location: this.tokenLocation($e) } );
|
|
2416
|
+
$hasEllipsis++;
|
|
2417
|
+
}
|
|
2418
|
+
)
|
|
2375
2419
|
(
|
|
2376
2420
|
',' { if (this.isStraightBefore(']')) break; } // allow ',' before ']'
|
|
2377
|
-
|
|
2421
|
+
(
|
|
2422
|
+
tail=arrayValue { $val.val.push( $tail.val ); }
|
|
2423
|
+
|
|
|
2424
|
+
e='...'
|
|
2425
|
+
{
|
|
2426
|
+
$val.val.push( { literal: 'token', val: '...', location: this.tokenLocation($e) } );
|
|
2427
|
+
if(++$hasEllipsis > 1)
|
|
2428
|
+
this.error( 'syntax-unexpected-ellipsis', $e, { code: '...' },
|
|
2429
|
+
'Expected no more than one $(CODE)' );
|
|
2430
|
+
}
|
|
2431
|
+
)
|
|
2378
2432
|
)*
|
|
2379
2433
|
)?
|
|
2380
2434
|
']'
|
|
@@ -2409,7 +2463,6 @@ namedValue[ struct ] locals[ namedVal = { name: {} } ]
|
|
|
2409
2463
|
($ctx.elem) ? Object.assign($namedVal, $elem.val) : $namedVal ); }
|
|
2410
2464
|
;
|
|
2411
2465
|
|
|
2412
|
-
|
|
2413
2466
|
arrayValue returns[ val ]
|
|
2414
2467
|
@after { this.attachLocation($val); }
|
|
2415
2468
|
:
|
|
@@ -2565,6 +2618,7 @@ ident[ category ] returns[ id ]
|
|
|
2565
2618
|
| EXCLUDING
|
|
2566
2619
|
| EXTEND
|
|
2567
2620
|
| FIRST
|
|
2621
|
+
| FLOATING
|
|
2568
2622
|
| FULL
|
|
2569
2623
|
| FUNCTION
|
|
2570
2624
|
| GROUP
|
|
@@ -2595,6 +2649,7 @@ ident[ category ] returns[ id ]
|
|
|
2595
2649
|
| ORDER
|
|
2596
2650
|
| OUTER
|
|
2597
2651
|
| PARAMETERS
|
|
2652
|
+
| PARTITION
|
|
2598
2653
|
| PROJECTION
|
|
2599
2654
|
| REDIRECTED
|
|
2600
2655
|
| RETURNS
|
|
@@ -2607,6 +2662,7 @@ ident[ category ] returns[ id ]
|
|
|
2607
2662
|
| TO
|
|
2608
2663
|
| TYPE
|
|
2609
2664
|
| USING
|
|
2665
|
+
| VARIABLE
|
|
2610
2666
|
| VIEW
|
|
2611
2667
|
| YEAR
|
|
2612
2668
|
;
|
|
@@ -2723,6 +2779,7 @@ EXCEPT : [eE][xX][cC][eE][pP][tT] ;
|
|
|
2723
2779
|
EXCLUDING : [eE][xX][cC][lL][uU][dD][iI][nN][gG] ;
|
|
2724
2780
|
EXTEND : [eE][xX][tT][eE][nN][dD] ;
|
|
2725
2781
|
FIRST : [fF][iI][rR][sS][tT] ;
|
|
2782
|
+
FLOATING : [fF][lL][oO][aA][tT][iI][nN][gG] ;
|
|
2726
2783
|
FULL : [fF][uU][lL][lL] ;
|
|
2727
2784
|
FUNCTION : [fF][uU][nN][cC][tT][iI][oO][nN] ;
|
|
2728
2785
|
GROUP : [gG][rR][oO][uU][pP] ;
|
|
@@ -2752,7 +2809,9 @@ ONE : [oO][nN][eE] ;
|
|
|
2752
2809
|
OR : [oO][rR] ;
|
|
2753
2810
|
ORDER : [oO][rR][dD][eE][rR] ;
|
|
2754
2811
|
OUTER : [oO][uU][tT][eE][rR] ;
|
|
2812
|
+
// OVER : [oO][vV][eE][rR] ;
|
|
2755
2813
|
PARAMETERS : [pP][aA][rR][aA][mM][eE][tT][eE][rR][sS] ;
|
|
2814
|
+
PARTITION: [pP][aA][rR][tT][iI][tT][iI][oO][nN] ;
|
|
2756
2815
|
PROJECTION : [pP][rR][oO][jJ][eE][cC][tT][iI][oO][nN] ;
|
|
2757
2816
|
REDIRECTED : [rR][eE][dD][iI][rR][eE][cC][tT][eE][dD] ;
|
|
2758
2817
|
RETURNS : [rR][eE][tT][uU][rR][nN][sS] ;
|
|
@@ -2765,6 +2824,7 @@ TO : [tT][oO] ; // or make reserved? (is in SQL-92)
|
|
|
2765
2824
|
TYPE : [tT][yY][pP][eE] ;
|
|
2766
2825
|
UNION : [uU][nN][iI][oO][nN] ;
|
|
2767
2826
|
USING : [uU][sS][iI][nN][gG] ;
|
|
2827
|
+
VARIABLE : [vV][aA][rR][iI][aA][bB][lL][eE] ;
|
|
2768
2828
|
VIEW : [vV][iI][eE][wW] ;
|
|
2769
2829
|
// VIRTUAL: [vV][iI][rR][tT][uU][aA][lL] ; see tokens {}
|
|
2770
2830
|
YEAR : [yY][eE][aA][rR] ;
|