@sap/cds-compiler 5.7.0 → 5.7.4
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 +15 -0
- package/lib/base/location.js +1 -1
- package/lib/base/model.js +4 -5
- package/lib/compiler/define.js +3 -0
- package/lib/compiler/resolve.js +1 -1
- package/lib/gen/CdlParser.js +2367 -2361
- package/lib/main.d.ts +0 -1
- package/lib/parsers/AstBuildingParser.js +35 -18
- package/lib/parsers/CdlGrammar.g4 +15 -10
- package/lib/parsers/index.js +1 -1
- package/lib/render/utils/delta.js +1 -3
- package/package.json +1 -1
package/lib/main.d.ts
CHANGED
|
@@ -48,7 +48,7 @@ const PRECEDENCE_OF_IN_PREDICATE = 10;
|
|
|
48
48
|
const PRECEDENCE_OF_EQUAL = 10;
|
|
49
49
|
|
|
50
50
|
class AstBuildingParser extends BaseParser {
|
|
51
|
-
leanConditions = { afterBrace: true };
|
|
51
|
+
leanConditions = { afterBrace: true, fail: true };
|
|
52
52
|
|
|
53
53
|
constructor( lexer, keywords, table, options, messageFunctions ) {
|
|
54
54
|
super( lexer, keywords, table ); // lexer has file
|
|
@@ -171,7 +171,7 @@ class AstBuildingParser extends BaseParser {
|
|
|
171
171
|
this.dynamic_.generic = spec ? spec[call.argPos] : specialFunctions[''][1];
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
lGenericIntroOrExpr( tryGenericIntro = true ) {
|
|
174
|
+
lGenericIntroOrExpr( _mode, tryGenericIntro = true ) {
|
|
175
175
|
const { keyword, type } = this.la();
|
|
176
176
|
// TODO: use lower-case in specialFunctions
|
|
177
177
|
const text = typeof keyword === 'string' ? keyword.toUpperCase() : type;
|
|
@@ -180,37 +180,44 @@ class AstBuildingParser extends BaseParser {
|
|
|
180
180
|
if (this.dynamic_.generic?.IN === 'separator')
|
|
181
181
|
this.prec_ = PRECEDENCE_OF_IN_PREDICATE; // only expressions if `in` is separator
|
|
182
182
|
if (generic !== 'expr')
|
|
183
|
-
return (generic === 'intro') ? 'GenericIntro' :
|
|
183
|
+
return (generic === 'intro') ? 'GenericIntro' : type;
|
|
184
|
+
// if both intro and expr: specialFunctions[fn][argPos][token] = 'expr'
|
|
184
185
|
const next = this.tokens[this.tokenIdx + 1];
|
|
185
|
-
if (next.type !== ',' && next.type !== ')' &&
|
|
186
|
+
if (next && next.type !== ',' && next.type !== ')' &&
|
|
186
187
|
this.dynamic_.generic[next.keyword?.toUpperCase?.()] !== 'separator')
|
|
187
188
|
return 'GenericIntro';
|
|
188
189
|
}
|
|
189
|
-
return (generic === 'expr') ? 'GenericExpr' :
|
|
190
|
+
return (generic === 'expr') ? 'GenericExpr' : type;
|
|
190
191
|
}
|
|
191
192
|
|
|
192
193
|
lGenericExpr() {
|
|
193
|
-
return this.lGenericIntroOrExpr( false );
|
|
194
|
+
return this.lGenericIntroOrExpr( null, false );
|
|
194
195
|
}
|
|
195
196
|
|
|
196
|
-
lGenericSeparator() {
|
|
197
|
+
lGenericSeparator() {
|
|
197
198
|
const { keyword, type } = this.la();
|
|
198
199
|
// TODO: use lower-case in specialFunctions
|
|
199
200
|
const text = typeof keyword === 'string' ? keyword.toUpperCase() : type;
|
|
200
201
|
const generic = this.dynamic_.generic?.[text];
|
|
201
|
-
return (generic === 'separator') ? 'GenericSeparator' :
|
|
202
|
+
return (generic === 'separator') ? 'GenericSeparator' : type;
|
|
202
203
|
}
|
|
203
204
|
|
|
204
205
|
addTokenToSet_( set, tokenName, val, collectKeywordsOnly ) {
|
|
205
|
-
const
|
|
206
|
-
// TODO:
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
else {
|
|
206
|
+
const token = parserTokens[tokenName];
|
|
207
|
+
// TODO: use lower-case in specialFunctions
|
|
208
|
+
const realTokens = token && this.dynamic_.generic?.[token];
|
|
209
|
+
if (realTokens) {
|
|
211
210
|
for (const t of realTokens)
|
|
212
211
|
super.addTokenToSet_( set, t.toLowerCase(), val, collectKeywordsOnly );
|
|
213
212
|
}
|
|
213
|
+
else if (tokenName === 'DeleteStarFromSet') { // in rule `argumentsAndFilter`
|
|
214
|
+
// TODO: workaround for (`GenericExpr : Id_all | '*'`), see #13485.
|
|
215
|
+
// Works, since `DeleteStarFromSet` comes after `*` (length-sorted):
|
|
216
|
+
delete set['*'];
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
super.addTokenToSet_( set, tokenName, val, collectKeywordsOnly );
|
|
220
|
+
}
|
|
214
221
|
}
|
|
215
222
|
|
|
216
223
|
inSelectItem( _test, arg ) { // only as action
|
|
@@ -503,6 +510,15 @@ class AstBuildingParser extends BaseParser {
|
|
|
503
510
|
return this.tokens[this.tokenIdx + 1]?.text !== ':';
|
|
504
511
|
}
|
|
505
512
|
|
|
513
|
+
fail( mode ) {
|
|
514
|
+
// TODO TOOL: the following test belongs to the BaseParser.js:
|
|
515
|
+
if (this.conditionTokenIdx === this.tokenIdx && // tested on same
|
|
516
|
+
this.conditionStackLength == null && // after error recover
|
|
517
|
+
mode !== 'M')
|
|
518
|
+
return false;
|
|
519
|
+
return true; // mode !== 'Y';
|
|
520
|
+
}
|
|
521
|
+
|
|
506
522
|
// Space handling etc, locations ----------------------------------------------
|
|
507
523
|
|
|
508
524
|
// Use the following method for language constructs which we (currently) do
|
|
@@ -722,14 +738,15 @@ class AstBuildingParser extends BaseParser {
|
|
|
722
738
|
}
|
|
723
739
|
|
|
724
740
|
taggedIfQuery( query ) {
|
|
725
|
-
|
|
741
|
+
// attached actions are run even if rules ends prematurely → query can be
|
|
742
|
+
// undefined
|
|
743
|
+
return (query?.op && queryOps[query.op.val])
|
|
726
744
|
? { query, location: query.$parens?.at( -1 ) ?? query.location }
|
|
727
745
|
: query;
|
|
728
746
|
}
|
|
729
747
|
|
|
730
|
-
addNamedArg(
|
|
731
|
-
|
|
732
|
-
(args.args ?? args)[expr.name.id] = expr;
|
|
748
|
+
addNamedArg( pathItem, idToken, expr ) {
|
|
749
|
+
this.addDef( expr, pathItem, 'args', 0, this.identAst( idToken ) );
|
|
733
750
|
}
|
|
734
751
|
|
|
735
752
|
ixprAst( args ) {
|
|
@@ -128,7 +128,7 @@ usingDeclaration[ source ] locals[ decl = { kind: 'using' } ] // TODO: XsnArtifa
|
|
|
128
128
|
'{' { $decl.usings = this.createArray(); }
|
|
129
129
|
( usingProxy[ $decl, { kind: 'using' } ]
|
|
130
130
|
( ',' | <exitLoop> )
|
|
131
|
-
)
|
|
131
|
+
)*
|
|
132
132
|
'}'<prepare=afterBrace>
|
|
133
133
|
{ this.finalizeDictOrArray( $decl.usings ); }
|
|
134
134
|
( FROM String
|
|
@@ -1100,7 +1100,7 @@ queryExpression returns[ default expr = {} ] locals[ op, quantifier ]
|
|
|
1100
1100
|
)
|
|
1101
1101
|
query=queryExpression
|
|
1102
1102
|
// with same op/quantifier: make left-assoc binary to nary:
|
|
1103
|
-
{ if ($expr.$parens || $op.val !== $expr.op
|
|
1103
|
+
{ if ($expr.$parens || $op.val !== $expr.op?.val || $quantifier?.val !== $expr.quantifier?.val) $expr = { op, args: [$expr], quantifier, location: { ...$.expr.location } }; } // TODO: ...$
|
|
1104
1104
|
{ $quantifier = undefined; }
|
|
1105
1105
|
{ $expr.args.push( $query ); this.attachLocation( $expr ); }
|
|
1106
1106
|
)*
|
|
@@ -1169,9 +1169,9 @@ tableExpression returns[ default expr = {} ] // TableOrJoin
|
|
|
1169
1169
|
(
|
|
1170
1170
|
join=CROSS JOIN
|
|
1171
1171
|
{ if ($expr?.join?.val !== 'cross' || $expr.$parens) $expr = { op: this.valueWithLocation(), join: this.valueWithLocation( undefined, $join ), args: [ $expr ] }; }
|
|
1172
|
-
( tab=tableOrQueryParens {
|
|
1172
|
+
( tab=tableOrQueryParens { const r = this.taggedIfQuery( $tab ); if (r) $expr.args.push( r ); }
|
|
1173
1173
|
{ this.attachLocation( $expr ); }
|
|
1174
|
-
| tab=fromRefWithOptAlias { $expr.args.push( $tab ); }
|
|
1174
|
+
| tab=fromRefWithOptAlias { if ($tab) $expr.args.push( $tab ); }
|
|
1175
1175
|
{ this.attachLocation( $expr ); }
|
|
1176
1176
|
)
|
|
1177
1177
|
|
|
|
@@ -1393,11 +1393,11 @@ selectItemDef[ columns ] locals[ art = new XsnArtifact() ]
|
|
|
1393
1393
|
OVER { this.pushXprToken( $expr.suffix = [] ); }
|
|
1394
1394
|
overClause[ $expr.suffix ]
|
|
1395
1395
|
( e=expression[ ...{ expr: $expr } ]<atAltStart>
|
|
1396
|
-
{ Object.assign( $e.location, $expr.location ); $art.value = this.attachLocation( $e )}
|
|
1396
|
+
{ Object.assign( $e.location || {}, $expr.location ); $art.value = this.attachLocation( $e )}
|
|
1397
1397
|
)?
|
|
1398
1398
|
|
|
|
1399
1399
|
e=expression[ ...{ expr: $expr } ]<atAltStart>
|
|
1400
|
-
{ Object.assign( $e.location, $expr.location ); $art.value = this.attachLocation( $e )}
|
|
1400
|
+
{ Object.assign( $e.location || {}, $expr.location ); $art.value = this.attachLocation( $e )}
|
|
1401
1401
|
)
|
|
1402
1402
|
( AS Id['ItemAlias'] { $art.name = this.identAst(); }
|
|
1403
1403
|
| Id_restricted['ItemAlias'] { $art.name = this.fragileAlias( true ); }
|
|
@@ -1533,9 +1533,8 @@ valuePath returns[ default expr = { path: [] } ] locals[ pathItem ]
|
|
|
1533
1533
|
)*
|
|
1534
1534
|
;
|
|
1535
1535
|
|
|
1536
|
-
// TODO: ? params
|
|
1537
1536
|
expression returns[ default expr = {} ]
|
|
1538
|
-
|
|
1537
|
+
@finally{ if (this.s == null) this.attachLocation( $expr ); }
|
|
1539
1538
|
:
|
|
1540
1539
|
(
|
|
1541
1540
|
expressionOrQueryParens[ ...$ ]
|
|
@@ -1716,7 +1715,8 @@ options{ minTokensMatched = 1 }
|
|
|
1716
1715
|
(
|
|
1717
1716
|
','<prepare=nextFunctionArgument>
|
|
1718
1717
|
( expr=funcExpression { $pathStep.args.push( $expr ); }
|
|
1719
|
-
|
|
|
1718
|
+
| DeleteStarFromSet // Workaround for missing feature, see #13485, TODO
|
|
1719
|
+
| <exitLoop> // TODO <cond>: only before `)`
|
|
1720
1720
|
)
|
|
1721
1721
|
)*
|
|
1722
1722
|
( // ORDER BY in generic functions, e.g. `first_value(id order by name)`
|
|
@@ -1725,6 +1725,8 @@ options{ minTokensMatched = 1 }
|
|
|
1725
1725
|
orderByClauseAsXpr[ $expr.args ]
|
|
1726
1726
|
{ this.attachLocation( $expr ); }
|
|
1727
1727
|
)?
|
|
1728
|
+
|
|
|
1729
|
+
DeleteStarFromSet // Workaround for missing feature, see #13485, TODO
|
|
1728
1730
|
)?
|
|
1729
1731
|
|
|
|
1730
1732
|
// TODO: if we want perfect CC and error recovery, `isNamedArg` would work
|
|
@@ -1772,6 +1774,7 @@ funcExpression returns[ default expr ] locals[ args ]
|
|
|
1772
1774
|
{ $expr = this.applyOpToken(); $args = $expr.args; }
|
|
1773
1775
|
e=expression { $expr.args.push( $e ); }
|
|
1774
1776
|
)
|
|
1777
|
+
// TODO: some <restrict=Id> here?
|
|
1775
1778
|
( options{ lookahead = lGenericSeparator; }
|
|
1776
1779
|
:
|
|
1777
1780
|
GenericSeparator
|
|
@@ -1929,6 +1932,7 @@ annoAssignParen[ art ]
|
|
|
1929
1932
|
:
|
|
1930
1933
|
'('<prepare=annoInSameLine>
|
|
1931
1934
|
( annoAssignBase[ $art ]
|
|
1935
|
+
//( annoAssignErrorRecoveryHelper )?
|
|
1932
1936
|
( ',' | <exitLoop> )
|
|
1933
1937
|
)*
|
|
1934
1938
|
')'
|
|
@@ -2018,7 +2022,8 @@ annoValue returns[ default value = {} ]
|
|
|
2018
2022
|
if ($value.$flatten) $value.$flatten.push( $sub );
|
|
2019
2023
|
else this.addDef( $sub, $value, 'struct', null, $sub.name );
|
|
2020
2024
|
}
|
|
2021
|
-
( ',' | <exitLoop> )
|
|
2025
|
+
( ',' | <exitLoop> | <guard=fail, repeatLoop, restrict=Id> )
|
|
2026
|
+
// <guard=fail, repeatLoop>` for better error recovery for input `foo@bar`
|
|
2022
2027
|
)*
|
|
2023
2028
|
// TODO TOOL: allow:
|
|
2024
2029
|
// ( <guard=arrayAnno, …> '}' | <error> ) // TODO TOOL - workaround:
|
package/lib/parsers/index.js
CHANGED
|
@@ -21,7 +21,7 @@ function parseCdl( source, filename = '<undefined>.cds',
|
|
|
21
21
|
options = {}, messageFunctions = null,
|
|
22
22
|
rule = 'cdl' ) {
|
|
23
23
|
const rulespec = rules[rule];
|
|
24
|
-
if (!options.newParser
|
|
24
|
+
if (!options.newParser && !options.newparser)
|
|
25
25
|
return parseWithAntlr( source, filename, options, messageFunctions, rulespec );
|
|
26
26
|
const { CdlParser } = gen;
|
|
27
27
|
if (CdlParser.tracingParser) // tracing → direct console output of message
|
|
@@ -74,9 +74,7 @@ class DeltaRenderer {
|
|
|
74
74
|
alterColumns(artifactName, columnName, delta, definitionsStr, _eltName, _env) {
|
|
75
75
|
if (Array.isArray(definitionsStr)) {
|
|
76
76
|
const prefix = `ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} ALTER (`;
|
|
77
|
-
|
|
78
|
-
for (let i = 0; i < prefix.length; i++)
|
|
79
|
-
padding += ' ';
|
|
77
|
+
const padding = ' '.repeat(prefix.length);
|
|
80
78
|
const body = definitionsStr.map(s => padding + s).join(',\n').slice(padding.length); // no padding for first part
|
|
81
79
|
const postfix = ');';
|
|
82
80
|
return [ prefix + body + postfix ];
|