@sap/cds-compiler 4.0.2 → 4.1.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.
Files changed (84) hide show
  1. package/CHANGELOG.md +100 -5
  2. package/bin/cdsc.js +12 -12
  3. package/doc/CHANGELOG_BETA.md +11 -0
  4. package/lib/api/main.js +31 -11
  5. package/lib/api/validate.js +1 -1
  6. package/lib/base/location.js +6 -7
  7. package/lib/base/message-registry.js +84 -38
  8. package/lib/base/messages.js +11 -10
  9. package/lib/base/model.js +6 -2
  10. package/lib/checks/defaultValues.js +6 -6
  11. package/lib/checks/foreignKeys.js +0 -5
  12. package/lib/checks/onConditions.js +17 -12
  13. package/lib/checks/queryNoDbArtifacts.js +132 -72
  14. package/lib/checks/sql-snippets.js +15 -4
  15. package/lib/checks/types.js +3 -3
  16. package/lib/checks/utils.js +1 -1
  17. package/lib/compiler/assert-consistency.js +44 -16
  18. package/lib/compiler/base.js +1 -0
  19. package/lib/compiler/builtins.js +7 -8
  20. package/lib/compiler/checks.js +274 -197
  21. package/lib/compiler/classes.js +62 -0
  22. package/lib/compiler/cycle-detector.js +3 -3
  23. package/lib/compiler/define.js +63 -50
  24. package/lib/compiler/extend.js +38 -20
  25. package/lib/compiler/finalize-parse-cdl.js +2 -1
  26. package/lib/compiler/generate.js +0 -8
  27. package/lib/compiler/index.js +9 -7
  28. package/lib/compiler/kick-start.js +2 -0
  29. package/lib/compiler/populate.js +139 -110
  30. package/lib/compiler/propagator.js +4 -3
  31. package/lib/compiler/resolve.js +157 -126
  32. package/lib/compiler/shared.js +706 -404
  33. package/lib/compiler/tweak-assocs.js +21 -10
  34. package/lib/compiler/utils.js +228 -36
  35. package/lib/edm/annotations/genericTranslation.js +1 -1
  36. package/lib/edm/edm.js +4 -1
  37. package/lib/edm/edmPreprocessor.js +5 -4
  38. package/lib/edm/edmUtils.js +2 -4
  39. package/lib/gen/Dictionary.json +34 -10
  40. package/lib/gen/language.checksum +1 -1
  41. package/lib/gen/language.interp +1 -1
  42. package/lib/gen/languageParser.js +3987 -3963
  43. package/lib/json/from-csn.js +43 -47
  44. package/lib/json/to-csn.js +11 -11
  45. package/lib/language/antlrParser.js +2 -1
  46. package/lib/language/genericAntlrParser.js +52 -43
  47. package/lib/language/language.g4 +59 -59
  48. package/lib/language/multiLineStringParser.js +2 -0
  49. package/lib/main.d.ts +5 -0
  50. package/lib/model/csnRefs.js +37 -19
  51. package/lib/model/csnUtils.js +20 -16
  52. package/lib/model/revealInternalProperties.js +29 -21
  53. package/lib/modelCompare/compare.js +112 -39
  54. package/lib/modelCompare/utils/filter.js +54 -24
  55. package/lib/optionProcessor.js +6 -6
  56. package/lib/render/manageConstraints.js +20 -17
  57. package/lib/render/toCdl.js +34 -20
  58. package/lib/render/toHdbcds.js +2 -2
  59. package/lib/render/toRename.js +4 -9
  60. package/lib/render/toSql.js +77 -26
  61. package/lib/render/utils/common.js +3 -3
  62. package/lib/render/utils/unique.js +52 -0
  63. package/lib/transform/db/applyTransformations.js +61 -20
  64. package/lib/transform/db/assertUnique.js +7 -8
  65. package/lib/transform/db/associations.js +2 -2
  66. package/lib/transform/db/cdsPersistence.js +8 -8
  67. package/lib/transform/db/expansion.js +17 -21
  68. package/lib/transform/db/flattening.js +23 -23
  69. package/lib/transform/db/rewriteCalculatedElements.js +20 -14
  70. package/lib/transform/db/temporal.js +1 -1
  71. package/lib/transform/db/transformExists.js +8 -7
  72. package/lib/transform/db/views.js +73 -33
  73. package/lib/transform/draft/db.js +11 -9
  74. package/lib/transform/draft/odata.js +1 -1
  75. package/lib/transform/{forOdataNew.js → forOdata.js} +6 -6
  76. package/lib/transform/forRelationalDB.js +69 -75
  77. package/lib/transform/localized.js +6 -5
  78. package/lib/transform/odata/toFinalBaseType.js +3 -3
  79. package/lib/transform/{transformUtilsNew.js → transformUtils.js} +4 -101
  80. package/lib/transform/translateAssocsToJoins.js +14 -28
  81. package/package.json +1 -1
  82. package/share/messages/check-proper-type-of.md +1 -1
  83. package/share/messages/{check-proper-type.md → def-missing-type.md} +3 -5
  84. package/share/messages/message-explanations.json +1 -1
@@ -216,7 +216,7 @@ usingProxy[ outer, proxy ]
216
216
  )
217
217
  ;
218
218
 
219
- artifactDefOrExtend[ outer, defOnly = false ] locals[ art = {} ] // cannot use `parent` as parameter name!
219
+ artifactDefOrExtend[ outer, defOnly = false ] locals[ art = new parser.XsnArtifact() ] // cannot use `parent` as parameter name!
220
220
  @after{ /* #ATN 1 */ }
