@sap/cds-compiler 2.13.8 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/CHANGELOG.md +155 -1594
  2. package/bin/cdsc.js +144 -66
  3. package/doc/CHANGELOG_ARCHIVE.md +1592 -0
  4. package/doc/CHANGELOG_BETA.md +3 -4
  5. package/doc/CHANGELOG_DEPRECATED.md +35 -1
  6. package/doc/{DeprecatedOptions.md → DeprecatedOptions_v2.md} +3 -1
  7. package/doc/Versioning.md +20 -1
  8. package/lib/api/.eslintrc.json +2 -2
  9. package/lib/api/main.js +237 -122
  10. package/lib/api/options.js +17 -88
  11. package/lib/api/validate.js +12 -16
  12. package/lib/base/keywords.js +216 -109
  13. package/lib/base/message-registry.js +152 -37
  14. package/lib/base/messages.js +145 -83
  15. package/lib/base/model.js +44 -2
  16. package/lib/base/optionProcessorHelper.js +19 -0
  17. package/lib/checks/actionsFunctions.js +7 -5
  18. package/lib/checks/annotationsOData.js +11 -32
  19. package/lib/checks/arrayOfs.js +1 -34
  20. package/lib/checks/cdsPersistence.js +1 -0
  21. package/lib/checks/elements.js +6 -6
  22. package/lib/checks/invalidTarget.js +1 -1
  23. package/lib/checks/nonexpandableStructured.js +1 -1
  24. package/lib/checks/queryNoDbArtifacts.js +2 -1
  25. package/lib/checks/selectItems.js +5 -1
  26. package/lib/checks/types.js +4 -2
  27. package/lib/checks/utils.js +2 -2
  28. package/lib/checks/validator.js +4 -5
  29. package/lib/compiler/assert-consistency.js +16 -10
  30. package/lib/compiler/base.js +1 -0
  31. package/lib/compiler/builtins.js +98 -9
  32. package/lib/compiler/checks.js +22 -70
  33. package/lib/compiler/define.js +61 -13
  34. package/lib/compiler/extend.js +79 -14
  35. package/lib/compiler/finalize-parse-cdl.js +46 -29
  36. package/lib/compiler/index.js +100 -37
  37. package/lib/compiler/moduleLayers.js +7 -0
  38. package/lib/compiler/populate.js +19 -18
  39. package/lib/compiler/propagator.js +7 -4
  40. package/lib/compiler/resolve.js +297 -234
  41. package/lib/compiler/shared.js +107 -102
  42. package/lib/compiler/tweak-assocs.js +16 -11
  43. package/lib/compiler/utils.js +5 -0
  44. package/lib/edm/annotations/genericTranslation.js +93 -21
  45. package/lib/edm/csn2edm.js +230 -115
  46. package/lib/edm/edm.js +305 -226
  47. package/lib/edm/edmPreprocessor.js +509 -438
  48. package/lib/edm/edmUtils.js +31 -45
  49. package/lib/gen/Dictionary.json +98 -22
  50. package/lib/gen/language.checksum +1 -1
  51. package/lib/gen/language.interp +10 -30
  52. package/lib/gen/language.tokens +105 -114
  53. package/lib/gen/languageLexer.interp +1 -34
  54. package/lib/gen/languageLexer.js +889 -1007
  55. package/lib/gen/languageLexer.tokens +95 -106
  56. package/lib/gen/languageParser.js +20786 -22199
  57. package/lib/json/csnVersion.js +10 -11
  58. package/lib/json/from-csn.js +59 -51
  59. package/lib/json/to-csn.js +10 -10
  60. package/lib/language/antlrParser.js +2 -2
  61. package/lib/language/docCommentParser.js +62 -39
  62. package/lib/language/errorStrategy.js +52 -40
  63. package/lib/language/genericAntlrParser.js +348 -229
  64. package/lib/language/language.g4 +629 -653
  65. package/lib/language/multiLineStringParser.js +14 -42
  66. package/lib/language/textUtils.js +44 -0
  67. package/lib/main.d.ts +46 -43
  68. package/lib/main.js +108 -79
  69. package/lib/model/csnRefs.js +34 -7
  70. package/lib/model/csnUtils.js +337 -332
  71. package/lib/model/enrichCsn.js +1 -0
  72. package/lib/model/revealInternalProperties.js +30 -10
  73. package/lib/model/sortViews.js +32 -31
  74. package/lib/modelCompare/compare.js +6 -6
  75. package/lib/optionProcessor.js +73 -46
  76. package/lib/render/.eslintrc.json +1 -1
  77. package/lib/render/DuplicateChecker.js +4 -7
  78. package/lib/render/manageConstraints.js +70 -2
  79. package/lib/render/toCdl.js +1042 -882
  80. package/lib/render/toHdbcds.js +195 -245
  81. package/lib/render/toRename.js +44 -22
  82. package/lib/render/toSql.js +225 -241
  83. package/lib/render/utils/common.js +145 -15
  84. package/lib/render/utils/sql.js +20 -19
  85. package/lib/sql-identifier.js +6 -0
  86. package/lib/transform/db/.eslintrc.json +4 -3
  87. package/lib/transform/db/associations.js +2 -2
  88. package/lib/transform/db/cdsPersistence.js +5 -15
  89. package/lib/transform/db/constraints.js +4 -2
  90. package/lib/transform/db/expansion.js +22 -16
  91. package/lib/transform/db/flattening.js +109 -80
  92. package/lib/transform/db/transformExists.js +7 -7
  93. package/lib/transform/db/views.js +9 -6
  94. package/lib/transform/draft/.eslintrc.json +2 -2
  95. package/lib/transform/draft/db.js +6 -6
  96. package/lib/transform/draft/odata.js +6 -7
  97. package/lib/transform/forHanaNew.js +62 -48
  98. package/lib/transform/forOdataNew.js +49 -50
  99. package/lib/transform/localized.js +31 -20
  100. package/lib/transform/odata/toFinalBaseType.js +16 -14
  101. package/lib/transform/odata/typesExposure.js +146 -198
  102. package/lib/transform/odata/utils.js +1 -38
  103. package/lib/transform/transformUtilsNew.js +67 -84
  104. package/lib/transform/translateAssocsToJoins.js +7 -3
  105. package/lib/transform/universalCsn/.eslintrc.json +2 -2
  106. package/lib/transform/universalCsn/coreComputed.js +16 -9
  107. package/lib/transform/universalCsn/universalCsnEnricher.js +60 -10
  108. package/lib/utils/file.js +3 -3
  109. package/lib/utils/moduleResolve.js +13 -6
  110. package/lib/utils/timetrace.js +20 -21
  111. package/package.json +35 -4
  112. package/share/messages/message-explanations.json +2 -1
  113. package/share/messages/syntax-expected-integer.md +37 -0
  114. package/doc/ApiMigration.md +0 -237
  115. package/doc/CommandLineMigration.md +0 -58
  116. package/doc/ErrorMessages.md +0 -175
  117. package/doc/FioriAnnotations.md +0 -94
  118. package/doc/ODataTransformation.md +0 -273
  119. package/lib/backends.js +0 -529
  120. package/lib/fix_antlr4-8_warning.js +0 -56
  121. package/lib/transform/odata/attachPath.js +0 -96
  122. package/lib/transform/odata/expandStructKeysInAssociations.js +0 -59
  123. package/lib/transform/odata/generateForeignKeyElements.js +0 -261
  124. package/lib/transform/odata/referenceFlattener.js +0 -296
  125. package/lib/transform/odata/sortByAssociationDependency.js +0 -105
  126. package/lib/transform/odata/structuralPath.js +0 -72
  127. package/lib/transform/odata/structureFlattener.js +0 -171
@@ -125,14 +125,17 @@ tokens {
125
125
  HelperToken1, // used with setLocalToken(), does not appear in messages
126
126
  HelperToken2, // used with setLocalToken(), does not appear in messages
127
127
  HideAlternatives, // hide alternative tokens (no token seq!)
128
- GenericArgFull, // via token rewriting according to specialFunctions
128
+ GenericExpr, // via token rewriting according to specialFunctions
129
+ GenericSeparator, // via token rewriting according to specialFunctions
130
+ GenericIntro, // via token rewriting according to specialFunctions
129
131
  DOTbeforeBRACE, // via token rewrite
130
132
  COMPOSITIONofBRACE // via token rewrite in rule typeAssociationBase
131
133
  }
132
134
 
133
135
  // Top-Level -----------------------------------------------------------------
134
136
 
135
- start returns [ source = { kind: 'source' } ] locals [ _sync = 'recover' ]
137
+ start returns [ source ] locals [ _sync = 'recover' ]
138
+ @init{ $source = this.createSource(); }
136
139
  :
137
140
  usingDeclaration[$source]*
138
141
  (
@@ -161,53 +164,46 @@ namespaceDeclaration[ source ] locals[ decl = {} ]
161
164
  NAMESPACE simplePath[ $decl, 'Namespace' ] ';'
162
165
  ;
163
166
 
164
- usingDeclaration[ source ] locals[ decl ]
165
- @after { if ($decl) this.attachLocation($decl); }
167
+ usingDeclaration[ source ] locals[ decl = {} ]
168
+ @after { this.attachLocation($decl); }
166
169
  :
170
+ { $decl.location = this.startLocation(); }
167
171
  USING
168
172
  (
169
173
  FROM str=String
170
- {
171
- if (!$source.dependencies) $source.dependencies = [];
172
- $source.dependencies.push( this.quotedLiteral( $str, 'string' ) );
173
- }
174
+ { $source.dependencies.push( this.quotedLiteral( $str, 'string' ) ); }
174
175
  |
175
176
  path=externalPath
176
- { $decl = this.addItem( $source, 'usings', 'using', [], { extern: $path.extern } ); }
177
+ { this.addItem( $decl, $source, 'usings', 'using' );; $decl.extern = $path.extern; }
177
178
  ( AS name=ident['Using'] { $decl.name = $name.id; }
178
179
  | { this.classifyImplicitName( 'Using' ); }
179
180
  )
180
181
  ( FROM str=String
181
- {
182
- if (!$source.dependencies) $source.dependencies = [];
183
- $source.dependencies.push( $decl.fileDep = this.quotedLiteral( $str, 'string' ) );
184
- }
182
+ { $source.dependencies.push( $decl.fileDep = this.quotedLiteral( $str, 'string' ) ); }
185
183
  )?
186
184
  |
187
- { $decl = this.addItem( $source, 'usings', 'using', [] ); }
185
+ { this.addItem( $decl, $source, 'usings', 'using' ); }
188
186
  // We could just create "independent" USING declaration, but if we want
189
187
  // to have some check in the future whether the external artifacts are
190
188
  // really in the FROM source...
191
- '{'
189
+ '{' { $decl.usings = this.createArray(); }
192
190
  innerUsing[ $decl ]
193
191
  ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
194
192
  innerUsing[ $decl ] )*
195
- '}'
193
+ '}' { this.finalizeDictOrArray( $decl.usings ); }
196
194
  ( FROM str=String
197
- {
198
- if (!$source.dependencies) $source.dependencies = [];
199
- $source.dependencies.push( $decl.fileDep = this.quotedLiteral( $str, 'string' ) );
200
- }
195
+ { $source.dependencies.push( $decl.fileDep = this.quotedLiteral( $str, 'string' ) ); }
201
196
  )?
202
197
  )
203
198
  ';'
204
199
  ;
205
200
 
206
- innerUsing[ using ] locals[ decl ]
207
- @after { if ($decl) this.attachLocation($decl); }
201
+ innerUsing[ using ] locals[ decl = {} ]
202
+ @after { this.attachLocation($decl); }
208
203
  :
204
+ { $decl.location = this.startLocation(); }
209
205
  path=externalPath
210
- { $decl = this.addItem( $using, 'usings', 'using', null, { extern: $path.extern } ); }
206
+ { this.addItem( $decl, $using, 'usings', 'using' );; $decl.extern = $path.extern; }
211
207
  ( AS name=ident['Using'] { $decl.name = $name.id; }
212
208
  | { this.classifyImplicitName( 'Using' ); }
213
209
  )
@@ -225,18 +221,18 @@ externalPath returns [ extern = {} ]
225
221
  // @anno :p - x as x; // or: anno value true, select item :p-x
226
222
  // }
227
223
 
228
- annotationAssignment_1[ annos ] locals[ assignment = { name: {} } ]
229
- @after { $annos.push( this.attachLocation($assignment) ); }
224
+ annotationAssignment_1[ art ] locals[ assignment = { name: {} } ]
225
+ @after { this.assignAnnotation( $art, $assignment ); }
230
226
  :
231
227
  annotationPath[ $assignment.name, 'anno' ]
232
228
  annotationPathVariant[ $assignment.name ]?
233
229
  (
234
230
  ':' { this.meltKeywordToIdentifier(true); } // allow path as anno value start with reserved
235
- val=annoValue { $assignment.value = $val.val; }
231
+ val=annoValue[ $assignment ]
236
232
  )?
237
233
  ;
238
234
 
239
- annotationAssignment_paren[ annos ]
235
+ annotationAssignment_paren[ art ]
240
236
  :
241
237
  '('
242
238
  // allow completely useless `@()` with a warning, do not offer it for completion
@@ -251,28 +247,28 @@ annotationAssignment_paren[ annos ]
251
247
  return $ctx;
252
248
  }
253
249
  }
254
- annotationAssignment_1[ $annos ]
250
+ annotationAssignment_1[ $art ]
255
251
  ( ','
256
252
  {
257
253
  this.meltKeywordToIdentifier();
258
254
  if (this.isStraightBefore(')')) break; // allow ',' before ')'
259
255
  }
260
- annotationAssignment_1[ $annos ]
256
+ annotationAssignment_1[ $art ]
261
257
  )*
262
258
  ')'
263
259
  ;
264
260
 
265
- annotationAssignment_fix[ annos ] locals[ assignment ]
261
+ annotationAssignment_fix[ art ] locals[ assignment ]
266
262
  // value outside @(...)
267
263
  @after {
268
264
  if ($assignment) {
269
- $annos.push( this.attachLocation($assignment) );
270
- this.docComment( $annos );
265
+ this.assignAnnotation( $art, $assignment );
266
+ this.docComment( $art );
271
267
  }
272
268
  } :
273
269
  '@'
274
270
  (
275
- annotationAssignment_paren[ annos ]
271
+ annotationAssignment_paren[ $art ]
276
272
  |
277
273
  { $assignment = { name: {} }; }
278
274
  annotationPath[ $assignment.name, 'anno' ]
@@ -287,38 +283,38 @@ annotationAssignment_fix[ annos ] locals[ assignment ]
287
283
  )
288
284
  ;
289
285
 
290
- annotationAssignment_ll1[ annos ] locals[ assignment ]
286
+ annotationAssignment_ll1[ art ] locals[ assignment ]
291
287
  @after {
292
288
  if ($assignment) {
293
- $annos.push( this.attachLocation($assignment) );
294
- this.docComment( $annos );
289
+ this.assignAnnotation( $art, $assignment );
290
+ this.docComment( $art );
295
291
  }
296
292
  } :
297
293
  '@'
298
294
  (
299
- annotationAssignment_paren[ annos ]
295
+ annotationAssignment_paren[ $art ]
300
296
  |
301
297
  { $assignment = { name: {} }; }
302
298
  annotationPath[ $assignment.name, 'anno' ]
303
299
  annotationPathVariant[ $assignment.name ]?
304
300
  (
305
301
  ':' { this.meltKeywordToIdentifier(true); } // allow path as anno value start with reserved
306
- val=annoValue { $assignment.value = $val.val; }
302
+ val=annoValue[ $assignment ]
307
303
  )?
308
304
  )
309
305
  ;
310
306
 
311
307
  // Has previously used ATN, now via local token rewrite
312
- annotationAssignment_atn[ annos ] locals[ assignment ]
308
+ annotationAssignment_atn[ art ] locals[ assignment ]
313
309
  @after {
314
310
  if ($assignment) {
315
- $annos.push( this.attachLocation($assignment) );
316
- this.docComment( $annos );
311
+ this.assignAnnotation( $art, $assignment );
312
+ this.docComment( $art );
317
313
  }
318
314
  } :
