@sap/cds-compiler 5.8.0 → 5.9.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.
Files changed (89) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/bin/cds_remove_invalid_whitespace.js +5 -3
  3. package/bin/cds_update_identifiers.js +9 -6
  4. package/bin/cdsc.js +79 -59
  5. package/bin/cdsse.js +14 -10
  6. package/bin/cdsv2m.js +3 -1
  7. package/lib/api/options.js +28 -6
  8. package/lib/base/message-registry.js +15 -4
  9. package/lib/checks/validator.js +3 -0
  10. package/lib/compiler/base.js +1 -1
  11. package/lib/compiler/checks.js +70 -50
  12. package/lib/compiler/extend.js +1 -1
  13. package/lib/compiler/generate.js +8 -2
  14. package/lib/compiler/index.js +1 -1
  15. package/lib/compiler/lsp-api.js +1 -1
  16. package/lib/compiler/propagator.js +2 -2
  17. package/lib/compiler/resolve.js +78 -31
  18. package/lib/compiler/shared.js +3 -3
  19. package/lib/compiler/tweak-assocs.js +1 -1
  20. package/lib/compiler/utils.js +10 -0
  21. package/lib/compiler/xpr-rewrite.js +1 -1
  22. package/lib/edm/annotations/edmJson.js +42 -39
  23. package/lib/edm/annotations/genericTranslation.js +55 -55
  24. package/lib/edm/annotations/preprocessAnnotations.js +5 -5
  25. package/lib/edm/csn2edm.js +21 -16
  26. package/lib/edm/edm.js +62 -62
  27. package/lib/edm/edmAnnoPreprocessor.js +2 -2
  28. package/lib/edm/edmInboundChecks.js +1 -1
  29. package/lib/edm/edmPreprocessor.js +32 -32
  30. package/lib/edm/edmUtils.js +8 -8
  31. package/lib/gen/CdlGrammar.checksum +1 -1
  32. package/lib/gen/CdlParser.js +77 -81
  33. package/lib/gen/Dictionary.json +3062 -3072
  34. package/lib/gen/language.checksum +1 -1
  35. package/lib/gen/language.interp +1 -1
  36. package/lib/gen/languageParser.js +1238 -1236
  37. package/lib/json/from-csn.js +1 -1
  38. package/lib/json/to-csn.js +30 -3
  39. package/lib/language/genericAntlrParser.js +16 -0
  40. package/lib/main.d.ts +79 -1
  41. package/lib/model/csnRefs.js +12 -5
  42. package/lib/model/xprAsTree.js +71 -0
  43. package/lib/modelCompare/utils/filter.js +1 -1
  44. package/lib/optionProcessor.js +46 -32
  45. package/lib/parsers/CdlGrammar.g4 +33 -28
  46. package/lib/parsers/Lexer.js +1 -1
  47. package/lib/parsers/XprTree.js +25 -16
  48. package/lib/render/toCdl.js +902 -414
  49. package/lib/render/toHdbcds.js +1 -1
  50. package/lib/render/toSql.js +8 -0
  51. package/lib/render/utils/common.js +2 -2
  52. package/lib/render/utils/operators.js +160 -0
  53. package/lib/render/utils/pretty.js +337 -0
  54. package/lib/sql-identifier.js +7 -9
  55. package/lib/transform/addTenantFields.js +39 -41
  56. package/lib/transform/db/applyTransformations.js +4 -4
  57. package/lib/transform/db/assertUnique.js +6 -5
  58. package/lib/transform/db/associations.js +3 -3
  59. package/lib/transform/db/assocsToQueries/transformExists.js +13 -13
  60. package/lib/transform/db/assocsToQueries/utils.js +8 -0
  61. package/lib/transform/db/backlinks.js +19 -14
  62. package/lib/transform/db/constraints.js +6 -6
  63. package/lib/transform/db/expansion.js +1 -1
  64. package/lib/transform/db/flattening.js +2 -2
  65. package/lib/transform/db/groupByOrderBy.js +1 -1
  66. package/lib/transform/db/processSqlServices.js +3 -3
  67. package/lib/transform/db/rewriteCalculatedElements.js +2 -2
  68. package/lib/transform/db/temporal.js +7 -9
  69. package/lib/transform/db/views.js +6 -6
  70. package/lib/transform/draft/odata.js +2 -0
  71. package/lib/transform/effective/annotations.js +1 -1
  72. package/lib/transform/effective/associations.js +1 -1
  73. package/lib/transform/effective/main.js +1 -0
  74. package/lib/transform/effective/service.js +2 -2
  75. package/lib/transform/forRelationalDB.js +11 -5
  76. package/lib/transform/localized.js +2 -0
  77. package/lib/transform/odata/adaptAnnotationRefs.js +10 -9
  78. package/lib/transform/odata/createForeignKeys.js +1 -1
  79. package/lib/transform/odata/flattening.js +2 -1
  80. package/lib/transform/parseExpr.js +2 -2
  81. package/lib/transform/transformUtils.js +9 -7
  82. package/lib/transform/translateAssocsToJoins.js +0 -2
  83. package/lib/transform/universalCsn/coreComputed.js +2 -2
  84. package/lib/utils/moduleResolve.js +7 -5
  85. package/package.json +1 -1
  86. package/share/messages/def-upcoming-virtual-change.md +55 -0
  87. package/share/messages/file-unexpected-case-mismatch.md +61 -0
  88. package/share/messages/message-explanations.json +2 -0
  89. package/lib/transform/braceExpression.js +0 -77