221
221
  :
222
222
  { $art.location = this.startLocation(); this.docComment( $art ); }
@@ -285,13 +285,13 @@ optionalSemi
285
285
 
286
286
  // Annotation def and main definitions ------------------------------------------
287
287
 
288
- annotationDef[ art, outer ] locals[ name = {} ]
288
+ annotationDef[ art, outer ] locals[ name = new parser.XsnName() ]
289
289
  @after { this.attachLocation( $art ); }
290
290
  :
291
291
  annotation=ANNOTATION simplePath[ $name, 'AnnoDef' ]
292
292
  { if ($outer.kind !== 'source') { // this is a syntax restriction to avoid confusion
293
293
  this.error( 'syntax-unexpected-vocabulary', $annotation, { '#': $outer.kind } );
294
- $art = {}; }
294
+ $art = new this.XsnArtifact(); }
295
295
  else {
296
296
  if (!$outer.vocabularies) $outer.vocabularies = Object.create(null);
297
297
  this.addDef( $art, $outer, 'vocabularies', 'annotation', $name );
@@ -301,7 +301,7 @@ annotationDef[ art, outer ] locals[ name = {} ]
301
301
  typeSpecSemi[ $art ] // also 'includes'...
302
302
  ;
303
303
 
304
- serviceDef[ art, outer, defOnly = false ] locals[ name = {} ]
304
+ serviceDef[ art, outer, defOnly = false ] locals[ name = new parser.XsnName(); ]
305
305
  @after { this.attachLocation( $art ); }
306
306
  :
307
307
  SERVICE simplePath[ $name, 'Service' ]
@@ -309,7 +309,7 @@ serviceDef[ art, outer, defOnly = false ] locals[ name = {} ]
309
309
  optArtifactsBlock[ $art, defOnly ]
310
310
  ;
311
311
 
312
- contextDef[ art, outer, defOnly = false ] locals[ name = {} ]
312
+ contextDef[ art, outer, defOnly = false ] locals[ name = new parser.XsnName(); ]
313
313
  @after { this.attachLocation( $art ); }
314
314
  :
315
315
  CONTEXT simplePath[ $name, 'Context' ]
@@ -317,7 +317,7 @@ contextDef[ art, outer, defOnly = false ] locals[ name = {} ]
317
317
  optArtifactsBlock[ $art, defOnly ]
318
318
  ;
319
319
 
320
- eventDef[ art, outer ] locals[ name = {} ]
320
+ eventDef[ art, outer ] locals[ name = new parser.XsnName(); ]
321
321
  @after { /* #ATN 1 */ this.attachLocation( $art ); }
322
322
  :
323
323
  EVENT simplePath[ $name, 'Event' ]
@@ -353,7 +353,7 @@ eventDef[ art, outer ] locals[ name = {} ]
353
353
  )
354
354
  ;
355
355
 
356
- viewDef[ art, outer ] locals[ name = {} ]
356
+ viewDef[ art, outer ] locals[ name = new parser.XsnName(); ]
357
357
  @after { this.attachLocation( $art ); }
358
358
  :
359
359
  v=VIEW simplePath[ $name, 'Entity' ]
@@ -376,7 +376,7 @@ viewDef[ art, outer ] locals[ name = {} ]
376
376
  requiredSemi
377
377
  ;
378
378
 
379
- entityDef[ art, outer ] locals[ name = {} ]
379
+ entityDef[ art, outer ] locals[ name = new parser.XsnName() ]
380
380
  @after { this.attachLocation( $art ); }
381
381
  :
382
382
  ENTITY simplePath[ $name, 'Entity' ]
@@ -424,7 +424,7 @@ entityDef[ art, outer ] locals[ name = {} ]
424
424
  )
425
425
  ;
426
426
 
427
- aspectDef[ art, outer ] locals[ name = {} ]
427
+ aspectDef[ art, outer ] locals[ name = new parser.XsnName() ]
428
428
  @after { this.attachLocation( $art ); }
429
429
  :
430
430
  ( ASPECT | ( abs=ABSTRACT | HideAlternatives ) ent=ENTITY )
@@ -453,12 +453,11 @@ aspectDef[ art, outer ] locals[ name = {} ]
453
453
  )?
454
454
  optionalSemi
455
455
  | // `aspect MyAspect;`, e.g. for annotation aspects.
456
- { this.aspectWithoutElements( $art ); }
457
456
  requiredSemi
458
457
  )
459
458
  ;
460
459
 
461
- typeDef[ art, outer ] locals[ name = {} ]
460
+ typeDef[ art, outer ] locals[ name = new parser.XsnName() ]
462
461
  @after { this.attachLocation( $art ); }
463
462
  :
464
463
  TYPE simplePath[ $name, 'Type' ]
@@ -468,7 +467,7 @@ typeDef[ art, outer ] locals[ name = {} ]
468
467
  typeSpecSemi[ $art ]
469
468
  ;
470
469
 
471
- actionFunctionMainDef[ art, outer ] locals[ name = {} ]
470
+ actionFunctionMainDef[ art, outer ] locals[ name = new parser.XsnName() ]
472
471
  @after { this.attachLocation( $art ); }
473
472
  :
474
473
  ACTION simplePath[ $name, 'Action' ]
