@sap/cds-compiler 2.11.4 → 2.13.8

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 (133) hide show
  1. package/CHANGELOG.md +159 -1
  2. package/bin/cds_update_identifiers.js +7 -7
  3. package/bin/cdsc.js +22 -23
  4. package/bin/cdsse.js +2 -2
  5. package/doc/CHANGELOG_ARCHIVE.md +1 -1
  6. package/doc/CHANGELOG_BETA.md +25 -6
  7. package/doc/CHANGELOG_DEPRECATED.md +22 -6
  8. package/doc/NameResolution.md +21 -16
  9. package/lib/api/main.js +30 -63
  10. package/lib/api/options.js +5 -5
  11. package/lib/api/validate.js +0 -5
  12. package/lib/backends.js +15 -23
  13. package/lib/base/dictionaries.js +0 -8
  14. package/lib/base/error.js +26 -0
  15. package/lib/base/keywords.js +7 -17
  16. package/lib/base/location.js +9 -4
  17. package/lib/base/message-registry.js +52 -2
  18. package/lib/base/messages.js +16 -26
  19. package/lib/base/model.js +2 -62
  20. package/lib/base/optionProcessorHelper.js +246 -183
  21. package/lib/checks/.eslintrc.json +2 -0
  22. package/lib/checks/actionsFunctions.js +2 -1
  23. package/lib/checks/annotationsOData.js +1 -1
  24. package/lib/checks/cdsPersistence.js +2 -1
  25. package/lib/checks/enricher.js +17 -1
  26. package/lib/checks/foreignKeys.js +4 -4
  27. package/lib/checks/invalidTarget.js +3 -1
  28. package/lib/checks/managedInType.js +4 -4
  29. package/lib/checks/managedWithoutKeys.js +3 -1
  30. package/lib/checks/queryNoDbArtifacts.js +1 -3
  31. package/lib/checks/selectItems.js +4 -4
  32. package/lib/checks/sql-snippets.js +94 -0
  33. package/lib/checks/types.js +1 -1
  34. package/lib/checks/validator.js +12 -7
  35. package/lib/compiler/assert-consistency.js +10 -6
  36. package/lib/compiler/base.js +0 -1
  37. package/lib/compiler/builtins.js +8 -6
  38. package/lib/compiler/checks.js +46 -12
  39. package/lib/compiler/cycle-detector.js +1 -1
  40. package/lib/compiler/define.js +1103 -0
  41. package/lib/compiler/extend.js +983 -0
  42. package/lib/compiler/finalize-parse-cdl.js +231 -0
  43. package/lib/compiler/index.js +33 -14
  44. package/lib/compiler/kick-start.js +190 -0
  45. package/lib/compiler/moduleLayers.js +4 -4
  46. package/lib/compiler/populate.js +1226 -0
  47. package/lib/compiler/propagator.js +113 -47
  48. package/lib/compiler/resolve.js +1433 -0
  49. package/lib/compiler/shared.js +76 -38
  50. package/lib/compiler/tweak-assocs.js +529 -0
  51. package/lib/compiler/utils.js +204 -33
  52. package/lib/edm/.eslintrc.json +5 -0
  53. package/lib/edm/annotations/genericTranslation.js +38 -25
  54. package/lib/edm/annotations/preprocessAnnotations.js +3 -3
  55. package/lib/edm/csn2edm.js +10 -9
  56. package/lib/edm/edm.js +19 -20
  57. package/lib/edm/edmPreprocessor.js +166 -95
  58. package/lib/edm/edmUtils.js +127 -34
  59. package/lib/gen/Dictionary.json +92 -43
  60. package/lib/gen/language.checksum +1 -1
  61. package/lib/gen/language.interp +11 -1
  62. package/lib/gen/language.tokens +86 -82
  63. package/lib/gen/languageLexer.interp +18 -1
  64. package/lib/gen/languageLexer.js +925 -847
  65. package/lib/gen/languageLexer.tokens +78 -74
  66. package/lib/gen/languageParser.js +5434 -4298
  67. package/lib/json/from-csn.js +59 -17
  68. package/lib/json/to-csn.js +143 -71
  69. package/lib/language/antlrParser.js +3 -3
  70. package/lib/language/docCommentParser.js +3 -3
  71. package/lib/language/genericAntlrParser.js +144 -54
  72. package/lib/language/language.g4 +424 -203
  73. package/lib/language/multiLineStringParser.js +536 -0
  74. package/lib/main.d.ts +472 -61
  75. package/lib/main.js +38 -11
  76. package/lib/model/api.js +3 -1
  77. package/lib/model/csnRefs.js +321 -204
  78. package/lib/model/csnUtils.js +224 -263
  79. package/lib/model/enrichCsn.js +97 -40
  80. package/lib/model/revealInternalProperties.js +27 -6
  81. package/lib/model/sortViews.js +2 -1
  82. package/lib/modelCompare/compare.js +17 -12
  83. package/lib/optionProcessor.js +7 -6
  84. package/lib/render/DuplicateChecker.js +1 -1
  85. package/lib/render/manageConstraints.js +36 -33
  86. package/lib/render/toCdl.js +174 -275
  87. package/lib/render/toHdbcds.js +201 -115
  88. package/lib/render/toRename.js +7 -10
  89. package/lib/render/toSql.js +149 -75
  90. package/lib/render/utils/common.js +22 -8
  91. package/lib/render/utils/sql.js +10 -7
  92. package/lib/render/utils/stringEscapes.js +111 -0
  93. package/lib/sql-identifier.js +1 -1
  94. package/lib/transform/.eslintrc.json +5 -0
  95. package/lib/transform/braceExpression.js +4 -2
  96. package/lib/transform/db/.eslintrc.json +2 -0
  97. package/lib/transform/db/applyTransformations.js +35 -12
  98. package/lib/transform/db/assertUnique.js +1 -1
  99. package/lib/transform/db/associations.js +187 -0
  100. package/lib/transform/db/cdsPersistence.js +150 -0
  101. package/lib/transform/db/constraints.js +61 -56
  102. package/lib/transform/db/expansion.js +50 -29
  103. package/lib/transform/db/flattening.js +552 -105
  104. package/lib/transform/db/groupByOrderBy.js +3 -1
  105. package/lib/transform/db/temporal.js +236 -0
  106. package/lib/transform/db/transformExists.js +94 -28
  107. package/lib/transform/db/views.js +5 -4
  108. package/lib/transform/draft/.eslintrc.json +38 -0
  109. package/lib/transform/{db/draft.js → draft/db.js} +9 -7
  110. package/lib/transform/draft/odata.js +227 -0
  111. package/lib/transform/forHanaNew.js +94 -801
  112. package/lib/transform/forOdataNew.js +22 -175
  113. package/lib/transform/localized.js +36 -32
  114. package/lib/transform/odata/generateForeignKeyElements.js +3 -3
  115. package/lib/transform/odata/referenceFlattener.js +95 -89
  116. package/lib/transform/odata/structureFlattener.js +1 -1
  117. package/lib/transform/odata/toFinalBaseType.js +86 -12
  118. package/lib/transform/odata/typesExposure.js +5 -5
  119. package/lib/transform/odata/utils.js +2 -2
  120. package/lib/transform/transformUtilsNew.js +47 -33
  121. package/lib/transform/translateAssocsToJoins.js +10 -27
  122. package/lib/transform/universalCsn/.eslintrc.json +36 -0
  123. package/lib/transform/universalCsn/coreComputed.js +170 -0
  124. package/lib/transform/universalCsn/universalCsnEnricher.js +715 -0
  125. package/lib/transform/universalCsn/utils.js +63 -0
  126. package/lib/utils/file.js +2 -1
  127. package/lib/utils/objectUtils.js +30 -0
  128. package/lib/utils/timetrace.js +8 -2
  129. package/package.json +1 -1
  130. package/share/messages/README.md +26 -0
  131. package/lib/compiler/definer.js +0 -2340
  132. package/lib/compiler/resolver.js +0 -2988
  133. package/lib/transform/universalCsnEnricher.js +0 -67
@@ -393,7 +393,7 @@ artifactDef[ outer, defOnly = false ] locals[ annos = [] ] // cannot use `parent
393
393
  | extendProjection[ $outer, this.startLocation(), $annos ]
394
394
  | extendType[ $outer, this.startLocation(), $annos ]
395
395
  | extendAspect[ $outer, this.startLocation(), $annos ]
396
- // TODO: what about extendAction
396
+ // Streamlined Syntax
397
397
  | extendArtifact[ $outer, this.startLocation(), $annos ]
398
398
  )
399
399
  |
@@ -418,7 +418,9 @@ contextDef[ outer, loc, annos, defOnly = false ] locals[ art, name = {} ]
418
418
  this.docComment( $annos ); }
419
419
  annotationAssignment_fix[ $annos ]*
420
420
  (
421
- '{' artifactDef[ $art, defOnly, true ]* '}'
421
+ '{' { $art.artifacts = this.createDict(); }
422
+ artifactDef[ $art, defOnly ]*
423
+ '}' { this.setDictEndLocation( $art.artifacts ); }
422
424
  optionalSemi
423
425
  |
424
426
  requiredSemi
@@ -436,9 +438,9 @@ extendContext[ outer, loc, annos ] locals[ art, name = {} ]
436
438
  { this.docComment( $annos ); }
437
439
  annotationAssignment_ll1[ $annos ]*
438
440
  (
439
- '{'
440
- artifactDef[ $art, $service ? 'SERVICE' : 'CONTEXT', true ]*
441
- '}'
441
+ '{' { $art.artifacts = this.createDict(); }
442
+ artifactDef[ $art, $service ? 'SERVICE' : 'CONTEXT' ]*
443
+ '}' { this.setDictEndLocation( $art.artifacts ); }
442
444
  optionalSemi
443
445
  |
444
446
  requiredSemi
@@ -461,23 +463,35 @@ entityDef[ outer, loc, annos ] locals[ art, name = {} ]
461
463
  )*
462
464
  )?