319
315
  '@'
320
316
  (
321
- annotationAssignment_paren[ annos ]
317
+ annotationAssignment_paren[ $art ]
322
318
  |
323
319
  { $assignment = { name: {} }; }
324
320
  annotationPath[ $assignment.name, 'anno' ]
@@ -337,14 +333,13 @@ annotationAssignment_atn[ annos ] locals[ assignment ]
337
333
  ( HelperToken2 // ':'
338
334
  { this.meltKeywordToIdentifier(true); } // allow path as anno value start with reserved
339
335
  (
340
- val=annoValueBase { $assignment.value = $val.val; }
336
+ val=annoValueBase[ $assignment ]
341
337
  |
342
- { $assignment.value = {}; } // TODO: think about expression value representation
343
- at='@'? annotationPath[ $assignment.value, 'ref', $at ]
338
+ at='@'? annotationPath[ $assignment, 'ref', $at ]
344
339
  { this.setLocalToken( '#', 'HelperToken1', null, true ); } // see above
345
340
  (
346
341
  HelperToken1 { this.meltKeywordToIdentifier(); }
347
- variant=ident['variant'] { $assignment.value.variant = $variant.id; }
342
+ variant=ident['variant'] { $assignment.variant = $variant.id; }
348
343
  )?
349
344
  )
350
345
  )?
@@ -364,97 +359,95 @@ optionalSemi
364
359
  ';'?
365
360
  ;
366
361
 
367
- artifactDef[ outer, defOnly = false ] locals[ annos = [] ] // cannot use `parent` as parameter name!
362
+ artifactDef[ outer, defOnly = false ] locals[ art = {} ] // cannot use `parent` as parameter name!
368
363
  @after{ /* #ATN 1 */ }
369
364
  :
370
- { this.docComment( $annos ); }
371
- annotationAssignment_ll1[ $annos ]*
365
+ { $art.location = this.startLocation(); this.docComment( $art ); }
366
+ annotationAssignment_ll1[ $art ]*
372
367
  (
373
368
  DEFINE?
374
- ( contextDef[ $outer, this.startLocation(), $annos, defOnly ]
375
- | entityDef[ $outer, this.startLocation(), $annos ]
376
- | typeDef[ $outer, this.startLocation(), $annos ]
377
- | aspectDef[ $outer, this.startLocation(), $annos ]
378
- | annotationDef[ $outer, this.startLocation(), $annos ]
379
- | viewDef[ $outer, this.startLocation(), $annos ]
380
- | eventDef[ $outer, this.startLocation(), $annos ]
381
- | actionFunctionMainDef[ $outer, this.startLocation(), $annos ]
369
+ ( contextDef[ $art, $outer, defOnly ]
370
+ | entityDef[ $art, $outer ]
371
+ | typeDef[ $art, $outer ]
372
+ | aspectDef[ $art, $outer ]
373
+ | annotationDef[ $art, $outer ]
374
+ | viewDef[ $art, $outer ]
375
+ | eventDef[ $art, $outer ]
376
+ | actionFunctionMainDef[ $art, $outer ]
382
377
  )
383
378
  |
384
379
  extend=EXTEND
385
- { if (defOnly) // this is a syntax restriction which is ensured in CSN in
386
- // another way
380
+ { if (defOnly)
387
381
  this.error( 'syntax-extend-context', $extend,
388
382
  { code: 'EXTEND artifact', kind: defOnly },
389
- 'No $(CODE) within $(KIND) extensions' ); }
383
+ 'No $(CODE) within $(KIND) extensions' );
384
+ if (!$outer.extensions) $outer.extensions = [];
385
+ }
390
386
  // #ATN: EXTEND elem, while CONTEXT, ENTITY etc are not reserved
391
- ( extendContext[ $outer, this.startLocation(), $annos ]
392
- | extendEntity[ $outer, this.startLocation(), $annos ]
393
- | extendProjection[ $outer, this.startLocation(), $annos ]
394
- | extendType[ $outer, this.startLocation(), $annos ]
395
- | extendAspect[ $outer, this.startLocation(), $annos ]
387
+ ( extendContext[ $art, $outer ]
388
+ | extendEntity[ $art, $outer ]
389
+ | extendProjection[ $art, $outer ]
390
+ | extendType[ $art, $outer ]
391
+ | extendAspect[ $art, $outer ]
396
392
  // Streamlined Syntax
397
- | extendArtifact[ $outer, this.startLocation(), $annos ]
393
+ | extendArtifact[ $art, $outer ]
398
394
  )
399
395
  |
400
396
  annotate=ANNOTATE
401
- { if (defOnly) // this is a syntax restriction which is ensured in CSN in
402
- // another way
397
+ { if (defOnly)
403
398
  this.error( 'syntax-extend-context', $annotate,
404
399
  { code: 'ANNOTATE artifact', kind: defOnly },
405
400
  'No $(CODE) within $(KIND) extensions' );
406
401
  this.meltKeywordToIdentifier();
407
402
  }
408
- annotateArtifact[ $outer, this.startLocation(), $annos ] // not kind-specific
403
+ annotateArtifact[ $art, $outer ] // not kind-specific
409
404
  )
410
405
  ;
411
406
 
412
- contextDef[ outer, loc, annos, defOnly = false ] locals[ art, name = {} ]
413
- @after { this.attachLocation($art); }
407
+ contextDef[ art, outer, defOnly = false ] locals[ name = {} ]
408
+ @after { this.attachLocation( $art ); }
414
409
  :
415
410
  ( CONTEXT | service=SERVICE ) simplePath[ $name, $service ? 'Service' : 'Context' ]
416
- { $art = this.addDef( $outer, 'artifacts', $service ? 'service' : 'context', $name, $annos,
417
- {}, $loc );
418
- this.docComment( $annos ); }
419
- annotationAssignment_fix[ $annos ]*
411
+ { this.addDef( $art, $outer, 'artifacts', $service ? 'service' : 'context', $name );
412
+ this.docComment( $art ); }
413
+ annotationAssignment_fix[ $art ]*
420
414
  (
421
- '{' { $art.artifacts = this.createDict(); }
415
+ '{' { $art.artifacts = this.createDict(); $art.extensions = []; }
422
416
  artifactDef[ $art, defOnly ]*
423
- '}' { this.setDictEndLocation( $art.artifacts ); }
417
+ '}' { this.finalizeDictOrArray( $art.artifacts ); }
424
418
  optionalSemi
425
419
  |
426
420
  requiredSemi
427
421
  )
428
422
  ;
429
423
 
430
- extendContext[ outer, loc, annos ] locals[ art, name = {} ]
431
- @after { this.attachLocation($art); }
424
+ extendContext[ art, outer ] locals[ name = {} ]
425
+ @after { this.attachLocation( $art ); }
432
426
  :
433
- ( CONTEXT | service=SERVICE ) simplePath[ $name, $service ? 'Service' : 'Context' ] // not 'Extend' here
434
- { $art = this.addItem( $outer, 'extensions', 'extend', $annos,
435
- { name: $name, expectedKind: $service ? 'service' : 'context' },
436
- $loc ); }
427
+ ( CONTEXT { $art.expectedKind = 'context'; } | service=SERVICE { $art.expectedKind = 'service'; })
428
+ simplePath[ $name, $service ? 'Service' : 'Context' ] // not 'Extend' here
429
+ { $art.name = $name; this.addItem( $art, $outer, 'extensions', 'extend' ); }
437
430
  ( WITH { this.noSemicolonHere(); } )?
438
- { this.docComment( $annos ); }
439
- annotationAssignment_ll1[ $annos ]*
431
+ { this.docComment( $art ); }
432
+ annotationAssignment_ll1[ $art ]*
440
433
  (
441
434
  '{' { $art.artifacts = this.createDict(); }
442
435
  artifactDef[ $art, $service ? 'SERVICE' : 'CONTEXT' ]*
443
- '}' { this.setDictEndLocation( $art.artifacts ); }
436
+ '}' { this.finalizeDictOrArray( $art.artifacts ); }
444
437
  optionalSemi
445
438
  |
446
439
  requiredSemi
447
440
  )
448
441
  ;
449
442
 
450
- entityDef[ outer, loc, annos ] locals[ art, name = {} ]
451
- @after { this.attachLocation($art); }
443
+ entityDef[ art, outer ] locals[ name = {} ]
444
+ @after { this.attachLocation( $art ); }
452
445
  :
453
446
  ENTITY simplePath[ $name, 'Entity' ]
454
- { $art = this.addDef( $outer, 'artifacts', 'entity', $name, $annos, {}, $loc );
455
- this.docComment( $annos ); }
456
- annotationAssignment_fix[ $annos ]*
457
- entityParameters[ $art ]?
447
+ { this.addDef( $art, $outer, 'artifacts', 'entity', $name );
448
+ this.docComment( $art ); }
449
+ annotationAssignment_fix[ $art ]*
450
+ parameterListDef[ $art ]?
458
451
  (
459
452
  ( ':'
460
453
  includeRef[ $art ]
@@ -462,15 +455,14 @@ entityDef[ outer, loc, annos ] locals[ art, name = {} ]
462
455
  includeRef[ $art ]
463
456
  )*
464
457
  )?
465
- '{'
466
- { $art.elements = this.createDict(); } // better for include and annotate
458
+ '{' { $art.elements = this.createDict(); }
467
459
  elementDef[ $art ]*
468
- '}' { this.setDictEndLocation( $art.elements ); }
460
+ '}' { this.finalizeDictOrArray( $art.elements ); }
469
461
  // TODO: action definitions in a specific section?
470
462
  (
471
463
  ACTIONS '{' { $art.actions = this.createDict(); }
472
464
  actionFunctionDef[ $art ]*
473
- '}' { this.setDictEndLocation( $art.actions ); }
465
+ '}' { this.finalizeDictOrArray( $art.actions ); }
474
466
  )?
475
467
  optionalSemi
476
468
  |
@@ -480,7 +472,7 @@ entityDef[ outer, loc, annos ] locals[ art, name = {} ]
480
472
  (
481
473
  ACTIONS '{' { $art.actions = this.createDict(); }
482
474
  actionFunctionDef[ $art ]*
483
- '}' { this.setDictEndLocation( $art.actions ); }
475
+ '}' { this.finalizeDictOrArray( $art.actions ); }
484
476
  optionalSemi
485
477
  | requiredSemi
486
478
  )
@@ -490,7 +482,7 @@ entityDef[ outer, loc, annos ] locals[ art, name = {} ]
490
482
  (
491
483
  ACTIONS '{' { $art.actions = this.createDict(); }
492
484
  actionFunctionDef[ $art ]*
493
- '}' { this.setDictEndLocation( $art.actions ); }
485
+ '}' { this.finalizeDictOrArray( $art.actions ); }
494
486
  )?
495
487
  optionalSemi // TODO: not fully correct without columns or excluding
496
488
  )
@@ -514,7 +506,7 @@ projectionSpec returns[ query ] locals[ src ]
514
506
  ( AS aliasName=ident['FromAlias'] { $src.name = $aliasName.id } )?
515
507
  // ANTLR errors are better if we use ( A )? instead of ( A | ):
516
508
  { if (!$src.name) this.classifyImplicitName( $src.scope ? 'FromAlias' : 'Without' ); }
517
- bracedSelectItemListDef[ $query ]?
509
+ bracedSelectItemListDef[ $query, 'columns' ]?
518
510
  excludingClause[ $query ]?
519
511
  ;
520
512
 
@@ -541,25 +533,26 @@ excludingClause[ query ]
541
533
  ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
542
534
  projectionExclusion[ $query ]
543
535
  )*
544
- '}' { this.setDictEndLocation( $query.excludingDict ); }
536
+ '}' { this.finalizeDictOrArray( $query.excludingDict ); }
545
537
  ;
546
538
 
547
- projectionExclusion[ outer ] locals[ art ]
539
+ projectionExclusion[ outer ] locals[ art = {} ]
548
540
  @after { this.attachLocation($art); }
549
541
  :
550
542
  name=ident['ref']
551
- { $art = this.addDef( $outer, 'excludingDict', '', $name.id ); }
543
+ { this.addDef( $art, $outer, 'excludingDict', '', $name.id ); }
552
544
  ;
553
545
 
554
- extendEntity[ outer, loc, annos ] locals[ art, name = {} ]
555
- @after { /* #ATN 1 */ this.attachLocation($art); }
546
+ extendEntity[ art, outer ] locals[ name = {} ]
547
+ @after { /* #ATN 1 */ this.attachLocation( $art ); }
556
548
  :
557
549
  ENTITY simplePath[ $name, 'Extend' ]
558
- { $art = this.addItem( $outer, 'extensions', 'extend', $annos,
559
- { name: $name, expectedKind: 'entity' }, $loc ); }
550
+ { $art.expectedKind = 'entity'; $art.name = $name;
551
+ this.addItem( $art, $outer, 'extensions', 'extend' );
552
+ }
560
553
  (
561
- WITH { this.noSemicolonHere(); this.docComment( $annos ); }
562
- annotationAssignment_ll1[ $annos ]*
554
+ WITH { this.noSemicolonHere(); this.docComment( $art ); }
555
+ annotationAssignment_ll1[ $art ]*
563
556
  // ATN: the ref can start with ACTIONS
564
557
  (
565
558
  includeRef[ $art ]
@@ -568,8 +561,8 @@ extendEntity[ outer, loc, annos ] locals[ art, name = {} ]
568
561
  extendForEntity[ $art ]
569
562
  )
570
563
  |
571
- { this.docComment( $annos ); }
572
- annotationAssignment_ll1[ $annos ]*
564
+ { this.docComment( $art ); }
565
+ annotationAssignment_ll1[ $art ]*
573
566
  extendForEntity[ $art ]
574
567
  )
575
568
  ;
@@ -578,33 +571,32 @@ extendForEntity[ art ]
578
571
  :
579
572
  '{' { $art.elements = this.createDict(); }
580
573
  elementDefOrExtend[ $art ]*
581
- '}' { this.setDictEndLocation( $art.elements ); }
574
+ '}' { this.finalizeDictOrArray( $art.elements ); }
582
575
  (
583
576
  ACTIONS '{' { $art.actions = this.createDict(); }
584
577
  actionFunctionDef[ $art ]*
585
- '}' { this.setDictEndLocation( $art.actions ); }
578
+ '}' { this.finalizeDictOrArray( $art.actions ); }
586
579
  )?
587
580
  optionalSemi
588
581
  |
589
582
  ACTIONS '{' { $art.actions = this.createDict(); }
590
583
  actionFunctionDef[ $art ]*
591
- '}' { this.setDictEndLocation( $art.actions ); }
584
+ '}' { this.finalizeDictOrArray( $art.actions ); }
592
585
  optionalSemi
593
586
  |
594
587
  requiredSemi
595
588
  ;
596
589
 
597
- extendProjection[ outer, loc, annos ] locals[ art, name = {} ]
598
- @after { this.attachLocation($art); }
590
+ extendProjection[ art, outer ] locals[ name = {} ]
591
+ @after { this.attachLocation( $art ); }
599
592
  :
600
593
  expected=PROJECTION simplePath[ $name, 'Extend' ]
601
- {
602
- $art = this.addItem( $outer, 'extensions', 'extend', $annos,
603
- { name: $name, expectedKind: 'entity' }, // or 'projection'?
604
- $loc ); }
594
+ { $art.expectedKind = 'entity'; $art.name = $name;
595
+ this.addItem( $art, $outer, 'extensions', 'extend' );
596
+ }
605
597
  ( WITH { this.noSemicolonHere(); } )?
606
- { this.docComment( $annos ); }
607
- annotationAssignment_ll1[ $annos ]*
598
+ { this.docComment( $art ); }
599
+ annotationAssignment_ll1[ $art ]*
608
600
  (
609
601
  '{' { $art.columns = []; }
610
602
  (
@@ -617,13 +609,13 @@ extendProjection[ outer, loc, annos ] locals[ art, name = {} ]
617
609
  (
618
610
  ACTIONS '{' { $art.actions = this.createDict(); }
619
611
  actionFunctionDef[ $art ]*
620
- '}' { this.setDictEndLocation( $art.actions ); }
612
+ '}' { this.finalizeDictOrArray( $art.actions ); }
621
613
  )?
622
614
  optionalSemi
623
615
  |
624
616
  ACTIONS '{' { $art.actions = this.createDict(); }
625
617
  actionFunctionDef[ $art ]*
626
- '}' { this.setDictEndLocation( $art.actions ); }
618
+ '}' { this.finalizeDictOrArray( $art.actions ); }
627
619
  optionalSemi
628
620
  |
629
621
  requiredSemi
@@ -631,53 +623,53 @@ extendProjection[ outer, loc, annos ] locals[ art, name = {} ]
631
623
  ;
632
624
 
633
625
  // TODO: no action extension?
634
- actionFunctionDef[ outer ] locals[ art, annos = [] ]
635
- @after { this.attachLocation($art); }
626
+ actionFunctionDef[ outer ] locals[ art = {} ]
627
+ @after { this.attachLocation( $art ); }
636
628
  :
637
- { this.docComment( $annos ); }
638
- annotationAssignment_ll1[ $annos ]*
629
+ { $art.location = this.startLocation();; this.docComment( $art ); }
630
+ annotationAssignment_ll1[ $art ]*
639
631
  (
640
632
  ACTION name=ident['BoundAction']
641
- { $art = this.addDef( $outer, 'actions', 'action', $name.id, $annos );
642
- this.docComment( $annos ); }
643
- annotationAssignment_fix[ $annos ]*
633
+ { this.addDef( $art, $outer, 'actions', 'action', $name.id );
634
+ this.docComment( $art ); }
635
+ annotationAssignment_fix[ $art ]*
644
636
  parameterListDef[ $art ]
645
- ( returnTypeSpec[ $art, $annos ] | requiredSemi )
637
+ ( returnTypeSpec[ $art ] | requiredSemi )
646
638
  |
647
639
  FUNCTION name=ident['BoundAction']
648
- { $art = this.addDef( $outer, 'actions', 'function', $name.id, $annos );
649
- this.docComment( $annos ); }
650
- annotationAssignment_fix[ $annos ]*
640
+ { this.addDef( $art, $outer, 'actions', 'function', $name.id );
641
+ this.docComment( $art ); }
642
+ annotationAssignment_fix[ $art ]*
651
643
  parameterListDef[ $art ]
652
- returnTypeSpec[ $art, $annos ]
644
+ returnTypeSpec[ $art ]
653
645
  )
654
646
  ;
655
647
 
656
- actionFunctionMainDef[ outer, loc, annos ] locals[ art, name = {} ]
657
- @after { this.attachLocation($art); }
648
+ actionFunctionMainDef[ art, outer ] locals[ name = {} ]
649
+ @after { this.attachLocation( $art ); }
658
650
  :
659
651
  ACTION simplePath[ $name, 'Action' ]
660
- { $art = this.addDef( $outer, 'artifacts', 'action', $name, $annos, {}, $loc );
661
- this.docComment( $annos ); }
662
- annotationAssignment_fix[ $annos ]*
652
+ { this.addDef( $art, $outer, 'artifacts', 'action', $name );
653
+ this.docComment( $art ); }
654
+ annotationAssignment_fix[ $art ]*
663
655
  parameterListDef[ $art ]
664
- ( returnTypeSpec[ $art, $annos ] | requiredSemi )
656
+ ( returnTypeSpec[ $art ] | requiredSemi )
665
657
  |
666
658
  FUNCTION simplePath[ $name, 'Action' ]
667
- { $art = this.addDef( $outer, 'artifacts', 'function', $name, $annos, {}, $loc );
668
- this.docComment( $annos ); }
669
- annotationAssignment_fix[ $annos ]*
659
+ { this.addDef( $art, $outer, 'artifacts', 'function', $name );
660
+ this.docComment( $art ); }
661
+ annotationAssignment_fix[ $art ]*
670
662
  parameterListDef[ $art ]
671
- returnTypeSpec[ $art, $annos ]
663
+ returnTypeSpec[ $art ]
672
664
  ;
673
665
 
674
- eventDef[ outer, loc, annos ] locals[ art, name = {} ]
675
- @after { /* #ATN 1 */ this.attachLocation($art); }
666
+ eventDef[ art, outer ] locals[ name = {} ]
667
+ @after { /* #ATN 1 */ this.attachLocation( $art ); }
676
668
  :
677
669
  EVENT simplePath[ $name, 'Event' ]
678
- { $art = this.addDef( $outer, 'artifacts', 'event', $name, $annos, {}, $loc );
679
- this.docComment( $annos ); }
680
- annotationAssignment_fix[ $annos ]*
670
+ { this.addDef( $art, $outer, 'artifacts', 'event', $name );
671
+ this.docComment( $art ); }
672
+ annotationAssignment_fix[ $art ]*
681
673
  (
682
674
  typeStruct[ $art ] optionalSemi
683
675
  |
@@ -693,8 +685,8 @@ eventDef[ outer, loc, annos ] locals[ art, name = {} ]
693
685
  )*
694
686
  typeStruct[ $art ] optionalSemi
695
687
  |
696
- { this.docComment( $annos ); }
697
- annotationAssignment_ll1[ $annos ]*
688
+ { this.docComment( $art ); }
689
+ annotationAssignment_ll1[ $art ]*
698
690
  requiredSemi
699
691
  )
700
692
  |
@@ -708,18 +700,18 @@ eventDef[ outer, loc, annos ] locals[ art, name = {} ]
708
700
  )
709
701
  ;
710
702
 
711
- aspectDef[ outer, loc, annos ] locals[ art, name = {} ]
712
- @after { this.attachLocation($art); }
703
+ aspectDef[ art, outer ] locals[ name = {} ]
704
+ @after { this.attachLocation( $art ); }
713
705
  :
714
706
  ( ASPECT | ( abs=ABSTRACT | HideAlternatives ) ent=ENTITY )
715
707
  simplePath[ $name, 'Type' ]
716
- { $art = this.addDef( $outer, 'artifacts', 'aspect', $name, $annos, {}, $loc );
708
+ { this.addDef( $art, $outer, 'artifacts', 'aspect', $name );
717
709
  // backends do not like ['$'+'syntax']: ($ent ? 'entity' : 'aspect')
718
710
  if ($ent)
719
711
  this.warning( 'syntax-deprecated-abstract', this.tokenLocation( $abs, $ent ), {},
720
712
  'Abstract entity definitions are deprecated; use aspect definitions instead' );
721
- this.docComment( $annos ); }
722
- annotationAssignment_fix[ $annos ]*
713
+ this.docComment( $art ); }
714
+ annotationAssignment_fix[ $art ]*
723
715
  ( ':'
724
716
  (
725
717
  includeRef[ $art ]
@@ -730,99 +722,93 @@ aspectDef[ outer, loc, annos ] locals[ art, name = {} ]
730
722
  )?
731
723
  '{' { $art.elements = this.createDict(); }
732
724
  ( elementDef[ $art ]* )
733
- '}' { this.setDictEndLocation( $art.elements ); }
725
+ '}' { this.finalizeDictOrArray( $art.elements ); }
734
726
  // TODO: action definitions in a specific section?
735
727
  (
736
728
  ACTIONS '{' { $art.actions = this.createDict(); }
737
729
  actionFunctionDef[ $art ]*
738
- '}' { this.setDictEndLocation( $art.actions ); }
730
+ '}' { this.finalizeDictOrArray( $art.actions ); }
739
731
  )?
740
732
  optionalSemi
741
733
  ;
742
734
 
743
- typeDef[ outer, loc, annos ] locals[ art, name = {} ]
744
- @after { this.attachLocation($art); }
735
+ typeDef[ art, outer ] locals[ name = {} ]
736
+ @after { this.attachLocation( $art ); }
745
737
  :
746
738
  TYPE simplePath[ $name, 'Type' ]
747
- { $art = this.addDef( $outer, 'artifacts', 'type', $name, $annos, {}, $loc );
748
- this.docComment( $annos ); }
749
- annotationAssignment_fix[ $annos ]*
750
- typeSpecSemi[ $art, $annos ]
739
+ { this.addDef( $art, $outer, 'artifacts', 'type', $name );
740
+ this.docComment( $art ); }
741
+ annotationAssignment_fix[ $art ]*
742
+ typeSpecSemi[ $art ]
751
743
  ;
752
744
 
753
- extendType[ outer, loc, annos ] locals[ art, name = {} ]
754
- @after { this.attachLocation($art); }
745
+ extendType[ art, outer ] locals[ name = {} ]
746
+ @after { this.attachLocation( $art ); }
755
747
  :
756
748
  // aspects are types, i.e. kind is 'type' for aspects
757
749
  TYPE simplePath[ $name, 'Extend' ]
758
- { $art = this.addItem( $outer, 'extensions', 'extend', $annos,
759
- { name: $name, expectedKind: 'type' },
760
- $loc ); }
761
- extendWithOptElements[ $art, $annos ]
750
+ { $art.expectedKind = 'type'; $art.name = $name;
751
+ this.addItem( $art, $outer, 'extensions', 'extend' );
752
+ }
753
+ extendWithOptElements[ $art, $art ]
762
754
  ;
763
755
 
764
- extendAspect[ outer, loc, annos ] locals[ art, name = {} ]
765
- @after { this.attachLocation($art); }
756
+ extendAspect[ art, outer ] locals[ name = {} ]
757
+ @after { this.attachLocation( $art ); }
766
758
  :
767
759
  // aspects are types, i.e. kind is 'type' for aspects
768
760
  ASPECT simplePath[ $name, 'Extend' ]
769
- { $art = this.addItem( $outer, 'extensions', 'extend', $annos,
770
- { name: $name, expectedKind: 'aspect' },
771
- $loc ); }
772
- extendWithOptElements[ $art, $annos ]
761
+ { $art.expectedKind = 'aspect'; $art.name = $name;
762
+ this.addItem( $art, $outer, 'extensions', 'extend' );
763
+ }
764
+ extendWithOptElements[ $art, $art ]
773
765
  ;
774
766
 
775
- annotationDef[ outer, loc, annos ] locals[ art, name = {} ]
776
- @after { this.attachLocation($art); }
767
+ annotationDef[ art, outer ] locals[ name = {} ]
768
+ @after { this.attachLocation( $art ); }
777
769
  :
778
770
  annotation=ANNOTATION simplePath[ $name, 'AnnoDef' ]
779
771
  { if ($outer.kind !== 'source') { // this is a syntax restriction to avoid confusion
780
- this.error( 'syntax-no-inner-vocabulary', $annotation, {},
781
- 'Annotation definitions can\'t be defined inside contexts or services' );
772
+ this.error( 'syntax-unexpected-vocabulary', $annotation, { '#': $outer.kind } );
782
773
  $art = {}; }
783
- else
784
- $art = this.addDef( $outer, 'vocabularies', 'annotation', $name, $annos, {}, $loc );
785
- this.docComment( $annos ); }
786
- annotationAssignment_fix[ $annos ]*
787
- typeSpecSemi[ $art, $annos ] // also 'includes'...
774
+ else {
775
+ if (!$outer.vocabularies) $outer.vocabularies = Object.create(null);
776
+ this.addDef( $art, $outer, 'vocabularies', 'annotation', $name );
777
+ }
778
+ this.docComment( $art ); }
779
+ annotationAssignment_fix[ $art ]*
780
+ typeSpecSemi[ $art ] // also 'includes'...
788
781
  ;
789
782
 
790
- extendArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
791
- @after{ /* #ATN 1 */ this.attachLocation($art); }
783
+ extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
784
+ @after{ /* #ATN 1 */ this.attachLocation( $art ); }
792
785
  :
793
786
  simplePath[ $name, 'Extend' ]
787
+ ( ':' simplePath[ $elemName, 'Element'] )?
788
+ { this.addExtension( $art, $outer, 'extend', $name, $elemName.path ); }
794
789
  (
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 ]*
790
+ { this.docComment( $art ); }
791
+ annotationAssignment_ll1[ $art ]*
807
792
  (
808
793
  '{' { $art.elements = this.createDict(); }
809
794
  elementDefOrExtend[ $art ]*
810
- '}' { this.setDictEndLocation( $art.elements ); }
795
+ '}' { this.finalizeDictOrArray( $art.elements ); }
811
796
  optionalSemi
812
797
  |
813
798
  requiredSemi
814
799
  )
815
800
  |
816
- WITH { this.noSemicolonHere(); this.docComment( $annos ); }
817
- annotationAssignment_ll1[ $annos ]*
801
+ WITH { this.noSemicolonHere(); this.docComment( $art ); }
802
+ annotationAssignment_ll1[ $art ]*
818
803
  // #ATN: DEFINITIONS, COLUMNS, ACTIONS etc are not reserved and could be identifiers (ref).
804
+ // TODO: exclude "expected" according to disallowElementExtension()
819
805
  (
820
806
  includeRef[ $art ]
821
807
  requiredSemi
822
808
  |
823
809
  '{' { $art.elements = this.createDict(); }
824
810
  elementDefOrExtend[ $art ]*
825
- '}' { this.setDictEndLocation( $art.elements ); }
811
+ '}' { this.finalizeDictOrArray( $art.elements ); }
826
812
  optionalSemi
827
813
  |
828
814
  requiredSemi
@@ -831,7 +817,7 @@ extendArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
831
817
  DEFINITIONS
832
818
  '{' { $art.artifacts = this.createDict(); }
833
819
  artifactDef[ $art, true ]*
834
- '}' { this.setDictEndLocation( $art.artifacts ); }
820
+ '}' { this.finalizeDictOrArray( $art.artifacts ); }
835
821
  optionalSemi
836
822
  |
837
823
  { this.disallowElementExtension( $elemName, $outer, 'columns' ); }
@@ -849,84 +835,75 @@ extendArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
849
835
  { this.disallowElementExtension( $elemName, $outer, 'actions' ); }
850
836
  ACTIONS '{' { $art.actions = this.createDict(); }
851
837
  actionFunctionDef[ $art ]*
852
- '}' { this.setDictEndLocation( $art.actions ); }
838
+ '}' { this.finalizeDictOrArray( $art.actions ); }
853
839
  optionalSemi
854
840
  |
855
841
  ELEMENTS '{' { $art.elements = this.createDict(); }
856
842
  elementDefOrExtend[ $art ]*
857
- '}' { this.setDictEndLocation( $art.elements ); }
843
+ '}' { this.finalizeDictOrArray( $art.elements ); }
858
844
  optionalSemi
859
845
  |
860
846
  ENUM '{' { $art.enum = this.createDict(); }
861
847
  enumSymbolDef[ $art ]*
862
- '}' { this.setDictEndLocation( $art.enum ); }
848
+ '}' { this.finalizeDictOrArray( $art.enum ); }
863
849
  optionalSemi
864
850
  )
865
851
  )
