@sap/cds-compiler 3.4.4 → 3.5.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 +58 -0
- package/README.md +1 -0
- package/bin/cds_update_identifiers.js +5 -5
- package/bin/cdsc.js +12 -12
- package/doc/CHANGELOG_ARCHIVE.md +1 -1
- package/doc/CHANGELOG_BETA.md +9 -1
- package/doc/CHANGELOG_DEPRECATED.md +2 -0
- package/lib/api/main.js +58 -59
- package/lib/api/options.js +4 -2
- package/lib/api/validate.js +2 -2
- package/lib/base/cleanSymbols.js +2 -3
- package/lib/base/dictionaries.js +6 -6
- package/lib/base/error.js +2 -2
- package/lib/base/keywords.js +6 -6
- package/lib/base/location.js +11 -12
- package/lib/base/message-registry.js +124 -28
- package/lib/base/messages.js +247 -179
- package/lib/base/model.js +14 -11
- package/lib/base/node-helpers.js +9 -10
- package/lib/base/optionProcessorHelper.js +138 -129
- package/lib/checks/actionsFunctions.js +5 -5
- package/lib/checks/annotationsOData.js +4 -4
- package/lib/checks/arrayOfs.js +1 -1
- package/lib/checks/cdsPersistence.js +1 -1
- package/lib/checks/checkForTypes.js +3 -3
- package/lib/checks/defaultValues.js +3 -3
- package/lib/checks/elements.js +7 -7
- package/lib/checks/emptyOrOnlyVirtual.js +2 -2
- package/lib/checks/foreignKeys.js +1 -1
- package/lib/checks/invalidTarget.js +4 -4
- package/lib/checks/managedInType.js +1 -1
- package/lib/checks/managedWithoutKeys.js +1 -1
- package/lib/checks/nonexpandableStructured.js +5 -3
- package/lib/checks/nullableKeys.js +1 -1
- package/lib/checks/onConditions.js +5 -6
- package/lib/checks/parameters.js +1 -1
- package/lib/checks/queryNoDbArtifacts.js +2 -2
- package/lib/checks/selectItems.js +4 -4
- package/lib/checks/sql-snippets.js +4 -4
- package/lib/checks/types.js +7 -7
- package/lib/checks/utils.js +4 -4
- package/lib/checks/validator.js +16 -13
- package/lib/compiler/.eslintrc.json +1 -1
- package/lib/compiler/assert-consistency.js +0 -1
- package/lib/compiler/builtins.js +1 -1
- package/lib/compiler/checks.js +73 -15
- package/lib/compiler/define.js +3 -7
- package/lib/compiler/extend.js +212 -32
- package/lib/compiler/finalize-parse-cdl.js +7 -2
- package/lib/compiler/index.js +17 -14
- package/lib/compiler/populate.js +2 -5
- package/lib/compiler/propagator.js +2 -0
- package/lib/compiler/shared.js +23 -12
- package/lib/compiler/tweak-assocs.js +5 -6
- package/lib/compiler/utils.js +6 -0
- package/lib/edm/annotations/genericTranslation.js +553 -319
- package/lib/edm/annotations/preprocessAnnotations.js +39 -35
- package/lib/edm/csn2edm.js +88 -75
- package/lib/edm/edm.js +17 -3
- package/lib/edm/edmAnnoPreprocessor.js +5 -5
- package/lib/edm/edmPreprocessor.js +106 -76
- package/lib/edm/edmUtils.js +41 -2
- package/lib/gen/Dictionary.json +34 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +66 -63
- package/lib/gen/language.tokens +81 -81
- package/lib/gen/languageLexer.interp +4 -10
- package/lib/gen/languageLexer.js +854 -869
- package/lib/gen/languageLexer.tokens +79 -81
- package/lib/gen/languageParser.js +14360 -14146
- package/lib/inspect/inspectModelStatistics.js +2 -2
- package/lib/inspect/inspectPropagation.js +6 -6
- package/lib/inspect/inspectUtils.js +2 -2
- package/lib/json/from-csn.js +82 -40
- package/lib/json/to-csn.js +82 -157
- package/lib/language/.eslintrc.json +1 -4
- package/lib/language/genericAntlrParser.js +59 -38
- package/lib/language/language.g4 +1508 -1490
- package/lib/language/multiLineStringParser.js +1 -1
- package/lib/main.js +3 -3
- package/lib/model/csnUtils.js +130 -122
- package/lib/model/revealInternalProperties.js +1 -1
- package/lib/model/sortViews.js +4 -6
- package/lib/modelCompare/utils/filter.js +4 -3
- package/lib/optionProcessor.js +5 -0
- package/lib/render/DuplicateChecker.js +1 -1
- package/lib/render/manageConstraints.js +12 -12
- package/lib/render/toCdl.js +225 -159
- package/lib/render/toHdbcds.js +63 -63
- package/lib/render/toRename.js +5 -5
- package/lib/render/toSql.js +55 -65
- package/lib/render/utils/common.js +20 -37
- package/lib/render/utils/delta.js +3 -3
- package/lib/render/utils/sql.js +22 -6
- package/lib/render/utils/stringEscapes.js +3 -3
- package/lib/transform/db/applyTransformations.js +3 -3
- package/lib/transform/db/assertUnique.js +13 -12
- package/lib/transform/db/associations.js +5 -5
- package/lib/transform/db/cdsPersistence.js +10 -8
- package/lib/transform/db/constraints.js +14 -14
- package/lib/transform/db/expansion.js +20 -22
- package/lib/transform/db/flattening.js +24 -42
- package/lib/transform/db/groupByOrderBy.js +3 -3
- package/lib/transform/db/temporal.js +6 -6
- package/lib/transform/db/transformExists.js +23 -23
- package/lib/transform/db/views.js +16 -16
- package/lib/transform/draft/db.js +10 -10
- package/lib/transform/draft/odata.js +2 -2
- package/lib/transform/forOdataNew.js +12 -40
- package/lib/transform/forRelationalDB.js +17 -7
- package/lib/transform/localized.js +2 -2
- package/lib/transform/odata/toFinalBaseType.js +41 -27
- package/lib/transform/odata/typesExposure.js +106 -62
- package/lib/transform/parseExpr.js +209 -106
- package/lib/transform/transformUtilsNew.js +2 -2
- package/lib/transform/translateAssocsToJoins.js +24 -19
- package/lib/transform/universalCsn/coreComputed.js +10 -10
- package/lib/transform/universalCsn/universalCsnEnricher.js +26 -26
- package/lib/transform/universalCsn/utils.js +3 -3
- package/lib/utils/file.js +5 -5
- package/lib/utils/moduleResolve.js +13 -13
- package/lib/utils/objectUtils.js +6 -6
- package/lib/utils/term.js +5 -2
- package/lib/utils/timetrace.js +51 -24
- package/package.json +5 -7
- package/share/messages/check-proper-type-of.md +1 -1
- package/share/messages/message-explanations.json +1 -1
- package/share/messages/redirected-to-complex.md +4 -4
- package/share/messages/{syntax-expecting-integer.md → syntax-expecting-unsigned-int.md} +7 -4
package/lib/json/to-csn.js
CHANGED
|
@@ -30,9 +30,9 @@ const normalizedKind = {
|
|
|
30
30
|
let gensrcFlavor = true; // good enough here...
|
|
31
31
|
let universalCsn = false;
|
|
32
32
|
let strictMode = false; // whether to dump with unknown properties (in standard)
|
|
33
|
-
let parensAsStrings = false;
|
|
34
33
|
let projectionAsQuery = false;
|
|
35
34
|
let withLocations = false;
|
|
35
|
+
let structXpr = false;
|
|
36
36
|
let dictionaryPrototype = null;
|
|
37
37
|
|
|
38
38
|
// Properties for dictionaries, set in compileX() and TODO: parseX(), must be
|
|
@@ -93,7 +93,7 @@ const transformers = {
|
|
|
93
93
|
where: condition, // also pathItem after 'cardinality' before 'args'
|
|
94
94
|
having: condition,
|
|
95
95
|
args, // also pathItem after 'where', before 'on'/'orderBy'
|
|
96
|
-
suffix:
|
|
96
|
+
suffix: ignore, // handled in exprInternal()
|
|
97
97
|
orderBy: arrayOf( orderBy ), // TODO XSN: make `sort` and `nulls` sibling properties
|
|
98
98
|
sort: value,
|
|
99
99
|
nulls: value,
|
|
@@ -191,41 +191,6 @@ const typeProperties = [
|
|
|
191
191
|
'foreignKeys', 'on', // for explicit ON/keys with REDIRECTED
|
|
192
192
|
];
|
|
193
193
|
|
|
194
|
-
const operators = {
|
|
195
|
-
// standard is: binary infix (and corresponding n-ary), unary prefix
|
|
196
|
-
isNot: [ 'is', 'not' ], // TODO XSN: 'is not'
|
|
197
|
-
isNull: postfix( [ 'is', 'null' ] ),
|
|
198
|
-
isNotNull: postfix( [ 'is', 'not', 'null' ] ),
|
|
199
|
-
in: binaryRightParen( [ 'in' ] ),
|
|
200
|
-
notIn: binaryRightParen( [ 'not', 'in' ] ),
|
|
201
|
-
between: ternary( [ 'between' ], [ 'and' ] ),
|
|
202
|
-
notBetween: ternary( [ 'not', 'between' ], [ 'and' ] ),
|
|
203
|
-
like: ternary( [ 'like' ], [ 'escape' ] ),
|
|
204
|
-
notLike: ternary( [ 'not', 'like' ], [ 'escape' ] ),
|
|
205
|
-
when: exprs => [ 'when', ...exprs[0], 'then', ...exprs[1] ],
|
|
206
|
-
case: exprs => [ 'case' ].concat( ...exprs, [ 'end' ] ),
|
|
207
|
-
over: exprs => [ 'over', { xpr: [].concat( ...exprs ) } ],
|
|
208
|
-
orderBy: exprs => [ // ORDER BY in generic functions
|
|
209
|
-
...exprs[0], ...operators.overOrderBy(exprs.slice(1)),
|
|
210
|
-
],
|
|
211
|
-
overOrderBy: exprs => [ // ORDER BY in OVER() clause
|
|
212
|
-
'order', 'by', ...exprs[0].concat( ...exprs.slice(1).map( e => [ ',', ...e ] ) ),
|
|
213
|
-
],
|
|
214
|
-
partitionBy: exprs => [
|
|
215
|
-
'partition', 'by', ...exprs[0].concat( ...exprs.slice(1).map( e => [ ',', ...e ] ) ),
|
|
216
|
-
],
|
|
217
|
-
rows: exprs => [
|
|
218
|
-
'rows', ...exprs[0].concat( ...exprs.slice(1).map( e => [ ',', ...e ] ) ),
|
|
219
|
-
],
|
|
220
|
-
preceding: postfix( [ 'preceding' ] ),
|
|
221
|
-
unboundedPreceding: [ 'unbounded', 'preceding' ],
|
|
222
|
-
currentRow: [ 'current', 'row' ],
|
|
223
|
-
unboundedFollowing: [ 'unbounded', 'following' ],
|
|
224
|
-
following: postfix( [ 'following' ] ),
|
|
225
|
-
frameBetween: exprs => [ 'between', ...exprs[0], 'and', ...exprs[1] ],
|
|
226
|
-
ixpr: exprs => [].concat( ...exprs ), // xpr extra, due to extra parentheses
|
|
227
|
-
};
|
|
228
|
-
|
|
229
194
|
const csnDictionaries = [
|
|
230
195
|
'args', 'params', 'enum', 'mixin', 'elements', 'actions', 'definitions',
|
|
231
196
|
];
|
|
@@ -281,7 +246,7 @@ function sortCsn( csn, cloneOptions = false ) {
|
|
|
281
246
|
return r;
|
|
282
247
|
}
|
|
283
248
|
|
|
284
|
-
function cloneAnnotationValue(val) {
|
|
249
|
+
function cloneAnnotationValue( val ) {
|
|
285
250
|
if (typeof val !== 'object') // scalar
|
|
286
251
|
return val;
|
|
287
252
|
return JSON.parse( JSON.stringify( val ) );
|
|
@@ -296,7 +261,7 @@ function cloneAnnotationValue(val) {
|
|
|
296
261
|
* @param {string} property
|
|
297
262
|
* @returns
|
|
298
263
|
*/
|
|
299
|
-
function hasNonEnumerable(object, property) {
|
|
264
|
+
function hasNonEnumerable( object, property ) {
|
|
300
265
|
return {}.hasOwnProperty.call( object, property ) &&
|
|
301
266
|
!{}.propertyIsEnumerable.call( object, property );
|
|
302
267
|
}
|
|
@@ -346,7 +311,7 @@ function compactModel( model, options = model.options || {} ) {
|
|
|
346
311
|
for (const first in srcDict) {
|
|
347
312
|
const { namespace } = srcDict[first];
|
|
348
313
|
if (namespace && namespace.path)
|
|
349
|
-
csn.namespace = namespace.path
|
|
314
|
+
csn.namespace = pathName( namespace.path );
|
|
350
315
|
break;
|
|
351
316
|
}
|
|
352
317
|
set( 'definitions', csn, model );
|
|
@@ -740,8 +705,11 @@ function annotationsAndDocComment( node ) {
|
|
|
740
705
|
if (sub !== undefined)
|
|
741
706
|
csn[prop] = sub;
|
|
742
707
|
}
|
|
743
|
-
if (node.doc)
|
|
744
|
-
|
|
708
|
+
if (node.doc) {
|
|
709
|
+
const doc = transformers.doc(node.doc);
|
|
710
|
+
if (doc !== undefined)
|
|
711
|
+
csn.doc = doc;
|
|
712
|
+
}
|
|
745
713
|
return csn;
|
|
746
714
|
}
|
|
747
715
|
|
|
@@ -829,21 +797,18 @@ function dictionary( dict, keys, prop ) {
|
|
|
829
797
|
}
|
|
830
798
|
|
|
831
799
|
function foreignKeys( dict, csn, node ) {
|
|
832
|
-
if (universalCsn)
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
for (const n in dict) {
|
|
840
|
-
const d = definition( dict[n] );
|
|
841
|
-
if (d !== undefined)
|
|
842
|
-
keys.push( d );
|
|
843
|
-
else
|
|
800
|
+
if (universalCsn && dict[$inferred] === 'keys' || !target( node.target, csn, node ) )
|
|
801
|
+
return;
|
|
802
|
+
|
|
803
|
+
if (gensrcFlavor) {
|
|
804
|
+
if (node._origin?.$inferred === 'REDIRECTED')
|
|
805
|
+
dict = node._origin.foreignKeys;
|
|
806
|
+
if (dict[$inferred])
|
|
844
807
|
return;
|
|
845
808
|
}
|
|
846
|
-
csn.keys =
|
|
809
|
+
csn.keys = [];
|
|
810
|
+
for (const n in dict)
|
|
811
|
+
csn.keys.push( definition( dict[n] ) );
|
|
847
812
|
}
|
|
848
813
|
|
|
849
814
|
function returns( art, csn, _node, prop ) {
|
|
@@ -1231,7 +1196,7 @@ function renderArtifactPath( node, path, terse, scope ) {
|
|
|
1231
1196
|
const name = item._artifact && item._artifact.name;
|
|
1232
1197
|
// In localization views, the _artifact link of `item` is important
|
|
1233
1198
|
const id = name && name.absolute ||
|
|
1234
|
-
path.slice( 0, scope )
|
|
1199
|
+
pathName( path.slice( 0, scope ) );
|
|
1235
1200
|
path = [ Object.assign( {}, item, { id } ), ...path.slice( scope ) ];
|
|
1236
1201
|
}
|
|
1237
1202
|
const ref = path.map( pathItem );
|
|
@@ -1255,7 +1220,7 @@ function args( node ) {
|
|
|
1255
1220
|
return node.map( expression );
|
|
1256
1221
|
const dict = Object.create( dictionaryPrototype );
|
|
1257
1222
|
for (const param in node)
|
|
1258
|
-
dict[param] = expression( node[param]
|
|
1223
|
+
dict[param] = expression( node[param] );
|
|
1259
1224
|
return dict;
|
|
1260
1225
|
}
|
|
1261
1226
|
|
|
@@ -1298,7 +1263,7 @@ function enumValue( v, csn, node ) {
|
|
|
1298
1263
|
return;
|
|
1299
1264
|
// (with gensrc, the symbol itself would not make it into the CSN)
|
|
1300
1265
|
if (node.kind === 'enum' || node._parent && node._parent.kind === 'extend')
|
|
1301
|
-
Object.assign( csn, expression( v
|
|
1266
|
+
Object.assign( csn, expression( v ) );
|
|
1302
1267
|
}
|
|
1303
1268
|
|
|
1304
1269
|
|
|
@@ -1313,128 +1278,89 @@ function onCondition( cond, csn, node ) {
|
|
|
1313
1278
|
}
|
|
1314
1279
|
|
|
1315
1280
|
function condition( node ) {
|
|
1316
|
-
const expr =
|
|
1317
|
-
|
|
1318
|
-
|
|
1281
|
+
const expr = exprInternal( node, 'no' );
|
|
1282
|
+
return (Array.isArray( expr ))
|
|
1283
|
+
? flattenenInternalXpr( expr )
|
|
1284
|
+
: !expr.cast && !expr.func && expr.xpr || [ expr ];
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
function expression( node ) {
|
|
1288
|
+
const expr = exprInternal( node, 'no' );
|
|
1289
|
+
return (Array.isArray( expr ))
|
|
1290
|
+
? { xpr: flattenenInternalXpr( expr ) }
|
|
1291
|
+
: expr;
|
|
1319
1292
|
}
|
|
1320
1293
|
|
|
1321
|
-
function
|
|
1322
|
-
const dollarExtraNode = dollarExtra !== 'ignoreExtra' && node;
|
|
1294
|
+
function exprInternal( node, xprParens ) {
|
|
1323
1295
|
if (typeof node === 'string')
|
|
1324
1296
|
return node;
|
|
1325
1297
|
if (!node) // make to-csn robst
|
|
1326
1298
|
return {};
|
|
1327
1299
|
if (node.scope === 'param') {
|
|
1328
1300
|
if (node.path)
|
|
1329
|
-
return extra( { ref: node.path.map( pathItem ), param: true },
|
|
1301
|
+
return extra( { ref: node.path.map( pathItem ), param: true }, node );
|
|
1330
1302
|
return { ref: [ node.param.val ], param: true }; // CDL rule for runtimes
|
|
1331
1303
|
}
|
|
1332
1304
|
if (node.path) {
|
|
1333
1305
|
const ref = node.path.map( pathItem );
|
|
1334
|
-
if (node.path.$prefix)
|
|
1306
|
+
if (node.path.$prefix) // auto-corrected ORDER BY refs without table alias
|
|
1335
1307
|
ref.unshift( node.path.$prefix );
|
|
1336
1308
|
// we would need to consider node.global here if we introduce that
|
|
1337
|
-
return extra( { ref },
|
|
1309
|
+
return extra( { ref }, node );
|
|
1338
1310
|
}
|
|
1339
1311
|
if (node.literal) {
|
|
1340
1312
|
if (typeof node.val === node.literal || node.val === null)
|
|
1341
|
-
return extra( { val: node.val },
|
|
1313
|
+
return extra( { val: node.val }, node );
|
|
1342
1314
|
else if (node.literal === 'enum')
|
|
1343
|
-
return extra( { '#': node.sym.id },
|
|
1315
|
+
return extra( { '#': node.sym.id }, node );
|
|
1344
1316
|
else if (node.literal === 'token')
|
|
1345
1317
|
return node.val; // * in COUNT(*)
|
|
1346
|
-
return extra( { val: node.val, literal: node.literal },
|
|
1318
|
+
return extra( { val: node.val, literal: node.literal }, node );
|
|
1347
1319
|
}
|
|
1348
1320
|
if (node.func) { // TODO XSN: remove op: 'call', func is no path
|
|
1349
1321
|
const call = { func: node.func.path[0].id };
|
|
1350
|
-
if (node.args)
|
|
1322
|
+
if (node.args) // no args from CSN input for CURRENT_DATE etc
|
|
1351
1323
|
call.args = args( node.args );
|
|
1352
|
-
const arg0 = call.args[0];
|
|
1353
|
-
const { quantifier } = node.func.path[0];
|
|
1354
|
-
if (arg0 && quantifier) {
|
|
1355
|
-
if (typeof arg0 !== 'object' || !arg0.xpr)
|
|
1356
|
-
call.args[0] = { xpr: [ quantifier.val, arg0 ] };
|
|
1357
|
-
else
|
|
1358
|
-
arg0.xpr.unshift( quantifier.val );
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
1324
|
if (node.suffix)
|
|
1362
|
-
call.xpr =
|
|
1363
|
-
|
|
1325
|
+
call.xpr = condition( { op: { val: 'ixpr' }, args: node.suffix } );
|
|
1326
|
+
// remark: node.suffix.map( expression ) would add $parens: 1 for xpr after "over"
|
|
1327
|
+
return extra( call, node );
|
|
1364
1328
|
}
|
|
1365
1329
|
if (node.query)
|
|
1366
1330
|
return query( node.query, null, null, null, 1 );
|
|
1367
1331
|
if (!node.op) // parse error
|
|
1368
1332
|
return { xpr: [] };
|
|
1369
|
-
else if (node.op.val === 'xpr')
|
|
1370
|
-
// do not use xpr() for xpr, as it would flatten inner xpr's
|
|
1371
|
-
return extra({ xpr: node.args.map( expression ) }, dollarExtraNode, 1 );
|
|
1372
|
-
else if (node.op.val === 'cast')
|
|
1373
|
-
return cast( expression( node.args[0] ), dollarExtraNode );
|
|
1374
|
-
// from here on: CDL input (no $extra possible - but $parens)
|
|
1375
|
-
else if (node.op.val !== ',')
|
|
1376
|
-
return extra( { xpr: xpr( node ) }, dollarExtraNode, (dollarExtra === 'sub-xpr' ? 1 : 0) );
|
|
1377
|
-
return (parensAsStrings)
|
|
1378
|
-
? { xpr: [ '(', ...xpr( node ), ')' ] }
|
|
1379
|
-
// the inner parens belong to the tuple construct, i.e. won't count as parens
|
|
1380
|
-
: extra( { list: node.args.map( expression ) }, dollarExtraNode, 0 );
|
|
1381
|
-
}
|
|
1382
|
-
|
|
1383
|
-
function xpr( node ) {
|
|
1384
|
-
// if (!node.op) console.log(node)
|
|
1385
|
-
const op = operators[node.op.val] || node.op.val.split(' ');
|
|
1386
|
-
const exprs = node.args.map( xprArg );
|
|
1387
|
-
if (op instanceof Function)
|
|
1388
|
-
return op( exprs );
|
|
1389
|
-
if (node.quantifier)
|
|
1390
|
-
op.push( node.quantifier.val );
|
|
1391
|
-
if (exprs.length < 2)
|
|
1392
|
-
return [ ...op, ...exprs[0] || [] ];
|
|
1393
|
-
return exprs[0].concat( ...exprs.slice(1).map( a => [ ...op, ...a ] ) );
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
|
-
function xprArg( sub ) {
|
|
1397
|
-
const realXpr = sub.op && sub.op.val === 'xpr';
|
|
1398
|
-
const expr = expression( sub, 'sub-xpr' );
|
|
1399
|
-
// `sort`/`nulls` will be attached to arguments of orderBy
|
|
1400
|
-
// which might be either `path`s or `xpr`s
|
|
1401
|
-
const sortAndNulls = [];
|
|
1402
|
-
if (sub.sort)
|
|
1403
|
-
sortAndNulls.push( sub.sort.val );
|
|
1404
|
-
if (sub.nulls)
|
|
1405
|
-
sortAndNulls.push( ...[ 'nulls', sub.nulls.val ] );
|
|
1406
|
-
// return !sub.$parens && !expr.cast && !expr.func && expr.xpr || [ expr ];
|
|
1407
|
-
// if parensAsStrings is gone
|
|
1408
|
-
if (realXpr || expr.cast || expr.func || !expr.xpr || sub.$parens && !parensAsStrings)
|
|
1409
|
-
return [ expr, ...sortAndNulls ];
|
|
1410
|
-
else if (sub.$parens && sub.op.val !== ',')
|
|
1411
|
-
return [ '(', ...expr.xpr, ')' ];
|
|
1412
|
-
|
|
1413
|
-
expr.xpr.push( ...sortAndNulls );
|
|
1414
|
-
return expr.xpr;
|
|
1415
|
-
}
|
|
1416
|
-
|
|
1417
|
-
function ternary( op1, op2 ) {
|
|
1418
|
-
return function ternaryOp( exprs ) {
|
|
1419
|
-
return (exprs[2])
|
|
1420
|
-
? [ ...exprs[0], ...op1, ...exprs[1], ...op2, ...exprs[2] ]
|
|
1421
|
-
: [ ...exprs[0], ...op1, ...exprs[1] ];
|
|
1422
|
-
};
|
|
1423
|
-
}
|
|
1424
1333
|
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1334
|
+
const { val } = node.op;
|
|
1335
|
+
switch (val) {
|
|
1336
|
+
case 'ixpr':
|
|
1337
|
+
case 'xpr':
|
|
1338
|
+
break;
|
|
1339
|
+
case 'cast':
|
|
1340
|
+
return cast( expression( node.args[0] ), node );
|
|
1341
|
+
case 'list':
|
|
1342
|
+
return extra( { list: node.args.map( expression ) }, node, 0 );
|
|
1343
|
+
default: { // '=', 'and', CSN v0 input: binary (n-ary) and unary prefix
|
|
1344
|
+
if (!node.args.length)
|
|
1345
|
+
return { xpr: [] };
|
|
1346
|
+
const nary = [];
|
|
1347
|
+
for (const item of node.args)
|
|
1348
|
+
nary.push( { val, literal: 'token' }, item );
|
|
1349
|
+
node = {
|
|
1350
|
+
op: { val: 'ixpr' },
|
|
1351
|
+
args: (nary.length > 2 ? nary.slice(1) : nary),
|
|
1352
|
+
$parens: node.$parens,
|
|
1353
|
+
};
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
const rargs = node.args.map( exprInternal );
|
|
1357
|
+
if (val === 'xpr' || node.$parens)
|
|
1358
|
+
return extra( { xpr: flattenenInternalXpr( rargs ) }, node, (xprParens === 'no' ? 0 : 1) );
|
|
1359
|
+
return rargs.length === 1 ? rargs[0] : rargs;
|
|
1429
1360
|
}
|
|
1430
1361
|
|
|
1431
|
-
function
|
|
1432
|
-
return (
|
|
1433
|
-
const right = exprs[1].length === 1 ? exprs[1][0] : {};
|
|
1434
|
-
return (right.xpr || right.list || !right.$parens)
|
|
1435
|
-
? [ ...exprs[0], ...op, ...exprs[1] ]
|
|
1436
|
-
: [ ...exprs[0], ...op, { xpr: exprs[1] } ];
|
|
1437
|
-
};
|
|
1362
|
+
function flattenenInternalXpr( array ) {
|
|
1363
|
+
return (structXpr) ? array : array.flat( Infinity );
|
|
1438
1364
|
}
|
|
1439
1365
|
|
|
1440
1366
|
function query( node, csn, xsn, _prop, expectedParens = 0 ) {
|
|
@@ -1538,7 +1464,7 @@ function addElementAsColumn( elem, cols ) {
|
|
|
1538
1464
|
gensrcFlavor = gensrcFlavor || 'column';
|
|
1539
1465
|
set( 'virtual', col, elem );
|
|
1540
1466
|
set( 'key', col, elem );
|
|
1541
|
-
const expr = expression( elem.value
|
|
1467
|
+
const expr = expression( elem.value );
|
|
1542
1468
|
Object.assign( col, (expr.cast ? { xpr: [ expr ] } : expr) );
|
|
1543
1469
|
gensrcFlavor = gensrcSaved; // for not having annotations in inline etc
|
|
1544
1470
|
if (elem.expand)
|
|
@@ -1574,7 +1500,7 @@ function orderBy( node ) {
|
|
|
1574
1500
|
expr.sort = node.sort.val;
|
|
1575
1501
|
if (node.nulls)
|
|
1576
1502
|
expr.nulls = node.nulls.val;
|
|
1577
|
-
return
|
|
1503
|
+
return expr; // extra properties are before sort/nulls - who cares?
|
|
1578
1504
|
}
|
|
1579
1505
|
|
|
1580
1506
|
function extra( csn, node, expectedParens = 0 ) {
|
|
@@ -1639,19 +1565,18 @@ function compactQuery( q ) { // TODO: options
|
|
|
1639
1565
|
|
|
1640
1566
|
function compactExpr( e ) { // TODO: options
|
|
1641
1567
|
initModuleVars();
|
|
1642
|
-
return e && expression( e
|
|
1568
|
+
return e && expression( e );
|
|
1643
1569
|
}
|
|
1644
1570
|
|
|
1645
1571
|
/**
|
|
1646
1572
|
* @param {CSN.Options} options
|
|
1647
1573
|
*/
|
|
1648
1574
|
function initModuleVars( options = { csnFlavor: 'gensrc' } ) {
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
universalCsn =
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
!options.parseCdl;
|
|
1575
|
+
const flavor = options.csnFlavor || options.toCsn?.flavor;
|
|
1576
|
+
gensrcFlavor = options.parseCdl || flavor === 'gensrc';
|
|
1577
|
+
universalCsn = flavor === 'universal' &&
|
|
1578
|
+
isBetaEnabled( options, 'enableUniversalCsn' ) &&
|
|
1579
|
+
!options.parseCdl;
|
|
1655
1580
|
strictMode = options.testMode;
|
|
1656
1581
|
const proto = options.dictionaryPrototype;
|
|
1657
1582
|
// eslint-disable-next-line no-nested-ternary
|
|
@@ -1659,7 +1584,7 @@ function initModuleVars( options = { csnFlavor: 'gensrc' } ) {
|
|
|
1659
1584
|
? proto
|
|
1660
1585
|
: (proto) ? Object.prototype : null;
|
|
1661
1586
|
withLocations = options.withLocations;
|
|
1662
|
-
|
|
1587
|
+
structXpr = options.structXpr;
|
|
1663
1588
|
projectionAsQuery = isDeprecatedEnabled( options, '_projectionAsQuery' );
|
|
1664
1589
|
}
|
|
1665
1590
|
|
|
@@ -86,15 +86,15 @@ Object.assign(GenericAntlrParser.prototype, {
|
|
|
86
86
|
previousTokenAtLocation,
|
|
87
87
|
combinedLocation,
|
|
88
88
|
surroundByParens,
|
|
89
|
+
secureParens,
|
|
89
90
|
unaryOpForParens,
|
|
90
91
|
leftAssocBinaryOp,
|
|
91
92
|
classifyImplicitName,
|
|
92
93
|
warnIfColonFollows,
|
|
93
94
|
fragileAlias,
|
|
94
95
|
identAst,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
xprToken,
|
|
96
|
+
pushXprToken,
|
|
97
|
+
argsExpression,
|
|
98
98
|
valuePathAst,
|
|
99
99
|
signedExpression,
|
|
100
100
|
numberLiteral,
|
|
@@ -249,9 +249,15 @@ const genericTokenTypes = {
|
|
|
249
249
|
intro: 'GenericIntro',
|
|
250
250
|
};
|
|
251
251
|
|
|
252
|
+
/**
|
|
253
|
+
* @memberOf GenericAntlrParser
|
|
254
|
+
*
|
|
255
|
+
* @param pathItem
|
|
256
|
+
* @param [expected]
|
|
257
|
+
*/
|
|
252
258
|
function prepareGenericKeywords( pathItem, expected = null ) {
|
|
253
259
|
const length = pathItem?.args?.length || 0;
|
|
254
|
-
const argPos =
|
|
260
|
+
const argPos = length;
|
|
255
261
|
const func = pathItem?.id && specialFunctions[pathItem.id.toUpperCase()];
|
|
256
262
|
const spec = func && func[argPos] || specialFunctions[''][argPos ? 1 : 0];
|
|
257
263
|
this.$genericKeywords = spec;
|
|
@@ -477,7 +483,7 @@ function tokenLocation( token, endToken = null ) {
|
|
|
477
483
|
function isMultiLineToken( token ) {
|
|
478
484
|
return (
|
|
479
485
|
token.type === this.constructor.DocComment ||
|
|
480
|
-
token.type === this.constructor.String ||
|
|
486
|
+
token.type === this.constructor.String || // TODO: do not check every string content
|
|
481
487
|
token.type === this.constructor.UnterminatedLiteral
|
|
482
488
|
);
|
|
483
489
|
}
|
|
@@ -547,6 +553,23 @@ function combinedLocation( start, end ) {
|
|
|
547
553
|
return locUtils.combinedLocation( start, end );
|
|
548
554
|
}
|
|
549
555
|
|
|
556
|
+
// make sure that the parens of `IN (…)` do not disappear:
|
|
557
|
+
function secureParens( expr ) {
|
|
558
|
+
const op = expr?.op?.val;
|
|
559
|
+
const $parens = expr?.$parens;
|
|
560
|
+
if (!$parens || expr.query || op && op !== 'call' && op !== 'cast')
|
|
561
|
+
return expr;
|
|
562
|
+
// ensure that references, literals and functions keep their surrounding parentheses
|
|
563
|
+
// (is for expressions the case anyway)
|
|
564
|
+
delete expr.$parens;
|
|
565
|
+
return {
|
|
566
|
+
op: { val: 'xpr', location: this.startLocation() },
|
|
567
|
+
args: [ expr ],
|
|
568
|
+
location: { ...expr.location },
|
|
569
|
+
$parens,
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
|
|
550
573
|
function surroundByParens( expr, open, close, asQuery = false ) {
|
|
551
574
|
if (!expr)
|
|
552
575
|
return expr;
|
|
@@ -657,33 +680,27 @@ function identAst( token, category, noTokenTypeCheck = false ) {
|
|
|
657
680
|
return { id, $delimited: true, location: this.tokenLocation( token ) };
|
|
658
681
|
}
|
|
659
682
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
args,
|
|
670
|
-
location,
|
|
671
|
-
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
function setLastAsXpr( args ) {
|
|
675
|
-
const pos = args.length - 1;
|
|
676
|
-
const last = args[pos];
|
|
677
|
-
if (!last || last?.op?.val === 'ixpr') // actuall an internal xpr, which is always flattened
|
|
678
|
-
return last;
|
|
679
|
-
const location = { ...last.location };
|
|
680
|
-
args[pos] = { op: { location, val: 'ixpr' }, args: [ last ], location };
|
|
681
|
-
return args[pos].args;
|
|
683
|
+
// only to be used in @after
|
|
684
|
+
// TODO: remove compatible stuff (A2J/checks use op: 'and'/'=')
|
|
685
|
+
function argsExpression( args, useFirstLocation, compatible = null ) {
|
|
686
|
+
// console.log('AE:',args);
|
|
687
|
+
if (args.length === 1)
|
|
688
|
+
return args[0];
|
|
689
|
+
const location = useFirstLocation && args[0] && { ...args[0].location };
|
|
690
|
+
const op = compatible && args.length === 3 && args[1].val === compatible && args[1];
|
|
691
|
+
const expr = (op)
|
|
692
|
+
? { op: { val: op.val, location: op.location }, args: [ args[0], args[2] ], location }
|
|
693
|
+
: { op: { val: 'ixpr', location: this.startLocation() }, args, location };
|
|
694
|
+
return this.attachLocation( expr );
|
|
682
695
|
}
|
|
683
696
|
|
|
684
|
-
function
|
|
697
|
+
function pushXprToken( args ) {
|
|
685
698
|
const token = this._input.LT(-1);
|
|
686
|
-
|
|
699
|
+
args.push( {
|
|
700
|
+
location: this.tokenLocation( token ),
|
|
701
|
+
val: token.text.toLowerCase(), // TODO: remove toLowerCase() ?
|
|
702
|
+
literal: 'token',
|
|
703
|
+
} );
|
|
687
704
|
}
|
|
688
705
|
|
|
689
706
|
function valuePathAst( ref ) {
|
|
@@ -720,10 +737,11 @@ function valuePathAst( ref ) {
|
|
|
720
737
|
|
|
721
738
|
// If a '-' is directly before an unsigned number, consider it part of the number;
|
|
722
739
|
// otherwise (including for '+'), represent it as extra unary prefix operator.
|
|
723
|
-
function signedExpression(
|
|
724
|
-
|
|
740
|
+
function signedExpression( args, expr ) {
|
|
741
|
+
// if (args.length !== 1) throw Error()
|
|
742
|
+
const sign = args[0];
|
|
725
743
|
const nval
|
|
726
|
-
= (
|
|
744
|
+
= (sign.val === '-' &&
|
|
727
745
|
expr && // expr may be null if `-` rule can't be parsed
|
|
728
746
|
expr.literal === 'number' &&
|
|
729
747
|
sign.location.endLine === expr.location.line &&
|
|
@@ -731,11 +749,14 @@ function signedExpression( signToken, expr ) {
|
|
|
731
749
|
(typeof expr.val === 'number'
|
|
732
750
|
? expr.val >= 0 && -expr.val
|
|
733
751
|
: !expr.val.startsWith('-') && `-${ expr.val }`)) || false;
|
|
734
|
-
if (nval === false)
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
752
|
+
if (nval === false) {
|
|
753
|
+
args.push( expr );
|
|
754
|
+
}
|
|
755
|
+
else {
|
|
756
|
+
expr.val = nval;
|
|
757
|
+
--expr.location.col;
|
|
758
|
+
args[0] = expr;
|
|
759
|
+
}
|
|
739
760
|
}
|
|
740
761
|
|
|
741
762
|
// Return AST for number token `token` with optional token `sign`. Represent
|
|
@@ -756,7 +777,7 @@ function numberLiteral( token, sign, text = token.text ) {
|
|
|
756
777
|
const num = Number.parseFloat( text || '0' ); // not Number.parseInt() !
|
|
757
778
|
if (!Number.isSafeInteger(num)) {
|
|
758
779
|
if (sign == null) {
|
|
759
|
-
this.error( 'syntax-expecting-
|
|
780
|
+
this.error( 'syntax-expecting-unsigned-int', token,
|
|
760
781
|
{ '#': !text.match(/^[0-9]*$/) ? 'normal' : 'unsafe' } );
|
|
761
782
|
}
|
|
762
783
|
|