463
465
  '{'
464
- { $art.elements = Object.create(null); } // better for include and annotate
466
+ { $art.elements = this.createDict(); } // better for include and annotate
465
467
  elementDef[ $art ]*
466
- '}'
468
+ '}' { this.setDictEndLocation( $art.elements ); }
467
469
  // TODO: action definitions in a specific section?
468
- ( ACTIONS '{' actionFunctionDef[ $art ]* '}' )?
470
+ (
471
+ ACTIONS '{' { $art.actions = this.createDict(); }
472
+ actionFunctionDef[ $art ]*
473
+ '}' { this.setDictEndLocation( $art.actions ); }
474
+ )?
469
475
  optionalSemi
470
476
  |
471
477
  AS
472
478
  ( qe=queryExpression
473
479
  { $art.query = $qe.query; $art['$'+'syntax'] = 'entity' }
474
- ( ACTIONS '{' actionFunctionDef[ $art ]* '}' optionalSemi
480
+ (
481
+ ACTIONS '{' { $art.actions = this.createDict(); }
482
+ actionFunctionDef[ $art ]*
483
+ '}' { this.setDictEndLocation( $art.actions ); }
484
+ optionalSemi
475
485
  | requiredSemi
476
486
  )
477
487
  | qp=projectionSpec
478
488
  { $art.query = $qp.query; $art['$'+'syntax'] = 'projection'; }
479
489
  projectionClauses[ $qp.query ]
480
- ( ACTIONS '{' actionFunctionDef[ $art ]* '}' )?
490
+ (
491
+ ACTIONS '{' { $art.actions = this.createDict(); }
492
+ actionFunctionDef[ $art ]*
493
+ '}' { this.setDictEndLocation( $art.actions ); }
494
+ )?
481
495
  optionalSemi // TODO: not fully correct without columns or excluding
482
496
  )
483
497
  )
@@ -490,7 +504,7 @@ projectionSpec returns[ query ] locals[ src ]
490
504
  // now a simplified `tableTerm`:
491
505
  {
492
506
  $src = { path: [], scope: 0 };
493
- $query = { op: this.tokenLocation( $proj, undefined, 'SELECT' ), from: $src, location: this.startLocation() };
507
+ $query = { op: this.valueWithTokenLocation( 'SELECT', $proj ), from: $src, location: this.startLocation() };
494
508
  }
495
509
  fromPath[ $src, 'artref']
496
510
  ( ':'
@@ -522,12 +536,12 @@ excludingClause[ query ]
522
536
  :
523
537
  // syntax is less than ideal - EXCLUDING is only useful for `*` - with
524
538
  // this syntax, people wonder what happens with explicit select items
525
- EXCLUDING '{'
539
+ EXCLUDING '{' { $query.excludingDict = this.createDict(); }
526
540
  projectionExclusion[ $query ]
527
541
  ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
528
542
  projectionExclusion[ $query ]
529
543
  )*
530
- '}'
544
+ '}' { this.setDictEndLocation( $query.excludingDict ); }
531
545
  ;
532
546
 
533
547
  projectionExclusion[ outer ] locals[ art ]
@@ -562,13 +576,19 @@ extendEntity[ outer, loc, annos ] locals[ art, name = {} ]
562
576
 
563
577
  extendForEntity[ art ]
564
578
  :
565
- '{'
579
+ '{' { $art.elements = this.createDict(); }
566
580
  elementDefOrExtend[ $art ]*
567
- '}'
568
- ( ACTIONS '{' actionFunctionDef[ $art ]* '}' )?
581
+ '}' { this.setDictEndLocation( $art.elements ); }
582
+ (
583
+ ACTIONS '{' { $art.actions = this.createDict(); }
584
+ actionFunctionDef[ $art ]*
585
+ '}' { this.setDictEndLocation( $art.actions ); }
586
+ )?
569
587
  optionalSemi
570
588
  |
571
- ACTIONS '{' actionFunctionDef[ $art ]* '}'
589
+ ACTIONS '{' { $art.actions = this.createDict(); }
590
+ actionFunctionDef[ $art ]*
591
+ '}' { this.setDictEndLocation( $art.actions ); }
572
592
  optionalSemi
573
593
  |
574
594
  requiredSemi
@@ -594,10 +614,16 @@ extendProjection[ outer, loc, annos ] locals[ art, name = {} ]
594
614
  )*
595
615
  )?
596
616
  '}'
597
- ( ACTIONS '{' actionFunctionDef[ $art ]* '}' )?
617
+ (
618
+ ACTIONS '{' { $art.actions = this.createDict(); }
619
+ actionFunctionDef[ $art ]*
620
+ '}' { this.setDictEndLocation( $art.actions ); }
621
+ )?
598
622
  optionalSemi
599
623
  |
600
- ACTIONS '{' actionFunctionDef[ $art ]* '}'
624
+ ACTIONS '{' { $art.actions = this.createDict(); }
625
+ actionFunctionDef[ $art ]*
626
+ '}' { this.setDictEndLocation( $art.actions ); }
601
627
  optionalSemi
602
628
  |
603
629
  requiredSemi
@@ -702,12 +728,15 @@ aspectDef[ outer, loc, annos ] locals[ art, name = {} ]
702
728
  )*
703
729
  )?
704
730
  )?
705
- '{'
706
- { $art.elements = Object.create(null); } // better for include and annotate
731
+ '{' { $art.elements = this.createDict(); }
707
732
  ( elementDef[ $art ]* )
708
- '}'
733
+ '}' { this.setDictEndLocation( $art.elements ); }
709
734
  // TODO: action definitions in a specific section?
710
- ( ACTIONS '{' actionFunctionDef[ $art ]* '}' )?
735
+ (
736
+ ACTIONS '{' { $art.actions = this.createDict(); }
737
+ actionFunctionDef[ $art ]*
738
+ '}' { this.setDictEndLocation( $art.actions ); }
739
+ )?
711
740
  optionalSemi
712
741
  ;
713
742
 
@@ -758,13 +787,82 @@ annotationDef[ outer, loc, annos ] locals[ art, name = {} ]
758
787
  typeSpecSemi[ $art, $annos ] // also 'includes'...
759
788
  ;
760
789
 
761
- extendArtifact[ outer, loc, annos ] locals[ art, name = {} ]
762
- @after { this.attachLocation($art); }
790
+ extendArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
791
+ @after{ /* #ATN 1 */ this.attachLocation($art); }
763
792
  :
764
793
  simplePath[ $name, 'Extend' ]
765
- { $art = this.addItem( $outer, 'extensions', 'extend', $annos,
766
- { name: $name }, $loc ); }
767
- extendWithOptElements[ $art, $annos ]
794
+ (
795
+ { $art = this.addItem( $outer, 'extensions', 'extend', $annos, { name: $name }, $loc ); }
796
+ |
797
+ ':'
798
+ simplePath[ $elemName, 'ref']
799
+ {{
800
+ const def = this.addItem( $outer, 'extensions', 'extend', null, { name: $name }, $loc );
801
+ $art = this.artifactForElementAnnotateOrExtend( 'extend', def, $elemName.path, $annos, $loc );
802
+ }}
803
+ )
804
+ (
805
+ { this.docComment( $annos ); }
806
+ annotationAssignment_ll1[ $annos ]*
807
+ (
808
+ '{' { $art.elements = this.createDict(); }
809
+ elementDefOrExtend[ $art ]*
810
+ '}' { this.setDictEndLocation( $art.elements ); }
811
+ optionalSemi
812
+ |
813
+ requiredSemi
814
+ )
815
+ |
816
+ WITH { this.noSemicolonHere(); this.docComment( $annos ); }
817
+ annotationAssignment_ll1[ $annos ]*
818
+ // #ATN: DEFINITIONS, COLUMNS, ACTIONS etc are not reserved and could be identifiers (ref).
819
+ (
820
+ includeRef[ $art ]
821
+ requiredSemi
822
+ |
823
+ '{' { $art.elements = this.createDict(); }
824
+ elementDefOrExtend[ $art ]*
825
+ '}' { this.setDictEndLocation( $art.elements ); }
826
+ optionalSemi
827
+ |
828
+ requiredSemi
829
+ |
830
+ { this.disallowElementExtension( $elemName, $outer, 'definitions' ); }
831
+ DEFINITIONS
832
+ '{' { $art.artifacts = this.createDict(); }
833
+ artifactDef[ $art, true ]*
834
+ '}' { this.setDictEndLocation( $art.artifacts ); }
835
+ optionalSemi
836
+ |
837
+ { this.disallowElementExtension( $elemName, $outer, 'columns' ); }
838
+ COLUMNS
839
+ '{' { $art.columns = []; }
840
+ (
841
+ selectItemDef[ $art.columns ]
842
+ ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
843
+ selectItemDef[ $art.columns ]
844
+ )*
845
+ )?
846
+ '}'
847
+ optionalSemi
848
+ |
849
+ { this.disallowElementExtension( $elemName, $outer, 'actions' ); }
850
+ ACTIONS '{' { $art.actions = this.createDict(); }
851
+ actionFunctionDef[ $art ]*
852
+ '}' { this.setDictEndLocation( $art.actions ); }
853
+ optionalSemi
854
+ |
855
+ ELEMENTS '{' { $art.elements = this.createDict(); }
856
+ elementDefOrExtend[ $art ]*
857
+ '}' { this.setDictEndLocation( $art.elements ); }
858
+ optionalSemi
859
+ |
860
+ ENUM '{' { $art.enum = this.createDict(); }
861
+ enumSymbolDef[ $art ]*
862
+ '}' { this.setDictEndLocation( $art.enum ); }
863
+ optionalSemi
864
+ )
865
+ )
768
866
  ;
769
867
 
770
868
  extendWithOptElements[ art, annos ]
@@ -775,9 +873,9 @@ extendWithOptElements[ art, annos ]
775
873
  includeRef[ $art ]
776
874
  requiredSemi
777
875
  |