@@ -488,7 +487,7 @@ actionFunctionMainDef[ art, outer ] locals[ name = {} ]
488
487
 
489
488
  // Member definitions: actions, elements, enums, parameters: --------------------
490
489
 
491
- actionFunctionDef[ outer ] locals[ art = {} ]
490
+ actionFunctionDef[ outer ] locals[ art = new parser.XsnArtifact() ]
492
491
  @after { this.attachLocation( $art ); }
493
492
  :
494
493
  { $art.location = this.startLocation();; this.docComment( $art ); }
@@ -510,7 +509,7 @@ actionFunctionDef[ outer ] locals[ art = {} ]
510
509
  )
511
510
  ;
512
511
 
513
- parameterDef[ outer ] locals[ art = {} ]
512
+ parameterDef[ outer ] locals[ art = new parser.XsnArtifact() ]
514
513
  @after { this.attachLocation( $art ); }
515
514
  :
516
515
  { this.meltKeywordToIdentifier();; this.docComment( $art ); }
@@ -546,7 +545,7 @@ parameterListDef[ art ]
546
545
  ')' { this.finalizeDictOrArray( $art.params ); }
547
546
  ;
548
547
 
549
- enumSymbolDef[ outer ] locals[ art = {} ]
548
+ enumSymbolDef[ outer ] locals[ art = new parser.XsnArtifact() ]
550
549
  @after { this.attachLocation( $art ); }
551
550
  :
552
551
  { $art.location = this.startLocation();; this.docComment( $art ); }
@@ -570,14 +569,14 @@ enumSymbolDef[ outer ] locals[ art = {} ]
570
569
  requiredSemi
571
570
  ;
572
571
 
573
- elementDef[ outer ] locals[ $art = {} ]
572
+ elementDef[ outer ] locals[ $art = new parser.XsnArtifact() ]
574
573
  :
575
574
  { $art.location = this.startLocation();; this.docComment( $art ); }
576
575
  annotationAssignment_ll1[ $art ]*
577
- elementDefInner[ $art, $outer, false ]
576
+ elementDefInner[ $art, $outer ]
578
577
  ;
579
578
 
580
- elementDefInner[ art, outer, mightBeEnum ]
579
+ elementDefInner[ art, outer, explicitElement = false ]
581
580
  @after{ this.attachLocation( $art ); }
582
581
  :
583
582
  // VIRTUAL is keyword, except if before the following tokens texts:
@@ -592,7 +591,7 @@ elementDefInner[ art, outer, mightBeEnum ]
592
591
  }
593
592
  )?
594
593
  { this.setLocalToken( 'ELEMENT', 'ELEMENT', /^[;:{@=}]$/ ); }
595
- ( ELEMENT { $mightBeEnum = false; } )? // auto-recognizable at other places
594
+ ( ELEMENT { $explicitElement = true; } )? // auto-recognizable at other places
596
595
  name=ident['Element']
597
596
  { this.addDef( $art, $outer, 'elements', 'element', $name.id );
598
597
  this.docComment( $art ); }
@@ -605,7 +604,7 @@ elementDefInner[ art, outer, mightBeEnum ]
605
604
  )
606
605
  |
607
606
  ':'
608
- elementType[ $art, $mightBeEnum ]
607
+ elementType[ $art ]
609
608
  |
610
609
  eq='=' e=expression // SQL has syntax variant using AS - we DO NOT
611
610
  stored=STORED?
@@ -613,10 +612,8 @@ elementDefInner[ art, outer, mightBeEnum ]
613
612
  // this.setIntroLocation( eq ); -- future
614
613
  if ($stored)
615
614
  $art.value.stored = this.valueWithTokenLocation( true, $stored );
616
- if ($mightBeEnum && !$stored &&
617
- ($e.expr?.val !== undefined || $e.expr?.sym !== undefined) &&
618
- !$virtual && !$key && !$masked && !$art.elements && !$art.type)
619
- $art['$'+'syntax'] = 'enum';
615
+ if ($explicitElement)
616
+ $art['$'+'syntax'] = 'element';
620
617
  }
621
618
  { this.docComment( $art ); }
622
619
  annotationAssignment_ll1[ $art ]* // for enum symbol def via EXTEND
@@ -750,7 +747,7 @@ defaultValue[ art ] locals[ elem, elements = {} ]
750
747
 
751
748
  // Extend and annotate ----------------------------------------------------------
752
749
 
753
- extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
750
+ extendArtifact[ art, outer ] locals[ name = new parser.XsnName(), elemName = new parser.XsnName() ]
754
751
  @after{ /* #ATN 1 */ this.attachLocation( $art ); }
755
752
  :
756
753
  simplePath[ $name, 'Extend' ]
@@ -771,7 +768,7 @@ extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
771
768
  (
772
769
  // all the alternatives from `extendWithOptElementsOrType` --------------
773
770
  '{' { $art.elements = this.createDict(); }
774
- elementDefOrExtend[ $art, true ]*
771
+ elementDefOrExtend[ $art ]*
775
772
  '}' { this.finalizeDictOrArray( $art.elements ); }
776
773
  { this.checkExtensionDict( $art.elements ); }
777
774
  optionalSemi
@@ -779,7 +776,7 @@ extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
779
776
  requiredSemi
780
777
  |
781
778
  ELEMENTS { $art.elements = this.createDict(); } '{'
782
- elementDefOrExtend[ $art ]*
779
+ elementDefOrExtend[ $art, true ]*
783
780
  '}' { this.finalizeDictOrArray( $art.elements ); }
784
781
  { this.checkExtensionDict( $art.elements ); }
785
782
  optionalSemi
@@ -823,7 +820,7 @@ extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
823
820
  )