866
852
  ;
867
853
 
868
- extendWithOptElements[ art, annos ]
854
+ extendWithOptElements[ art ]
869
855
  :
870
- WITH { this.noSemicolonHere(); this.docComment( $annos ); }
871
- annotationAssignment_ll1[ $annos ]*
856
+ WITH { this.noSemicolonHere(); this.docComment( $art ); }
857
+ annotationAssignment_ll1[ $art ]*
872
858
  (
873
859
  includeRef[ $art ]
874
860
  requiredSemi
875
861
  |
876
862
  '{' { $art.elements = this.createDict(); }
877
863
  elementDefOrExtend[ $art ]*
878
- '}' { this.setDictEndLocation( $art.elements ); }
864
+ '}' { this.finalizeDictOrArray( $art.elements ); }
879
865
  optionalSemi
880
866
  |
881
867
  requiredSemi
882
868
  )
883
869
  |
884
- { this.docComment( $annos ); }
885
- annotationAssignment_ll1[ $annos ]*
870
+ { this.docComment( $art ); }
871
+ annotationAssignment_ll1[ $art ]*
886
872
  (
887
873
  '{' { $art.elements = this.createDict(); }
888
874
  elementDefOrExtend[ $art ]*
889
- '}' { this.setDictEndLocation( $art.elements ); }
875
+ '}' { this.finalizeDictOrArray( $art.elements ); }
890
876
  optionalSemi
891
877
  |
892
878
  requiredSemi
893
879
  )