@@ -772,6 +772,7 @@ extendElementsBlock[ art, start = undefined ]
772
772
  elementDefOrExtend[ outer ] locals[ art = new XsnArtifact() ]
773
773
  @finally{ this.checkWith( $keyword ); this.attachLocation( $art ); }
774
774
  :
775
+ { $art.location = this.startLocation(); }
775
776
  { this.docComment( $art ); } annoAssignStd[ $art ]*
776
777
  (
777
778
  elementDef[ $outer, $art ]
@@ -1604,6 +1605,8 @@ expression returns[ default expr = {} ]
1604
1605
  | <prec=10, assoc=none> '='/'<>'/'>'/'>='/'<'/'<='/'!='
1605
1606
  { $expr = this.applyOpToken( $expr ); }
1606
1607
  ( ANY/SOME/ALL { this.pushXprToken( $expr ); } )?
1608
+ | <prec=10, assoc=none> '=='
1609
+ { $expr = this.applyOpToken( $expr ); }
1607
1610
  )
1608
1611
  e=expression { $expr.args.push( $e ); }
1609
1612
 
@@ -1707,30 +1710,10 @@ options{ minTokensMatched = 1 }
1707
1710
  // action here, default action won't be executed with failed condition (TODO
1708
1711
  // TOOL? at least msg)
1709
1712
  (
1710
- <default=fallback> // TODO TOOL: allow in loop
1711
- (
1712
- expr=funcExpression { $pathStep.args.push( $expr ); }
1713
- (
1714
- ','<prepare=nextFunctionArgument>
1715
- ( expr=funcExpression { $pathStep.args.push( $expr ); }
1716
- | DeleteStarFromSet // Workaround for missing feature, see #13485, TODO
1717
- | <exitLoop, guard=atRightParen>
1718
- // TODO: later allow ')' <exitRule>, or ')'<mock, exitLoop>, or <exitBlock=MainAlt> with ( options{ block=MainAlt }: …)
1719
- )
1720
- )*
1721
- ( // ORDER BY in generic functions, e.g. `first_value(id order by name)`
1722
- ORDER { $expr = $pathStep.args[$pathStep.args.length - 1] = this.applyOpToken( $expr ); }
1723
- BY { this.pushXprToken( $expr ); }
1724
- orderByClauseAsXpr[ $expr.args ]
1725
- { this.attachLocation( $expr ); }
1726
- )?
1727
- |
1728
- DeleteStarFromSet // Workaround for missing feature, see #13485, TODO
1729
- )?
1730
- |
1731
- // TODO: if we want perfect CC and error recovery, `isNamedArg` would work
1732
- // like keyword prediction and also do something similar to the (future)
1733
- // "identifier confirmation prediction" (consider argument `(par ‡ : 42)`
1713
+ // TODO: if we want perfect CC and error recovery, `isNamedArg` would not
1714
+ // only check the next token for the ':'/'=>', but probably also for the
1715
+ // one after that, at least if the next token could not be a valid
1716
+ // operator (consider that parameter references look like `:PAR`)
1734
1717
  <guard=isNamedArg> id=Id_all['paramname']
1735
1718
  (
1736
1719
  ':' { $pathStep.args = this.createDict( $open ); $pathStep.$syntax = ':'; }
@@ -1752,6 +1735,24 @@ options{ minTokensMatched = 1 }
1752
1735
  )
1753
1736
  )*