824
821
  ;
825
822
 
826
- extendService[ art, outer ] locals[ name = {} ]
823
+ extendService[ art, outer ] locals[ name = new parser.XsnName() ]
827
824
  @after { this.attachLocation( $art ); }
828
825
  :
829
826
  SERVICE { $art.expectedKind = this.valueWithTokenLocation(); }
@@ -833,7 +830,7 @@ extendService[ art, outer ] locals[ name = {} ]
833
830
  optArtifactsBlock[ art, 'service' ]
834
831
  ;
835
832
 
836
- extendContext[ art, outer ] locals[ name = {} ]
833
+ extendContext[ art, outer ] locals[ name = new parser.XsnName() ]
837
834
  @after { this.attachLocation( $art ); }
838
835
  :
839
836
  CONTEXT { $art.expectedKind = this.valueWithTokenLocation(); }
@@ -843,7 +840,7 @@ extendContext[ art, outer ] locals[ name = {} ]
843
840
  optArtifactsBlock[ art, 'context' ]
844
841
  ;
845
842
 
846
- extendEntityOrAspect[ art, outer ] locals[ name = {} ]
843
+ extendEntityOrAspect[ art, outer ] locals[ name = new parser.XsnName() ]
847
844
  @after { /* #ATN 1 */ this.attachLocation( $art ); }
848
845
  :
849
846
  (ASPECT | ENTITY) { $art.expectedKind = this.valueWithTokenLocation(); }
@@ -888,7 +885,7 @@ extendForEntity[ art ]
888
885
  requiredSemi
889
886
  ;
890
887
 
891
- extendProjection[ art, outer ] locals[ name = {} ]
888
+ extendProjection[ art, outer ] locals[ name = new parser.XsnName() ]
892
889
  @after { this.attachLocation( $art ); }
893
890
  :
894
891
  PROJECTION { $art.expectedKind = this.valueWithTokenLocation( 'entity' ); }
@@ -924,7 +921,7 @@ extendProjection[ art, outer ] locals[ name = {} ]
924
921
  )
925
922
  ;
926
923
 
927
- extendType[ art, outer ] locals[ name = {} ]
924
+ extendType[ art, outer ] locals[ name = new parser.XsnName() ]
928
925
  @after { this.attachLocation( $art ); }
929
926
  :
930
927
  TYPE { $art.expectedKind = this.valueWithTokenLocation(); }
@@ -940,7 +937,7 @@ extendType[ art, outer ] locals[ name = {} ]
940
937
  annotationAssignment_ll1[ $art ]*
941
938
  (
942
939
  '{' { $art.elements = this.createDict(); }
943
- elementDefOrExtend[ $art, true ]*
940
+ elementDefOrExtend[ $art ]*
944
941
  '}' { this.finalizeDictOrArray( $art.elements ); }
945
942
  { this.checkExtensionDict( $art.elements ); }
946
943
  optionalSemi
@@ -965,13 +962,13 @@ extendWithOptElementsOrType[ art ]
965
962
  annotationAssignment_ll1[ $art ]*
966
963
  (
967
964
  '{' { $art.elements = this.createDict(); }
968
- elementDefOrExtend[ $art, true ]*
965
+ elementDefOrExtend[ $art ]*
969
966
  '}' { this.finalizeDictOrArray( $art.elements ); }
970
967
  { this.checkExtensionDict( $art.elements ); }
971
968
  optionalSemi
972
969
  |
973
970
  ELEMENTS { $art.elements = this.createDict(); } '{'
974
- elementDefOrExtend[ $art ]*
971
+ elementDefOrExtend[ $art, true ]*
975
972
  '}' { this.finalizeDictOrArray( $art.elements ); }
976
973
  { this.checkExtensionDict( $art.elements ); }
977
974
  optionalSemi
@@ -995,7 +992,7 @@ extendWithOptElementsNoWith[ art ]
995
992
  annotationAssignment_ll1[ $art ]*
996
993
  (
997
994
  '{' { $art.elements = this.createDict(); }
998
- elementDefOrExtend[ $art, true ]*
995
+ elementDefOrExtend[ $art ]*
999
996
  '}' { this.finalizeDictOrArray( $art.elements ); }
1000
997
  { this.checkExtensionDict( $art.elements ); }
1001
998
  optionalSemi
@@ -1006,7 +1003,7 @@ extendWithOptElementsNoWith[ art ]
1006
1003
 
1007
1004
  // For `extend … with elements` or `extend entity … with`, `extend aspect … with`,
1008
1005
  // i.e. definitions in { … } are never enums
1009
- elementDefOrExtend[ outer, mightBeEnum = false ] locals[ art = {} ]
1006
+ elementDefOrExtend[ outer, explicitElement = false ] locals[ art = new parser.XsnArtifact() ]
1010
1007
  @after { /* #ATN 1 */ } // if ($art) this.attachLocation( $art ); }
1011
1008
  :
1012
1009
  { $art.location = this.startLocation();; this.docComment( $art ); }
@@ -1016,7 +1013,7 @@ elementDefOrExtend[ outer, mightBeEnum = false ] locals[ art = {} ]
1016
1013
  EXTEND
1017
1014
  extendElement[ $art, $outer ]
1018
1015
  |
1019
- elementDefInner[ $art, $outer, $mightBeEnum ]
1016
+ elementDefInner[ $art, $outer, $explicitElement ]
1020
1017
  )
1021
1018
  ;
1022
1019
 
@@ -1030,7 +1027,7 @@ extendElement[ art, outer ]
1030
1027
  extendWithOptElementsOrType[ $art, $art ]
1031
1028
  ;
1032
1029
 
1033
- annotateArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
1030
+ annotateArtifact[ art, outer ] locals[ name = new parser.XsnName(), elemName = new parser.XsnName() ]
1034
1031
  @after { this.attachLocation( $art ); }
1035
1032
  :
1036
1033
  simplePath[ $name, 'Annotate' ]
@@ -1090,7 +1087,7 @@ annotateArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
1090
1087
  )
1091
1088
  ;
1092
1089
 
1093
- annotateElement[ outer ] locals[ art = {} ]
1090
+ annotateElement[ outer ] locals[ art = new parser.XsnArtifact() ]
1094
1091
  @after{ this.attachLocation( $art ); }
1095
1092
  :
1096
1093
  { $art.location = this.startLocation();; this.docComment( $art ); }
@@ -1110,7 +1107,7 @@ annotateElement[ outer ] locals[ art = {} ]
1110
1107
  )