894
880
  ;
895
881
 
896
- annotateArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
897
- @after { this.attachLocation($art); }
882
+ annotateArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
883
+ @after { this.attachLocation( $art ); }
898
884
  :
899
885
  simplePath[ $name, 'Annotate' ]
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
-
886
+ ( ':' simplePath[ $elemName, 'Element'] )?
887
+ { this.addExtension( $art, $outer, 'annotate', $name, $elemName.path ); }
911
888
  ( WITH { this.noSemicolonHere(); } )?
912
- { this.docComment( $annos ); }
913
- annotationAssignment_ll1[ $annos ]*
889
+ { this.docComment( $art ); }
890
+ annotationAssignment_ll1[ $art ]*
914
891
  (
915
892
  '{' { $art.elements = this.createDict(); }
916
893
  annotateElement[ $art ]*
917
- '}' { this.setDictEndLocation( $art.elements ); }
894
+ '}' { this.finalizeDictOrArray( $art.elements ); }
918
895
  (
919
896
  ACTIONS
920
897
  '{' { $art.actions = this.createDict(); }
921
898
  annotateAction[ $art ]*
922
- '}' { this.setDictEndLocation( $art.actions ); }
899
+ '}' { this.finalizeDictOrArray( $art.actions ); }
923
900
  )?
924
901
  optionalSemi
925
902
  |
926
903
  ACTIONS
927
904
  '{' { $art.actions = this.createDict(); }
928
905
  annotateAction[ $art ]*
929
- '}' { this.setDictEndLocation( $art.actions ); }
906
+ '}' { this.finalizeDictOrArray( $art.actions ); }
930
907
  optionalSemi
931
908
  |
932
909
  '(' { $art.params = this.createDict(); }
@@ -934,12 +911,12 @@ annotateArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
934
911
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
935
912
  annotateParam[ $art ]
936
913
  )*
937
- ')' { this.setDictEndLocation( $art.params ); }
914
+ ')' { this.finalizeDictOrArray( $art.params ); }
938
915
  (
939
916
  RETURNS { $art['$'+'syntax'] = 'returns'; }
940
917
  '{' { $art.elements = this.createDict(); }
941
918
  annotateElement[ $art ]*
942
- '}' { this.setDictEndLocation( $art.elements ); }
919
+ '}' { this.finalizeDictOrArray( $art.elements ); }
943
920
  optionalSemi
944
921
  |
945
922
  requiredSemi
@@ -948,7 +925,7 @@ annotateArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
948
925
  RETURNS { $art['$'+'syntax'] = 'returns'; }
949
926
  '{' { $art.elements = this.createDict(); }
950
927
  annotateElement[ $art ]*
951
- '}' { this.setDictEndLocation( $art.elements ); }
928
+ '}' { this.finalizeDictOrArray( $art.elements ); }
952
929
  optionalSemi
953
930
 
954
931
  |
@@ -956,74 +933,74 @@ annotateArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
956
933
  )
957
934
  ;
958
935
 
959
- annotateElement[ outer ] locals[ art, annos = [] ]
960
- @after{ this.attachLocation($art); }
936
+ annotateElement[ outer ] locals[ art = {} ]
937
+ @after{ this.attachLocation( $art ); }
961
938
  :
962
- { this.docComment( $annos ); }
963
- annotationAssignment_ll1[ $annos ]*
939
+ { $art.location = this.startLocation();; this.docComment( $art ); }
940
+ annotationAssignment_ll1[ $art ]*
964
941
  name=ident['Element']
965
- { $art = this.addDef( $outer, 'elements', 'annotate', $name.id, $annos );
966
- this.docComment( $annos ); }
967
- annotationAssignment_ll1[ $annos ]*
942
+ { this.addDef( $art, $outer, 'elements', 'annotate', $name.id );
943
+ this.docComment( $art ); }
944
+ annotationAssignment_ll1[ $art ]*
968
945
  (
969
946
  '{' { $art.elements = this.createDict(); }
970
947
  annotateElement[ $art ]*
971
- '}' { this.setDictEndLocation( $art.elements ); }
948
+ '}' { this.finalizeDictOrArray( $art.elements ); }
972
949
  optionalSemi
973
950
  |
974
951
  requiredSemi
975
952
  )
976
953
  ;
977
954
 
978
- annotateAction [ outer ] locals [ art, annos = [] ]
979
- @after{ this.attachLocation($art); }
955
+ annotateAction [ outer ] locals [ art = {} ]
956
+ @after{ this.attachLocation( $art ); }
980
957
  :
981
- { this.docComment( $annos ); }
982
- annotationAssignment_ll1[ $annos ]*
958
+ { $art.location = this.startLocation();; this.docComment( $art ); }
959
+ annotationAssignment_ll1[ $art ]*
983
960
  name=ident['BoundAction']
984
- { $art = this.addDef( $outer, 'actions', 'annotate', $name.id, $annos );
985
- this.docComment( $annos ); }
986
- annotationAssignment_ll1[ $annos ]*
961
+ { this.addDef( $art, $outer, 'actions', 'annotate', $name.id );
962
+ this.docComment( $art ); }
963
+ annotationAssignment_ll1[ $art ]*
987
964
  (
988
965
  '(' { $art.params = this.createDict(); }
989
966
  annotateParam[ $art ]
990
967
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
991
968
  annotateParam[ $art ]
992
969
  )*
993
- ')' { this.setDictEndLocation( $art.params ); }
970
+ ')' { this.finalizeDictOrArray( $art.params ); }
994
971
  )?
995
972
  (
996
973
  RETURNS '{' { $art.elements = this.createDict(); }
997
974
  annotateElement[ $art ]*
998
- '}' { this.setDictEndLocation( $art.elements ); }
975
+ '}' { this.finalizeDictOrArray( $art.elements ); }
999
976
  optionalSemi
1000
977
  |
1001
978
  requiredSemi
1002
979
  )
1003
980
  ;
1004
981
 
1005
- annotateParam [ outer ] locals [ art, annos = [] ]
1006
- @after{ this.attachLocation($art); }
982
+ annotateParam [ outer ] locals [ art = {} ]
983
+ @after{ this.attachLocation( $art ); }
1007
984
  :
1008
- { this.docComment( $annos ); }
1009
- annotationAssignment_ll1[ $annos ]*
985
+ { $art.location = this.startLocation();; this.docComment( $art ); }
986
+ annotationAssignment_ll1[ $art ]*
1010
987
  param=ident['Param']
1011
- { $art = this.addDef( $outer, 'params', 'annotate', $param.id, $annos );
1012
- this.docComment( $annos ); }
1013
- annotationAssignment_ll1[ $annos ]*
988
+ { this.addDef( $art, $outer, 'params', 'annotate', $param.id );
989
+ this.docComment( $art ); }
990
+ annotationAssignment_ll1[ $art ]*
1014
991
  ;
1015
992
 
1016
993
  // Element definition and its helpers ----------------------------------------
1017
994
 
1018
- enumSymbolDef[ outer ] locals[ art, annos = [] ]
1019
- @after { this.attachLocation($art); }
995
+ enumSymbolDef[ outer ] locals[ art = {} ]
996
+ @after { this.attachLocation( $art ); }
1020
997
  :
1021
- { this.docComment( $annos ); }
1022
- annotationAssignment_ll1[ $annos ]*
998
+ { $art.location = this.startLocation();; this.docComment( $art ); }
999
+ annotationAssignment_ll1[ $art ]*
1023
1000
  name=ident['Enum']
1024
- { $art = this.addDef( $outer, 'enum', 'enum', $name.id, $annos );
1025
- this.docComment( $annos ); }
1026
- annotationAssignment_ll1[ $annos ]*
1001
+ { this.addDef( $art, $outer, 'enum', 'enum', $name.id );
1002
+ this.docComment( $art ); }
1003
+ annotationAssignment_ll1[ $art ]*
1027
1004
  ( '='
1028
1005
  { this.excludeExpected( ['Boolean', 'QuotedLiteral', "'#'", 'NULL'] ); }
1029
1006
  (
@@ -1033,8 +1010,8 @@ enumSymbolDef[ outer ] locals[ art, annos = [] ]
1033
1010
  ( plus='+' | min='-' ) num=Number
1034
1011
  { $art.value = this.numberLiteral( $num, $plus||$min ); }
1035
1012
  )
1036
- { this.docComment( $annos ); }
1037
- annotationAssignment_ll1[ $annos ]*
1013
+ { this.docComment( $art ); }
1014
+ annotationAssignment_ll1[ $art ]*
1038
1015
  )?
1039
1016
  requiredSemi
1040
1017
  ;
@@ -1045,37 +1022,35 @@ defaultValue[ art ] locals[ elem, elements = {} ]
1045
1022
  DEFAULT expr=expression { $art.default = $expr.expr; }
1046
1023
  ;
1047
1024
 
1048
- elementDefOrExtend[ outer ] locals[ annos = [] ]
1049
- @after { /* #ATN 1 */ if ($ctx.art) this.attachLocation($art.art); }
1050
- // tool complains if I test for ($art)
1025
+ elementDefOrExtend[ outer ] locals[ art = {} ]
1026
+ @after { /* #ATN 1 */ } // if ($art) this.attachLocation( $art ); }
1051
1027
  :
1052
- { this.docComment( $annos ); }
1053
- annotationAssignment_ll1[ $annos ]*
1028
+ { $art.location = this.startLocation();; this.docComment( $art ); }
1029
+ annotationAssignment_ll1[ $art ]*
1054
1030
  // #ATN: element name for definition can be EXTEND
1055
1031
  (
1056
1032
  EXTEND
1057
- extendElement[ $outer, this.startLocation(), $annos ]
1033
+ extendElement[ $art, $outer ]
1058
1034
  |
1059
- art = elementDefInner[ $outer, this.startLocation(), $annos, true ]
1035
+ elementDefInner[ $art, $outer, true ]
1060
1036
  )
1061
1037
  ;
1062
1038
 
1063
- elementDef[ outer ] locals[ annos = [] ]
1064
- @after { this.attachLocation($art.art); }
1039
+ elementDef[ outer ] locals[ $art = {} ]
1065
1040
  :
1066
- { this.docComment( $annos ); }
1067
- annotationAssignment_ll1[ $annos ]*
1068
- art = elementDefInner[ $outer, this.startLocation(), $annos, false ]
1041
+ { $art.location = this.startLocation();; this.docComment( $art ); }
1042
+ annotationAssignment_ll1[ $art ]*
1043
+ elementDefInner[ $art, $outer, false ]
1069
1044
  ;
1070
1045
 
1071
1046
  // Actually, this is a subset if elementDefInner...
1072
1047
  // TODO: the corresponding restrictions must also be checked in the core
1073
1048
  // compiler, as the mixin element could come via CSN
1074
- mixinElementDef[ outer ] locals[ art ]
1049
+ mixinElementDef[ outer ] locals[ art = {} ]
1075
1050
  @after { /* #ATN 2 */ this.attachLocation($art); }
1076
1051
  :
1077
1052
  name=ident['Mixin']
1078
- { $art = this.addDef( $outer, 'mixin', 'mixin', $name.id ); }
1053
+ { this.addDef( $art, $outer, 'mixin', 'mixin', $name.id ); }
1079
1054
  (
1080
1055
  ':'
1081
1056
  // #ATN: referenced type name can be ASSOCIATION or COMPOSITION
@@ -1097,33 +1072,30 @@ mixinElementDef[ outer ] locals[ art ]
1097
1072
  requiredSemi
1098
1073
  ;
1099
1074
 
1100
- misplacedAnnotations[ annos, messageId ]
1101
- :
1102
- // No docComment() here
1103
- annotationAssignment_ll1[ $annos ]+
1104
- { if ($messageId) // issue specified in central registry
1105
- this.message( messageId, this.tokenLocation( $ctx.start, this.getCurrentToken() ) );
1106
- }
1107
- ;
1108
-
1109
- elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1110
- @after{ /* #ATN 5 */ }
1075
+ elementDefInner[ art, outer, allowEq ]
1076
+ @after{ /* #ATN 5 */ this.attachLocation( $art ); }
1111
1077
  :
1112
1078
  // TODO: it would be excellent to remove ELEMENT...
1113
1079
  // or have a special ident rule without the ELEMENT
1114
1080
  // Reason: it would be good for error recovery to start a major block without LL1 ambiguity
1115
1081
  // VIRTUAL is keyword, except if before the following tokens texts:
1116
1082
  { this.setLocalToken( 'VIRTUAL', 'VIRTUAL', /^[:{@=}]$/ ); }
1117
- virtual=VIRTUAL? key=KEY?
1083
+ ( virtual=VIRTUAL { $art.virtual = this.valueWithTokenLocation( true, $virtual ); } )?
1084
+ ( key=KEY { $art.key = this.valueWithTokenLocation( true, $key ); } )?
1118
1085
  // #ATN: element name can be MASKED or ELEMENT (2x)
1119
- masked=MASKED? // TODO: order?
1086
+ ( masked=MASKED
1087
+ {
1088
+ $art.masked = this.valueWithTokenLocation( true, $masked ) ;
1089
+ this.message( 'syntax-invalid-masked', $masked, { keyword: 'masked' },
1090
+ 'Keyword $(KEYWORD) not supported' );
1091
+ }
1092
+ )?
1093
+ // TODO: order?
1120
1094
  ELEMENT?
1121
1095
  name=ident['Element']
1122
- { $art = this.addDef( $outer, 'elements', 'element', $name.id, $annos,
1123
- { virtual: $virtual, key: $key, masked: $masked },
1124
- $loc );
1125
- this.docComment( $annos ); }
1126
- annotationAssignment_fix[ $annos ]*
1096
+ { this.addDef( $art, $outer, 'elements', 'element', $name.id );
1097
+ this.docComment( $art ); }
1098
+ annotationAssignment_fix[ $art ]*
1127
1099
  // TODO: we can think of making the typeSpec optional and do checks instead:
1128
1100
  // type optional with '=', type required otherwise
1129
1101
  (
@@ -1138,7 +1110,6 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1138
1110
  (
1139
1111
  typeStruct[ $art ]
1140
1112
  nullability[ $art ]?
1141
- misplacedAnnotations[ $annos, 'syntax-anno-after-struct' ]?
1142
1113
  requiredSemi
1143
1114
  |
1144
1115
  typeAssociationBase[ $art, true ]
@@ -1155,11 +1126,11 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1155
1126
  typeCompoStruct[ $art.target ] optionalSemi
1156
1127
  |
1157
1128
  // we do not support `Composition of many { e }` - ambiguity ad-hoc target versus foreign keys!
1158
- typeToMany[ $art ] typeAssociationElementCont[ $art, $annos ]
1129
+ typeToMany[ $art ] typeAssociationElementCont[ $art ]
1159
1130
  |
1160
- typeToOne[ $art ] typeAssociationElementCont[ $art, $annos ]
1131
+ typeToOne[ $art ] typeAssociationElementCont[ $art ]
1161
1132
  |
1162
- simplePath[ $art.target, 'artref' ] typeAssociationElementCont[ $art, $annos ]
1133
+ simplePath[ $art.target, 'artref' ] typeAssociationElementCont[ $art ]
1163
1134
  )
1164
1135
  |
1165
1136
  (
@@ -1171,52 +1142,55 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1171
1142
  // #ATN: typeRefOptArgs can start with TYPE
1172
1143
  ( typeStruct[ $art.items ]
1173
1144
  nullability[ $art.items ]?
1174
- misplacedAnnotations[ $annos, 'syntax-anno-after-struct' ]?
1175
1145
  | typeTypeOf[ $art.items ]
1176
1146
  nullability[ $art.items ]?
1177
- { this.docComment( $annos ); }
1178
- annotationAssignment_ll1[ $annos ]*
1147
+ { this.docComment( $art ); }
1148
+ annotationAssignment_ll1[ $art ]*
1179
1149
  | typeRefOptArgs[ $art.items ]
1180
- nullability[ $art.items ]?
1181
- { this.docComment( $annos ); }
1182
- annotationAssignment_ll1[ $annos ]*
1150
+ nullability[ $art.items ]? // only if not followed by `enum`
1151
+ { this.docComment( $art ); }
1152
+ annotationAssignment_ll1[ $art ]*
1183
1153
  (
1154
+ { if ($art.items.notNull) {
1155
+ this.message( 'syntax-unexpected-null', $art.items.notNull.location,
1156
+ { keyword: $art.items.notNull.val ? 'not null' : 'null' } );
1157
+ }
1158
+ }
1184
1159
  ENUM '{' { $art.items.enum = this.createDict(); }
1185
1160
  enumSymbolDef[ $art.items ]*
1186
- '}' { this.setDictEndLocation( $art.items.enum ); }
1187
- misplacedAnnotations[ $annos, 'syntax-anno-after-enum' ]?
1161
+ '}' { this.finalizeDictOrArray( $art.items.enum ); }
1162
+ nullability[ $art.items ]?
1188
1163
  )?
1189
1164
  )
1190
1165
  requiredSemi // also req after struct/enum
1191
1166
  |
1192
1167
  typeTypeOf[ $art ] elementProperties[ $art ]?
1193
- { this.docComment( $annos ); }
1194
- annotationAssignment_ll1[ $annos ]*
1168
+ { this.docComment( $art ); }
1169
+ annotationAssignment_ll1[ $art ]*
1195
1170
  requiredSemi // also req after foreign key spec
1196
1171
  |
1197
1172
  l=LOCALIZED { $art.localized = this.valueWithTokenLocation( true, $l ); }
1198
1173
  typeRefOptArgs[ $art ]
1199
- { this.docComment( $annos ); }
1200
- annotationAssignment_ll1[ $annos ]*
1174
+ { this.docComment( $art ); }
1175
+ annotationAssignment_ll1[ $art ]*
1201
1176
  ( elementProperties[ $art ]
1202
- { this.docComment( $annos ); }
1203
- annotationAssignment_ll1[ $annos ]*
1177
+ { this.docComment( $art ); }
1178
+ annotationAssignment_ll1[ $art ]*
1204
1179
  )?
1205
1180
  requiredSemi
1206
1181
  |
1207
1182
  typeRefOptArgs[ $art ]
1208
- { this.docComment( $annos ); }
1209
- annotationAssignment_ll1[ $annos ]*
1183
+ { this.docComment( $art ); }
1184
+ annotationAssignment_ll1[ $art ]*
1210
1185
  (
1211
1186
  ENUM '{' { $art.enum = this.createDict(); }
1212
1187
  enumSymbolDef[ $art ]*
1213
- '}' { this.setDictEndLocation( $art.enum ); }
1188
+ '}' { this.finalizeDictOrArray( $art.enum ); }
1214
1189
  elementProperties[ $art ]?
1215
- misplacedAnnotations[ $annos, 'syntax-anno-after-enum' ]?
1216
1190
  |
1217
1191
  elementProperties[ $art ]
1218
- { this.docComment( $annos ); }
1219
- annotationAssignment_ll1[ $annos ]*
1192
+ { this.docComment( $art ); }
1193
+ annotationAssignment_ll1[ $art ]*
1220
1194
  )?
1221
1195
  requiredSemi // also req after enum spec
1222
1196
  )
@@ -1229,65 +1203,45 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1229
1203
  else if ($e.expr)
1230
1204
  $art.value = $e.expr;
1231
1205
  }
1232
- { this.docComment( $annos ); }
1233
- annotationAssignment_ll1[ $annos ]* // for enum symbol def via EXTEND
1206
+ { this.docComment( $art ); }
1207
+ annotationAssignment_ll1[ $art ]* // for enum symbol def via EXTEND
1234
1208
  requiredSemi
1235
1209
  )