1754
1737
  )
1738
+ |
1739
+ <default=fallback>
1740
+ (
1741
+ expr=funcExpression { $pathStep.args.push( $expr ); }
1742
+ (
1743
+ ','<prepare=nextFunctionArgument>
1744
+ ( expr=funcExpression { $pathStep.args.push( $expr ); }
1745
+ | <exitLoop, guard=atRightParen>
1746
+ // TODO: later allow ')' <exitRule>, or ')'<mock, exitLoop>, or <exitBlock=MainAlt> with ( options{ block=MainAlt }: …)
1747
+ )
1748
+ )*
1749
+ ( // ORDER BY in generic functions, e.g. `first_value(id order by name)`
1750
+ ORDER { $expr = $pathStep.args[$pathStep.args.length - 1] = this.applyOpToken( $expr ); }
1751
+ BY { this.pushXprToken( $expr ); }
1752
+ orderByClauseAsXpr[ $expr.args ]
1753
+ { this.attachLocation( $expr ); }
1754
+ )?
1755
+ )?
1755
1756
  )
1756
1757
  ')' { this.finalizeDictOrArray( $pathStep.args ); }
1757
1758
  )?
@@ -1789,8 +1790,8 @@ funcExpression returns[ default expr ] locals[ args ]
1789
1790
  ;
1790
1791
 
1791
1792
  // TODO: check Id_all - necessary if generic token is a reserved word?
1792
- GenericExpr
1793
- : Id_all | '*' ;
1793
+ GenericExpr // workaround TODO Runtime: no-skip/exit recovery w/o guards, see #13485
1794
+ : Id_all | '*' | DeleteStarFromSet ; // → DeleteStarFromSet to avoid failing on same token
1794
1795
  GenericIntro
1795
1796
  : Id_all ;
1796
1797
  GenericSeparator
@@ -2055,11 +2056,15 @@ annoValue returns[ default value = {} ]
2055
2056
  ;
2056
2057
 
2057
2058
  // Shorten tokens array in this.gr() calls in top-level rules by reducing
2058
- // intersection follow set:
2059
+ // intersection follow set, see cap/redepage#97:
2059
2060
  ignoredRule
2060
2061
  options{ excludeRuleFrom = Parser }
2061
2062
  :
2062
2063
  usingDeclaration ';'
2063
2064
  artifactDefOrExtend ';'
2065
+ boundActionFunctionDef ';'
2066
+ elementDef ';'
2067
+ annotateBoundAction ';'
2068
+ annotateElement ';'
2069
+ elementDefOrExtend ';'
2064
2070
  ;