778
- '{'
876
+ '{' { $art.elements = this.createDict(); }
779
877
  elementDefOrExtend[ $art ]*
780
- '}'
878
+ '}' { this.setDictEndLocation( $art.elements ); }
781
879
  optionalSemi
782
880
  |
783
881
  requiredSemi
@@ -786,59 +884,71 @@ extendWithOptElements[ art, annos ]
786
884
  { this.docComment( $annos ); }
787
885
  annotationAssignment_ll1[ $annos ]*
788
886
  (
789
- '{'
887
+ '{' { $art.elements = this.createDict(); }
790
888
  elementDefOrExtend[ $art ]*
791
- '}'
889
+ '}' { this.setDictEndLocation( $art.elements ); }
792
890
  optionalSemi
793
891
  |
794
892
  requiredSemi
795
893
  )
796
894
  ;
797
895
 
798
- annotateArtifact[ outer, loc, annos ] locals[ art, name = {} ]
896
+ annotateArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
799
897
  @after { this.attachLocation($art); }
800
898
  :
801
899
  simplePath[ $name, 'Annotate' ]
802
- { $art = this.addItem( $outer, 'extensions', 'annotate', $annos, { name: $name }, $loc ); }
900
+ (
901
+ { $art = this.addItem( $outer, 'extensions', 'annotate', $annos, { name: $name }, $loc ); }
902
+ |
903
+ ':'
904
+ simplePath[ $elemName, 'ref']
905
+ {{
906
+ const def = this.addItem( $outer, 'extensions', 'annotate', null, { name: $name }, $loc );
907
+ $art = this.artifactForElementAnnotateOrExtend( 'annotate', def, $elemName.path, $annos, $loc );
908
+ }}
909
+ )
910
+
803
911
  ( WITH { this.noSemicolonHere(); } )?
804
912
  { this.docComment( $annos ); }
805
913
  annotationAssignment_ll1[ $annos ]*
806
914
  (
807
- '{'
915
+ '{' { $art.elements = this.createDict(); }
808
916
  annotateElement[ $art ]*
809
- '}'
917
+ '}' { this.setDictEndLocation( $art.elements ); }
810
918
  (
811
919
  ACTIONS
812
- '{'
920
+ '{' { $art.actions = this.createDict(); }
813
921
  annotateAction[ $art ]*
814
- '}'
922
+ '}' { this.setDictEndLocation( $art.actions ); }
815
923
  )?
816
924
  optionalSemi
817
925
  |
818
926
  ACTIONS
819
- '{'
927
+ '{' { $art.actions = this.createDict(); }
820
928
  annotateAction[ $art ]*
821
- '}'
929
+ '}' { this.setDictEndLocation( $art.actions ); }
822
930
  optionalSemi
823
931
  |
824
- '('
932
+ '(' { $art.params = this.createDict(); }
825
933
  annotateParam[ $art ]
826
934
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
827
935
  annotateParam[ $art ]
828
936
  )*
829
- ')'
937
+ ')' { this.setDictEndLocation( $art.params ); }
830
938
  (
831
- RETURNS '{' { $art['$'+'syntax'] = 'returns'; }
939
+ RETURNS { $art['$'+'syntax'] = 'returns'; }
940
+ '{' { $art.elements = this.createDict(); }
832
941
  annotateElement[ $art ]*
833
- '}'
942
+ '}' { this.setDictEndLocation( $art.elements ); }
834
943
  optionalSemi
835
944
  |
836
945
  requiredSemi
837
946
  )
838
947
  |
839
- RETURNS '{' { $art['$'+'syntax'] = 'returns'; }
948
+ RETURNS { $art['$'+'syntax'] = 'returns'; }
949
+ '{' { $art.elements = this.createDict(); }
840
950
  annotateElement[ $art ]*
841
- '}'
951
+ '}' { this.setDictEndLocation( $art.elements ); }
842
952
  optionalSemi
843
953
 
844
954
  |
@@ -856,9 +966,9 @@ annotateElement[ outer ] locals[ art, annos = [] ]
856
966
  this.docComment( $annos ); }
857
967
  annotationAssignment_ll1[ $annos ]*
858
968
  (
859
- '{'
969
+ '{' { $art.elements = this.createDict(); }
860
970
  annotateElement[ $art ]*
861
- '}'
971
+ '}' { this.setDictEndLocation( $art.elements ); }
862
972
  optionalSemi
863
973
  |
864
974
  requiredSemi
@@ -875,17 +985,17 @@ annotateAction [ outer ] locals [ art, annos = [] ]
875
985
  this.docComment( $annos ); }
876
986
  annotationAssignment_ll1[ $annos ]*
877
987
  (
878
- '('
988
+ '(' { $art.params = this.createDict(); }
879
989
  annotateParam[ $art ]
880
990
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
881
991
  annotateParam[ $art ]
882
992
  )*
883
- ')'
993
+ ')' { this.setDictEndLocation( $art.params ); }
884
994
  )?
885
995
  (
886
- RETURNS '{'
996
+ RETURNS '{' { $art.elements = this.createDict(); }
887
997
  annotateElement[ $art ]*
888
- '}'
998
+ '}' { this.setDictEndLocation( $art.elements ); }
889
999
  optionalSemi
890
1000
  |
891
1001
  requiredSemi
@@ -929,6 +1039,12 @@ enumSymbolDef[ outer ] locals[ art, annos = [] ]
929
1039
  requiredSemi
930
1040
  ;
931
1041
 
1042
+ defaultValue[ art ] locals[ elem, elements = {} ]
1043
+ :
1044
+ // TODO: We may support structured default values here.
1045
+ DEFAULT expr=expression { $art.default = $expr.expr; }
1046
+ ;
1047
+
932
1048
  elementDefOrExtend[ outer ] locals[ annos = [] ]
933
1049
  @after { /* #ATN 1 */ if ($ctx.art) this.attachLocation($art.art); }
934
1050
  // tool complains if I test for ($art)
@@ -983,6 +1099,7 @@ mixinElementDef[ outer ] locals[ art ]
983
1099
 
984
1100
  misplacedAnnotations[ annos, messageId ]
985
1101
  :
1102
+ // No docComment() here
986
1103
  annotationAssignment_ll1[ $annos ]+
987
1104
  { if ($messageId) // issue specified in central registry
988
1105
  this.message( messageId, this.tokenLocation( $ctx.start, this.getCurrentToken() ) );
@@ -994,7 +1111,7 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
994
1111
  :
995
1112
  // TODO: it would be excellent to remove ELEMENT...
996
1113
  // or have a special ident rule without the ELEMENT
997
- // Reason: it would be good for error recover to start a major block without LL1 ambiguity
1114
+ // Reason: it would be good for error recovery to start a major block without LL1 ambiguity
998
1115
  // VIRTUAL is keyword, except if before the following tokens texts:
999
1116
  { this.setLocalToken( 'VIRTUAL', 'VIRTUAL', /^[:{@=}]$/ ); }
1000
1117
  virtual=VIRTUAL? key=KEY?
@@ -1046,7 +1163,7 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1046
1163
  )
1047
1164
  |
1048
1165
  (
1049
- array=ARRAY of=OF
1166
+ array=ARRAY of=OF
1050
1167
  { $art.items = { location: this.tokenLocation( $array, $of ) }; }
1051
1168
  | many=MANY
1052
1169
  { $art.items = { location: this.tokenLocation( $many ) };}
@@ -1064,10 +1181,9 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1064
1181
  { this.docComment( $annos ); }
1065
1182
  annotationAssignment_ll1[ $annos ]*
1066
1183
  (
1067
- ENUM '{'
1068
- { $art.items.enum = Object.create(null); }
1069
- enumSymbolDef[ $art.items ]*
1070
- '}'
1184
+ ENUM '{' { $art.items.enum = this.createDict(); }
1185
+ enumSymbolDef[ $art.items ]*
1186
+ '}' { this.setDictEndLocation( $art.items.enum ); }
1071
1187
  misplacedAnnotations[ $annos, 'syntax-anno-after-enum' ]?
1072
1188
  )?
1073
1189
  )
@@ -1078,7 +1194,7 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1078
1194
  annotationAssignment_ll1[ $annos ]*
1079
1195
  requiredSemi // also req after foreign key spec
1080
1196
  |
1081
- l=LOCALIZED { $art.localized = this.tokenLocation( $l, undefined, true ); }
1197
+ l=LOCALIZED { $art.localized = this.valueWithTokenLocation( true, $l ); }
1082
1198
  typeRefOptArgs[ $art ]
1083
1199
  { this.docComment( $annos ); }
1084
1200
  annotationAssignment_ll1[ $annos ]*
@@ -1091,13 +1207,14 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1091
1207
  typeRefOptArgs[ $art ]
1092
1208
  { this.docComment( $annos ); }
1093
1209
  annotationAssignment_ll1[ $annos ]*
1094
- ( ENUM '{'
1095
- { $art.enum = Object.create(null); }
1096
- enumSymbolDef[ $art ]*
1097
- '}'
1210
+ (
1211
+ ENUM '{' { $art.enum = this.createDict(); }
1212
+ enumSymbolDef[ $art ]*
1213
+ '}' { this.setDictEndLocation( $art.enum ); }
1098
1214
  elementProperties[ $art ]?
1099
1215
  misplacedAnnotations[ $annos, 'syntax-anno-after-enum' ]?
1100
- | elementProperties[ $art ]
1216
+ |
1217
+ elementProperties[ $art ]
1101
1218
  { this.docComment( $annos ); }
1102
1219
  annotationAssignment_ll1[ $annos ]*
1103
1220
  )?
@@ -1146,7 +1263,7 @@ selectItemDef[ outer ] locals[ annos = [] ]
1146
1263
  @after{ if ($ctx.art) this.attachLocation($art.art); }
1147
1264
  :
1148
1265
  star='*'
1149
- { $outer.push( this.tokenLocation( $star, undefined, '*' ) ); }
1266
+ { $outer.push( this.valueWithTokenLocation( '*', $star ) ); }
1150
1267
  |
1151
1268
  { this.docComment( $annos ); }
1152
1269
  annotationAssignment_atn[ $annos ]*
@@ -1156,8 +1273,8 @@ selectItemDef[ outer ] locals[ annos = [] ]
1156
1273
  key=KEY?
1157
1274
  art=selectItemDefBody[ $outer, $annos ]
1158
1275
  {
1159
- if ($virtual) $art.art.virtual = this.tokenLocation( $virtual, undefined, true );
1160
- if ($key) $art.art.key = this.tokenLocation( $key, undefined, true );
1276
+ if ($virtual) $art.art.virtual = this.valueWithTokenLocation( true, $virtual );
1277
+ if ($key) $art.art.key = this.valueWithTokenLocation( true, $key );
1161
1278
  }
1162
1279
  ;
1163
1280
 
@@ -1190,7 +1307,7 @@ selectItemDefBody[ outer, annos ] returns[ art = {} ]
1190
1307
  excludingClause[ $art ]?
1191
1308
  |
1192
1309
  star='*'
1193
- { $art.inline = [ this.tokenLocation( $star, undefined, '*' ) ]; }
1310
+ { $art.inline = [ this.valueWithTokenLocation( '*', $star ) ]; }
1194
1311
  )
1195
1312
  )?