1236
1210
  ;
1237
1211
 
1238
- extendElement[ outer, loc, annos ] locals[ art ]
1239
- @after{ /* #ATN 1 */ this.attachLocation($art); }
1212
+ extendElement[ art, outer ]
1213
+ @after{ /* #ATN 1 */ this.attachLocation( $art ); }
1240
1214
  :
1241
1215
  // #ATN: element name can be ELEMENT
1242
- expected=ELEMENT? name=ident['Element']
1243
- { $art = this.addDef( $outer, 'elements', 'extend', $name.id, $annos,
1244
- { expectedKind: $expected && 'element' },
1245
- $loc ); }
1246
- extendWithOptElements[ $art, $annos ]
1247
- ;
1248
-
1249
- bracedSelectItemListDef[ query ]
1250
- :
1251
- '{'
1252
- { if (!$query.columns) $query.columns = []; } // set it early to avoid "wildcard" errors
1253
- (
1254
- selectItemDef[ $query.columns ]
1255
- ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
1256
- selectItemDef[ $query.columns ]
1257
- )*
1258
- )?
1259
- '}'
1216
+ ( expected=ELEMENT { $art.expectedKind = 'element'; } )?
1217
+ name=ident['Element']
1218
+ { this.addDef( $art, $outer, 'elements', 'extend', $name.id ); }
1219
+ extendWithOptElements[ $art, $art ]
1260
1220
  ;
1261
1221
 
1262
- selectItemDef[ outer ] locals[ annos = [] ]
1263
- @after{ if ($ctx.art) this.attachLocation($art.art); }
1222
+ selectItemDef[ outer ] locals[ art ]
1223
+ @after{ if ($art) this.attachLocation( $art ); }
1264
1224
  :
1265
1225
  star='*'
1266
1226
  { $outer.push( this.valueWithTokenLocation( '*', $star ) ); }
1267
1227
  |
1268
- { this.docComment( $annos ); }
1269
- annotationAssignment_atn[ $annos ]*
1228
+ { $art = {};; this.docComment( $art ); }
1229
+ annotationAssignment_atn[ $art ]*
1270
1230
  // VIRTUAL is keyword, except if before the following tokens texts:
1271
1231
  { this.setLocalToken( 'VIRTUAL', 'VIRTUAL', /^([,.:\[@]|as)$/i ) ; } // not '{'
1272
- virtual=VIRTUAL?
1273
- key=KEY?
1274
- art=selectItemDefBody[ $outer, $annos ]
1275
- {
1276
- if ($virtual) $art.art.virtual = this.valueWithTokenLocation( true, $virtual );
1277
- if ($key) $art.art.key = this.valueWithTokenLocation( true, $key );
1278
- }
1232
+ ( virtual=VIRTUAL { $art.virtual = this.valueWithTokenLocation( true, $virtual ); } )?
1233
+ ( key=KEY { $art.key = this.valueWithTokenLocation( true, $key ); } )?
1234
+ selectItemDefBody[ $art, $outer ]
1279
1235
  ;
1280
1236
 
1281
- selectItemDefBody[ outer, annos ] returns[ art = {} ]
1282
- @after{ /* #ATN 1 */ this.attachLocation($art); }
1237
+ selectItemDefBody[ art, outer ]
1238
+ @after{ /* #ATN 2 */ }
1283
1239
  :
1240
+ { $outer.push( $art ); }
1284
1241
  (
1285
- e=expression
1242
+ e=expression { $art.value = $e.expr; }
1286
1243
  // we cannot use 'condition' instead, as long as we allow aliases without
1287
1244
  // AS (using rule 'ident' instead of 'identNoKeyword') -> ambiguities
1288
- {
1289
- $art = this.addItem( $outer, null, null, $annos, { value: $e.expr } );
1290
- }
1291
1245
  ( AS n1=ident['Item'] { $art.name = $n1.id }
1292
1246
  | n2=ident['Item'] { $art.name = this.fragileAlias( $n2.id, true ); }
1293
1247
  | { if (this.getCurrentToken().text !== '.') this.classifyImplicitName( 'Item', $e.expr ); }
@@ -1311,13 +1265,12 @@ selectItemDefBody[ outer, annos ] returns[ art = {} ]
1311
1265
  )
1312
1266
  )?
1313
1267
  |
1314
- { $art = this.addItem( $outer, null, null, $annos ); }
1315
1268
  selectItemInlineList[ $art, 'expand' ]
1316
1269
  excludingClause[ $art ]?
1317
1270
  AS n1=ident['Item'] { $art.name = $n1.id }
1318
1271
  )
1319
- { this.docComment( $annos ); }
1320
- annotationAssignment_fix[ $annos ]*
1272
+ { this.docComment( $art ); }
1273
+ annotationAssignment_fix[ $art ]*
1321
1274
  ( ':'
1322
1275
  // #ATN: typeRefOptArgs can start with TYPE, REDIRECTED
1323
1276
  ( re=REDIRECTED to=TO
@@ -1326,41 +1279,58 @@ selectItemDefBody[ outer, annos ] returns[ art = {} ]
1326
1279
  (
1327
1280
  typeAssociationCont[ $art ]
1328
1281
  |
1329
- { this.docComment( $annos ); }
1330
- annotationAssignment_ll1[ $annos ]*
1282
+ { this.docComment( $art ); }
1283
+ annotationAssignment_ll1[ $art ]*
1331
1284
  )
1332
1285
  | typeTypeOf[ $art ]
1333
- { this.docComment( $annos ); }
1334
- annotationAssignment_ll1[ $annos ]*
1335
- | typeRefOptArgs[ $art ] // TODO: annos here?
1336
- { this.docComment( $annos ); }
1337
- annotationAssignment_ll1[ $annos ]*
1286
+ { this.docComment( $art ); }
1287
+ annotationAssignment_ll1[ $art ]*
1288
+ | typeRefOptArgs[ $art ]
1289
+ { this.docComment( $art ); }
1290
+ annotationAssignment_ll1[ $art ]*
1291
+ |
1292
+ typeAssociationBase[ $art, false ]
1293
+ // #ATN: path could start with MANY or ONE - make sure a token follows in same rule!
1294
+ ( typeToMany[ $art ] | typeToOne[ $art ] | simplePath[ $art.target, 'artref' ] )
1295
+ typeAssociationCont[ $art ]?
1296
+ { this.associationInSelectItem( $art ); }
1338
1297
  )
1339
1298
  )?
1340
1299
  ;
1341
1300
 
1301
+ bracedSelectItemListDef[ query ]
1302
+ :
1303
+ '{' { $query.columns = this.createArray(); }
1304
+ (
1305
+ selectItemDef[ $query.columns ]
1306
+ ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
1307
+ selectItemDef[ $query.columns ]
1308
+ )*
1309
+ )?
1310
+ '}' { this.finalizeDictOrArray( $query.columns ); }
1311
+ ;
1312
+
1342
1313
  selectItemInlineList[ art, clause ]
1343
1314
  :
1344
- '{'
1345
- { $art[$clause] = []; }
1315
+ '{' { $art[$clause] = this.createArray(); }
1346
1316
  (
1347
1317
  selectItemInlineDef[ $art[$clause] ]
1348
1318
  ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
1349
1319
  selectItemInlineDef[ $art[$clause] ]
1350
1320
  )*
1351
1321
  )?
1352
- '}'
1322
+ '}' { this.finalizeDictOrArray( $art[$clause] ); }
1353
1323
  ;
1354
1324
 
1355
- selectItemInlineDef[ outer ] locals[ annos = [] ]
1356
- @after{ if ($ctx.art) this.attachLocation($art.art); }
1325
+ selectItemInlineDef[ outer ] locals[ art ]
1326
+ @after{ if ($art) this.attachLocation( $art ); }
1357
1327
  :
1358
1328
  star='*'
1359
1329
  { $outer.push( this.valueWithTokenLocation( '*', $star ) ); }
1360
1330
  |
1361
- { this.docComment( $annos ); }
1362
- annotationAssignment_atn[ $annos ]*
1363
- art=selectItemDefBody[ $outer, $annos ]
1331
+ { $art = {};; this.docComment( $art ); }
1332
+ annotationAssignment_atn[ $art ]*
1333
+ selectItemDefBody[ $art, $outer ]
1364
1334
  ;
1365
1335
 
1366
1336
  parameterListDef[ art ]
@@ -1374,51 +1344,22 @@ parameterListDef[ art ]
1374
1344
  parameterDef[ $art ]
1375
1345
  )*
1376
1346
  )?
1377
- ')' { this.setDictEndLocation( $art.params ); }
1347
+ ')' { this.finalizeDictOrArray( $art.params ); }
1378
1348
  ;
1379
1349
 
1380
- parameterDef[ outer ] locals[ art, annos = [] ]
1381
- @after { this.attachLocation($art); }
1350
+ parameterDef[ outer ] locals[ art = {} ]
1351
+ @after { this.attachLocation( $art ); }
1382
1352
  :
1383
- { this.docComment( $annos ); }
1384
- annotationAssignment_ll1[ $annos ]*
1353
+ { this.docComment( $art ); }
1354
+ annotationAssignment_ll1[ $art ]*
1385
1355
  name=ident['Param']
1386
- { $art = this.addDef( $outer, 'params', 'param', $name.id, $annos );
1387
- this.docComment( $annos ); }
1388
- annotationAssignment_fix[ $annos ]*
1356
+ { this.addDef( $art, $outer, 'params', 'param', $name.id );
1357
+ this.docComment( $art ); }
1358
+ annotationAssignment_fix[ $art ]*
1389
1359
  typeSpec[ $art ]
1390
1360
  defaultValue[ $art ]?
1391
- { this.docComment( $annos ); }
1392
- annotationAssignment_ll1[ $annos ]*
1393
- ;
1394
-
1395
- entityParameters[ art ]
1396
- :
1397
- '(' { $art.params = this.createDict(); }
1398
- // also empty param list (we might do some hacking later to allow reserved words)
1399
- // see annotationAssignment_paren
1400
- (
1401
- entityParameterDef[ $art ]
1402
- ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
1403
- entityParameterDef[ $art ]
1404
- )*
1405
- )?
1406
- ')' { this.setDictEndLocation( $art.params ); }
1407
- ;
1408
-
1409
- entityParameterDef[ outer ] locals[ art, annos = [] ]
1410
- @after { this.attachLocation($art); }
1411
- :
1412
- { this.docComment( $annos ); }
1413
- annotationAssignment_ll1[ $annos ]*
1414
- name=ident['Param']
1415
- { $art = this.addDef( $outer, 'params', 'param', $name.id, $annos );
1416
- this.docComment( $annos ); }
1417
- annotationAssignment_fix[ $annos ]*
1418
- typeSpec[ $art ]
1419
- defaultValue[ $art ]?
1420
- { this.docComment( $annos ); }
1421
- annotationAssignment_ll1[ $annos ]*
1361
+ { this.docComment( $art ); }
1362
+ annotationAssignment_ll1[ $art ]*
1422
1363
  ;
1423
1364
 
1424
1365
  nullability[ art ]
@@ -1445,21 +1386,25 @@ elementProperties[ elem ]
1445
1386
 
1446
1387
  // View definitions ----------------------------------------------------------
1447
1388
 
1448
- viewDef[ outer, loc, annos ] locals[ art, name = {} ]
1449
- @after { this.attachLocation($art); }
1389
+ viewDef[ art, outer ] locals[ name = {} ]
1390
+ @after { this.attachLocation( $art ); }
1450
1391
  :
1451
1392
  v=VIEW simplePath[ $name, 'Entity' ]
1452
- { $art = this.addDef( $outer, 'artifacts', 'entity', $name, $annos, { ['$'+'syntax']: 'view' }, $loc );
1453
- this.docComment( $annos ); }
1454
- annotationAssignment_fix[ $annos ]*
1393
+ { $art['$'+'syntax'] = 'view';
1394
+ this.addDef( $art, $outer, 'artifacts', 'entity', $name );
1395
+ this.docComment( $art ); }
1396
+ annotationAssignment_fix[ $art ]*
1455
1397
  (
1456
- entityParameters[ $art ]
1398
+ parameterListDef[ $art ]
1457
1399
  |
1458
- ( HideAlternatives | WITH ) PARAMETERS
1459
- entityParameterDef[ $art ]
1460
- ( ',' entityParameterDef[ $art ] )* // no optional final ',' here
1400
+ // TODO: warning deprecated?
1401
+ ( HideAlternatives | WITH ) { $art.params = this.createDict(); }
1402
+ PARAMETERS
1403
+ parameterDef[ $art ]
1404
+ ( ',' parameterDef[ $art ] )* // no optional final ',' here
1405
+ { this.finalizeDictOrArray( $art.params ); }
1461
1406
  )?
