@sap/cds-compiler 3.6.2 → 3.8.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 +109 -1
- package/README.md +3 -0
- package/bin/cdsc.js +12 -5
- package/doc/CHANGELOG_ARCHIVE.md +6 -6
- package/doc/CHANGELOG_BETA.md +35 -2
- package/doc/CHANGELOG_DEPRECATED.md +2 -2
- package/doc/DeprecatedOptions_v2.md +1 -1
- package/doc/NameResolution.md +1 -1
- package/lib/api/main.js +63 -23
- package/lib/api/options.js +1 -0
- package/lib/api/validate.js +5 -0
- package/lib/base/dictionaries.js +15 -3
- package/lib/base/keywords.js +2 -0
- package/lib/base/message-registry.js +120 -34
- package/lib/base/messages.js +51 -27
- package/lib/base/model.js +4 -2
- package/lib/base/shuffle.js +2 -1
- package/lib/checks/arrayOfs.js +1 -1
- package/lib/checks/defaultValues.js +1 -1
- package/lib/checks/elements.js +29 -1
- package/lib/checks/{emptyOrOnlyVirtual.js → hasPersistedElements.js} +10 -6
- package/lib/checks/invalidTarget.js +1 -1
- package/lib/checks/nonexpandableStructured.js +1 -1
- package/lib/checks/onConditions.js +15 -9
- package/lib/checks/sql-snippets.js +2 -2
- package/lib/checks/types.js +5 -1
- package/lib/checks/validator.js +7 -3
- package/lib/compiler/assert-consistency.js +42 -26
- package/lib/compiler/base.js +50 -4
- package/lib/compiler/builtins.js +17 -8
- package/lib/compiler/checks.js +241 -246
- package/lib/compiler/define.js +113 -146
- package/lib/compiler/extend.js +889 -383
- package/lib/compiler/finalize-parse-cdl.js +5 -58
- package/lib/compiler/index.js +1 -1
- package/lib/compiler/kick-start.js +7 -8
- package/lib/compiler/populate.js +297 -293
- package/lib/compiler/propagator.js +27 -18
- package/lib/compiler/resolve.js +146 -463
- package/lib/compiler/shared.js +36 -79
- package/lib/compiler/tweak-assocs.js +30 -28
- package/lib/compiler/utils.js +31 -5
- package/lib/edm/annotations/genericTranslation.js +131 -59
- package/lib/edm/annotations/preprocessAnnotations.js +3 -0
- package/lib/edm/csn2edm.js +22 -5
- package/lib/edm/edm.js +6 -4
- package/lib/edm/edmAnnoPreprocessor.js +1 -0
- package/lib/edm/edmPreprocessor.js +42 -26
- package/lib/gen/Dictionary.json +38 -2
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +3 -1
- package/lib/gen/languageLexer.js +1 -1
- package/lib/gen/languageParser.js +4828 -4472
- package/lib/inspect/inspectPropagation.js +20 -34
- package/lib/json/from-csn.js +140 -44
- package/lib/json/to-csn.js +114 -122
- package/lib/language/errorStrategy.js +2 -0
- package/lib/language/genericAntlrParser.js +156 -36
- package/lib/language/language.g4 +100 -58
- package/lib/language/textUtils.js +13 -0
- package/lib/main.d.ts +43 -3
- package/lib/main.js +4 -2
- package/lib/model/csnRefs.js +15 -3
- package/lib/model/csnUtils.js +12 -74
- package/lib/model/revealInternalProperties.js +4 -2
- package/lib/modelCompare/compare.js +2 -1
- package/lib/optionProcessor.js +3 -0
- package/lib/render/manageConstraints.js +5 -2
- package/lib/render/toCdl.js +216 -104
- package/lib/render/toHdbcds.js +2 -9
- package/lib/render/toRename.js +14 -51
- package/lib/render/toSql.js +4 -3
- package/lib/render/utils/common.js +9 -5
- package/lib/transform/braceExpression.js +6 -0
- package/lib/transform/db/assertUnique.js +2 -1
- package/lib/transform/db/expansion.js +2 -0
- package/lib/transform/db/flattening.js +37 -36
- package/lib/transform/db/rewriteCalculatedElements.js +600 -0
- package/lib/transform/db/transformExists.js +4 -0
- package/lib/transform/db/views.js +40 -37
- package/lib/transform/forOdataNew.js +20 -15
- package/lib/transform/forRelationalDB.js +58 -41
- package/lib/transform/odata/typesExposure.js +50 -15
- package/lib/transform/parseExpr.js +16 -8
- package/lib/transform/transformUtilsNew.js +42 -14
- package/lib/transform/translateAssocsToJoins.js +60 -37
- package/lib/transform/universalCsn/coreComputed.js +15 -7
- package/lib/transform/universalCsn/universalCsnEnricher.js +4 -4
- package/package.json +2 -1
package/lib/json/to-csn.js
CHANGED
|
@@ -55,7 +55,7 @@ const transformers = {
|
|
|
55
55
|
kind,
|
|
56
56
|
id: n => n, // in path item
|
|
57
57
|
doc: value,
|
|
58
|
-
'@':
|
|
58
|
+
'@': anno,
|
|
59
59
|
virtual: value,
|
|
60
60
|
key: value,
|
|
61
61
|
unique: value,
|
|
@@ -73,6 +73,17 @@ const transformers = {
|
|
|
73
73
|
// type properties (without 'elements') ------------------------------------
|
|
74
74
|
localized: value,
|
|
75
75
|
type,
|
|
76
|
+
$typeArgs: (node, csn, xsn) => {
|
|
77
|
+
const typeArgs = xsn.$typeArgs;
|
|
78
|
+
// One or two arguments are interpreted as either length or precision/scale.
|
|
79
|
+
if (typeArgs?.length === 1) {
|
|
80
|
+
csn.length = value(typeArgs[0]);
|
|
81
|
+
}
|
|
82
|
+
else if (typeArgs?.length === 2) {
|
|
83
|
+
csn.precision = value(typeArgs[0]);
|
|
84
|
+
csn.scale = value(typeArgs[1]);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
76
87
|
length: value,
|
|
77
88
|
precision: value,
|
|
78
89
|
scale: value,
|
|
@@ -190,6 +201,7 @@ const typeProperties = [
|
|
|
190
201
|
'cardinality', // for association publishing in views
|
|
191
202
|
'type', 'length', 'precision', 'scale', 'srid', 'localized', 'notNull',
|
|
192
203
|
'foreignKeys', 'on', // for explicit ON/keys with REDIRECTED
|
|
204
|
+
'$typeArgs', // for unresolved type arguments, e.g. through parseCql
|
|
193
205
|
];
|
|
194
206
|
|
|
195
207
|
const csnDictionaries = [
|
|
@@ -243,6 +255,12 @@ function sortCsn( csn, cloneOptions = false ) {
|
|
|
243
255
|
setHidden( r, 'elements', csnDictionary( csn.elements, false, cloneOptions ) );
|
|
244
256
|
if (hasNonEnumerable( csn, '$tableConstraints' ) && !r.$tableConstraints)
|
|
245
257
|
setHidden( r, '$tableConstraints', csn.$tableConstraints );
|
|
258
|
+
if (cloneOptions.hiddenPropertiesToClone) {
|
|
259
|
+
cloneOptions.hiddenPropertiesToClone.forEach((property) => {
|
|
260
|
+
if ({}.hasOwnProperty.call( csn, property )) // used in generic reference flattener
|
|
261
|
+
setHidden( r, property, csn[property] );
|
|
262
|
+
});
|
|
263
|
+
}
|
|
246
264
|
}
|
|
247
265
|
return r;
|
|
248
266
|
}
|
|
@@ -382,109 +400,19 @@ function extensions( node, csn, model ) {
|
|
|
382
400
|
if (model.kind && model.kind !== 'source')
|
|
383
401
|
return undefined;
|
|
384
402
|
const exts = node.map( definition );
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
const art = model.definitions[name];
|
|
389
|
-
|
|
390
|
-
// For namespaces and builtins: Extract annotations since they cannot be represented
|
|
391
|
-
// in CSN. For all other artifacts, check whether they may be auto-exposed,
|
|
392
|
-
// $inferred, etc. and extract their annotations.
|
|
393
|
-
// In parseCdl mode extensions were already put into "extensions".
|
|
394
|
-
if (!model.options.parseCdl && (art.kind === 'namespace' || art.builtin)) {
|
|
395
|
-
extractAnnotationsToExtension( art );
|
|
396
|
-
}
|
|
397
|
-
else if (gensrcFlavor) {
|
|
403
|
+
if (gensrcFlavor) {
|
|
404
|
+
for (const name of Object.getOwnPropertyNames( model.definitions || {} ).sort()) {
|
|
405
|
+
const art = model.definitions[name];
|
|
398
406
|
// From definitions (without redefinitions) with potential inferred elements:
|
|
399
407
|
const result = { annotate: Object.create(null) };
|
|
400
|
-
attachAnnotations(result, 'annotate', { [name]: art }, art.$inferred );
|
|
408
|
+
attachAnnotations( result, 'annotate', { [name]: art }, art.$inferred );
|
|
401
409
|
if (result.annotate[name])
|
|
402
|
-
exts.push({ annotate: name, ...result.annotate[name] } );
|
|
410
|
+
exts.push( { annotate: name, ...result.annotate[name] } );
|
|
403
411
|
}
|
|
404
412
|
}
|
|
405
|
-
|
|
406
|
-
return exts.sort(
|
|
413
|
+
return exts.sort( // TODO: really sort with parse.cdl?
|
|
407
414
|
(a, b) => (a.annotate || a.extend).localeCompare( b.annotate || b.extend )
|
|
408
415
|
);
|
|
409
|
-
|
|
410
|
-
/*
|
|
411
|
-
function attachElementAnnos( annotate, art ) {
|
|
412
|
-
while (art.items)
|
|
413
|
-
art = art.items;
|
|
414
|
-
if (art.elements) {
|
|
415
|
-
const elems = inferred( art.elements, art.$inferred );
|
|
416
|
-
if (Object.keys( elems ).length)
|
|
417
|
-
annotate.elements = elems;
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
function attachParamAnnos( annotate, art ) {
|
|
422
|
-
const inferredParent = art.$inferred;
|
|
423
|
-
if (art.params) {
|
|
424
|
-
const ext = Object.create( dictionaryPrototype );
|
|
425
|
-
for (const name in art.params) {
|
|
426
|
-
const par = art.params[name];
|
|
427
|
-
if (!inferredParent && !par.$inferred && par.$expand !== 'annotate')
|
|
428
|
-
continue;
|
|
429
|
-
const render = annotationsAndDocComment( par );
|
|
430
|
-
const subElems = par.$expand !== 'origin' && (par.items || par).elements;
|
|
431
|
-
if (subElems) {
|
|
432
|
-
const sub = inferred( subElems, par.$inferred );
|
|
433
|
-
if (Object.keys( sub ).length)
|
|
434
|
-
render.elements = sub;
|
|
435
|
-
}
|
|
436
|
-
if (Object.keys(render).length)
|
|
437
|
-
ext[name] = render;
|
|
438
|
-
}
|
|
439
|
-
if (obj.keys( ext ))
|
|
440
|
-
annotate.params = ext;
|
|
441
|
-
}
|
|
442
|
-
if (art.returns) {
|
|
443
|
-
const par = art.returns;
|
|
444
|
-
if (!inferredParent && !par.$inferred && par.$expand !== 'annotate')
|
|
445
|
-
return;
|
|
446
|
-
const render = annotationsAndDocComment( par );
|
|
447
|
-
const subElems = par.$expand !== 'origin' && (par.items || par).elements;
|
|
448
|
-
if (subElems) {
|
|
449
|
-
const sub = inferred( subElems, par.$inferred );
|
|
450
|
-
if (Object.keys( sub ).length)
|
|
451
|
-
render.elements = sub;
|
|
452
|
-
}
|
|
453
|
-
if (Object.keys(render).length)
|
|
454
|
-
const sub = inferred( subElems, par.$inferred );
|
|
455
|
-
if (Object.keys( sub ).length)
|
|
456
|
-
render.elements = sub;
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
return ext;
|
|
460
|
-
*/
|
|
461
|
-
|
|
462
|
-
// extract namespace/builtin annotations
|
|
463
|
-
function extractAnnotationsToExtension( art ) {
|
|
464
|
-
const name = art.name.absolute;
|
|
465
|
-
// 'true' because annotations on namespaces and builtins can only
|
|
466
|
-
// happen through extensions.
|
|
467
|
-
const annos = annotationsAndDocComment( art );
|
|
468
|
-
const annotate = Object.assign( { annotate: name }, annos );
|
|
469
|
-
if (Object.keys( annotate ).length > 1) {
|
|
470
|
-
const loc = locationForAnnotationExtension();
|
|
471
|
-
if (loc)
|
|
472
|
-
location( loc, annotate, art );
|
|
473
|
-
exts.push( annotate );
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
// Either the artifact's name's location or (for builtin types) the location
|
|
477
|
-
// of its first annotation.
|
|
478
|
-
function locationForAnnotationExtension() {
|
|
479
|
-
if (art.location)
|
|
480
|
-
return art.location;
|
|
481
|
-
for (const key in art) {
|
|
482
|
-
if (key.charAt(0) === '@' && art[key].name)
|
|
483
|
-
return art[key].name.location;
|
|
484
|
-
}
|
|
485
|
-
return null;
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
416
|
}
|
|
489
417
|
|
|
490
418
|
/**
|
|
@@ -522,7 +450,10 @@ function sources( srcDict, csn ) {
|
|
|
522
450
|
|
|
523
451
|
function attachAnnotations( annotate, prop, dict, inferred, insideReturns = false ) {
|
|
524
452
|
const annoDict = Object.create( dictionaryPrototype );
|
|
525
|
-
|
|
453
|
+
const names = Object.keys( dict );
|
|
454
|
+
if (strictMode)
|
|
455
|
+
names.sort();
|
|
456
|
+
for (const name of names) {
|
|
526
457
|
const entry = dict[name];
|
|
527
458
|
const inf = inferred || entry.$inferred; // is probably always inferred if parent was
|
|
528
459
|
const sub = (inf) ? annotationsAndDocComment( entry ) : {};
|
|
@@ -531,7 +462,7 @@ function attachAnnotations( annotate, prop, dict, inferred, insideReturns = fals
|
|
|
531
462
|
attachAnnotations( sub, 'actions', entry.actions, inf );
|
|
532
463
|
else if (entry.params)
|
|
533
464
|
attachAnnotations( sub, 'params', entry.params, inf );
|
|
534
|
-
const obj = entry.returns || entry;
|
|
465
|
+
const obj = entry.returns || entry; // TODO: create returns !
|
|
535
466
|
const many = obj.items || obj;
|
|
536
467
|
const elems = (many.targetAspect || many).elements;
|
|
537
468
|
if (elems)
|
|
@@ -631,9 +562,11 @@ function elements( dict, csn, node ) {
|
|
|
631
562
|
// no 'elements' with SELECT or inferred elements with gensrc;
|
|
632
563
|
// hidden or visible 'elements' will be set in query()
|
|
633
564
|
return undefined;
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
565
|
+
// TODO(!): inside `annotate`, use sorted with --test-mode
|
|
566
|
+
if (dict === 0)
|
|
567
|
+
return undefined;
|
|
568
|
+
// In "super annotate" statements, use sorted dictionary
|
|
569
|
+
return (node.$inferred === '') ? sortedDict( dict ) : insertOrderDict( dict );
|
|
637
570
|
}
|
|
638
571
|
|
|
639
572
|
function enumDict( dict, csn, node ) {
|
|
@@ -748,7 +681,7 @@ function location( loc, csn, xsn ) {
|
|
|
748
681
|
* @param {object} csn
|
|
749
682
|
*/
|
|
750
683
|
function addLocation( loc, csn ) {
|
|
751
|
-
if (loc) {
|
|
684
|
+
if (loc?.file) {
|
|
752
685
|
// Remove endLine/endCol:
|
|
753
686
|
// Reasoning: $location is mostly attached to definitions/members but the name
|
|
754
687
|
// is often not the reason for an error or warning. So we gain little benefit for
|
|
@@ -773,8 +706,10 @@ function sortedDict( dict ) {
|
|
|
773
706
|
return dictionary( dict, keys );
|
|
774
707
|
}
|
|
775
708
|
|
|
776
|
-
function actions( dict ) {
|
|
709
|
+
function actions( dict, _csn, node ) {
|
|
777
710
|
const keys = Object.keys( dict );
|
|
711
|
+
if (strictMode && node.kind === 'annotate')
|
|
712
|
+
keys.sort(); // TODO: always sort with --test-mode ?
|
|
778
713
|
return (keys.length)
|
|
779
714
|
? dictionary( dict, keys, 'actions' )
|
|
780
715
|
: undefined;
|
|
@@ -812,12 +747,12 @@ function foreignKeys( dict, csn, node ) {
|
|
|
812
747
|
csn.keys.push( definition( dict[n] ) );
|
|
813
748
|
}
|
|
814
749
|
|
|
815
|
-
function returns( art, csn,
|
|
750
|
+
function returns( art, csn, node, prop ) {
|
|
816
751
|
// TODO: currently, the `returns` structure might just have been created by the propagator
|
|
817
752
|
// if that is the case, there should be no reason to store it in universal CSN
|
|
818
|
-
if (universalCsn && art.$inferred === 'proxy')
|
|
753
|
+
if (universalCsn && (art.$inferred === 'proxy' || node.$expand === 'origin'))
|
|
819
754
|
return undefined;
|
|
820
|
-
return definition( art, csn,
|
|
755
|
+
return definition( art, csn, node, prop );
|
|
821
756
|
}
|
|
822
757
|
|
|
823
758
|
function definition( art, _csn, _node, prop ) {
|
|
@@ -872,16 +807,35 @@ function includesOrigin( includes, art ) {
|
|
|
872
807
|
for (const prop in aspect) {
|
|
873
808
|
if ((prop.charAt(0) === '@' || prop === 'doc') &&
|
|
874
809
|
(!art[prop] || art[prop].$inferred)) {
|
|
875
|
-
const
|
|
876
|
-
if (
|
|
877
|
-
//
|
|
878
|
-
result[prop] = value( Object.create(
|
|
810
|
+
const annoVal = aspect[prop];
|
|
811
|
+
if (annoVal.val !== null)
|
|
812
|
+
// materialize non-null annos (whether direct or inherited)
|
|
813
|
+
result[prop] = value( Object.create( annoVal, { $inferred: { value: null } } ) );
|
|
879
814
|
}
|
|
880
815
|
}
|
|
881
816
|
}
|
|
882
817
|
return (Object.keys( result ).length === 1) ? $origin : result;
|
|
883
818
|
}
|
|
884
819
|
|
|
820
|
+
/**
|
|
821
|
+
* Calculated elements via `includes` can inherit annotations from sibling elements.
|
|
822
|
+
* These annotations need to be put into `$origin`, because `$origin` points to
|
|
823
|
+
* the calculated element, not the simple ref's artifact.
|
|
824
|
+
*/
|
|
825
|
+
function calculatedElementOrigin( csn, xsn, origin ) {
|
|
826
|
+
const $origin = originRef( origin );
|
|
827
|
+
const result = { $origin };
|
|
828
|
+
for (const prop in xsn) {
|
|
829
|
+
if ((prop.charAt(0) === '@' || prop === 'doc') && !origin[prop] && xsn[prop].$inferred) {
|
|
830
|
+
const annoVal = xsn[prop];
|
|
831
|
+
if (annoVal.val !== null)
|
|
832
|
+
// materialize non-null annos (whether direct or inherited)
|
|
833
|
+
result[prop] = value( Object.create( annoVal, { $inferred: { value: null } } ) );
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
return (Object.keys( result ).length === 1) ? undefined : result;
|
|
837
|
+
}
|
|
838
|
+
|
|
885
839
|
function addOrigin( csn, xsn, node ) {
|
|
886
840
|
if (!universalCsn)
|
|
887
841
|
return;
|
|
@@ -926,18 +880,32 @@ function addOrigin( csn, xsn, node ) {
|
|
|
926
880
|
return;
|
|
927
881
|
}
|
|
928
882
|
// from here on: member:
|
|
883
|
+
// TODO: write a xsnNode._csnOrigin, which is useful to decide whether to write
|
|
884
|
+
// $origins for its members
|
|
929
885
|
const parent = getParent( xsn );
|
|
930
886
|
const parentOrigin = getOrigin( parent );
|
|
887
|
+
// console.log( 'X:',xsn, origin, parent, parentOrigin, getParent( origin ) );
|
|
931
888
|
if (!origin) {
|
|
932
|
-
if (
|
|
889
|
+
if (parent && parentOrigin &&
|
|
890
|
+
(parent.kind !== 'select' || parent === parent._main._leadingQuery) &&
|
|
891
|
+
!(parent.enum && !parent.$origin && parent.type))
|
|
933
892
|
csn.$origin = null;
|
|
934
893
|
return;
|
|
935
894
|
}
|
|
936
|
-
if (
|
|
895
|
+
if (parent?.kind !== 'select' && parentOrigin?.kind !== 'select' &&
|
|
896
|
+
parentOrigin === getParent( origin )) {
|
|
937
897
|
// implicit prototype or shortened reference
|
|
938
898
|
const { id } = origin.name || {};
|
|
939
|
-
|
|
899
|
+
|
|
900
|
+
if (id && xsn.name && id !== xsn.name.id) {
|
|
940
901
|
csn.$origin = id;
|
|
902
|
+
}
|
|
903
|
+
else if (xsn._calcOrigin) {
|
|
904
|
+
const calcOrigin = calculatedElementOrigin( csn, xsn, origin );
|
|
905
|
+
if (calcOrigin)
|
|
906
|
+
csn.$origin = calcOrigin;
|
|
907
|
+
}
|
|
908
|
+
|
|
941
909
|
return;
|
|
942
910
|
}
|
|
943
911
|
if (origin.kind === 'mixin') {
|
|
@@ -1034,13 +1002,13 @@ function getOrigin( art ) {
|
|
|
1034
1002
|
if (art.$noOrigin)
|
|
1035
1003
|
return undefined;
|
|
1036
1004
|
const { _origin } = art;
|
|
1037
|
-
if (_origin)
|
|
1038
|
-
return (_origin.kind === 'builtin') ? undefined : _origin;
|
|
1005
|
+
if (_origin) // also for query entities
|
|
1006
|
+
return (_origin.kind === 'builtin') ? undefined : _origin;
|
|
1007
|
+
|
|
1039
1008
|
if (hasExplicitProp( art.type, 'cast' ))
|
|
1040
1009
|
return art.type._artifact;
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
// must come after _from, since queries can have includes as well.
|
|
1010
|
+
// must come after checking _origin, since entities can have both queries and
|
|
1011
|
+
// includes as well -> the query wins
|
|
1044
1012
|
if (art.includes)
|
|
1045
1013
|
return art.includes[0]._artifact;
|
|
1046
1014
|
return undefined;
|
|
@@ -1052,7 +1020,7 @@ function hasExplicitProp( ref, alsoLikeExplicit ) {
|
|
|
1052
1020
|
|
|
1053
1021
|
/**
|
|
1054
1022
|
* @param art
|
|
1055
|
-
* @param user
|
|
1023
|
+
* @param [user]
|
|
1056
1024
|
* @return {boolean|string[]}
|
|
1057
1025
|
*/
|
|
1058
1026
|
function originRef( art, user ) {
|
|
@@ -1230,6 +1198,12 @@ function args( node ) {
|
|
|
1230
1198
|
return dict;
|
|
1231
1199
|
}
|
|
1232
1200
|
|
|
1201
|
+
function anno( node ) {
|
|
1202
|
+
if (node.$tokenTexts) // expressions in annotation values
|
|
1203
|
+
return Object.assign({ '=': node.$tokenTexts }, expression( node ));
|
|
1204
|
+
return value(node);
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1233
1207
|
function value( node ) {
|
|
1234
1208
|
// "Short" value form, e.g. for annotation assignments
|
|
1235
1209
|
if (!node)
|
|
@@ -1243,6 +1217,8 @@ function value( node ) {
|
|
|
1243
1217
|
}
|
|
1244
1218
|
if (node.$inferred && gensrcFlavor)
|
|
1245
1219
|
return undefined;
|
|
1220
|
+
if (node.$tokenTexts)
|
|
1221
|
+
return Object.assign({ '=': node.$tokenTexts }, expression( node ));
|
|
1246
1222
|
if (node.path) {
|
|
1247
1223
|
const ref = pathName( node.path );
|
|
1248
1224
|
return extra( { '=': node.variant ? `${ ref }#${ pathName(node.variant.path) }` : ref }, node );
|
|
@@ -1300,7 +1276,7 @@ function expression( node ) {
|
|
|
1300
1276
|
function exprInternal( node, xprParens ) {
|
|
1301
1277
|
if (typeof node === 'string')
|
|
1302
1278
|
return node;
|
|
1303
|
-
if (!node) // make to-csn
|
|
1279
|
+
if (!node) // make to-csn robust
|
|
1304
1280
|
return {};
|
|
1305
1281
|
if (node.scope === 'param') {
|
|
1306
1282
|
if (node.path)
|
|
@@ -1343,6 +1319,8 @@ function exprInternal( node, xprParens ) {
|
|
|
1343
1319
|
case 'ixpr':
|
|
1344
1320
|
case 'xpr':
|
|
1345
1321
|
break;
|
|
1322
|
+
case '?:':
|
|
1323
|
+
return ternaryOperator( node );
|
|
1346
1324
|
case 'cast':
|
|
1347
1325
|
return cast( expression( node.args[0] ), node );
|
|
1348
1326
|
case 'list':
|
|
@@ -1379,6 +1357,20 @@ function flattenInternalXpr( array, op ) {
|
|
|
1379
1357
|
return left;
|
|
1380
1358
|
}
|
|
1381
1359
|
|
|
1360
|
+
function ternaryOperator( node ) {
|
|
1361
|
+
const rargs = [
|
|
1362
|
+
'case',
|
|
1363
|
+
'when', exprInternal(node.args[0]),
|
|
1364
|
+
'then', exprInternal(node.args[2]),
|
|
1365
|
+
'else', exprInternal(node.args[4]),
|
|
1366
|
+
'end',
|
|
1367
|
+
];
|
|
1368
|
+
|
|
1369
|
+
if (node.$parens?.length)
|
|
1370
|
+
return { xpr: flattenInternalXpr( rargs, 'xpr' ) };
|
|
1371
|
+
return flattenInternalXpr( rargs, 'xpr' );
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1382
1374
|
function query( node, csn, xsn, _prop, expectedParens = 0 ) {
|
|
1383
1375
|
if (node.op.val === 'SELECT') {
|
|
1384
1376
|
if (xsn && xsn.query === node && xsn.$syntax === 'projection' &&
|
|
@@ -1548,7 +1540,7 @@ function setHidden( obj, prop, val ) {
|
|
|
1548
1540
|
}
|
|
1549
1541
|
|
|
1550
1542
|
function addExplicitAs( node, name, implicit ) {
|
|
1551
|
-
if (name && name
|
|
1543
|
+
if (name?.id && name.$inferred !== '$internal' &&
|
|
1552
1544
|
(!name.$inferred || !node.ref && !node.func || implicit && implicit(name.id) ))
|
|
1553
1545
|
node.as = name.id;
|
|
1554
1546
|
return node;
|
|
@@ -101,6 +101,7 @@ Object.assign( KeywordErrorStrategy.prototype, {
|
|
|
101
101
|
|
|
102
102
|
// Attempt to recover from problems in subrules, except if rule has defined a
|
|
103
103
|
// local variable `_sync` with value 'nop'
|
|
104
|
+
// TODO: consider performance - see #8800
|
|
104
105
|
function sync( recognizer ) {
|
|
105
106
|
// If already recovering, don't try to sync
|
|
106
107
|
if (this.inErrorRecoveryMode(recognizer))
|
|
@@ -406,6 +407,7 @@ function intervalSetToArray( recognizer, expected, excludesForNextToken ) {
|
|
|
406
407
|
return names;
|
|
407
408
|
}
|
|
408
409
|
|
|
410
|
+
// Used for sorting in messages
|
|
409
411
|
const token1sort = {
|
|
410
412
|
// 0: Identifier, Number, ...
|
|
411
413
|
// 1: separators:
|