1111
1108
  ;
1112
1109
 
1113
- annotateAction [ outer ] locals [ art = {} ]
1110
+ annotateAction [ outer ] locals [ art = new parser.XsnArtifact() ]
1114
1111
  @after{ this.attachLocation( $art ); }
1115
1112
  :
1116
1113
  { $art.location = this.startLocation();; this.docComment( $art ); }
@@ -1138,7 +1135,7 @@ annotateAction [ outer ] locals [ art = {} ]
1138
1135
  annotateReturns[ art ]
1139
1136
  @after{ this.attachLocation( $art.returns ); }
1140
1137
  :
1141
- ret=RETURNS { $art.returns = { kind: 'annotate' }; }
1138
+ ret=RETURNS { $art.returns = new this.XsnArtifact();; $art.returns.kind = 'annotate'; }
1142
1139
  { this.docComment( $art.returns ); }
1143
1140
  annotationAssignment_ll1[ $art.returns ]*
1144
1141
  ( '{' { $art.returns.elements = this.createDict(); }
@@ -1150,7 +1147,7 @@ annotateReturns[ art ]
1150
1147
  )
1151
1148
  ;
1152
1149
 
1153
- annotateParam [ outer ] locals [ art = {} ]
1150
+ annotateParam [ outer ] locals [ art = new parser.XsnArtifact() ]
1154
1151
  @after{ this.attachLocation( $art ); }
1155
1152
  :
1156
1153
  { $art.location = this.startLocation();; this.docComment( $art ); }
@@ -1424,9 +1421,12 @@ typeAssociationCont[ art ]
1424
1421
  )*
1425
1422
  )?
1426
1423
  '}' { this.finalizeDictOrArray( $art.foreignKeys ); }
1424
+ defaultAndNullability[ $art ]?
1427
1425
  |
1428
1426
  ON cond=condition
1429
1427
  { $art.on=$cond.cond; }
1428
+ |
1429
+ defaultAndNullability[ $art ]
1430
1430
  )
1431
1431
  ;
1432
1432
 
@@ -1442,12 +1442,12 @@ typeAssociationElementCont[ art ] // including Composition
1442
1442
  )*
1443
1443
  )?
1444
1444
  '}' { this.finalizeDictOrArray( $art.foreignKeys ); }
1445
- nullability[ $art ]?
1445
+ defaultAndNullability[ $art ]?
1446
1446
  |
1447
1447
  ON cond=condition
1448
1448
  { $art.on=$cond.cond; }
1449
1449
  |
1450
- nullability[ $art ]
1450
+ defaultAndNullability[ $art ]
1451
1451
  )?
1452
1452
  { this.docComment( $art ); }
1453
1453
  annotationAssignment_ll1[ $art ]*
@@ -1515,7 +1515,7 @@ nullability[ art ]
1515
1515
  | n1=NULL
1516
1516
  ;
1517
1517
 
1518
- foreignKey[ outer ] locals[ art = {}, elem = {} ]
1518
+ foreignKey[ outer ] locals[ art = new parser.XsnArtifact(), elem = {} ]
1519
1519
  @after { this.attachLocation($art); }
1520
1520
  :
1521
1521
  simplePath[ $elem, 'ref' ] { $art.targetElement = $elem; }
@@ -1784,7 +1784,7 @@ tableTerm returns [ table ]
1784
1784
  }
1785
1785
  ':' fromPath[ $table, 'ref']
1786
1786
  )?
1787
- ( AS n1=ident['FromAlias'] { $table.name = $n1.id }
1787
+ ( AS n1=ident['FromAlias'] { $table.name = $n1.id; }
1788
1788
  | n2=identNoKeyword['FromAlias'] { $table.name = this.fragileAlias( $n2.id ); }
1789
1789
  // if we would use rule `ident`, we would either had to make all JOIN
1790
1790
  // kinds reserved or introduce ATN
@@ -1823,7 +1823,7 @@ fromPath[ qp, idkind ] returns[ dotAfterFilter = null ]
1823
1823
  if (!$qp.scope) $qp.scope = $qp.path.length;
1824
1824
  } }
1825
1825
  '.' id=ident[$idkind] { this.pushIdent( $qp.path, $id.id ); }