2065
-
@@ -19,7 +19,7 @@ const { Location } = require('../base/location'); // TODO main: add tokenIndex
19
19
  const rules = [ // must not contain capturing groups!
20
20
  { type: comment, re: '/[*/]' },
21
21
  // token type = token text (`type: null`):
22
- { type: null, re: '[-+*?()\\[\\]{},;:/@#]|\\.(?:\\.\\.?)?|<[=>]?|>=?|=>?|!=|\\|\\|' },
22
+ { type: null, re: '[-+*?()\\[\\]{},;:/@#]|\\.(?:\\.\\.?)?|<[=>]?|>=?|=[=>]?|!=|\\|\\|' },
23
23
  { type: ident, re: '[$_\\p{ID_Start}][$\\p{ID_Continue}\u200C\u200D]*|!\\[|"' },
24
24
  { type: string, re: '[\'"]|`(?:``)?' }, // strings, template literal without …${}
25
25
  { type: 'Number', re: '\\d+(?:\\.\\d+)?(?:e[-+]?\\d+)?' },
@@ -2,6 +2,7 @@
2
2
 
3
3
  // See ./CdlGrammar.js for the operator precedences.
4
4
 
5
+ // CSN representation of window functions: unfortunately not Option 4 in #7632
5
6
 
6
7
  'use strict';
7
8
 
@@ -31,7 +32,7 @@ const binaryOperators = {
31
32
  '<': 10,
32
33
  '<=': 10,
33
34
  '!=': 10,
34
- '==': 10, // not supported yet in CDL or backends
35
+ '==': 10,
35
36
  and: 4,
36
37
  or: 2,
37
38
  // with second token or ternary (in the grammar, these ops have prec=10, but
@@ -56,8 +57,10 @@ const secondTokens = {
56
57
  };
57
58
 
58
59
  const naryOperators = {
60
+ // all strings on the right must not have a precedence mentioned in secondTokens
61
+ // true must not be used for operator (precedence) with secondTokens
59
62
  __proto__: null,
60
- '.': true, // CSN-tree really as left-assoc binary?
63
+ '.': true, // CSN-tree not as left-assoc binary?
61
64
  '*': true,
62
65
  '/': true,
63
66
  '+': true,
@@ -74,7 +77,7 @@ class XprTree {
74
77
  nodes; // array value of CSN property `xpr`/`where`/…
75
78
  nodeIdx = 0;
76
79
  args; // corresponding XSN array, with already tree-like sub expressions
77
- location;
80
+ location; // true → CSN input: direct array, no n-ary
78
81
 
79
82
  constructor( nodes, args, location ) {
80
83
  this.nodes = nodes;
@@ -85,15 +88,21 @@ class XprTree {
85
88
  tree() {
86
89
  const args = [];
87
90
  const { length } = this.args;
91
+ // TODO: orderByClauseAsXpr, overClause
88
92
  while (this.nodeIdx < length) {
89
93
  const expr = this.expression( -1 );
90
94
  if (expr)
91
95
  args.push( expr );
92
96
  }
93
- return (args.length === 1) ? args[0] : this.create( args );
97
+ if (args.length === 1) {
98
+ // For CSN, keep xpr arrays as arrays
99
+ return (this.location === true) ? args : args[0];
100
+ }
101
+ return this.create( args );
94
102
  }
95
103
 
96
104
  expression( parentPrec ) {
105
+ // console.log('B:',this.nodeIdx,parentPrec)
97
106
  let append;
98
107
  let naryOp;
99
108
  let args;
@@ -129,23 +138,20 @@ class XprTree {
129
138
  if (!prec || parentPrec >= prec)
130
139
  return expr;
131
140
 
132
- // handle n-ary operators including ternary
133
- append = (typeof naryOp === 'string')
134
- ? !append && naryOp // `and` after `between`, `escape` after `like`˛
135
- : naryOp && node; // nary operators like `+`
136
- if (node === append) {
141
+ // handle n-ary extensions of binary operators
142
+ if (node === append && this.location !== true) { // not for CSN input
137
143
  args.push( this.args[this.nodeIdx++] );
138
144
  }
139
145
  else {
140
146
  naryOp = naryOperators[node];
141
- append = false;
147
+ append = naryOp === true && node;
142
148
  args = [ expr, this.args[this.nodeIdx++] ];
143
149
  expr = this.create( args, naryOp === true );
144
150
  }
145
151
 
146
- // handle second token of operator:
152
+ // handle second token of operator (there must be none for naryOp=true):
147
153
  const second = this.nodes[this.nodeIdx];
148
- if (typeof second === 'string' && secondTokens[second] === prec && !append) {
154
+ if (typeof second === 'string' && secondTokens[second] === prec) {
149
155
  args.push( this.args[this.nodeIdx++] );
150
156
  if (node === 'not')
151
157
  naryOp = naryOperators[second];
@@ -157,8 +163,10 @@ class XprTree {
157
163
  return expr;
158
164
  args.push( right );
159
165
  node = this.nodes[this.nodeIdx];
160
- // TODO: simplyfy between-and and like-escape with pushTokenAndExpression()
166
+ if (node === naryOp && typeof node === 'string')
167
+ node = this.pushTokenAndExpression( args, prec );
161
168
  }
169
+ // console.log('E:',this.nodeIdx)
162
170
  return expr;
163
171
  }
164
172
 
@@ -183,16 +191,17 @@ class XprTree {
183
191
  return expr;
184
192
  }
185
193
 
186
- pushTokenAndExpression( args ) {
194
+ pushTokenAndExpression( args, prec = -1 ) {
187
195
  args.push( this.args[this.nodeIdx++] );
188
- const value = this.expression( -1 );
196
+ const value = this.expression( prec );
189
197
  if (value)
190
198
  args.push( value );
191
199
  return this.nodes[this.nodeIdx];
192
200
  }
193
201
 
194
202
  create( args, isNary = false ) {
195
- // could be adopted for CSN expression tree
203
+ if (this.location === true) // for CSN
204
+ return args;
196
205
  return {
197
206
  op: { val: (isNary ? 'nary' : 'ixpr'), location: this.location },
198
207
  location: this.location,