1462
- AS qe=queryExpression { $art.query = $qe.query; } // beta-mode test now in definer
1407
+ AS qe=queryExpression { $art.query = $qe.query; }
1463
1408
  // TODO check ANTLR: bad msg with 'view V as'<eof> but 'view V as FOO' is fine
1464
1409
  requiredSemi
1465
1410
  ;
@@ -1490,12 +1435,12 @@ typeSpec[ art ] // for params
1490
1435
  (
1491
1436
  ENUM '{' { $art.enum = this.createDict(); }
1492
1437
  enumSymbolDef[ $art ]*
1493
- '}' { this.setDictEndLocation( $art.enum ); }
1438
+ '}' { this.finalizeDictOrArray( $art.enum ); }
1494
1439
  )?
1495
1440
  )
1496
1441
  ;
1497
1442
 
1498
- returnTypeSpec[ art, annos ]
1443
+ returnTypeSpec[ art ]
1499
1444
  @after{ /* #ATN 1 */ }
1500
1445
  :
1501
1446
  ret=RETURNS { $art.returns = { location: this.tokenLocation( $ret ), kind: 'param' }; }
@@ -1511,17 +1456,15 @@ returnTypeSpec[ art, annos ]
1511
1456
  (
1512
1457
  ENUM '{' { $art.returns.enum = this.createDict(); }
1513
1458
  enumSymbolDef[ $art.returns ]*
1514
- '}' { this.setDictEndLocation( $art.returns.enum ); }
1515
- |
1516
- misplacedAnnotations[ $annos, 'syntax-anno-after-params' ]
1459
+ '}' { this.finalizeDictOrArray( $art.returns.enum ); }
1517
1460
  )?
1518
1461
  )
1519
1462
 
1520
- requiredSemi // currently for all - might change if we get rid of the misplaced annos
1463
+ requiredSemi // currently for all - might change if we get rid of the misplaced annos (TODO: Now removed)
1521
1464
  ;
1522
1465
 
1523
1466
 
1524
- typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1467
+ typeSpecSemi[ art ] // with 'includes', for type and annotation defs
1525
1468
  @after{ /* #ATN 3 */ }
1526
1469
  :
1527
1470
  typeStruct[ $art ]
@@ -1559,18 +1502,28 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1559
1502
  optionalSemi
1560
1503
  | typeTypeOf[ $art.items ]
1561
1504
  nullability[ $art.items ]?
1562
- { this.docComment( $annos ); }
1563
- annotationAssignment_ll1[ $annos ]*
1505
+ { this.docComment( $art ); }
1506
+ annotationAssignment_ll1[ $art ]*
1564
1507
  requiredSemi
1565
1508
  | typeRefOptArgs[ $art.items ]
1566
- nullability[ $art.items ]?
1567
- { this.docComment( $annos ); }
1568
- annotationAssignment_ll1[ $annos ]*
1509
+ nullability[ $art.items ]? // only if not followed by `enum`
1510
+ { this.docComment( $art ); }
1511
+ annotationAssignment_ll1[ $art ]*
1569
1512
  (
1513
+ { if ($art.items.notNull) {
1514
+ this.message( 'syntax-unexpected-null', $art.items.notNull.location,
1515
+ { keyword: $art.items.notNull.val ? 'not null' : 'null' } );
1516
+ }
1517
+ }
1570
1518
  ENUM '{' { $art.items.enum = this.createDict(); }
1571
1519
  enumSymbolDef[ $art.items ]*
1572
- '}' { this.setDictEndLocation( $art.items.enum ); }
1573
- optionalSemi
1520
+ '}' { this.finalizeDictOrArray( $art.items.enum ); }
1521
+ (
1522
+ nullability[ $art.items ]
1523
+ requiredSemi
1524
+ |
1525
+ optionalSemi
1526
+ )
1574
1527
  |
1575
1528
  requiredSemi
1576
1529
  )
@@ -1578,46 +1531,27 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1578
1531
  |
1579
1532
  typeTypeOf[ $art ]
1580
1533
  defaultValue[ $art ]?
1581
- { this.docComment( $annos ); }
1582
- annotationAssignment_ll1[ $annos ]* requiredSemi
1534
+ { this.docComment( $art ); }
1535
+ annotationAssignment_ll1[ $art ]* requiredSemi
1583
1536
  |
1584
1537
  l=LOCALIZED { $art.localized = this.valueWithTokenLocation( true, $l ); }
1585
1538
  typeRefOptArgs[ $art ]
1586
1539
  defaultValue[ $art ]?
1587
- { this.docComment( $annos ); }
1588
- annotationAssignment_ll1[ $annos ]*
1540
+ { this.docComment( $art ); }
1541
+ annotationAssignment_ll1[ $art ]*
1589
1542
  requiredSemi
1590
1543
  |
1591
1544
  // alt lookahead includes MANY '{'
1592
1545
  { $art.type = {}; }
1593
1546
  simplePath[ $art.type, 'artref' ]
1594
1547
  (
1595
- '(' // with type args, e.g. `type T : String(100) enum { ... }`
1596
- head=Number
1597
- { $art['$'+'typeArgs'] = [ this.numberLiteral( $head ) ]; }
1598
- ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
1599
- (
1600
- v=VARIABLE
1601
- { $art['$'+'typeArgs'].push(
1602
- { literal: 'string', val: 'variable', location: this.tokenLocation($v) } );
1603
- }
1604
- |
1605
- f=FLOATING
1606
- { $art['$'+'typeArgs'].push(
1607
- { literal: 'string', val: 'floating', location: this.tokenLocation($f) } );
1608
- }
1609
- |
1610
- tail=Number
1611
- { $art['$'+'typeArgs'].push( this.numberLiteral( $tail ) ); }
1612
- )
1613
- )*
1614
- ')'
1615
- { this.docComment( $annos ); }
1616
- annotationAssignment_ll1[ $annos ]*
1548
+ typeRefArgs[ $art ]
1549
+ { this.docComment( $art ); }
1550
+ annotationAssignment_ll1[ $art ]*
1617
1551
  (
1618
1552
  ENUM '{' { $art.enum = this.createDict(); }
1619
1553
  enumSymbolDef[ $art ]*
1620
- '}' { this.setDictEndLocation( $art.enum ); }
1554
+ '}' { this.finalizeDictOrArray( $art.enum ); }
1621
1555
  (
1622
1556
  optionalSemi
1623
1557
  |
@@ -1632,12 +1566,12 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1632
1566
  ':' // with element, e.g. `type T : E:elem enum { ... }`
1633
1567
  { $art.type.scope = $art.type.path.length; }
1634
1568
  simplePath[ $art.type, 'ref']
1635
- { this.docComment( $annos ); }
1636
- annotationAssignment_ll1[ $annos ]*
1569
+ { this.docComment( $art ); }
1570
+ annotationAssignment_ll1[ $art ]*
1637
1571
  (
1638
1572
  ENUM '{' { $art.enum = this.createDict(); }
1639
1573
  enumSymbolDef[ $art ]*
1640
- '}' { this.setDictEndLocation( $art.enum ); }
1574
+ '}' { this.finalizeDictOrArray( $art.enum ); }
1641
1575
  (
1642
1576
  optionalSemi
1643
1577
  |
@@ -1649,12 +1583,12 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1649
1583
  requiredSemi
1650
1584
  )
1651
1585
  |
1652
- { this.docComment( $annos ); }
1653
- annotationAssignment_ll1[ $annos ]*
1586
+ { this.docComment( $art ); }
1587
+ annotationAssignment_ll1[ $art ]*
1654
1588
  (
1655
1589
  ENUM '{' { $art.enum = this.createDict(); }
1656
1590
  enumSymbolDef[ $art ]*
1657
- '}' { this.setDictEndLocation( $art.enum ); }
1591
+ '}' { this.finalizeDictOrArray( $art.enum ); }
1658
1592
  (
1659
1593
  optionalSemi
1660
1594
  |
@@ -1682,7 +1616,7 @@ typeStruct[ art, attachLoc = false ]
1682
1616
  :
1683
1617
  '{' { $art.elements = this.createDict(); }
1684
1618
  elementDef[ $art ]*
1685
- '}' { this.setDictEndLocation( $art.elements ); }
1619
+ '}' { this.finalizeDictOrArray( $art.elements ); }
1686
1620
  ;
1687
1621
 
1688
1622
  typeCompoStruct[ art ]
@@ -1690,7 +1624,7 @@ typeCompoStruct[ art ]
1690
1624
  :
1691
1625
  COMPOSITIONofBRACE { $art.elements = this.createDict(); }
1692
1626
  elementDef[ $art ]*
1693
- '}' { this.setDictEndLocation( $art.elements ); }
1627
+ '}' { this.finalizeDictOrArray( $art.elements ); }
1694
1628
  ;
1695
1629
 
1696
1630
  typeArray[ art ]
@@ -1712,7 +1646,7 @@ typeArray[ art ]
1712
1646
  (
1713
1647
  ENUM '{' { $art.items.enum = this.createDict(); }
1714
1648
  enumSymbolDef[ $art.items ]*
1715
- '}' { this.setDictEndLocation( $art.items.enum ); }
1649
+ '}' { this.finalizeDictOrArray( $art.items.enum ); }
1716
1650
  )?
1717
1651
  )
1718
1652
  ;
@@ -1741,33 +1675,31 @@ typeAssociationCont[ art ]
1741
1675
  :
1742
1676
  (
1743
1677
  '{' { $art.foreignKeys = this.createDict(); }
1744
- { this.addDef( $art, 'foreignKeys' ); }
1745
1678
  (
1746
1679
  foreignKey[ $art ]
1747
1680
  ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
1748
1681
  foreignKey[ $art ]
1749
1682
  )*
1750
1683
  )?
1751
- '}' { this.setDictEndLocation( $art.foreignKeys ); }
1684
+ '}' { this.finalizeDictOrArray( $art.foreignKeys ); }
1752
1685
  |
1753
1686
  ON cond=condition
1754
1687
  { $art.on=$cond.cond; }
1755
1688
  )
1756
1689
  ;
1757
1690
 
1758
- typeAssociationElementCont[ art, annos ] // including Composition
1691
+ typeAssociationElementCont[ art ] // including Composition
1759
1692
  // optional NULL / NOT NULL for managed association only
1760
1693
  :
1761
1694
  (
1762
1695
  '{' { $art.foreignKeys = this.createDict(); }
1763
- { this.addDef( $art, 'foreignKeys' ); }
1764
1696
  (
1765
1697
  foreignKey[ $art ]
1766
1698
  ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
1767
1699
  foreignKey[ $art ]
1768
1700
  )*
1769
1701
  )?
1770
- '}' { this.setDictEndLocation( $art.foreignKeys ); }
1702
+ '}' { this.finalizeDictOrArray( $art.foreignKeys ); }
1771
1703
  nullability[ $art ]?
1772
1704
  |
1773
1705
  ON cond=condition
@@ -1775,8 +1707,8 @@ typeAssociationElementCont[ art, annos ] // including Composition
1775
1707
  |
1776
1708
  nullability[ $art ]
1777
1709
  )?
1778
- { this.docComment( $annos ); }
1779
- annotationAssignment_ll1[ $annos ]*
1710
+ { this.docComment( $art ); }
1711
+ annotationAssignment_ll1[ $art ]*
1780
1712
  requiredSemi // also req after foreign key spec
1781
1713
  ;
1782
1714
 
@@ -1830,10 +1762,9 @@ cardinality[ art ] locals[ card = {} ]
1830
1762
  foreignKey[ outer ] locals[ art = {}, elem = {} ]
1831
1763
  @after { this.attachLocation($art); }
1832
1764
  :
1833
- simplePath[ $elem, 'ref' ]
1765
+ simplePath[ $elem, 'ref' ] { $art.targetElement = $elem; }
1834
1766
  ( AS name=ident['Key'] )?
1835
- { $art = this.addDef( $outer, 'foreignKeys', 'key', ($ctx.name) ? $name.id : $elem.path,
1836
- undefined, { targetElement: $elem } ); }
1767
+ { this.addDef( $art, $outer, 'foreignKeys', 'key', ($ctx.name) ? $name.id : $elem.path ); }
1837
1768
  ;
1838
1769
 
1839
1770
  typeTypeOf[ art ] locals[ _sync = 'nop' ]
@@ -1855,9 +1786,21 @@ typeRefOptArgs[ art ]
1855
1786
  :
1856
1787
  simplePath[ $art.type, 'artref' ]
1857
1788
  (
1858
- '('
1789
+ typeRefArgs[ $art ]
1790
+ |
1791
+ ':'
1792
+ { $art.type.scope = $art.type.path.length; }
1793
+ simplePath[ $art.type, 'ref']
1794
+ )?
1795
+ ;
1796
+
1797
+ typeRefArgs[ art ]
1798
+ :
1799
+ paren='(' { $art['$'+'typeArgs'] = this.createArray(); }
1800
+ (
1801
+ // unnamed arguments
1859
1802
  head=Number
1860
- { $art['$'+'typeArgs'] = [ this.numberLiteral( $head ) ]; }
1803
+ { $art['$'+'typeArgs'].push( this.numberLiteral( $head ) ); }
1861
1804
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
1862
1805
  (
1863
1806
  v=VARIABLE
@@ -1874,14 +1817,45 @@ typeRefOptArgs[ art ]
1874
1817
  { $art['$'+'typeArgs'].push( this.numberLiteral( $tail ) ); }
1875
1818
  )
1876
1819
  )*
1877
- ')'
1878
1820
  |
1879
- ':'
1880
- { $art.type.scope = $art.type.path.length; }
1881
- simplePath[ $art.type, 'ref']
1882
- )?
1821
+ // named arguments
1822
+ typeNamedArg[ $art ]
1823
+ ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
1824
+ typeNamedArg[ $art ]
1825
+ )*
1826
+ )
1827
+ ')'{ this.finalizeDictOrArray( $art['$'+'typeArgs']); }
1883
1828
  ;
1884
1829
 
1830
+ typeNamedArg[ art ] locals[ arg = '' ]
1831
+ :
1832
+ name=ident['paramname']
1833
+ ':'
1834
+ { if (this.checkTypeFacet( $art, $name.id ))
1835
+ $arg = $name.id.id;
1836
+ }
1837
+ (
1838
+ val=Number
1839
+ { if ($arg && $art && $name.id) {
1840
+ $art[$arg] = this.numberLiteral( $val );
1841
+ }
1842
+ }
1843
+ |
1844
+ v=VARIABLE
1845
+ { if ($arg && $art && $name.id) {
1846
+ $art[$arg] = { literal: 'string', val: 'variable', location: this.tokenLocation($v) };
1847
+ }
1848
+ }
1849
+ |
1850
+ f=FLOATING
1851
+ { if ($arg && $art && $name.id) {
1852
+ $art[$arg] = { literal: 'string', val: 'floating', location: this.tokenLocation($f) };
1853
+ }
1854
+ }
1855
+ )
1856
+ ;
1857
+
1858
+
1885
1859
  // Queries -------------------------------------------------------------------
1886
1860
 
1887
1861
  queryExpression returns[ query ] // QLSubqueryComplex, SubqueryComplex
@@ -1996,7 +1970,7 @@ overClause returns [ over ]
1996
1970
  @after { this.attachLocation( $over ); }
1997
1971
  :
1998
1972
  o=OVER { $over = { op: this.valueWithTokenLocation( 'over', $o ) , args: [] } }
1999
- '('
1973
+ '(' // TODO: check whether an extra location could be useful
2000
1974
  ( pb=partitionByClause { $over.args.push( $pb.expr ); } )?
2001
1975
  ( ob=overOrderByClause { $over.args.push( $ob.expr ); } )?
2002
1976
  ( wf=windowFrameClause { $over.args.push( $wf.wf ); } )?
@@ -2049,13 +2023,13 @@ queryPrimary returns[ query = {} ]
2049
2023
  (
2050
2024
  mixin=MIXIN '{' { $query.mixin = this.createDict(); }
2051
2025
  mixinElementDef[ $query ]*
2052
- '}' { this.setDictEndLocation( $query.mixin ); }
2026
+ '}' { this.finalizeDictOrArray( $query.mixin ); }
2053
2027
  INTO
2054
2028
  )?