1196
1313
  |
@@ -1239,7 +1356,7 @@ selectItemInlineDef[ outer ] locals[ annos = [] ]
1239
1356
  @after{ if ($ctx.art) this.attachLocation($art.art); }
1240
1357
  :
1241
1358
  star='*'
1242
- { $outer.push( this.tokenLocation( $star, undefined, '*' ) ); }
1359
+ { $outer.push( this.valueWithTokenLocation( '*', $star ) ); }
1243
1360
  |
1244
1361
  { this.docComment( $annos ); }
1245
1362
  annotationAssignment_atn[ $annos ]*
@@ -1248,7 +1365,7 @@ selectItemInlineDef[ outer ] locals[ annos = [] ]
1248
1365
 
1249
1366
  parameterListDef[ art ]
1250
1367
  :
1251
- '('
1368
+ '(' { $art.params = this.createDict(); }
1252
1369
  // also empty param list (we might do some hacking later to allow reserved words)
1253
1370
  // see annotationAssignment_paren
1254
1371
  (
@@ -1257,7 +1374,7 @@ parameterListDef[ art ]
1257
1374
  parameterDef[ $art ]
1258
1375
  )*
1259
1376
  )?
1260
- ')'
1377
+ ')' { this.setDictEndLocation( $art.params ); }
1261
1378
  ;
1262
1379
 
1263
1380
  parameterDef[ outer ] locals[ art, annos = [] ]
@@ -1270,14 +1387,14 @@ parameterDef[ outer ] locals[ art, annos = [] ]
1270
1387
  this.docComment( $annos ); }
1271
1388
  annotationAssignment_fix[ $annos ]*
1272
1389
  typeSpec[ $art ]
1273
- ( DEFAULT expr=expression { $art.default = $expr.expr; } )?
1390
+ defaultValue[ $art ]?
1274
1391
  { this.docComment( $annos ); }
1275
1392
  annotationAssignment_ll1[ $annos ]*
1276
1393
  ;
1277
1394
 
1278
1395
  entityParameters[ art ]
1279
1396
  :
1280
- '('
1397
+ '(' { $art.params = this.createDict(); }
1281
1398
  // also empty param list (we might do some hacking later to allow reserved words)
1282
1399
  // see annotationAssignment_paren
1283
1400
  (
@@ -1286,7 +1403,7 @@ entityParameters[ art ]
1286
1403
  entityParameterDef[ $art ]
1287
1404
  )*
1288
1405
  )?
1289
- ')'
1406
+ ')' { this.setDictEndLocation( $art.params ); }
1290
1407
  ;
1291
1408
 
1292
1409
  entityParameterDef[ outer ] locals[ art, annos = [] ]
@@ -1299,31 +1416,27 @@ entityParameterDef[ outer ] locals[ art, annos = [] ]
1299
1416
  this.docComment( $annos ); }
1300
1417
  annotationAssignment_fix[ $annos ]*
1301
1418
  typeSpec[ $art ]
1302
- ( DEFAULT expr=expression { $art.default = $expr.expr; } )?
1419
+ defaultValue[ $art ]?
1420
+ { this.docComment( $annos ); }
1421
+ annotationAssignment_ll1[ $annos ]*
1303
1422
  ;
1304
1423
 
1305
1424
  nullability[ art ]
1306
1425
  :
1307
1426
  not=NOT n1=NULL
1308
- { $art.notNull = this.tokenLocation($not,$n1,true); }
1427
+ { $art.notNull = this.valueWithTokenLocation( true, $not, $n1 ); }
1309
1428
  |
1310
1429
  n2=NULL
1311
- { $art.notNull = this.tokenLocation($n2,undefined,false); }
1430
+ { $art.notNull = this.valueWithTokenLocation( false, $n2 ); }
1312
1431
  ;
1313
1432
 
1314
1433
  elementProperties[ elem ]
1315
1434
  :
1316
- nullability[$elem]
1317
- (
1318
- DEFAULT expr=expression
1319
- { $elem.default = $expr.expr; }
1320
- )?
1435
+ nullability[ $elem ]
1436
+ defaultValue[ $elem ]?
1321
1437
  |
1322
- (
1323
- DEFAULT expr=expression
1324
- { $elem.default = $expr.expr; }
1325
- )
1326
- nullability[$elem]?
1438
+ defaultValue[ $elem ]
1439
+ nullability[ $elem ]?
1327
1440
  |
1328
1441
  eq='='
1329
1442
  { this.notSupportedYet( 'Calculated fields are not supported yet', $eq ); }
@@ -1374,10 +1487,10 @@ typeSpec[ art ] // for params
1374
1487
  // TODO: no LOCALIZED ?
1375
1488
  | typeRefOptArgs[ $art ]
1376
1489
  nullability[ $art ]?
1377
- ( ENUM '{'
1378
- { $art.enum = Object.create(null); }
1379
- enumSymbolDef[ $art ]*
1380
- '}'
1490
+ (
1491
+ ENUM '{' { $art.enum = this.createDict(); }
1492
+ enumSymbolDef[ $art ]*
1493
+ '}' { this.setDictEndLocation( $art.enum ); }
1381
1494
  )?
1382
1495
  )
1383
1496
  ;
@@ -1387,7 +1500,7 @@ returnTypeSpec[ art, annos ]
1387
1500
  :
1388
1501
  ret=RETURNS { $art.returns = { location: this.tokenLocation( $ret ), kind: 'param' }; }
1389
1502
  // #ATN: typeSimple can start with ARRAY or TYPE