1826
- ( fromArguments[ $id.id ] cardinalityAndFilter[ $id.id ]?
1826
+ ( fromArguments[ $id.id ] cardinalityAndFilter[ $id.id ]?
1827
1827
  { if (!$dotAfterFilter) $dotAfterFilter = false; }
1828
1828
  | cardinalityAndFilter[ $id.id ]
1829
1829
  { if (!$dotAfterFilter) $dotAfterFilter = false; }
@@ -1887,7 +1887,7 @@ selectItemDef[ outer ] locals[ art ]
1887
1887
  star='*'
1888
1888
  { $outer.push( this.valueWithTokenLocation( '*', $star ) ); }
1889
1889
  |
1890
- { $art = {};; this.docComment( $art ); }
1890
+ { $art = new this.XsnArtifact();; this.docComment( $art ); }
1891
1891
  annotationAssignment_atn[ $art ]*
1892
1892
  // VIRTUAL is keyword, except if before the following tokens texts:
1893
1893
  { this.setLocalToken( 'VIRTUAL', 'VIRTUAL', /^([,.:\[@]|as)$/i ) ; } // not '{'
@@ -1904,7 +1904,7 @@ selectItemDefBody[ art, outer ] locals[ assoc ]
1904
1904
  e=expression { $art.value = $e.expr; }
1905
1905
  // we cannot use 'condition' instead, as long as we allow aliases without
1906
1906
  // AS (using rule 'ident' instead of 'identNoKeyword') -> ambiguities
1907
- ( as=AS n1=ident['Item'] { $art.name = $n1.id }
1907
+ ( as=AS n1=ident['Item'] { $art.name = $n1.id; }
1908
1908
  | n2=ident['Item'] { $art.name = this.fragileAlias( $n2.id, true ); }
1909
1909
  | { this.classifyImplicitName( 'Item', $e.expr ); }
1910
1910
  )
@@ -1929,7 +1929,7 @@ selectItemDefBody[ art, outer ] locals[ assoc ]
1929
1929
  |
1930
1930
  selectItemInlineList[ $art, 'expand' ]
1931
1931
  excludingClause[ $art ]?
1932
- AS n1=ident['Item'] { $art.name = $n1.id }
1932
+ AS n1=ident['Item'] { $art.name = $n1.id; }
1933
1933
  )
1934
1934
  { this.docComment( $art ); }
1935
1935
  annotationAssignment_fix[ $art ]*
@@ -1995,7 +1995,7 @@ selectItemInlineDef[ outer ] locals[ art ]
1995
1995
  star='*'
1996
1996
  { $outer.push( this.valueWithTokenLocation( '*', $star ) ); }
1997
1997
  |
1998
- { $art = {};; this.docComment( $art ); }
1998
+ { $art = new this.XsnArtifact();; this.docComment( $art ); }
1999
1999
  annotationAssignment_atn[ $art ]*
2000
2000
  selectItemDefBody[ $art, $outer ]
2001
2001
  ;
@@ -2312,7 +2312,7 @@ expressionTerm returns [ expr ] locals [ args = [] ]
2312
2312
  )
2313
2313
  ;
2314
2314
 
2315
- specialFunction returns [ ret = {} ] locals[ art = {} ]
2315
+ specialFunction returns [ ret = {} ] locals[ art = new parser.XsnArtifact() ]
2316
2316
  :
2317
2317
  ca=CAST '(' // see createArray() in action
2318
2318
  {
@@ -2663,7 +2663,7 @@ annotationAssignment_fix[ art ] locals[ assignment ]
2663
2663
  (
2664
2664
  annotationAssignment_paren[ $art ]
2665
2665
  |
2666
- { $assignment = { name: {} }; }
2666
+ { $assignment = { name: new this.XsnName() }; }
2667
2667
  annotationPath[ $assignment.name, 'anno' ]
2668
2668
  ( '#' annotationPathVariant[ $assignment.name ] )?
2669
2669
  { this.warnIfColonFollows( $assignment ); }
@@ -2681,7 +2681,7 @@ annotationAssignment_ll1[ art ] locals[ assignment ]
2681
2681
  (
2682
2682
  annotationAssignment_paren[ $art ]
2683
2683
  |
2684
- { $assignment = { name: {} }; }
2684
+ { $assignment = { name: new this.XsnName() }; }
2685
2685
  annotationPath[ $assignment.name, 'anno' ]
2686
2686
  ( '#' annotationPathVariant[ $assignment.name ] )?
2687
2687
  (
@@ -2703,7 +2703,7 @@ annotationAssignment_atn[ art ] locals[ assignment ]
2703
2703
  (
2704
2704
  annotationAssignment_paren[ $art ]
2705
2705
  |
2706
- { $assignment = { name: {} }; }
2706
+ { $assignment = { name: new this.XsnName() }; }
2707
2707
  annotationPath[ $assignment.name, 'anno' ]
2708
2708
  // '#' is in the follow set of this rule, as it is used in rule "selectItemDef"
2709
2709
  // before an "expression" which can start with a '#' for an enum value
@@ -2749,7 +2749,7 @@ annotationAssignment_paren[ art ]
2749
2749
  ')'
2750
2750
  ;
2751
2751
 
2752
- annotationAssignment_1[ art ] locals[ assignment = { name: {} } ]
2752
+ annotationAssignment_1[ art ] locals[ assignment = { name: new parser.XsnName() } ]
2753
2753
  @after { this.assignAnnotation( $art, $assignment ); }
2754
2754
  :
2755
2755
  annotationPath[ $assignment.name, 'anno' ]
@@ -2865,7 +2865,7 @@ annoValueBase[ assignment ] locals [ seenEllipsis = false ]
2865
2865
  ')'
2866
2866
  ;
2867
2867
 
2868
- flattenedValue[ assignment ] locals[ val = { name: {} } ]
2868
+ flattenedValue[ assignment ] locals[ val = { name: new parser.XsnName() } ]
2869
2869
  :
2870
2870
  at='@'? annotationPath[ $val.name, 'name', $at ]
2871
2871
  ( '#' annotationPathVariant[ $val.name ] )?
@@ -2876,7 +2876,7 @@ flattenedValue[ assignment ] locals[ val = { name: {} } ]
2876
2876
  { $assignment['$'+'flatten'].push( $val ); }
2877
2877
  ;
2878
2878
 
2879
- namedValue[ struct ] locals[ val = { name: {} } ]
2879
+ namedValue[ struct ] locals[ val = { name: new parser.XsnName() } ]
2880
2880
  :
2881
2881
  at='@'? annotationPath[ $val.name, 'name', $at ]
2882
2882
  ( ':' { this.meltKeywordToIdentifier(true); }
@@ -6,6 +6,7 @@ const {
6
6
  cdlNewLineRegEx,
7
7
  } = require('./textUtils');
8
8
  const { CompilerAssertion } = require('../base/error');
9
+ const { CsnLocation } = require('../compiler/classes');
9
10
 
10
11
  /**
11
12
  * Strips and counts the indentation from the given string.
@@ -462,6 +463,7 @@ class MultiLineStringParser {
462
463
  */
463
464
  _locationForCharacters(i, width) {
464
465
  return {
466
+ __proto__: CsnLocation.prototype,
465
467
  file: this.parser.filename,
466
468
  line: this.token.line + this._lineInString,
467
469
  endLine: this.token.line + this._lineInString,
package/lib/main.d.ts CHANGED
@@ -466,6 +466,11 @@ declare namespace compiler {
466
466
  */
467
467
  export class CompilationError extends Error {
468
468
  constructor(messages: CompileMessage[], model?: any, text?: string, ...args: any[]);
469
+ /**
470
+ * String to identify this class. Can be used instead of relying on `instanceof`.
471
+ * @since v4.0.0
472
+ */
473
+ code = 'ERR_CDS_COMPILATION_FAILURE';
469
474
  messages: CompileMessage[];
470
475
  toString(): string;
471
476
  /**
@@ -49,14 +49,14 @@
49
49
  // inspectRef() - to enable caching.
50
50
  //
51
51
  // If any of these conditions are not given, our functions usually simply
52
- // throws an exception (which might even be a plain TypeError), but it might
52
+ // throw an exception (which might even be a plain TypeError), but it might
53
53
  // also just return any value. CSN processors can provide user-friendly error
54
54
  // messages by calling the Core Compiler in case of exceptions. For details,
55
55
  // see internalDoc/CoreCompiler.md#use-of-the-core-compiler-for-csn-processors.
56
56
 
57
57
  // During a transformation, care must be taken to adhere to these conditions.
58
58
  // E.g. a structure flattening function cannot create an element `s_x` and
59
- // delete `s` and then still expects inspectRef() to be able to resolve a
59
+ // delete `s` and then still expect inspectRef() to be able to resolve a
60
60
  // reference `['s', 'x']`.
61
61
 
62
62
  // There are currently 3 (SQL) backend issues for which we provide a workaround:
@@ -205,15 +205,14 @@ const artifactProperties = [ 'elements', 'columns', 'keys', 'mixin', 'enum',
205
205
  // - lexical: false | Function - determines where to look first for “lexical names”
206
206
  // - dynamic: String - describes the dynamic environment (if in query)
207
207
  // - assoc: String, with dynamic: 'global' - what to do with assoc steps
208
- // * 'static': visit elements of anonymous aspect if not last ref item
209
208
  // * 'target': always follow target, including last ref item
210
- // * other (& not provided) = follow target if not last ref item
209
+ // * other (& not provided) = follow target (targetAspect if no target) if not last ref item
211
210
  const referenceSemantics = {
212
211
  $init: { $initOnly: true },
213
- type: { lexical: false, dynamic: 'global', assoc: 'static' },
214
- includes: { lexical: false, dynamic: 'global', assoc: 'static' }, // no elem ref anyway
215
- target: { lexical: false, dynamic: 'global', assoc: 'static' }, // no elem ref anyway
216
- targetAspect: { lexical: false, dynamic: 'global', assoc: 'static' },
212
+ type: { lexical: false, dynamic: 'global' },
213
+ includes: { lexical: false, dynamic: 'global' },
214
+ target: { lexical: false, dynamic: 'global' },
215
+ targetAspect: { lexical: false, dynamic: 'global' },
217
216
  from: { lexical: false, dynamic: 'global', assoc: 'target' },
218
217
  keys: { lexical: false, dynamic: 'target' },
219
218
  keys_origin: { lexical: false, dynamic: 'target' },
@@ -265,6 +264,9 @@ function csnRefs( csn, universalReady ) {
265
264
  queryOrMain,
266
265
  getColumn: elem => getCache( elem, '_column' ),
267
266
  getElement: col => getCache( col, '_element' ),
267
+ /** Returns the column's name; either explicit, implicit or internal one. */
268
+ getColumnName: col => getCache( col, '$as' ),
269
+ $getQueries: def => getCache( def, '$queries' ), // unstable API
268
270
  initDefinition,
269
271
  dropDefinitionCache,
270
272
  targetAspect,
@@ -314,7 +316,7 @@ function csnRefs( csn, universalReady ) {
314
316
  env = effectiveType( env.items );
315
317
  if (env.elements) // shortcut
316
318
  return env;
317
- const target = (staticAssoc ? targetAspect( env ) : env.target);
319
+ const target = (staticAssoc ? targetAspect( env ) : env.target || env.targetAspect);
318
320
  if (typeof target !== 'string')
319
321
  return target || env;
320
322
  const def = csn.definitions[target];
@@ -352,7 +354,7 @@ function csnRefs( csn, universalReady ) {
352
354
 
353
355
  function fromArtifactRef( ref ) {
354
356
  // do not cache while there is second param
355
- const art = artifactFromRef( ref, true );
357
+ const art = artifactFromRef( ref );
356
358
  if (art)
357
359
  return art;
358
360
  throw new ModelError( `Unknown artifact reference: ${ typeof ref !== 'string' ? JSON.stringify(ref.ref) : ref }` );
@@ -363,7 +365,7 @@ function csnRefs( csn, universalReady ) {
363
365
  let art = csn.definitions[pathId( head )];
364
366
  initDefinition( art );
365
367
  for (const elem of tail) {
366
- const env = navigationEnv( art, true );
368
+ const env = navigationEnv( art );
367
369
  art = env.elements[pathId( elem )];
368
370
  }
369
371
  return art;
@@ -758,7 +760,7 @@ function csnRefs( csn, universalReady ) {
758
760
  qcache.elements = elements;
759
761
  const { columns } = qcache._select;
760
762
  if (elements && columns)
761
- columns.map( c => initColumnElement( c, qcache ) );
763
+ columns.map( (col, colIndex) => initColumnElement( col, colIndex, qcache ) );
762
764
  else if (columns && !elements)
763
765
  throw new ModelError( `Query elements not available: ${ Object.keys( (index ? qcache._select : main) ).join('+') }`);
764
766
  } );
@@ -784,16 +786,19 @@ function csnRefs( csn, universalReady ) {
784
786
  : { $aliases: Object.create(null), $next: pcache.$next };
785
787
  }
786
788
 
787
- function initColumnElement( col, parentElementOrQueryCache ) {
789
+ function initColumnElement( col, colIndex, parentElementOrQueryCache ) {
788
790
  if (col === '*')
789
791
  return;
790
792
  if (col.inline) {
791
- col.inline.map( c => initColumnElement( c, parentElementOrQueryCache ) );
793
+ col.inline.map( c => initColumnElement( c, null, parentElementOrQueryCache ) );
792
794
  return;
793
795
  }
794
796
  setCache( col, '_parent', // not set for query (has property _select)
795
797
  !parentElementOrQueryCache._select && parentElementOrQueryCache );
796
- const as = col.as || col.func || implicitAs( col.ref );
798
+ let as = columnAlias( col );
799
+ if (!as && colIndex !== null)
800
+ as = `$_column_${ colIndex + 1 }`;
801
+ setCache( col, '$as', as );
797
802
  let type = parentElementOrQueryCache;
798
803
  while (type.items)
799
804
  type = type.items;
@@ -801,7 +806,7 @@ function csnRefs( csn, universalReady ) {
801
806
  if (elem) // TODO to.sql: something is strange if this is not set
802
807
  setCache( elem, '_column', col );
803
808
  if (col.expand)
804
- col.expand.map( c => initColumnElement( c, elem ) );
809
+ col.expand.map( c => initColumnElement( c, null, elem ) );
805
810
  }
806
811
 
807
812
  // property name convention in cache:
@@ -843,10 +848,11 @@ function csnRefs( csn, universalReady ) {
843
848
  }
844
849
  }
845
850
 
846
- // Return value of a query SELECT for the query node, or the main artifact,
847
- // i.e. a value with an `elements` property.
848
- // TODO: only used in forRelationalDB - move somewhere else
849
851
  /**
852
+ * Return value of a query SELECT for the query node, or the main artifact,
853
+ * i.e. a value with an `elements` property.
854
+ * TODO: only used in forRelationalDB - move somewhere else
855
+ *
850
856
  * @param {object} query node (object with SET or SELECT property)
851
857
  * @param {object} main definition
852
858
  */
@@ -1122,6 +1128,17 @@ function isSelectQuery( query ) {
1122
1128
  return true;
1123
1129
  }
1124
1130
 
1131
+ /**
1132
+ * Alias is either explicit or implicit from reference or function without arguments.
1133
+ * If the column is an expression without explicit alias, `false` is returned.
1134
+ * Use csnRefs.getColumnName() instead.
1135
+ *
1136
+ * @returns {string|false}
1137
+ */
1138
+ function columnAlias( col ) {
1139
+ return col.as || (!col.args && col.func) || (col.ref && implicitAs( col.ref ));
1140
+ }
1141
+
1125
1142
  module.exports = {
1126
1143
  csnRefs,
1127
1144
  traverseQuery,
@@ -1129,4 +1146,5 @@ module.exports = {
1129
1146
  implicitAs,
1130
1147
  analyseCsnPath,
1131
1148
  pathId,
1149
+ columnAlias,
1132
1150
  };