2055
2029
  ( ad=( ALL | DISTINCT ) // TODO: or directly after SELECT ?
2056
2030
  { $query.quantifier = this.valueWithTokenLocation( $ad.text.toLowerCase(), $ad ); }
2057
2031
  )?
2058
- bracedSelectItemListDef[ $query ]?
2032
+ bracedSelectItemListDef[ $query, 'columns' ]?
2059
2033
  excludingClause[ $query ]?
2060
2034
  |
2061
2035
  ( ad=( ALL | DISTINCT ) // TODO: or directly after SELECT ?
@@ -2241,6 +2215,7 @@ conditionAnd returns [ cond ] locals [ args = [], andl = [] ]
2241
2215
  ( and=AND c2=conditionTerm { $args.push($c2.cond); $andl.push(this.valueWithTokenLocation( 'and', $and )) } )*
2242
2216
  ;
2243
2217
 
2218
+ // Note: New operators need to be added to functionExpressionOperatorsRequireParentheses[] in toCdl.js.
2244
2219
  conditionTerm returns [ cond ]
2245
2220
  @after{
2246
2221
  if ($cond) { this.attachLocation($cond); } else { $cond = $expr.expr; }
@@ -2288,6 +2263,7 @@ conditionTerm returns [ cond ]
2288
2263
  )? // optional: for conditions in parentheses
2289
2264
  ;
2290
2265
 
2266
+ // Note: New operators need to be added to functionExpressionOperatorsRequireParentheses[] in toCdl.js.
2291
2267
  predicate[ cond, negated ]
2292
2268
  // As an alternative, we could have a `negated` properties for the operations
2293
2269
  // `isNull`(!), `in`, `between` and `like` (or produce the same AST as for
@@ -2397,7 +2373,9 @@ expressionTerm returns [ expr ] locals [ op, args = [] ]
2397
2373
  }
2398
2374
  )
2399
2375
  |
2400
- qm=( HideAlternatives | '?' )
2376
+ qm= '?' // is automatically not mentioned as CC candidate
2377
+ // if we have an HideAlternatives here, we would block it to use it in
2378
+ // parallel to an expression (would produce adaptivePredict() otherwise)
2401
2379
  { $expr = { param: this.valueWithTokenLocation( '?', $qm ), scope: 'param' };
2402
2380
  this.csnParseOnly( 'Dynamic parameter "?" is not supported', $qm );
2403
2381
  }
@@ -2425,39 +2403,12 @@ expressionTerm returns [ expr ] locals [ op, args = [] ]
2425
2403
  ;
2426
2404
 
2427
2405
  specialFunction returns [ ret = { } ] locals[ art = {} ]
2428
- @after{ /* #ATN 1 */ }
2429
2406
  :
2430
- fun=TRIM open='('
2431
- { $ret = this.functionAst( $fun, $open ); }
2432
- // #ATN: we do not want to reserve these three optional keywords
2433
- (
2434
- t=( LEADING | TRAILING | BOTH ) { $ret.args[0].args.push( $t.text ); }
2435
- ( e=expression { $ret.args[0].args.push( $e.expr ); } )?
2436
- t=FROM e=expression { $ret.args[0].args.push( $t.text, $e.expr ); }
2437
- |
2438
- e=expression
2439
- (
2440
- { $ret.args[0].args.push( $e.expr ); }
2441
- t=FROM e=expression
2442
- { $ret.args[0].args.push( $t.text, $e.expr ); }
2443
- |
2444
- { $ret.args[0] = $e.expr; }
2445
- )
2446
- )
2447
- ')'
2448
- |
2449
- fun=EXTRACT open='('
2450
- { $ret = this.functionAst( $fun, $open ); }
2451
- t=( YEAR | MONTH | DAY | HOUR | MINUTE | SECOND )
2452
- f=FROM e=expression
2453
- { $ret.args[0].args.push( $t.text, $f.text, $e.expr ); }
2454
- ')'
2455
- |
2456
- ca=CAST open='('
2407
+ ca=CAST '(' // see createArray() in action
2457
2408
  {
2458
2409
  $ret = {
2459
2410
  op: this.valueWithTokenLocation( 'cast', $ca ),
2460
- args: [ ],
2411
+ args: this.createArray(),
2461
2412
  location: this.tokenLocation( $ca )
2462
2413
  };
2463
2414
  }
@@ -2465,8 +2416,7 @@ specialFunction returns [ ret = { } ] locals[ art = {} ]
2465
2416
  {
2466
2417
  $ret.args.push( $e.expr );
2467
2418
  }
2468
- ')'
2469
- // TODO: ROUND - see also resolver.js
2419
+ ')' { this.finalizeDictOrArray( $ret.args ); }
2470
2420
  ;
2471
2421
 
2472
2422
  // query path includes aggregation:
@@ -2492,36 +2442,47 @@ valuePath[ category, location = null ] returns[ qp = { path: [] } ] locals[ _syn
2492
2442
  ;
2493
2443
 
2494
2444
  fromArguments[ pathStep ]
2445
+ @init{ if (!$pathStep) $pathStep = {}; } // grammar robustness, see test/negative/parser/NamedExpression.cds
2495
2446
  :
2496
- paren='('
2497
- namedExpression[ $pathStep ]
2447
+ '(' { $pathStep.args = this.createDict(); $pathStep['$'+'syntax'] = ':'; } // necessary?
2448
+ name=ident['paramname'] ':'
2449
+ namedExpression[ $pathStep, $name.id ]
2498
2450
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
2499
- namedExpression[ $pathStep ]
2451
+ name=ident['paramname'] ':'
2452
+ namedExpression[ $pathStep, $name.id ]
2500
2453
  )*
2501
- ')'
2454
+ ')' { this.finalizeDictOrArray( $pathStep.args ); }
2502
2455
  ;
2503
2456
 
2504
2457
  pathArguments[ pathStep, considerSpecial ]
2505
- @after{ /* #ATN 1 */ }
2458
+ @init{
2459
+ if (!$pathStep) $pathStep = {}; // grammar robustness, see test/negative/parser/NamedExpression.cds
2460
+ this.genericFunctionsStack.push( this['$'+'genericKeywords'] );
2461
+ }
2506
2462
  :
2507
2463
  { this.excludeExpected([ 'ORDER' ]); }
2508
- paren='('
2509
- { this.prepareGenericKeywords( $considerSpecial ); }
2510
- // ATN, LL2: Identifier can start both named arguments and the positional.
2464
+ '(' // dict or array, see below
2511
2465
  // Make sure that we do not introduce A:B paths in expressions!
2466
+ // Need to avoid adaptPredict(), otherwise Generic keywords won't work in funcExpression
2467
+ { this.setLocalTokenForId( { ':': 'HelperToken1', '=>': 'HelperToken2' } ); }
2512
2468
  (
2513
- namedExpression[ $pathStep ]
2469
+ { $pathStep.args = this.createDict(); $pathStep['$'+'syntax'] = ':'; }
2470
+ id=HelperToken1 ':'
2471
+ namedExpression[ $pathStep, this.identAst( $id, 'paramname', true ) ]
2514
2472
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
2515
- namedExpression[ $pathStep ]
2473
+ name=ident['paramname'] ':'
2474
+ namedExpression[ $pathStep, $name.id ]
2516
2475
  )*
2517
2476
  |
2518
- { $pathStep.args = Object.create(null); } // TODO: XSN func path cleanup
2519
- arrowedExpression[ $pathStep ]
2477
+ { $pathStep.args = this.createDict(); } // TODO: XSN func path cleanup
2478
+ id=HelperToken2 '=>'
2479
+ namedExpression[ $pathStep, this.identAst( $id, 'paramname', true ) ]
2520
2480
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
2521
- arrowedExpression[ $pathStep ]
2481
+ name=ident['paramname'] '=>'
2482
+ namedExpression[ $pathStep, $name.id ]
2522
2483
  )*
2523
2484
  |
2524
- { $pathStep.args = []; }
2485
+ { $pathStep.args = this.createArray(); }
2525
2486
  funcExpression[ $pathStep, $considerSpecial ]
2526
2487
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
2527
2488
  funcExpression[ $pathStep, $considerSpecial ]
@@ -2534,47 +2495,82 @@ pathArguments[ pathStep, considerSpecial ]
2534
2495
  }
2535
2496
  )?
2536
2497
  |
2537
- a=ALL { $pathStep.quantifier = this.valueWithTokenLocation( 'all', $a ); }
2538
- e1=expression { $pathStep.args = [ $e1.expr ]; }
2539
- |
2540
- d=DISTINCT { $pathStep.quantifier = this.valueWithTokenLocation( 'distinct', $d ); }
2541
- e1=expression { $pathStep.args = [ $e1.expr ]; }
2542
- ( ',' e2=expression { $pathStep.args.push( $e2.expr ); } )*
2543
- |
2544
- star='*'
2545
- { $pathStep.args = [ { location: this.tokenLocation( $star ), val: '*', literal: 'token' } ]; }
2546
- |
2547
- { $pathStep.args = []; }
2498
+ { $pathStep.args = this.createArray(); }
2548
2499
  )
2549
- ')'
2500
+ ')' { this.finalizeDictOrArray( $pathStep.args ); }
2550
2501
  ;
2502
+ finally { // see @init
2503
+ if (!$pathStep.args) $pathStep.args = [];
2504
+ this['$'+'genericKeywords'] = this.genericFunctionsStack.pop();
2505
+ }
2551
2506
 
2552
- namedExpression[ pathStep ]
2507
+ namedExpression[ pathStep, id ]
2553
2508
  :
