@sap/cds-compiler 5.8.2 → 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.
- package/CHANGELOG.md +31 -0
- package/bin/cds_remove_invalid_whitespace.js +5 -3
- package/bin/cds_update_identifiers.js +9 -6
- package/bin/cdsc.js +79 -59
- package/bin/cdsse.js +14 -10
- package/bin/cdsv2m.js +3 -1
- package/lib/api/options.js +28 -6
- package/lib/base/message-registry.js +15 -4
- package/lib/checks/validator.js +3 -0
- package/lib/compiler/base.js +1 -1
- package/lib/compiler/checks.js +70 -50
- package/lib/compiler/extend.js +1 -1
- package/lib/compiler/generate.js +8 -2
- package/lib/compiler/index.js +1 -1
- package/lib/compiler/lsp-api.js +1 -1
- package/lib/compiler/propagator.js +2 -2
- package/lib/compiler/resolve.js +78 -31
- package/lib/compiler/shared.js +3 -3
- package/lib/compiler/tweak-assocs.js +1 -1
- package/lib/compiler/utils.js +10 -0
- package/lib/compiler/xpr-rewrite.js +1 -1
- package/lib/edm/annotations/edmJson.js +42 -39
- package/lib/edm/annotations/genericTranslation.js +55 -55
- package/lib/edm/annotations/preprocessAnnotations.js +5 -5
- package/lib/edm/csn2edm.js +21 -16
- package/lib/edm/edm.js +62 -62
- package/lib/edm/edmAnnoPreprocessor.js +2 -2
- package/lib/edm/edmInboundChecks.js +1 -1
- package/lib/edm/edmPreprocessor.js +32 -32
- package/lib/edm/edmUtils.js +8 -8
- package/lib/gen/CdlGrammar.checksum +1 -1
- package/lib/gen/CdlParser.js +77 -81
- package/lib/gen/Dictionary.json +3062 -3072
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +1238 -1236
- package/lib/json/from-csn.js +1 -1
- package/lib/json/to-csn.js +30 -3
- package/lib/language/genericAntlrParser.js +16 -0
- package/lib/main.d.ts +79 -1
- package/lib/model/csnRefs.js +12 -5
- package/lib/model/xprAsTree.js +71 -0
- package/lib/modelCompare/utils/filter.js +1 -1
- package/lib/optionProcessor.js +46 -32
- package/lib/parsers/CdlGrammar.g4 +33 -28
- package/lib/parsers/Lexer.js +1 -1
- package/lib/parsers/XprTree.js +25 -16
- package/lib/render/toCdl.js +902 -414
- package/lib/render/toHdbcds.js +1 -1
- package/lib/render/toSql.js +8 -0
- package/lib/render/utils/common.js +2 -2
- package/lib/render/utils/operators.js +160 -0
- package/lib/render/utils/pretty.js +337 -0
- package/lib/sql-identifier.js +7 -9
- package/lib/transform/addTenantFields.js +39 -41
- package/lib/transform/db/applyTransformations.js +4 -4
- package/lib/transform/db/assertUnique.js +6 -5
- package/lib/transform/db/associations.js +3 -3
- package/lib/transform/db/assocsToQueries/transformExists.js +13 -13
- package/lib/transform/db/assocsToQueries/utils.js +8 -0
- package/lib/transform/db/backlinks.js +19 -14
- package/lib/transform/db/constraints.js +6 -6
- package/lib/transform/db/expansion.js +1 -1
- package/lib/transform/db/flattening.js +2 -2
- package/lib/transform/db/groupByOrderBy.js +1 -1
- package/lib/transform/db/processSqlServices.js +3 -3
- package/lib/transform/db/rewriteCalculatedElements.js +2 -2
- package/lib/transform/db/temporal.js +7 -9
- package/lib/transform/db/views.js +6 -6
- package/lib/transform/draft/odata.js +2 -0
- package/lib/transform/effective/annotations.js +1 -1
- package/lib/transform/effective/associations.js +1 -1
- package/lib/transform/effective/main.js +1 -0
- package/lib/transform/effective/service.js +2 -2
- package/lib/transform/forRelationalDB.js +11 -5
- package/lib/transform/localized.js +2 -0
- package/lib/transform/odata/adaptAnnotationRefs.js +10 -9
- package/lib/transform/parseExpr.js +2 -2
- package/lib/transform/transformUtils.js +9 -7
- package/lib/transform/translateAssocsToJoins.js +0 -2
- package/lib/transform/universalCsn/coreComputed.js +2 -2
- package/lib/utils/moduleResolve.js +7 -5
- package/package.json +1 -1
- package/share/messages/def-upcoming-virtual-change.md +55 -0
- package/share/messages/file-unexpected-case-mismatch.md +61 -0
- package/share/messages/message-explanations.json +2 -0
- 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
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
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
|
-
|
package/lib/parsers/Lexer.js
CHANGED
|
@@ -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+)?' },
|
package/lib/parsers/XprTree.js
CHANGED
|
@@ -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,
|
|
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
|
|
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
|
-
|
|
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
|
|
133
|
-
append
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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,
|