1390
- ( typeStruct[ $art.returns ]
1503
+ ( typeStruct[ $art.returns ]
1391
1504
  nullability[ $art.returns ]?
1392
1505
  | typeArray[ $art.returns ] // nullability is set in typeArray
1393
1506
  | typeTypeOf[ $art.returns ]
@@ -1395,11 +1508,12 @@ returnTypeSpec[ art, annos ]
1395
1508
  // TODO: no LOCALIZED ?
1396
1509
  | typeRefOptArgs[ $art.returns ]
1397
1510
  nullability[ $art.returns ]?
1398
- ( ENUM '{'
1399
- { $art.returns.enum = Object.create(null); }
1400
- enumSymbolDef[ $art.returns ]*
1401
- '}'
1402
- | misplacedAnnotations[ $annos, 'syntax-anno-after-params' ]
1511
+ (
1512
+ ENUM '{' { $art.returns.enum = this.createDict(); }
1513
+ enumSymbolDef[ $art.returns ]*
1514
+ '}' { this.setDictEndLocation( $art.returns.enum ); }
1515
+ |
1516
+ misplacedAnnotations[ $annos, 'syntax-anno-after-params' ]
1403
1517
  )?
1404
1518
  )
1405
1519
 
@@ -1440,7 +1554,7 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1440
1554
  { $art.items = { location: this.tokenLocation( $many ) };}
1441
1555
  )
1442
1556
  // #ATN: typeRefOptArgs can start with TYPE
1443
- ( typeStruct[ $art.items ]
1557
+ ( typeStruct[ $art.items ]
1444
1558
  nullability[ $art.items ]?
1445
1559
  optionalSemi
1446
1560
  | typeTypeOf[ $art.items ]
@@ -1452,21 +1566,24 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1452
1566
  nullability[ $art.items ]?
1453
1567
  { this.docComment( $annos ); }
1454
1568
  annotationAssignment_ll1[ $annos ]*
1455
- ( ENUM '{'
1456
- { $art.items.enum = Object.create(null); }
1457
- enumSymbolDef[ $art.items ]*
1458
- '}'
1459
- optionalSemi
1460
- | requiredSemi
1569
+ (
1570
+ ENUM '{' { $art.items.enum = this.createDict(); }
1571
+ enumSymbolDef[ $art.items ]*
1572
+ '}' { this.setDictEndLocation( $art.items.enum ); }
1573
+ optionalSemi
1574
+ |
1575
+ requiredSemi
1461
1576
  )
1462
1577
  )
1463
1578
  |
1464
1579
  typeTypeOf[ $art ]
1580
+ defaultValue[ $art ]?
1465
1581
  { this.docComment( $annos ); }
1466
1582
  annotationAssignment_ll1[ $annos ]* requiredSemi
1467
1583
  |
1468
- l=LOCALIZED { $art.localized = this.tokenLocation( $l, undefined, true ); }
1584
+ l=LOCALIZED { $art.localized = this.valueWithTokenLocation( true, $l ); }
1469
1585
  typeRefOptArgs[ $art ]
1586
+ defaultValue[ $art ]?
1470
1587
  { this.docComment( $annos ); }
1471
1588
  annotationAssignment_ll1[ $annos ]*
1472
1589
  requiredSemi
@@ -1497,12 +1614,19 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1497
1614
  ')'
1498
1615
  { this.docComment( $annos ); }
1499
1616
  annotationAssignment_ll1[ $annos ]*
1500
- ( ENUM '{'
1501
- { $art.enum = Object.create(null); }
1502
- enumSymbolDef[ $art ]*
1503
- '}'
1504
- optionalSemi
1505
- | requiredSemi
1617
+ (
1618
+ ENUM '{' { $art.enum = this.createDict(); }
1619
+ enumSymbolDef[ $art ]*
1620
+ '}' { this.setDictEndLocation( $art.enum ); }
1621
+ (
1622
+ optionalSemi
1623
+ |
1624
+ defaultValue[ $art ]
1625
+ requiredSemi
1626
+ )
1627
+ |
1628
+ defaultValue[ $art ]?
1629
+ requiredSemi
1506
1630
  )
1507
1631
  |
1508
1632
  ':' // with element, e.g. `type T : E:elem enum { ... }`
@@ -1510,22 +1634,36 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1510
1634
  simplePath[ $art.type, 'ref']
1511
1635
  { this.docComment( $annos ); }
1512
1636
  annotationAssignment_ll1[ $annos ]*
1513
- ( ENUM '{'
1514
- { $art.enum = Object.create(null); }
1515
- enumSymbolDef[ $art ]*
1516
- '}'
1517
- optionalSemi
1518
- | requiredSemi
1637
+ (
1638
+ ENUM '{' { $art.enum = this.createDict(); }
1639
+ enumSymbolDef[ $art ]*
1640
+ '}' { this.setDictEndLocation( $art.enum ); }
1641
+ (
1642
+ optionalSemi
1643
+ |
1644
+ defaultValue[ $art ]
1645
+ requiredSemi
1646
+ )
1647
+ |
1648
+ defaultValue[ $art ]?
1649
+ requiredSemi
1519
1650
  )
1520
1651
  |
1521
1652
  { this.docComment( $annos ); }
1522
1653
  annotationAssignment_ll1[ $annos ]*
1523
- ( ENUM '{'
1524
- { $art.enum = Object.create(null); }
1525
- enumSymbolDef[ $art ]*
1526
- '}'
1527
- optionalSemi
1528
- | requiredSemi
1654
+ (
1655
+ ENUM '{' { $art.enum = this.createDict(); }
1656
+ enumSymbolDef[ $art ]*
1657
+ '}' { this.setDictEndLocation( $art.enum ); }
1658
+ (
1659
+ optionalSemi
1660
+ |
1661
+ defaultValue[ $art ]
1662
+ requiredSemi
1663
+ )
1664
+ |
1665
+ defaultValue[ $art ]?
1666
+ requiredSemi
1529
1667
  )
1530
1668
  |
1531
1669
  // TODO: complain if used in anno def?
@@ -1542,15 +1680,17 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1542
1680
  typeStruct[ art, attachLoc = false ]
1543
1681
  @after { if ($attachLoc) this.attachLocation($art); }
1544
1682
  :
1545
- { $art.elements = Object.create(null); } // we allow empty structures
1546
- '{' elementDef[ $art ]* '}'
1683
+ '{' { $art.elements = this.createDict(); }
1684
+ elementDef[ $art ]*
1685
+ '}' { this.setDictEndLocation( $art.elements ); }
1547
1686
  ;
1548
1687
 
1549
1688
  typeCompoStruct[ art ]
1550
1689
  @after { this.attachLocation($art); }
1551
1690
  :
1552
- { $art.elements = Object.create(null); } // we allow empty structures
1553
- COMPOSITIONofBRACE elementDef[ $art ]* '}'
1691
+ COMPOSITIONofBRACE { $art.elements = this.createDict(); }
1692
+ elementDef[ $art ]*
1693
+ '}' { this.setDictEndLocation( $art.elements ); }
1554
1694
  ;
1555
1695
 
1556
1696
  typeArray[ art ]
@@ -1569,10 +1709,10 @@ typeArray[ art ]
1569
1709
  nullability[ $art.items ]?
1570
1710
  | typeRefOptArgs[ $art.items ]
1571
1711
  nullability[ $art.items ]?
1572
- ( ENUM '{'
1573
- { $art.items.enum = Object.create(null); }
1574
- enumSymbolDef[ $art.items ]*
1575
- '}'
1712
+ (
1713
+ ENUM '{' { $art.items.enum = this.createDict(); }
1714
+ enumSymbolDef[ $art.items ]*
1715
+ '}' { this.setDictEndLocation( $art.items.enum ); }
1576
1716
  )?
1577
1717
  )
1578
1718
  ;
@@ -1600,7 +1740,7 @@ typeAssociationBase[ art, handleTypeCompo ] // including Composition
1600
1740
  typeAssociationCont[ art ]
1601
1741
  :
1602
1742
  (
1603
- '{'
1743
+ '{' { $art.foreignKeys = this.createDict(); }
1604
1744
  { this.addDef( $art, 'foreignKeys' ); }
1605
1745
  (
1606
1746
  foreignKey[ $art ]
@@ -1608,7 +1748,7 @@ typeAssociationCont[ art ]
1608
1748
  foreignKey[ $art ]
1609
1749
  )*
1610
1750
  )?
1611
- '}'
1751
+ '}' { this.setDictEndLocation( $art.foreignKeys ); }
1612
1752
  |
1613
1753
  ON cond=condition
1614
1754
  { $art.on=$cond.cond; }
@@ -1619,7 +1759,7 @@ typeAssociationElementCont[ art, annos ] // including Composition
1619
1759
  // optional NULL / NOT NULL for managed association only
1620
1760
  :
1621
1761
  (
1622
- '{'
1762
+ '{' { $art.foreignKeys = this.createDict(); }
1623
1763
  { this.addDef( $art, 'foreignKeys' ); }
1624
1764
  (
1625
1765
  foreignKey[ $art ]
@@ -1627,7 +1767,7 @@ typeAssociationElementCont[ art, annos ] // including Composition
1627
1767
  foreignKey[ $art ]
1628
1768
  )*
1629
1769
  )?
1630
- '}'
1770
+ '}' { this.setDictEndLocation( $art.foreignKeys ); }
1631
1771
  nullability[ $art ]?
1632
1772
  |
1633
1773
  ON cond=condition
@@ -1767,33 +1907,47 @@ orderByClause[ inQuery ] returns [ query ]
1767
1907
  ( ',' obn=orderBySpec { $query.orderBy.push( $obn.ob ); } )*
1768
1908
  ;
1769
1909
 
1910
+ // Generic function ORDER BY clause, e.g. `first_value(id order by name)`
1911
+ // lhsExpr is the left expression of the ORDER BY clause.
1912
+ functionOrderByClause[ lhsExpr ] returns [ expr ]
1913
+ @after { this.attachLocation( $expr ); }
1914
+ :
1915
+ o=ORDER b=BY { $expr = { op: this.valueWithTokenLocation( 'orderBy', $o, $b ) , args: [ $lhsExpr ] }}
1916
+ ob1=orderBySpec { $expr.args.push( $ob1.ob ); }
1917
+ ( ',' obn=orderBySpec { $expr.args.push( $obn.ob ); } )*
1918
+ ;
1919
+
1770
1920
  overOrderByClause returns [ expr ]
1921
+ @after { this.attachLocation( $expr ); }
1771
1922
  :
1772
- o=ORDER b=BY { $expr = { op: this.tokenLocation($o, $b, 'orderBy' ) , args: [] }}
1923
+ o=ORDER b=BY { $expr = { op: this.valueWithTokenLocation( 'overOrderBy', $o, $b ) , args: [] }}
1773
1924
  ob1=orderBySpec { $expr.args.push( $ob1.ob ); }
1774
1925
  ( ',' obn=orderBySpec { $expr.args.push( $obn.ob ); } )*
1775
1926
  ;
1776
1927
 
1777
1928
  partitionByClause returns [ expr ]
1929
+ @after { this.attachLocation( $expr ); }
1778
1930
  :
1779
- p=PARTITION b=BY { $expr = { op: this.tokenLocation($p, $b, 'partitionBy' ) , args: [] }}
1931
+ p=PARTITION b=BY { $expr = { op: this.valueWithTokenLocation( 'partitionBy', $p, $b ) , args: [] }}
1780
1932
  e1=expression { $expr.args.push( $e1.expr ); }
1781
1933
  ( ',' en=expression { $expr.args.push( $en.expr ); } )*
1782
1934
  ;
1783
1935
 
1784
1936
  windowFrameClause returns [ wf ]
1937
+ @after { this.attachLocation( $wf ); }
1785
1938
  :
1786
- r=ROWS { $wf = { op: this.tokenLocation($r, null, 'rows' ) , args: [] }}
1939
+ r=ROWS { $wf = { op: this.valueWithTokenLocation( 'rows', $r ) , args: [] }}
1787
1940
  wfe=windowFrameExtentSpec { $wf.args.push( $wfe.wfe ); }
1788
1941
  ;
1789
1942
 
1790
1943
  windowFrameExtentSpec returns[ wfe ]
1944
+ @after { this.attachLocation( $wfe ); }
1791
1945
  :
1792
1946
  { $wfe = {} }
1793
1947
  windowFrameStartSpec [ $wfe ]
1794
1948
  |
1795
1949
  b=BETWEEN
1796
- { $wfe = { op: this.tokenLocation( $b, null, 'frameBetween' ), args: [] } }
1950
+ { $wfe = { op: this.valueWithTokenLocation( 'frameBetween', $b ), args: [] } }
1797
1951
  wfb1=windowFrameBoundSpec { $wfe.args.push( $wfb1.wfb ); }
1798
1952
  AND
1799
1953
  wfb2=windowFrameBoundSpec { $wfe.args.push( $wfb2.wfb ); }
@@ -1805,42 +1959,43 @@ windowFrameBoundSpec returns [ wfb ]
1805
1959
  // #ATN: Not ll1 because `UNBOUNDED` could also be part of the windowFrameStartSpec
1806
1960
  // `UNBOUNDED` would then be immediately followed by `PRECEDING`
1807
1961
  u=UNBOUNDED f=FOLLOWING
1808
- { $wfb = { op: this.tokenLocation($u, $f, 'unboundedFollowing' ), args: []} }
1962
+ { $wfb = { op: this.valueWithTokenLocation( 'unboundedFollowing', $u, $f ), args: []} }
1809
1963
  |
1810
1964
  // #ATN: Not ll1 because `Number` could also be part of the windowFrameStartSpec
1811
1965
  // `Number` would then be immediately followed by `PRECEDING`
1812
1966
  n=Number f=FOLLOWING
1813
- { $wfb = { op: this.tokenLocation($n, $f, 'following' ), args: [ this.numberLiteral( $n ) ]} }
1967
+ { $wfb = { op: this.valueWithTokenLocation( 'following', $n, $f ), args: [ this.numberLiteral( $n ) ]} }
1814
1968
  |
1815
1969
  { $wfb = {} }
1816
1970
  windowFrameStartSpec [ $wfb ]
1817
1971
  ;
1818
1972
 
1819
1973
  windowFrameStartSpec [ wf ]
1974
+ @after { this.attachLocation( $wf ); }
1820
1975
  :
1821
1976
  u=UNBOUNDED p=PRECEDING
1822
1977
  {
1823
- $wf.op = this.tokenLocation($u, $p, 'unboundedPreceding' );
1978
+ $wf.op = this.valueWithTokenLocation( 'unboundedPreceding', $u, $p );
1824
1979
  $wf.args = [];
1825
1980
  }
1826
1981
  |
1827
1982
  n=Number p=PRECEDING
1828
1983
  {
1829
- $wf.op = this.tokenLocation($p, null, 'preceding' );
1984
+ $wf.op = this.valueWithTokenLocation( 'preceding', $p );
1830
1985
  $wf.args = [ this.numberLiteral( $n ) ];
1831
1986
  }
1832
- |
1987
+ |
1833
1988
  c=CURRENT r=ROW
1834
1989
  {
1835
- $wf.op = this.tokenLocation($c, $r, 'currentRow' );
1990
+ $wf.op = this.valueWithTokenLocation( 'currentRow', $c, $r );
1836
1991
  $wf.args = [];
1837
1992
  }
1838
1993
  ;
1839
1994
 
1840
1995
  overClause returns [ over ]
1841
- @after { this.attachLocation($over); }
1996
+ @after { this.attachLocation( $over ); }
1842
1997
  :
1843
- o=OVER { $over = { op: this.tokenLocation( $o, null, 'over' ) , args: [] } }
1998
+ o=OVER { $over = { op: this.valueWithTokenLocation( 'over', $o ) , args: [] } }
1844
1999
  '('
1845
2000
  ( pb=partitionByClause { $over.args.push( $pb.expr ); } )?
1846
2001
  ( ob=overOrderByClause { $over.args.push( $ob.expr ); } )?
@@ -1861,11 +2016,11 @@ limitClause[ inQuery ] returns [ query ]
1861
2016
  orderBySpec returns[ ob ]
1862
2017
  :
1863
2018
  e=expression { $ob = $e.expr; }
1864
- ( asc=ASC { $ob.sort = this.tokenLocation( $asc, undefined, 'asc' ); }
1865
- | desc=DESC { $ob.sort = this.tokenLocation( $desc, undefined, 'desc' ); }
2019
+ ( asc=ASC { $ob.sort = this.valueWithTokenLocation( 'asc', $asc ); }
2020
+ | desc=DESC { $ob.sort = this.valueWithTokenLocation( 'desc', $desc ); }
1866
2021
  )?
1867
2022
  ( nb=NULLS ne=( FIRST | LAST )
1868
- { $ob.nulls = this.tokenLocation( $nb, $ne, $ne.text.toLowerCase() ); }
2023
+ { $ob.nulls = this.valueWithTokenLocation( $ne.text.toLowerCase(), $nb, $ne ); }
1869
2024
  )?
1870
2025
  ;
1871
2026
 
@@ -1888,22 +2043,23 @@ queryPrimary returns[ query = {} ]
1888
2043
  { $query = this.surroundByParens( $qe.query, $open, $close ); }
1889
2044
  |
1890
2045
  select=SELECT
1891
- { $query = { op: this.tokenLocation( $select, undefined, 'SELECT' ), location: this.startLocation() }; }
2046
+ { $query = { op: this.valueWithTokenLocation( 'SELECT', $select ), location: this.startLocation() }; }
1892
2047
  (
1893
2048
  FROM querySource[ $query ]
1894
2049
  (
1895
- mixin=MIXIN '{'
2050
+ mixin=MIXIN '{' { $query.mixin = this.createDict(); }
1896
2051
  mixinElementDef[ $query ]*
1897
- '}' INTO
2052
+ '}' { this.setDictEndLocation( $query.mixin ); }
2053
+ INTO
1898
2054
  )?
1899
2055
  ( ad=( ALL | DISTINCT ) // TODO: or directly after SELECT ?
1900
- { $query.quantifier = this.tokenLocation( $ad, undefined, $ad.text.toLowerCase() ); }
2056
+ { $query.quantifier = this.valueWithTokenLocation( $ad.text.toLowerCase(), $ad ); }
1901
2057
  )?
1902
2058
  bracedSelectItemListDef[ $query ]?
1903
2059
  excludingClause[ $query ]?
1904
2060
  |
1905
2061
  ( ad=( ALL | DISTINCT ) // TODO: or directly after SELECT ?
1906
- { $query.quantifier = this.tokenLocation( $ad, undefined, $ad.text.toLowerCase() ); }
2062
+ { $query.quantifier = this.valueWithTokenLocation( $ad.text.toLowerCase(), $ad ); }
1907
2063
  )?
1908
2064
  { $query.columns = []; } // set it early to avoid "wildcard" errors
1909
2065
  selectItemDef[ $query.columns ]
@@ -1957,8 +2113,8 @@ joinOp[ left ] returns[ table ] locals [ join ]
1957
2113
  | t1=RIGHT t2=OUTER? c=joinCardinality? op=JOIN { $join = 'right' }
1958
2114
  | t1=FULL t2=OUTER? c=joinCardinality? op=JOIN { $join = 'full' }
1959
2115
  )
1960
- { $table = { op: this.tokenLocation( $op, undefined, 'join' ),
1961
- join: this.tokenLocation( $t1 || $op, $t2, $join ),
2116
+ { $table = { op: this.valueWithTokenLocation( 'join', $op ),
2117
+ join: this.valueWithTokenLocation( $join, $t1 || $op, $t2 ),
1962
2118
  args: ($left ? [$left] : []),
1963
2119
  location: $left && $left.location };
1964
2120
  if ($ctx.c) $table.cardinality = $c.joinCard; }
@@ -2065,24 +2221,24 @@ fromPath[ qp, idkind ]
2065
2221
 
2066
2222
  condition returns [ cond ] locals [ args = [], orl = [] ]
2067
2223
  @after{
2068
- $cond = ($args.length == 1)
2224
+ $cond = ($args.length === 1)
2069
2225
  ? this.attachLocation( $args[0] )
2070
2226
  : this.attachLocation({ op: $orl[0], args: $args });
2071
2227
  }
2072
2228
  :
2073
2229
  c1=conditionAnd { $args.push($c1.cond); }
2074
- ( or=OR c2=conditionAnd { $args.push($c2.cond); $orl.push(this.tokenLocation( $or, undefined, 'or' ))} )*
2230
+ ( or=OR c2=conditionAnd { $args.push($c2.cond); $orl.push(this.valueWithTokenLocation( 'or', $or ))} )*
2075
2231
  ;
2076
2232
 
2077
2233
  conditionAnd returns [ cond ] locals [ args = [], andl = [] ]
2078
2234
  @after{
2079
- $cond = ($args.length == 1)
2235
+ $cond = ($args.length === 1)
2080
2236
  ? $args[0]
2081
2237
  : this.attachLocation({ op: $andl[0], args: $args });
2082
2238
  }
2083
2239
  :
2084
2240
  c1=conditionTerm { $args.push($c1.cond); }
2085
- ( and=AND c2=conditionTerm { $args.push($c2.cond); $andl.push(this.tokenLocation( $and, undefined, 'and' )) } )*
2241
+ ( and=AND c2=conditionTerm { $args.push($c2.cond); $andl.push(this.valueWithTokenLocation( 'and', $and )) } )*
2086
2242
  ;
2087
2243
 
2088
2244
  conditionTerm returns [ cond ]
@@ -2091,38 +2247,38 @@ conditionTerm returns [ cond ]
2091
2247
  }
2092
2248
  :
2093
2249
  nt=NOT ct=conditionTerm
2094
- { $cond = { op: this.tokenLocation( $nt, undefined, 'not' ), args: [ $ct.cond ] }; }
2250
+ { $cond = { op: this.valueWithTokenLocation( 'not', $nt ), args: [ $ct.cond ] }; }
2095
2251
  |
2096
2252
  ex=EXISTS
2097
2253
  (
2098
2254
  open='(' qe=queryExpression close=')'
2099
- { $cond = { op: this.tokenLocation( $ex, undefined, 'exists' ),
2255
+ { $cond = { op: this.valueWithTokenLocation( 'exists', $ex ),
2100
2256
  args: [ this.surroundByParens( $qe.query, $open, $close, true ) ] }; }
2101
2257
  |
2102
2258
  qm=( HideAlternatives | '?' )
2103
- { $cond = { op: this.tokenLocation( $ex, undefined, 'exists' ), args: [
2104
- { param: this.tokenLocation( $qm, undefined, '?' ), scope: 'param' }
2259
+ { $cond = { op: this.valueWithTokenLocation( 'exists', $ex ), args: [
2260
+ { param: this.valueWithTokenLocation( '?', $qm ), scope: 'param' }
2105
2261
  ] };
2106
2262
  this.csnParseOnly( 'Dynamic parameter "?" is not supported', $qm );
2107
2263
  }
2108
2264
  |
2109
2265
  ep=valuePath[ 'ref' ]
2110
2266
  { $ep.qp['$'+'expected'] = 'exists';
2111
- $cond = { op: this.tokenLocation( $ex, undefined, 'exists' ), args: [ $ep.qp ] };
2267
+ $cond = { op: this.valueWithTokenLocation( 'exists', $ex ), args: [ $ep.qp ] };
2112
2268
  }
2113
2269
  )
2114
2270
  |
2115
2271
  expr=expression // see @after
2116
2272
  (
2117
2273
  rel=( '=' | '<>' | '>' | '>=' | '<' | '<=' | '!=' )
2118
- { $cond = { op: this.tokenLocation( $rel, undefined, $rel.text), args: [ $expr.expr ] }; }
2274
+ { $cond = { op: this.valueWithTokenLocation( $rel.text, $rel ), args: [ $expr.expr ] }; }
2119
2275
  ( asa=( ANY | SOME | ALL )
2120
- { $cond.quantifier = this.tokenLocation($asa, undefined, $asa.text.toLowerCase()); }
2276
+ { $cond.quantifier = this.valueWithTokenLocation( $asa.text.toLowerCase(), $asa ); }
2121
2277
  )?
2122
2278
  e2=expression { $cond.args.push($e2.expr); }
2123
2279
  |
2124
2280
  IS ( inn=NOT NULL | innu=NULL )
2125
- { $cond = { op: $inn ? this.tokenLocation( $inn, undefined, 'isNotNull' ) : this.tokenLocation( $innu, undefined, 'isNull' ), args: [ $expr.expr ] }; }
2281
+ { $cond = { op: $inn ? this.valueWithTokenLocation( 'isNotNull', $inn ) : this.valueWithTokenLocation( 'isNull', $innu ), args: [ $expr.expr ] }; }
2126
2282
  |
2127
2283
  { $cond = { args: [ $expr.expr ] }; }
2128
2284
  NOT predicate[ $cond, true ]
@@ -2138,14 +2294,14 @@ predicate[ cond, negated ]
2138
2294
  // NOT (a BETWEEN b AND c)
2139
2295
  :
2140
2296
  ino=IN e1=expression // including ExpressionList
2141
- { $cond.op = this.tokenLocation( $ino, undefined, (negated) ? 'notIn' : 'in'); $cond.args.push( $e1.expr ); }
2297
+ { $cond.op = this.valueWithTokenLocation( (negated) ? 'notIn' : 'in', $ino ); $cond.args.push( $e1.expr ); }
2142
2298
  |
2143
2299
  bw=BETWEEN e2=expression
2144
- { $cond.op = this.tokenLocation( $bw, undefined, (negated) ? 'notBetween' : 'between' ); $cond.args.push( $e2.expr ); }
2300
+ { $cond.op = this.valueWithTokenLocation( (negated) ? 'notBetween' : 'between', $bw ); $cond.args.push( $e2.expr ); }
2145
2301
  AND e3=expression { $cond.args.push( $e3.expr ); }
2146
2302
  |
2147
2303
  lk=LIKE e4=expression
2148
- { $cond.op = this.tokenLocation( $lk, undefined, (negated) ? 'notLike' : 'like' ); $cond.args.push( $e4.expr ); }
2304
+ { $cond.op = this.valueWithTokenLocation( (negated) ? 'notLike' : 'like', $lk ); $cond.args.push( $e4.expr ); }
2149
2305
  ( ESCAPE e5=expression { $cond.args.push( $e5.expr ); } )?
2150
2306
  ;
2151
2307
 
@@ -2157,7 +2313,7 @@ expression returns [ expr ]
2157
2313
  or='||' e2=expressionSum
2158
2314
  {
2159
2315
  $expr = {
2160
- op: this.tokenLocation( $or, undefined, '||' ), args: [$expr, $e2.expr],
2316
+ op: this.valueWithTokenLocation( '||', $or ), args: [$expr, $e2.expr],
2161
2317
  location: this.combinedLocation( $expr, $e2.expr ) };
2162
2318
  }
2163
2319
  )*
@@ -2171,7 +2327,7 @@ expressionSum returns [ expr ]
2171
2327
  op=( '+' | '-' ) e2=expressionFactor
2172
2328
  {
2173
2329
  $expr = {
2174
- op: this.tokenLocation($op, undefined, $op.text), args: [$expr, $e2.expr],
2330
+ op: this.valueWithTokenLocation( $op.text, $op ), args: [$expr, $e2.expr],
2175
2331
  location: this.combinedLocation( $expr, $e2.expr ) };
2176
2332
  }
2177
2333
  )*
@@ -2185,7 +2341,7 @@ expressionFactor returns [ expr ]
2185
2341
  op=( '*' | '/' ) e2=expressionTerm
2186
2342
  {
2187
2343
  $expr = {
2188
- op: this.tokenLocation($op, undefined, $op.text), args: [$expr, $e2.expr],
2344
+ op: this.valueWithTokenLocation( $op.text, $op ), args: [$expr, $e2.expr],
2189
2345
  location: this.combinedLocation( $expr, $e2.expr ) };
2190
2346
  }
2191
2347
  )*
@@ -2205,7 +2361,7 @@ expressionTerm returns [ expr ] locals [ op, args = [] ]
2205
2361
  { $expr = $sf.ret; }
2206
2362
  |
2207
2363
  ca=CASE
2208
- { $expr = { op : this.tokenLocation( $ca, undefined, 'case' ), args: [] }; }
2364
+ { $expr = { op : this.valueWithTokenLocation( 'case', $ca ), args: [] }; }
2209
2365
  (
2210
2366
  e2=expression { $expr.args.push($e2.expr); }
2211
2367
  ( ow=WHEN ew=expression THEN e3=expression
@@ -2223,7 +2379,7 @@ expressionTerm returns [ expr ] locals [ op, args = [] ]
2223
2379
  |
2224
2380
  ne=NEW nqp=valuePath[ 'ref', null] // token rewrite for NEW
2225
2381
  // please note: there will be no compiler-supported code completion after NEW
2226
- { $expr = { op: this.tokenLocation( $ne, undefined, 'new' ), args: [] };
2382
+ { $expr = { op: this.valueWithTokenLocation( 'new', $ne ), args: [] };
2227
2383
  this.notSupportedYet( $ne ); }
2228
2384
  |
2229
2385
  vp=valuePath[ 'ref', null ] { $expr = this.valuePathAst( $vp.qp ); }
@@ -2242,7 +2398,7 @@ expressionTerm returns [ expr ] locals [ op, args = [] ]
2242
2398
  )
2243
2399
  |
2244
2400
  qm=( HideAlternatives | '?' )
2245
- { $expr = { param: this.tokenLocation( $qm, undefined, '?' ), scope: 'param' };
2401
+ { $expr = { param: this.valueWithTokenLocation( '?', $qm ), scope: 'param' };
2246
2402
  this.csnParseOnly( 'Dynamic parameter "?" is not supported', $qm );
2247
2403
  }
2248
2404
  |
@@ -2260,7 +2416,7 @@ expressionTerm returns [ expr ] locals [ op, args = [] ]
2260
2416
  close=')'
2261
2417
  {
2262
2418
  if ($expr.length > 1)
2263
- $expr = { op: this.tokenLocation( $open, undefined, ',' ), args: $expr };
2419
+ $expr = { op: this.valueWithTokenLocation( ',', $open ), args: $expr };
2264
2420
  else if ($expr[0]) // can be `null` if condition failed to parse
2265
2421
  $expr = this.surroundByParens( $expr[0], $open, $close );
2266
2422
  }
@@ -2300,7 +2456,7 @@ specialFunction returns [ ret = { } ] locals[ art = {} ]
2300
2456
  ca=CAST open='('
2301
2457
  {
2302
2458
  $ret = {
2303
- op: this.tokenLocation( $ca, undefined, 'cast' ),
2459
+ op: this.valueWithTokenLocation( 'cast', $ca ),
2304
2460
  args: [ ],
2305
2461
  location: this.tokenLocation( $ca )
2306
2462
  };
@@ -2348,6 +2504,7 @@ fromArguments[ pathStep ]
2348
2504
  pathArguments[ pathStep, considerSpecial ]
2349
2505
  @after{ /* #ATN 1 */ }
2350
2506
  :
2507
+ { this.excludeExpected([ 'ORDER' ]); }
2351
2508
  paren='('
2352
2509
  { this.prepareGenericKeywords( $considerSpecial ); }
2353
2510
  // ATN, LL2: Identifier can start both named arguments and the positional.
@@ -2369,16 +2526,23 @@ pathArguments[ pathStep, considerSpecial ]
2369
2526
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
2370
2527
  funcExpression[ $pathStep, $considerSpecial ]
2371
2528
  )*
2529
+ // Note: We can't move this into funcExpression, or we would increase the ATN count because of `,` amiguity.
2530
+ ( ob=functionOrderByClause[ $pathStep.args[$pathStep.args.length - 1] ]
2531
+ {
2532
+ // Remove the last entry which was copied to $ob.expr and push $ob.expr.
2533
+ $pathStep.args[$pathStep.args.length - 1] = $ob.expr;
2534
+ }
2535
+ )?
2372
2536
  |
2373
- a=ALL { $pathStep.quantifier = this.tokenLocation( $a, undefined, 'all' ); }
2537
+ a=ALL { $pathStep.quantifier = this.valueWithTokenLocation( 'all', $a ); }
2374
2538
  e1=expression { $pathStep.args = [ $e1.expr ]; }
2375
2539
  |
2376
- d=DISTINCT { $pathStep.quantifier = this.tokenLocation( $d, undefined, 'distinct' ); }
2540
+ d=DISTINCT { $pathStep.quantifier = this.valueWithTokenLocation( 'distinct', $d ); }
2377
2541
  e1=expression { $pathStep.args = [ $e1.expr ]; }
2378
2542
  ( ',' e2=expression { $pathStep.args.push( $e2.expr ); } )*
2379
2543
  |
2380
2544
  star='*'
2381
- { $pathStep.args = [ { location: this.tokenLocation($star), val: '*', literal: 'token' } ]; }
2545
+ { $pathStep.args = [ { location: this.tokenLocation( $star ), val: '*', literal: 'token' } ]; }
2382
2546
  |
2383
2547
  { $pathStep.args = []; }
2384
2548
  )
@@ -2452,7 +2616,7 @@ optionalWhereForFilter
2452
2616
 
2453
2617
  // Simple paths and values ---------------------------------------------------
2454
2618
 
2455
- annoValueBase returns[ val ] locals [ hasEllipsis=0 ]
2619
+ annoValueBase returns[ val ] locals [ seenEllipsis = false ]
2456
2620
  @after { this.attachLocation($val); }
2457
2621
  :
2458
2622
  { $val = { literal: 'struct', location: this.startLocation() }; }
@@ -2472,30 +2636,43 @@ annoValueBase returns[ val ] locals [ hasEllipsis=0 ]
2472
2636
  '['
2473
2637
  (
2474
2638
  (
2475
- head=arrayValue { $val.val.push( $head.val ); }
2476
- |
2477
- e='...'
2478
- {
2479
- $val.val.push( { literal: 'token', val: '...', location: this.tokenLocation($e) } );
2480
- $hasEllipsis++;
2481
- }
2639
+ head=arrayValue { $val.val.push( $head.val ); }
2640
+ |
2641
+ e='...' ( UP TO upTo=arrayValue )?
2642
+ {{
2643
+ const item = { literal: 'token', val: '...', location: this.tokenLocation($e) };
2644
+ $val.val.push( item );
2645
+ if ($ctx.upTo) item.upTo = $upTo.val;
2646
+ $seenEllipsis = !$ctx.upTo || 'upTo';
2647
+ }}
2482
2648
  )
2483
2649
  (
2484
2650
  ',' { if (this.isStraightBefore(']')) break; } // allow ',' before ']'
2485
2651
  (
2486
- tail=arrayValue { $val.val.push( $tail.val ); }
2487
- |
2488
- e='...'
2489
- {
2490
- $val.val.push( { literal: 'token', val: '...', location: this.tokenLocation($e) } );
2491
- if(++$hasEllipsis > 1)
2492
- this.error( 'syntax-unexpected-ellipsis', $e, { code: '...' },
2493
- 'Expected no more than one $(CODE)' );
2494
- }
2652
+ tail=arrayValue { $val.val.push( $tail.val ); }
2653
+ |
2654
+ { $ctx.upTo = null; } // is not reset
2655
+ e='...' ( UP TO upTo=arrayValue )?
2656
+ {{
2657
+ const item = { literal: 'token', val: '...', location: this.tokenLocation($e) };
2658
+ if ($ctx.upTo) item.upTo = $upTo.val;
2659
+ $val.val.push( item );
2660
+ if ($seenEllipsis === true) // TODO: adapt msg to UP TO
2661
+ this.error( 'syntax-unexpected-ellipsis', $e, { code: '...' },
2662
+ 'Expected no more than one $(CODE)' );
2663
+ else
2664
+ $seenEllipsis = !$ctx.upTo || 'upTo';
2665
+ }}
2495
2666
  )
2496
2667
  )*
2497
2668
  )?
2498
- ']'
2669
+ cb=']'
2670
+ {
2671
+ if ($seenEllipsis === 'upTo')
2672
+ this.error( 'syntax-expecting-ellipsis', $cb, // at closing bracket
2673
+ { code: '... up to', newcode: '...' },
2674
+ 'Expecting an array item $(NEWCODE) after an item with $(CODE)' );
2675
+ }
2499
2676
  |
2500
2677
  v1=literalValue { $val = $v1.val; }
2501
2678
  |
@@ -2663,6 +2840,7 @@ ident[ category ] returns[ id ]
2663
2840
  | ASSOCIATION
2664
2841
  | BETWEEN
2665
2842
  | BOTH
2843
+ | COLUMNS
2666
2844
  | COMPOSITION
2667
2845
  | CONTEXT
2668
2846
  | CROSS
@@ -2670,8 +2848,10 @@ ident[ category ] returns[ id ]
2670
2848
  | DAY
2671
2849
  | DEFAULT
2672
2850
  | DEFINE
2851
+ | DEFINITIONS
2673
2852
  | DESC
2674
2853
  | ELEMENT
2854
+ | ELEMENTS
2675
2855
  | ELSE
2676
2856
  | END
2677
2857
  | ENTITY
@@ -2728,6 +2908,7 @@ ident[ category ] returns[ id ]
2728
2908
  | THEN
2729
2909
  | TRAILING
2730
2910
  | UNION
2911
+ | UP
2731
2912
  | TO
2732
2913
  | TYPE
2733
2914
  | USING
@@ -2752,9 +2933,40 @@ LineComment : '//' ~[\r\n\u2028\u2029]* -> channel(HIDDEN);
2752
2933
 
2753
2934
  // Values --------------------------------------------------------------------
2754
2935
 
2755
- String
2936
+ // for syntactic code-completion: Combine all three string styles
2937
+ // Note: Use rule `string` instead as that also parses escape sequences!
2938
+ String : SingleLineString
2939
+ | MultiLineString
2940
+ | MutlLineStringBlock;
2941
+
2942
+ fragment SingleLineString
2756
2943
  :
2757
- ( '\'' ~[\u0027\n\r\u2028\u2029]* '\'' )+ // \u0027 = '\''
2944
+ // \u0027 = '\''
2945
+ // \u2028 = LS (Line Separator)
2946
+ // \u2029 = PS (Paragraph Separator)
2947
+ ( '\'' ~[\u0027\n\r\u2028\u2029]* '\'' )+ //
2948
+ ;
2949
+
2950
+ fragment MultiLineString
2951
+ :
2952
+ ('`' ( MultiLineStringContentChar | EscapeSequence )* '`' )
2953
+ ;
2954
+
2955
+ fragment MutlLineStringBlock
2956
+ :
2957
+ ('```' ( MultiLineStringContentChar | EscapeSequence )* '```')
2958
+ ;
2959
+
2960
+ fragment EscapeSequence
2961
+ :
2962
+ // we could list each escape sequence explicitly, but we already
2963
+ // decode them in genericAntlrParser.js, so no need to do work twice.
2964
+ '\\' .
2965
+ ;
2966
+
2967
+ fragment MultiLineStringContentChar
2968
+ :
2969
+ (~[\u0060\\]) // \u0060 = '`'
2758
2970
  ;
2759
2971
 
2760
2972
  QuotedLiteral
@@ -2763,10 +2975,15 @@ QuotedLiteral
2763
2975
  ( '\'' ~[\u0027\n\r\u2028\u2029]* '\'' )+ // \u0027 = '\''
2764
2976
  ;
2765
2977
 
2978
+ // This literal improves error messages for unterminated literals.
2766
2979
  UnterminatedLiteral
2767
2980
  :
2768
2981
  ( [xX] | [dD][aA][tT][eE] | [tT][iI][mM][eE] ( [sS][tT][aA][mM][pP] )? )?
2769
2982
  '\'' ~[\u0027\n\r\u2028\u2029]* // \u0027 = '\''
2983
+ |
2984
+ ('`' ( MultiLineStringContentChar | EscapeSequence )* )
2985
+ |
2986
+ ('```' ( MultiLineStringContentChar | EscapeSequence )* )
2770
2987
  ;
2771
2988
 
2772
2989
  UnterminatedDelimitedIdentifier
@@ -2830,6 +3047,7 @@ ASPECT : [aA][sS][pP][eE][cC][tT] ;
2830
3047
  ASSOCIATION : [aA][sS][sS][oO][cC][iI][aA][tT][iI][oO][nN] ;
2831
3048
  BETWEEN : [bB][eE][tT][wW][eE][eE][nN] ;
2832
3049
  BOTH : [bB][oO][tT][hH] ;
3050
+ COLUMNS : [cC][oO][lL][uU][mM][nN][sS];
2833
3051
  COMPOSITION : [cC][oO][mM][pP][oO][sS][iI][tT][iI][oO][nN] ;
2834
3052
  CONTEXT : [cC][oO][nN][tT][eE][xX][tT] ;
2835
3053
  CROSS : [cC][rR][oO][sS][sS] ;
@@ -2837,8 +3055,10 @@ CURRENT : [cC][uU][rR][rR][eE][nN][tT] ;
2837
3055
  DAY : [dD][aA][yY] ;
2838
3056
  DEFAULT : [dD][eE][fF][aA][uU][lL][tT] ;
2839
3057
  DEFINE : [dD][eE][fF][iI][nN][eE] ;
3058
+ DEFINITIONS : [dD][eE][fF][iI][nN][iI][tT][iI][oO][nN][sS] ;
2840
3059
  DESC : [dD][eE][sS][cC] ;
2841
3060
  ELEMENT : [eE][lL][eE][mM][eE][nN][tT] ;
3061
+ ELEMENTS : [eE][lL][eE][mM][eE][nN][tT][sS] ;
2842
3062
  ELSE : [eE][lL][sS][eE] ;
2843
3063
  END : [eE][nN][dD] ;
2844
3064
  ENTITY : [eE][nN][tT][iI][tT][yY] ;
@@ -2899,6 +3119,7 @@ TO : [tT][oO] ; // or make reserved? (is in SQL-92)
2899
3119
  TYPE : [tT][yY][pP][eE] ;
2900
3120
  UNION : [uU][nN][iI][oO][nN] ;
2901
3121
  UNBOUNDED : [uU][nN][bB][oO][uU][nN][dD][eE][dD] ;
3122
+ UP : [uU][pP] ;
2902
3123
  USING : [uU][sS][iI][nN][gG] ;
2903
3124
  VARIABLE : [vV][aA][rR][iI][aA][bB][lL][eE] ;
2904
3125
  VIEW : [vV][iI][eE][wW] ;