2554
- name=ident['paramname'] ':' elem=expression
2555
- { if ($pathStep && $name.id) {
2556
- this.addDef( $pathStep, 'args', 0, $name.id, true,
2557
- ($ctx.elem) ? $elem.expr : { location: $name.id.location } );
2558
- $pathStep['$'+'syntax'] = ':';
2509
+ elem=expression
2510
+ { if ($pathStep && $id) {
2511
+ this.addDef( ($ctx.elem) ? $elem.expr : { location: $id.location },
2512
+ $pathStep, 'args', 0, $id );
2559
2513
  }
2560
2514
  }
2561
2515
  ;
2562
2516
 
2563
- arrowedExpression[ pathStep ]
2564
- :
2565
- name=ident['paramname'] a='=>' elem=expression
2566
- { if ($name.id) this.addDef( $pathStep, 'args', 0, $name.id, true,
2567
- ($ctx.elem) ? $elem.expr : { location: $name.id.location } ); }
2568
- ;
2569
-
2570
- funcExpression[ pathStep, considerSpecial ]
2517
+ funcExpression[ pathStep, considerSpecial ] locals[ args ]
2571
2518
  @init { this.prepareGenericKeywords( $considerSpecial ); }
2572
2519
  :
2573
- only=GenericArgFull
2574
- { $pathStep.args.push( { location: this.tokenLocation($only), val: $only.text, literal: 'token' } ); }
2575
- |
2576
- expr=expression
2577
- { $pathStep.args.push( $expr.expr ); }
2520
+ (
2521
+ expr=expression
2522
+ { $pathStep.args.push( $expr.expr ); }
2523
+ |
2524
+ GenericExpr // keyword as replacement for expression, like '*'
2525
+ { $pathStep.args.push( this.xprToken() ); }
2526
+ |
2527
+ GenericIntro // keyword as introduction of expression, like DISTINCT
2528
+ { $pathStep.args.push( this.xprToken() ); }
2529
+ expr=expression
2530
+ { $args = this.setLastAsXpr( $pathStep.args );
2531
+ $args.push( $expr.expr ); }
2532
+ |
2533
+ // Rule 'pathArguments' makes a decision based on the first two lookahead
2534
+ // tokens of this rule → we need to list tokens which would be changed to
2535
+ // GenericExpr or GenericIntro, and are not already covered by 'expression'
2536
+ { this.reportErrorForGenericKeyword(); }
2537
+ ( HideAlternatives | '*' | ALL | DISTINCT )
2538
+ // now continue parsing like GenericExpr:
2539
+ { $pathStep.args.push( this.xprToken() ); }
2540
+ )
2541
+ (
2542
+ { if (!$args) $args = this.setLastAsXpr( $pathStep.args ); }
2543
+ (
2544
+ { this.prepareGenericKeywords( $considerSpecial, 'separator' ); }
2545
+ (
2546
+ GenericSeparator
2547
+ |
2548
+ // For ANTLR's lookahead calculations, we need to list tokens here
2549
+ // which could be changed to GenericSeparator. Do not invent a
2550
+ // keyword token which is just used here (Identifier does work
2551
+ // perfectly)! If we want, we could add all non-reserved keywords
2552
+ // except ORDER, and most reserved.
2553
+ { this.reportErrorForGenericKeyword(); }
2554
+ ( HideAlternatives | Identifier | FROM | IN | WITH | GROUP )
2555
+ )
2556
+ { $args.push( this.xprToken() );
2557
+ this.prepareGenericKeywords( $considerSpecial, 'expr' );
2558
+ }
2559
+ (
2560
+ expr=expression
2561
+ { $args.push( $expr.expr ); }
2562
+ |
2563
+ GenericExpr
2564
+ { $args.push( this.xprToken() ); }
2565
+ |
2566
+ { this.reportErrorForGenericKeyword(); }
2567
+ // Again, we need to list tokens which could make it to GenericExpr
2568
+ // and which do not start an expression
2569
+ ( HideAlternatives | ALL )
2570
+ { $args.push( this.xprToken() ); }
2571
+ )
2572
+ )+
2573
+ )?
2578
2574
  ;
2579
2575
 
2580
2576
  cardinalityAndFilter[ pathStep ] locals [ _sync = 'nop' ]
@@ -2616,32 +2612,41 @@ optionalWhereForFilter
2616
2612
 
2617
2613
  // Simple paths and values ---------------------------------------------------
2618
2614
 
2619
- annoValueBase returns[ val ] locals [ seenEllipsis = false ]
2620
- @after { this.attachLocation($val); }
2615
+ annoValue[ assignment ]
2621
2616
  :
2622
- { $val = { literal: 'struct', location: this.startLocation() }; }
2623
- '{'
2624
- { this.meltKeywordToIdentifier(); }
2625
- namedValue[ $val ]
2617
+ base=annoValueBase[ $assignment ]
2618
+ |
2619
+ // no docComment() here
2620
+ // this alternative is done with token rewrite in rule "annotationAssignment_atn"
2621
+ at='@'? annotationPath[ $assignment, 'ref', $at ]
2622
+ annotationPathVariant[ $assignment ]?
2623
+ ;
2624
+
2625
+ annoValueBase[ assignment ] locals [ seenEllipsis = false ]
2626
+ @after { this.attachLocation( $assignment ); }
2627
+ :
2628
+ '{' // no location here, we flatten
2629
+ { $assignment['$'+'flatten'] = []; this.meltKeywordToIdentifier(); }
2630
+ flattenedValue[ $assignment ]
2626
2631
  (
2627
2632
  ',' {
2628
2633
  this.meltKeywordToIdentifier();
2629
2634
  if (this.isStraightBefore("}")) break; // allow ',' before ')'
2630
2635
  }
2631
- namedValue[ $val ]
2636
+ flattenedValue[ $assignment ]
2632
2637
  )*
2633
2638
  '}'
2634
2639
  |
2635
- { $val = { literal: 'array', location: this.startLocation(), val: [] }; }
2636
- '['
2640
+ '[' // no need for createArray() here, $assignment.location is set
2641
+ { $assignment.val = []; $assignment.literal = 'array'; }
2637
2642
  (
2638
2643
  (
2639
- head=arrayValue { $val.val.push( $head.val ); }
2644
+ head=annoSubValue { $assignment.val.push( $head.val ); }
2640
2645
  |
2641
- e='...' ( UP TO upTo=arrayValue )?
2646
+ e='...' ( UP TO upTo=annoSubValue )?
2642
2647
  {{
2643
2648
  const item = { literal: 'token', val: '...', location: this.tokenLocation($e) };
2644
- $val.val.push( item );
2649
+ $assignment.val.push( item );
2645
2650
  if ($ctx.upTo) item.upTo = $upTo.val;
2646
2651
  $seenEllipsis = !$ctx.upTo || 'upTo';
2647
2652
  }}
@@ -2649,17 +2654,16 @@ annoValueBase returns[ val ] locals [ seenEllipsis = false ]
2649
2654
  (
2650
2655
  ',' { if (this.isStraightBefore(']')) break; } // allow ',' before ']'
2651
2656
  (
2652
- tail=arrayValue { $val.val.push( $tail.val ); }
2657
+ tail=annoSubValue { $assignment.val.push( $tail.val ); }
2653
2658
  |
2654
2659
  { $ctx.upTo = null; } // is not reset
2655
- e='...' ( UP TO upTo=arrayValue )?
2660
+ e='...' ( UP TO upTo=annoSubValue )?
2656
2661
  {{
2657
2662
  const item = { literal: 'token', val: '...', location: this.tokenLocation($e) };
2658
2663
  if ($ctx.upTo) item.upTo = $upTo.val;
2659
- $val.val.push( item );
2664
+ $assignment.val.push( item );
2660
2665
  if ($seenEllipsis === true) // TODO: adapt msg to UP TO
2661
- this.error( 'syntax-unexpected-ellipsis', $e, { code: '...' },
2662
- 'Expected no more than one $(CODE)' );
2666
+ this.error( 'syntax-unexpected-ellipsis', $e, { '#': 'std', code: '...' } );
2663
2667
  else
2664
2668
  $seenEllipsis = !$ctx.upTo || 'upTo';
2665
2669
  }}
@@ -2674,67 +2678,66 @@ annoValueBase returns[ val ] locals [ seenEllipsis = false ]
2674
2678
  'Expecting an array item $(NEWCODE) after an item with $(CODE)' );
2675
2679
  }
2676
2680
  |
2677
- v1=literalValue { $val = $v1.val; }
2681
+ v1=literalValue { Object.assign( $assignment, $v1.val ); }
2678
2682
  |
2679
2683
  ( plus='+' | min='-' ) num=Number
2680
- { $val = this.numberLiteral( $num, $plus||$min ); }
2684
+ { Object.assign( $assignment, this.numberLiteral( $num, $plus||$min ) ); }
2681
2685
  ;
2682
2686
 
2683
- annoValue returns[ val ]
2687
+ flattenedValue[ assignment ] locals[ val = { name: {} } ]
2684
2688
  :
2685
- base=annoValueBase { $val = $base.val }
2686
- |
2687
- { $val = {}; } // TODO: think about expression value representation
2688
- at='@'? annotationPath[ $val, 'ref', $at ]
2689
- annotationPathVariant[ $val ]?
2690
- ;
2691
-
2692
- namedValue[ struct ] locals[ namedVal = { name: {} } ]
2693
- :
2694
- at='@'? annotationPath[ $namedVal.name, 'name', $at ]
2689
+ at='@'? annotationPath[ $val.name, 'name', $at ]
2695
2690
  (
2696
2691
  '#' { this.meltKeywordToIdentifier(); }
2697
- variant=ident['variant'] { $namedVal.name.variant = $variant.id; }
2692
+ variant=ident['variant'] { $val.name.variant = $variant.id; }
2698
2693
  )?
2699
2694
  (
2700
2695
  ':' { this.meltKeywordToIdentifier(true); } // allow path as anno value start with reserved
2701
- elem=annoValue
2696
+ annoValue[ $val ]
2702
2697
  )?
2703
- { this.addItem( $struct, '_struct', null, true, // TODO: re-check _struct
2704
- ($ctx.elem) ? Object.assign($namedVal, $elem.val) : $namedVal ); }
2698
+ { $assignment['$'+'flatten'].push( $val ); }
2699
+ ;
2700
+
2701
+ namedValue[ struct ] locals[ val = { name: {} } ]
2702
+ :
2703
+ at='@'? annotationPath[ $val.name, 'name', $at ]
2704
+ ( ':' sub=annoSubValue { Object.assign( $val, $sub.val ); } )?
2705
+ {
2706
+ if (!$val.location) $val.location = $val.name.location;
2707
+ this.addDef( $val, $struct, 'struct', null, $val.name ); // TODO: re-check name
2708
+ }
2705
2709
  ;
2706
2710
 
2707
- arrayValue returns[ val ]
2711
+ annoSubValue returns[ val = {} ]
2708
2712
  @after { this.attachLocation($val); }
2709
2713
  :
2710
- { $val = { literal: 'struct', location: this.startLocation() }; }
2711
- '{'
2714
+ '{' // no need for createDict() here, $val.location is set
2715
+ { $val.struct = Object.create(null); $val.literal = 'struct'; }
2712
2716
  { this.meltKeywordToIdentifier(); }
2713
- namedValueInArray[ $val ]
2717
+ namedValue[ $val ]
2714
2718
  ( ','
2715
2719
  {
2716
2720
  this.meltKeywordToIdentifier();
2717
2721
  if (this.isStraightBefore("}")) break; // allow ',' before '}'
2718
2722
  }
2719
- namedValueInArray[ $val ]
2723
+ namedValue[ $val ]
2720
2724
  )*
2721
2725
  '}'
2722
2726
  |
2723
- { $val = { literal: 'array', location: this.startLocation(), val: [] }; }
2724
- '['
2725
- ( head=arrayValue { $val.val.push( $head.val ); }
2727
+ '[' // no need for createArray() here, $val.location is set
2728
+ { $val.val = []; $val.literal = 'array'; }
2729
+ ( head=annoSubValue { $val.val.push( $head.val ); }
2726
2730
  ( ',' { if (this.isStraightBefore(']')) break; } // allow ',' before ']'
2727
- tail=arrayValue { $val.val.push( $tail.val ); }
2731
+ tail=annoSubValue { $val.val.push( $tail.val ); }
2728
2732
  )*
2729
2733
  )?
2730
2734
  ']'
2731
2735
  |
2732
- v1=literalValue { $val = $v1.val; }
2736
+ v1=literalValue { Object.assign( $val, $v1.val ); }
2733
2737
  |
2734
2738
  ( plus='+' | min='-' ) num=Number
2735
- { $val = this.numberLiteral( $num, $plus||$min ); }
2739
+ { Object.assign( $val, this.numberLiteral( $num, $plus||$min ) ); }
2736
2740
  |
2737
- { $val = {}; } // TODO: think about expression value representation
2738
2741
  at='@'? annotationPath[ $val, 'ref', $at ]
2739
2742
  (
2740
2743
  '#' { this.meltKeywordToIdentifier(); }
@@ -2742,14 +2745,6 @@ arrayValue returns[ val ]
2742
2745
  )?
2743
2746
  ;
2744
2747
 
2745
- namedValueInArray[ struct ] locals[ name = {} ]
2746
- :
2747
- at='@'? annotationPath[ $name, 'name', $at ]
2748
- ( ':' elem=arrayValue )?
2749
- { this.addDef( $struct, 'struct', null, $name, true,
2750
- ($ctx.elem) ? $elem.val : { location: $name.location } ); }
2751
- ;
2752
-
2753
2748
  literalValue returns[ val ] locals[ tok ]
2754
2749
  @init{ $tok = this.getCurrentToken(); }
2755
2750
  @after { this.attachLocation($val); }
@@ -2808,7 +2803,7 @@ annotationPath[ art, category, headat = null ] locals[ _sync = 'nop' ]
2808
2803
  annotationPathVariant[ art ]
2809
2804
  @after { this.attachLocation($art); }
2810
2805
  :
2811
- // TODO: warning for space before and after '#'
2806
+ // TODO: warning for space after '#'
2812
2807
  '#' { this.meltKeywordToIdentifier(); }
2813
2808
  variant=ident['variant'] { $art.variant = $variant.id; }
2814
2809
  ;
@@ -2839,13 +2834,11 @@ ident[ category ] returns[ id ]
2839
2834
  | ASPECT
2840
2835
  | ASSOCIATION
2841
2836
  | BETWEEN
2842
- | BOTH
2843
2837
  | COLUMNS
2844
2838
  | COMPOSITION
2845
2839
  | CONTEXT
2846
2840
  | CROSS
2847
2841
  | CURRENT
2848
- | DAY
2849
2842
  | DEFAULT
2850
2843
  | DEFINE
2851
2844
  | DEFINITIONS
@@ -2869,14 +2862,12 @@ ident[ category ] returns[ id ]
2869
2862
  | FUNCTION
2870
2863
  | GROUP
2871
2864
  | HAVING
2872
- | HOUR
2873
2865
  | INNER
2874
2866
  | INTERSECT
2875
2867
  | INTO
2876
2868
  | IS
2877
2869
  | JOIN
2878
2870
  | LAST
2879
- | LEADING
2880
2871
  | LEFT
2881
2872
  | LIKE
2882
2873
  | LIMIT
@@ -2884,9 +2875,7 @@ ident[ category ] returns[ id ]
2884
2875
  | MANY
2885
2876
  | MASKED
2886
2877
  | MINUS
2887
- | MINUTE
2888
2878
  | MIXIN
2889
- | MONTH
2890
2879
  | NAMESPACE
2891
2880
  | NULLS
2892
2881
  | OFFSET
@@ -2903,10 +2892,8 @@ ident[ category ] returns[ id ]
2903
2892
  | RIGHT
2904
2893
  | ROW
2905
2894
  | ROWS
2906
- | SECOND
2907
2895
  | SERVICE
2908
2896
  | THEN
2909
- | TRAILING
2910
2897
  | UNION
2911
2898
  | UP
2912
2899
  | TO
@@ -2915,7 +2902,6 @@ ident[ category ] returns[ id ]
2915
2902
  | UNBOUNDED
2916
2903
  | VARIABLE
2917
2904
  | VIEW
2918
- | YEAR
2919
2905
  ;
2920
2906
 
2921
2907
  //----------------------------------------------------------------------------
@@ -3007,7 +2993,6 @@ CASE : [cC][aA][sS][eE] ;
3007
2993
  CAST : [cC][aA][sS][tT] ;
3008
2994
  DISTINCT : [dD][iI][sS][tT][iI][nN][cC][tT] ;
3009
2995
  EXISTS : [eE][xX][iI][sS][tT][sS] ;
3010
- EXTRACT : [eE][xX][tT][rR][aA][cC][tT] ;
3011
2996
  // FALSE: see Boolean
3012
2997
  FROM : [fF][rR][oO][mM] ;
3013
2998
  IN : [iI][nN] ;
@@ -3020,7 +3005,6 @@ ON : [oO][nN] ;
3020
3005
  SELECT : [sS][eE][lL][eE][cC][tT] ;
3021
3006
  SOME : [sS][oO][mM][eE] ;
3022
3007
  WHEN : [wW][hH][eE][nN] ;
3023
- TRIM : [tT][rR][iI][mM] ;
3024
3008
  // TRUE: see Boolean
3025
3009
  WHERE : [wW][hH][eE][rR][eE] ;
3026
3010
  WITH : [wW][iI][tT][hH] ;
@@ -3034,6 +3018,7 @@ Number // DO NOT RENAME OR MOVE THIS RULE !!!
3034
3018
  ;
3035
3019
 
3036
3020
  // Unreserved keywords (are case-insensitive): -------------------------------
3021
+ // Do not add keywords just for specialFunctions!
3037
3022
 
3038
3023
  ABSTRACT : [aA][bB][sS][tT][rR][aA][cC][tT] ;
3039
3024
  ACTION : [aA][cC][tT][iI][oO][nN] ;
@@ -3046,13 +3031,11 @@ ASC : [aA][sS][cC] ;
3046
3031
  ASPECT : [aA][sS][pP][eE][cC][tT] ;
3047
3032
  ASSOCIATION : [aA][sS][sS][oO][cC][iI][aA][tT][iI][oO][nN] ;
3048
3033
  BETWEEN : [bB][eE][tT][wW][eE][eE][nN] ;
3049
- BOTH : [bB][oO][tT][hH] ;
3050
3034
  COLUMNS : [cC][oO][lL][uU][mM][nN][sS];
3051
3035
  COMPOSITION : [cC][oO][mM][pP][oO][sS][iI][tT][iI][oO][nN] ;
3052
3036
  CONTEXT : [cC][oO][nN][tT][eE][xX][tT] ;
3053
3037
  CROSS : [cC][rR][oO][sS][sS] ;
3054
3038
  CURRENT : [cC][uU][rR][rR][eE][nN][tT] ;
3055
- DAY : [dD][aA][yY] ;
3056
3039
  DEFAULT : [dD][eE][fF][aA][uU][lL][tT] ;
3057
3040
  DEFINE : [dD][eE][fF][iI][nN][eE] ;
3058
3041
  DEFINITIONS : [dD][eE][fF][iI][nN][iI][tT][iI][oO][nN][sS] ;
@@ -3076,14 +3059,12 @@ FULL : [fF][uU][lL][lL] ;
3076
3059
  FUNCTION : [fF][uU][nN][cC][tT][iI][oO][nN] ;
3077
3060
  GROUP : [gG][rR][oO][uU][pP] ;
3078
3061
  HAVING : [hH][aA][vV][iI][nN][gG] ;
3079
- HOUR : [hH][oO][uU][rR] ;
3080
3062
  INNER : [iI][nN][nN][eE][rR] ;
3081
3063
  INTERSECT : [iI][nN][tT][eE][rR][sS][eE][cC][tT] ;
3082
3064
  INTO : [iI][nN][tT][oO] ;
3083
3065
  IS : [iI][sS] ;
3084
3066
  JOIN : [jJ][oO][iI][nN] ;
3085
3067
  LAST : [lL][aA][sS][tT] ;
3086
- LEADING : [lL][eE][aA][dD][iI][nN][gG] ;
3087
3068
  LEFT : [lL][eE][fF][tT] ;
3088
3069
  LIKE : [lL][iI][kK][eE] ;
3089
3070
  LIMIT : [lL][iI][mM][iI][tT] ;
@@ -3091,9 +3072,7 @@ LOCALIZED: [lL][oO][cC][aA][lL][iI][zZ][eE][dD];
3091
3072
  MANY : [mM][aA][nN][yY] ;
3092
3073
  MASKED : [mM][aA][sS][kK][eE][dD] ;
3093
3074
  MINUS : [mM][iI][nN][uU][sS] ;
3094
- MINUTE : [mM][iI][nN][uU][tT][eE] ;
3095
3075
  MIXIN : [mM][iI][xX][iI][nN] ;
3096
- MONTH : [mM][oO][nN][tT][hH] ;
3097
3076
  NAMESPACE : [nN][aA][mM][eE][sS][pP][aA][cC][eE] ;
3098
3077
  NULLS : [nN][uU][lL][lL][sS] ;
3099
3078
  OFFSET : [oO][fF][fF][sS][eE][tT] ;
@@ -3111,10 +3090,8 @@ RETURNS : [rR][eE][tT][uU][rR][nN][sS] ;
3111
3090
  RIGHT : [rR][iI][gG][hH][tT] ;
3112
3091
  ROW : [rR][oO][wW] ;
3113
3092
  ROWS : [rR][oO][wW][sS] ;
3114
- SECOND : [sS][eE][cC][oO][nN][dD] ;
3115
3093
  SERVICE : [sS][eE][rR][vV][iI][cC][eE] ;
3116
3094
  THEN : [tT][hH][eE][nN] ;
3117
- TRAILING : [tT][rR][aA][iI][lL][iI][nN][gG] ;
3118
3095
  TO : [tT][oO] ; // or make reserved? (is in SQL-92)
3119
3096
  TYPE : [tT][yY][pP][eE] ;
3120
3097
  UNION : [uU][nN][iI][oO][nN] ;
@@ -3124,7 +3101,6 @@ USING : [uU][sS][iI][nN][gG] ;
3124
3101
  VARIABLE : [vV][aA][rR][iI][aA][bB][lL][eE] ;
3125
3102
  VIEW : [vV][iI][eE][wW] ;
3126
3103
  // VIRTUAL: [vV][iI][rR][tT][uU][aA][lL] ; see tokens {}
3127
- YEAR : [yY][eE][aA][rR] ;
3128
3104
 
3129
3105
  // Identifiers, must BE LAST, DIRECTLY AFTER the unreserved keywords ---------
3130
3106