@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.
Files changed (106) hide show
  1. package/CHANGELOG.md +241 -1
  2. package/bin/.eslintrc.json +17 -0
  3. package/bin/cds_update_identifiers.js +8 -7
  4. package/bin/cdsc.js +180 -132
  5. package/bin/cdshi.js +18 -11
  6. package/bin/cdsse.js +38 -32
  7. package/bin/cdsv2m.js +8 -7
  8. package/doc/CHANGELOG_BETA.md +36 -1
  9. package/lib/api/main.js +81 -100
  10. package/lib/api/options.js +17 -11
  11. package/lib/api/validate.js +12 -8
  12. package/lib/backends.js +0 -81
  13. package/lib/base/keywords.js +32 -2
  14. package/lib/base/location.js +2 -2
  15. package/lib/base/message-registry.js +66 -4
  16. package/lib/base/messages.js +84 -27
  17. package/lib/base/model.js +2 -61
  18. package/lib/checks/arrayOfs.js +0 -1
  19. package/lib/checks/defaultValues.js +27 -2
  20. package/lib/checks/elements.js +1 -6
  21. package/lib/checks/enricher.js +8 -2
  22. package/lib/checks/foreignKeys.js +0 -6
  23. package/lib/checks/managedWithoutKeys.js +17 -0
  24. package/lib/checks/nonexpandableStructured.js +38 -0
  25. package/lib/checks/onConditions.js +9 -45
  26. package/lib/checks/queryNoDbArtifacts.js +27 -9
  27. package/lib/checks/selectItems.js +25 -2
  28. package/lib/checks/types.js +26 -2
  29. package/lib/checks/unknownMagic.js +38 -0
  30. package/lib/checks/utils.js +61 -0
  31. package/lib/checks/validator.js +66 -13
  32. package/lib/compiler/assert-consistency.js +24 -12
  33. package/lib/compiler/builtins.js +2 -0
  34. package/lib/compiler/checks.js +6 -4
  35. package/lib/compiler/definer.js +101 -39
  36. package/lib/compiler/index.js +88 -59
  37. package/lib/compiler/resolver.js +455 -209
  38. package/lib/compiler/shared.js +57 -33
  39. package/lib/edm/annotations/genericTranslation.js +183 -187
  40. package/lib/edm/csn2edm.js +128 -99
  41. package/lib/edm/edm.js +18 -21
  42. package/lib/edm/edmPreprocessor.js +361 -127
  43. package/lib/edm/edmUtils.js +103 -33
  44. package/lib/gen/Dictionary.json +74 -28
  45. package/lib/gen/language.checksum +1 -1
  46. package/lib/gen/language.interp +18 -4
  47. package/lib/gen/language.tokens +124 -118
  48. package/lib/gen/languageLexer.interp +13 -1
  49. package/lib/gen/languageLexer.js +870 -839
  50. package/lib/gen/languageLexer.tokens +116 -111
  51. package/lib/gen/languageParser.js +5894 -5614
  52. package/lib/json/from-csn.js +152 -67
  53. package/lib/json/to-csn.js +334 -135
  54. package/lib/language/antlrParser.js +4 -3
  55. package/lib/language/errorStrategy.js +1 -0
  56. package/lib/language/genericAntlrParser.js +24 -14
  57. package/lib/language/language.g4 +188 -128
  58. package/lib/main.d.ts +435 -0
  59. package/lib/main.js +31 -7
  60. package/lib/model/api.js +78 -0
  61. package/lib/model/csnRefs.js +463 -187
  62. package/lib/model/csnUtils.js +280 -136
  63. package/lib/model/enrichCsn.js +75 -4
  64. package/lib/model/revealInternalProperties.js +2 -1
  65. package/lib/modelCompare/compare.js +70 -25
  66. package/lib/optionProcessor.js +13 -10
  67. package/lib/render/.eslintrc.json +4 -1
  68. package/lib/render/DuplicateChecker.js +8 -5
  69. package/lib/render/toCdl.js +123 -40
  70. package/lib/render/toHdbcds.js +156 -65
  71. package/lib/render/toSql.js +87 -11
  72. package/lib/render/utils/common.js +55 -9
  73. package/lib/render/utils/sql.js +3 -3
  74. package/lib/sql-identifier.js +6 -1
  75. package/lib/transform/{sql → db}/.eslintrc.json +0 -0
  76. package/lib/transform/{sql → db}/assertUnique.js +7 -8
  77. package/lib/transform/{sql → db}/constraints.js +35 -20
  78. package/lib/transform/db/draft.js +353 -0
  79. package/lib/transform/db/expansion.js +582 -0
  80. package/lib/transform/db/flattening.js +325 -0
  81. package/lib/transform/{sql → db}/groupByOrderBy.js +8 -16
  82. package/lib/transform/{sql → db}/helpers.js +0 -0
  83. package/lib/transform/{sql → db}/transformExists.js +256 -60
  84. package/lib/transform/forHanaNew.js +216 -765
  85. package/lib/transform/forOdataNew.js +60 -56
  86. package/lib/transform/localized.js +48 -26
  87. package/lib/transform/odata/attachPath.js +19 -4
  88. package/lib/transform/odata/expandStructKeysInAssociations.js +2 -2
  89. package/lib/transform/odata/generateForeignKeyElements.js +13 -12
  90. package/lib/transform/odata/referenceFlattener.js +60 -36
  91. package/lib/transform/odata/sortByAssociationDependency.js +4 -4
  92. package/lib/transform/odata/structuralPath.js +76 -0
  93. package/lib/transform/odata/structureFlattener.js +21 -22
  94. package/lib/transform/odata/toFinalBaseType.js +5 -5
  95. package/lib/transform/odata/typesExposure.js +27 -17
  96. package/lib/transform/odata/utils.js +2 -2
  97. package/lib/transform/transformUtilsNew.js +141 -77
  98. package/lib/transform/translateAssocsToJoins.js +17 -14
  99. package/lib/transform/universalCsnEnricher.js +67 -0
  100. package/lib/utils/file.js +0 -11
  101. package/lib/utils/moduleResolve.js +6 -8
  102. package/lib/utils/timetrace.js +6 -1
  103. package/package.json +2 -1
  104. package/lib/base/deepCopy.js +0 -66
  105. package/lib/json/walker.js +0 -26
  106. package/lib/utils/string.js +0 -17
@@ -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 possibile. Thus, built-ins is a
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/langageParser.js' contains `n` occurrences of
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; this.docComment( $annos ); }
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
- ( star='*' // TODO: allow everywhere
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[ art = {}, annos = [], item = {} ] // AnnotatedQLSelectItem
1139
- @after{ /* #ATN 1 */ this.attachLocation($art); }
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 );; $art.name = $n2.id }
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 selectItemInlineSpec[ $art ]
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
- // TODO: use extra rule for expand with expressions
1174
- ( AS n1=ident['Item'] { $art.name = $n1.id }
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
- tail=Number
1424
- { $art['$'+'typeArgs'].push( this.numberLiteral( $tail ) ); }
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
- tail=Number
1649
- { $art['$'+'typeArgs'].push( this.numberLiteral( $tail ) ); }
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
- ( star='*'
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 );; $table.name = $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
- // TODO: if we have the surround query property,
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 );; $table.name = $a2.id; }
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: [ { query: $qe.query, location: this.tokenLocation( $open, $close ) } ] }; }
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=')' { $expr = { query: $qe.query }; } // TODO: surroundByParens
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
- head=arrayValue { $val.val.push( $head.val ); }
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
- tail=arrayValue { $val.val.push( $tail.val ); }
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] ;