@sap/cds-compiler 2.15.8 → 3.1.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 +102 -1590
  2. package/bin/.eslintrc.json +2 -1
  3. package/bin/cdsc.js +61 -46
  4. package/doc/API.md +11 -0
  5. package/doc/CHANGELOG_ARCHIVE.md +1592 -0
  6. package/doc/CHANGELOG_BETA.md +26 -5
  7. package/doc/CHANGELOG_DEPRECATED.md +55 -1
  8. package/doc/{DeprecatedOptions.md → DeprecatedOptions_v2.md} +3 -1
  9. package/doc/Versioning.md +20 -1
  10. package/lib/api/.eslintrc.json +2 -2
  11. package/lib/api/main.js +282 -156
  12. package/lib/api/options.js +17 -88
  13. package/lib/api/validate.js +6 -10
  14. package/lib/base/keywords.js +280 -110
  15. package/lib/base/message-registry.js +85 -25
  16. package/lib/base/messages.js +119 -89
  17. package/lib/base/model.js +46 -2
  18. package/lib/base/optionProcessorHelper.js +53 -21
  19. package/lib/checks/actionsFunctions.js +15 -12
  20. package/lib/checks/annotationsOData.js +1 -1
  21. package/lib/checks/cdsPersistence.js +1 -0
  22. package/lib/checks/elements.js +6 -6
  23. package/lib/checks/invalidTarget.js +1 -1
  24. package/lib/checks/nonexpandableStructured.js +1 -1
  25. package/lib/checks/queryNoDbArtifacts.js +2 -1
  26. package/lib/checks/selectItems.js +101 -15
  27. package/lib/checks/types.js +7 -8
  28. package/lib/checks/utils.js +2 -2
  29. package/lib/checks/validator.js +3 -3
  30. package/lib/compiler/assert-consistency.js +78 -21
  31. package/lib/compiler/base.js +6 -4
  32. package/lib/compiler/builtins.js +177 -10
  33. package/lib/compiler/checks.js +1 -1
  34. package/lib/compiler/define.js +28 -23
  35. package/lib/compiler/extend.js +75 -18
  36. package/lib/compiler/finalize-parse-cdl.js +25 -18
  37. package/lib/compiler/index.js +27 -11
  38. package/lib/compiler/moduleLayers.js +7 -0
  39. package/lib/compiler/populate.js +26 -39
  40. package/lib/compiler/propagator.js +12 -7
  41. package/lib/compiler/resolve.js +207 -236
  42. package/lib/compiler/shared.js +100 -93
  43. package/lib/compiler/tweak-assocs.js +13 -20
  44. package/lib/compiler/utils.js +20 -6
  45. package/lib/edm/annotations/preprocessAnnotations.js +12 -13
  46. package/lib/edm/csn2edm.js +35 -37
  47. package/lib/edm/edm.js +22 -13
  48. package/lib/edm/edmAnnoPreprocessor.js +349 -0
  49. package/lib/edm/edmInboundChecks.js +85 -0
  50. package/lib/edm/edmPreprocessor.js +338 -689
  51. package/lib/edm/edmUtils.js +97 -67
  52. package/lib/gen/Dictionary.json +29 -9
  53. package/lib/gen/language.checksum +1 -1
  54. package/lib/gen/language.interp +8 -31
  55. package/lib/gen/language.tokens +105 -114
  56. package/lib/gen/languageLexer.interp +1 -34
  57. package/lib/gen/languageLexer.js +892 -1007
  58. package/lib/gen/languageLexer.tokens +95 -106
  59. package/lib/gen/languageParser.js +20629 -22474
  60. package/lib/inspect/.eslintrc.json +4 -0
  61. package/lib/inspect/index.js +14 -0
  62. package/lib/inspect/inspectModelStatistics.js +81 -0
  63. package/lib/inspect/inspectPropagation.js +189 -0
  64. package/lib/inspect/inspectUtils.js +44 -0
  65. package/lib/json/from-csn.js +74 -69
  66. package/lib/json/to-csn.js +17 -14
  67. package/lib/language/antlrParser.js +2 -2
  68. package/lib/language/docCommentParser.js +61 -38
  69. package/lib/language/errorStrategy.js +52 -40
  70. package/lib/language/genericAntlrParser.js +424 -292
  71. package/lib/language/language.g4 +604 -687
  72. package/lib/language/multiLineStringParser.js +14 -42
  73. package/lib/language/textUtils.js +44 -0
  74. package/lib/main.d.ts +28 -42
  75. package/lib/main.js +104 -81
  76. package/lib/model/api.js +1 -1
  77. package/lib/model/csnRefs.js +57 -30
  78. package/lib/model/csnUtils.js +189 -287
  79. package/lib/model/revealInternalProperties.js +32 -10
  80. package/lib/model/sortViews.js +32 -31
  81. package/lib/modelCompare/compare.js +3 -0
  82. package/lib/optionProcessor.js +91 -57
  83. package/lib/render/.eslintrc.json +1 -1
  84. package/lib/render/DuplicateChecker.js +4 -7
  85. package/lib/render/manageConstraints.js +70 -2
  86. package/lib/render/toCdl.js +387 -367
  87. package/lib/render/toHdbcds.js +20 -16
  88. package/lib/render/toRename.js +44 -22
  89. package/lib/render/toSql.js +81 -59
  90. package/lib/render/utils/common.js +16 -3
  91. package/lib/render/utils/sql.js +20 -19
  92. package/lib/sql-identifier.js +6 -0
  93. package/lib/transform/db/.eslintrc.json +3 -2
  94. package/lib/transform/db/associations.js +43 -35
  95. package/lib/transform/db/cdsPersistence.js +5 -16
  96. package/lib/transform/db/constraints.js +1 -1
  97. package/lib/transform/db/expansion.js +7 -6
  98. package/lib/transform/db/flattening.js +16 -18
  99. package/lib/transform/db/transformExists.js +7 -5
  100. package/lib/transform/db/views.js +3 -3
  101. package/lib/transform/draft/.eslintrc.json +2 -2
  102. package/lib/transform/draft/db.js +6 -6
  103. package/lib/transform/draft/odata.js +6 -7
  104. package/lib/transform/forHanaNew.js +30 -24
  105. package/lib/transform/forOdataNew.js +14 -16
  106. package/lib/transform/localized.js +35 -25
  107. package/lib/transform/odata/toFinalBaseType.js +10 -10
  108. package/lib/transform/odata/typesExposure.js +17 -8
  109. package/lib/transform/odata/utils.js +1 -38
  110. package/lib/transform/transformUtilsNew.js +63 -77
  111. package/lib/transform/translateAssocsToJoins.js +2 -2
  112. package/lib/transform/universalCsn/.eslintrc.json +2 -2
  113. package/lib/transform/universalCsn/coreComputed.js +11 -6
  114. package/lib/transform/universalCsn/universalCsnEnricher.js +33 -5
  115. package/lib/utils/file.js +31 -21
  116. package/lib/utils/moduleResolve.js +0 -1
  117. package/lib/utils/timetrace.js +20 -21
  118. package/package.json +34 -4
  119. package/share/messages/syntax-expected-integer.md +9 -8
  120. package/doc/ApiMigration.md +0 -237
  121. package/doc/CommandLineMigration.md +0 -58
  122. package/doc/ErrorMessages.md +0 -175
  123. package/doc/FioriAnnotations.md +0 -94
  124. package/doc/ODataTransformation.md +0 -273
  125. package/lib/backends.js +0 -529
  126. package/lib/checks/unknownMagic.js +0 -41
  127. package/lib/fix_antlr4-8_warning.js +0 -56
@@ -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 ] // or aspect
389
+ | extendProjection[ $art, $outer ]
390
+ | extendType[ $art, $outer ]
396
391
  // Streamlined Syntax
397
- | extendArtifact[ $outer, this.startLocation(), $annos ]
392
+ | extendArtifact[ $art, $outer ]
398
393
  )
399
394
  |
400
395
  annotate=ANNOTATE
401
- { if (defOnly) // this is a syntax restriction which is ensured in CSN in
402
- // another way
396
+ { if (defOnly)
403
397
  this.error( 'syntax-extend-context', $annotate,
404
398
  { code: 'ANNOTATE artifact', kind: defOnly },
405
399
  'No $(CODE) within $(KIND) extensions' );
400
+ if (!$outer.extensions) $outer.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,35 +533,37 @@ 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
+ // also used for aspect
547
+ extendEntity[ art, outer ] locals[ name = {} ]
548
+ @after { /* #ATN 1 */ this.attachLocation( $art ); }
556
549
  :
557
- ENTITY simplePath[ $name, 'Extend' ]
558
- { $art = this.addItem( $outer, 'extensions', 'extend', $annos,
559
- { name: $name, expectedKind: 'entity' }, $loc ); }
550
+ kind=(ASPECT | ENTITY) simplePath[ $name, 'Extend' ]
551
+ { $art.expectedKind = $kind.text.toLowerCase(); $art.name = $name;
552
+ this.addItem( $art, $outer, 'extensions', 'extend' );
553
+ }
560
554
  (
561
- WITH { this.noSemicolonHere(); this.docComment( $annos ); }
562
- annotationAssignment_ll1[ $annos ]*
555
+ WITH { this.noSemicolonHere(); this.docComment( $art ); }
556
+ annotationAssignment_ll1[ $art ]*
563
557
  // ATN: the ref can start with ACTIONS
564
558
  (
565
- includeRef[ $art ]
559
+ includeRef[ $art ] ( ',' includeRef[ $art ] )*
566
560
  requiredSemi
567
561
  |
568
562
  extendForEntity[ $art ]
569
563
  )
570
564
  |
571
- { this.docComment( $annos ); }
572
- annotationAssignment_ll1[ $annos ]*
565
+ { this.docComment( $art ); }
566
+ annotationAssignment_ll1[ $art ]*
573
567
  extendForEntity[ $art ]
574
568
  )
575
569
  ;
@@ -578,33 +572,32 @@ extendForEntity[ art ]
578
572
  :
579
573
  '{' { $art.elements = this.createDict(); }
580
574
  elementDefOrExtend[ $art ]*
581
- '}' { this.setDictEndLocation( $art.elements ); }
575
+ '}' { this.finalizeDictOrArray( $art.elements ); }
582
576
  (
583
577
  ACTIONS '{' { $art.actions = this.createDict(); }
584
578
  actionFunctionDef[ $art ]*
585
- '}' { this.setDictEndLocation( $art.actions ); }
579
+ '}' { this.finalizeDictOrArray( $art.actions ); }
586
580
  )?
587
581
  optionalSemi
588
582
  |
589
583
  ACTIONS '{' { $art.actions = this.createDict(); }
590
584
  actionFunctionDef[ $art ]*
591
- '}' { this.setDictEndLocation( $art.actions ); }
585
+ '}' { this.finalizeDictOrArray( $art.actions ); }
592
586
  optionalSemi
593
587
  |
594
588
  requiredSemi
595
589
  ;
596
590
 
597
- extendProjection[ outer, loc, annos ] locals[ art, name = {} ]
598
- @after { this.attachLocation($art); }
591
+ extendProjection[ art, outer ] locals[ name = {} ]
592
+ @after { this.attachLocation( $art ); }
599
593
  :
600
594
  expected=PROJECTION simplePath[ $name, 'Extend' ]
601
- {
602
- $art = this.addItem( $outer, 'extensions', 'extend', $annos,
603
- { name: $name, expectedKind: 'entity' }, // or 'projection'?
604
- $loc ); }
595
+ { $art.expectedKind = 'entity'; $art.name = $name;
596
+ this.addItem( $art, $outer, 'extensions', 'extend' );
597
+ }
605
598
  ( WITH { this.noSemicolonHere(); } )?
606
- { this.docComment( $annos ); }
607
- annotationAssignment_ll1[ $annos ]*
599
+ { this.docComment( $art ); }
600
+ annotationAssignment_ll1[ $art ]*
608
601
  (
609
602
  '{' { $art.columns = []; }
610
603
  (
@@ -617,13 +610,13 @@ extendProjection[ outer, loc, annos ] locals[ art, name = {} ]
617
610
  (
618
611
  ACTIONS '{' { $art.actions = this.createDict(); }
619
612
  actionFunctionDef[ $art ]*
620
- '}' { this.setDictEndLocation( $art.actions ); }
613
+ '}' { this.finalizeDictOrArray( $art.actions ); }
621
614
  )?
622
615
  optionalSemi
623
616
  |
624
617
  ACTIONS '{' { $art.actions = this.createDict(); }
625
618
  actionFunctionDef[ $art ]*
626
- '}' { this.setDictEndLocation( $art.actions ); }
619
+ '}' { this.finalizeDictOrArray( $art.actions ); }
627
620
  optionalSemi
628
621
  |
629
622
  requiredSemi
@@ -631,53 +624,53 @@ extendProjection[ outer, loc, annos ] locals[ art, name = {} ]
631
624
  ;
632
625
 
633
626
  // TODO: no action extension?
634
- actionFunctionDef[ outer ] locals[ art, annos = [] ]
635
- @after { this.attachLocation($art); }
627
+ actionFunctionDef[ outer ] locals[ art = {} ]
628
+ @after { this.attachLocation( $art ); }
636
629
  :
637
- { this.docComment( $annos ); }
638
- annotationAssignment_ll1[ $annos ]*
630
+ { $art.location = this.startLocation();; this.docComment( $art ); }
631
+ annotationAssignment_ll1[ $art ]*
639
632
  (
640
633
  ACTION name=ident['BoundAction']
641
- { $art = this.addDef( $outer, 'actions', 'action', $name.id, $annos );
642
- this.docComment( $annos ); }
643
- annotationAssignment_fix[ $annos ]*
634
+ { this.addDef( $art, $outer, 'actions', 'action', $name.id );
635
+ this.docComment( $art ); }
636
+ annotationAssignment_fix[ $art ]*
644
637
  parameterListDef[ $art ]
645
- ( returnTypeSpec[ $art, $annos ] | requiredSemi )
638
+ ( returnTypeSpec[ $art ] | requiredSemi )
646
639
  |
647
640
  FUNCTION name=ident['BoundAction']
648
- { $art = this.addDef( $outer, 'actions', 'function', $name.id, $annos );
649
- this.docComment( $annos ); }
650
- annotationAssignment_fix[ $annos ]*
641
+ { this.addDef( $art, $outer, 'actions', 'function', $name.id );
642
+ this.docComment( $art ); }
643
+ annotationAssignment_fix[ $art ]*
651
644
  parameterListDef[ $art ]
652
- returnTypeSpec[ $art, $annos ]
645
+ returnTypeSpec[ $art ]
653
646
  )
654
647
  ;
655
648
 
656
- actionFunctionMainDef[ outer, loc, annos ] locals[ art, name = {} ]
657
- @after { this.attachLocation($art); }
649
+ actionFunctionMainDef[ art, outer ] locals[ name = {} ]
650
+ @after { this.attachLocation( $art ); }
658
651
  :
659
652
  ACTION simplePath[ $name, 'Action' ]
660
- { $art = this.addDef( $outer, 'artifacts', 'action', $name, $annos, {}, $loc );
661
- this.docComment( $annos ); }
662
- annotationAssignment_fix[ $annos ]*
653
+ { this.addDef( $art, $outer, 'artifacts', 'action', $name );
654
+ this.docComment( $art ); }
655
+ annotationAssignment_fix[ $art ]*
663
656
  parameterListDef[ $art ]
664
- ( returnTypeSpec[ $art, $annos ] | requiredSemi )
657
+ ( returnTypeSpec[ $art ] | requiredSemi )
665
658
  |
666
659
  FUNCTION simplePath[ $name, 'Action' ]
667
- { $art = this.addDef( $outer, 'artifacts', 'function', $name, $annos, {}, $loc );
668
- this.docComment( $annos ); }
669
- annotationAssignment_fix[ $annos ]*
660
+ { this.addDef( $art, $outer, 'artifacts', 'function', $name );
661
+ this.docComment( $art ); }
662
+ annotationAssignment_fix[ $art ]*
670
663
  parameterListDef[ $art ]
671
- returnTypeSpec[ $art, $annos ]
664
+ returnTypeSpec[ $art ]
672
665
  ;
673
666
 
674
- eventDef[ outer, loc, annos ] locals[ art, name = {} ]
675
- @after { /* #ATN 1 */ this.attachLocation($art); }
667
+ eventDef[ art, outer ] locals[ name = {} ]
668
+ @after { /* #ATN 1 */ this.attachLocation( $art ); }
676
669
  :
677
670
  EVENT simplePath[ $name, 'Event' ]
678
- { $art = this.addDef( $outer, 'artifacts', 'event', $name, $annos, {}, $loc );
679
- this.docComment( $annos ); }
680
- annotationAssignment_fix[ $annos ]*
671
+ { this.addDef( $art, $outer, 'artifacts', 'event', $name );
672
+ this.docComment( $art ); }
673
+ annotationAssignment_fix[ $art ]*
681
674
  (
682
675
  typeStruct[ $art ] optionalSemi
683
676
  |
@@ -693,8 +686,8 @@ eventDef[ outer, loc, annos ] locals[ art, name = {} ]
693
686
  )*
694
687
  typeStruct[ $art ] optionalSemi
695
688
  |
696
- { this.docComment( $annos ); }
697
- annotationAssignment_ll1[ $annos ]*
689
+ { this.docComment( $art ); }
690
+ annotationAssignment_ll1[ $art ]*
698
691
  requiredSemi
699
692
  )
700
693
  |
@@ -708,18 +701,18 @@ eventDef[ outer, loc, annos ] locals[ art, name = {} ]
708
701
  )
709
702
  ;
710
703
 
711
- aspectDef[ outer, loc, annos ] locals[ art, name = {} ]
712
- @after { this.attachLocation($art); }
704
+ aspectDef[ art, outer ] locals[ name = {} ]
705
+ @after { this.attachLocation( $art ); }
713
706
  :
714
707
  ( ASPECT | ( abs=ABSTRACT | HideAlternatives ) ent=ENTITY )
715
708
  simplePath[ $name, 'Type' ]
716
- { $art = this.addDef( $outer, 'artifacts', 'aspect', $name, $annos, {}, $loc );
709
+ { this.addDef( $art, $outer, 'artifacts', 'aspect', $name );
717
710
  // backends do not like ['$'+'syntax']: ($ent ? 'entity' : 'aspect')
718
711
  if ($ent)
719
712
  this.warning( 'syntax-deprecated-abstract', this.tokenLocation( $abs, $ent ), {},
720
713
  'Abstract entity definitions are deprecated; use aspect definitions instead' );
721
- this.docComment( $annos ); }
722
- annotationAssignment_fix[ $annos ]*
714
+ this.docComment( $art ); }
715
+ annotationAssignment_fix[ $art ]*
723
716
  ( ':'
724
717
  (
725
718
  includeRef[ $art ]
@@ -730,99 +723,84 @@ aspectDef[ outer, loc, annos ] locals[ art, name = {} ]
730
723
  )?
731
724
  '{' { $art.elements = this.createDict(); }
732
725
  ( elementDef[ $art ]* )
733
- '}' { this.setDictEndLocation( $art.elements ); }
726
+ '}' { this.finalizeDictOrArray( $art.elements ); }
734
727
  // TODO: action definitions in a specific section?
735
728
  (
736
729
  ACTIONS '{' { $art.actions = this.createDict(); }
737
730
  actionFunctionDef[ $art ]*
738
- '}' { this.setDictEndLocation( $art.actions ); }
731
+ '}' { this.finalizeDictOrArray( $art.actions ); }
739
732
  )?
740
733
  optionalSemi
741
734
  ;
742
735
 
743
- typeDef[ outer, loc, annos ] locals[ art, name = {} ]
744
- @after { this.attachLocation($art); }
736
+ typeDef[ art, outer ] locals[ name = {} ]
737
+ @after { this.attachLocation( $art ); }
745
738
  :
746
739
  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 ]
740
+ { this.addDef( $art, $outer, 'artifacts', 'type', $name );
741
+ this.docComment( $art ); }
742
+ annotationAssignment_fix[ $art ]*
743
+ typeSpecSemi[ $art ]
751
744
  ;
752
745
 
753
- extendType[ outer, loc, annos ] locals[ art, name = {} ]
754
- @after { this.attachLocation($art); }
746
+ extendType[ art, outer ] locals[ name = {} ]
747
+ @after { this.attachLocation( $art ); }
755
748
  :
756
749
  // aspects are types, i.e. kind is 'type' for aspects
757
750
  TYPE simplePath[ $name, 'Extend' ]
758
- { $art = this.addItem( $outer, 'extensions', 'extend', $annos,
759
- { name: $name, expectedKind: 'type' },
760
- $loc ); }
761
- extendWithOptElements[ $art, $annos ]
762
- ;
763
-
764
- extendAspect[ outer, loc, annos ] locals[ art, name = {} ]
765
- @after { this.attachLocation($art); }
766
- :
767
- // aspects are types, i.e. kind is 'type' for aspects
768
- ASPECT simplePath[ $name, 'Extend' ]
769
- { $art = this.addItem( $outer, 'extensions', 'extend', $annos,
770
- { name: $name, expectedKind: 'aspect' },
771
- $loc ); }
772
- extendWithOptElements[ $art, $annos ]
751
+ { $art.expectedKind = 'type'; $art.name = $name;
752
+ this.addItem( $art, $outer, 'extensions', 'extend' );
753
+ }
754
+ extendWithOptElements[ $art, $art ]
773
755
  ;
774
756
 
775
- annotationDef[ outer, loc, annos ] locals[ art, name = {} ]
776
- @after { this.attachLocation($art); }
757
+ annotationDef[ art, outer ] locals[ name = {} ]
758
+ @after { this.attachLocation( $art ); }
777
759
  :
778
760
  annotation=ANNOTATION simplePath[ $name, 'AnnoDef' ]
779
761
  { 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' );
762
+ this.error( 'syntax-unexpected-vocabulary', $annotation, { '#': $outer.kind } );
782
763
  $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'...
764
+ else {
765
+ if (!$outer.vocabularies) $outer.vocabularies = Object.create(null);
766
+ this.addDef( $art, $outer, 'vocabularies', 'annotation', $name );
767
+ }
768
+ this.docComment( $art ); }
769
+ annotationAssignment_fix[ $art ]*
770
+ typeSpecSemi[ $art ] // also 'includes'...
788
771
  ;
789
772
 
790
- extendArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
791
- @after{ /* #ATN 1 */ this.attachLocation($art); }
773
+ extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
774
+ @after{ /* #ATN 1 */ this.attachLocation( $art ); }
792
775
  :
793
776
  simplePath[ $name, 'Extend' ]
777
+ ( ':' simplePath[ $elemName, 'Element'] )?
778
+ { this.addExtension( $art, $outer, 'extend', $name, $elemName.path ); }
794
779
  (
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 ]*
780
+ { this.docComment( $art ); }
781
+ annotationAssignment_ll1[ $art ]*
807
782
  (
808
783
  '{' { $art.elements = this.createDict(); }
809
784
  elementDefOrExtend[ $art ]*
810
- '}' { this.setDictEndLocation( $art.elements ); }
785
+ '}' { this.finalizeDictOrArray( $art.elements ); }
786
+ { this.checkExtensionDict( $art.elements ); }
811
787
  optionalSemi
812
788
  |
813
789
  requiredSemi
814
790
  )
815
791
  |
816
- WITH { this.noSemicolonHere(); this.docComment( $annos ); }
817
- annotationAssignment_ll1[ $annos ]*
792
+ WITH { this.noSemicolonHere(); this.docComment( $art ); }
793
+ annotationAssignment_ll1[ $art ]*
818
794
  // #ATN: DEFINITIONS, COLUMNS, ACTIONS etc are not reserved and could be identifiers (ref).
795
+ // TODO: exclude "expected" according to disallowElementExtension()
819
796
  (
820
- includeRef[ $art ]
797
+ includeRef[ $art ] ( ',' includeRef[ $art ] )*
821
798
  requiredSemi
822
799
  |
823
800
  '{' { $art.elements = this.createDict(); }
824
801
  elementDefOrExtend[ $art ]*
825
- '}' { this.setDictEndLocation( $art.elements ); }
802
+ '}' { this.finalizeDictOrArray( $art.elements ); }
803
+ { this.checkExtensionDict( $art.elements ); }
826
804
  optionalSemi
827
805
  |
828
806
  requiredSemi
@@ -831,7 +809,7 @@ extendArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
831
809
  DEFINITIONS
832
810
  '{' { $art.artifacts = this.createDict(); }
833
811
  artifactDef[ $art, true ]*
834
- '}' { this.setDictEndLocation( $art.artifacts ); }
812
+ '}' { this.finalizeDictOrArray( $art.artifacts ); }
835
813
  optionalSemi
836
814
  |
837
815
  { this.disallowElementExtension( $elemName, $outer, 'columns' ); }
@@ -848,85 +826,82 @@ extendArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
848
826
  |
849
827
  { this.disallowElementExtension( $elemName, $outer, 'actions' ); }
850
828
  ACTIONS '{' { $art.actions = this.createDict(); }
851
- actionFunctionDef[ $art ]*
852
- '}' { this.setDictEndLocation( $art.actions ); }
829
+ actionFunctionDef[ $art ]* // TODO: no EXTEND in actions? (ok, would just allow annos)
830
+ '}' { this.finalizeDictOrArray( $art.actions ); }
853
831
  optionalSemi
854
832
  |
855
833
  ELEMENTS '{' { $art.elements = this.createDict(); }
856
834
  elementDefOrExtend[ $art ]*
857
- '}' { this.setDictEndLocation( $art.elements ); }
835
+ '}' { this.finalizeDictOrArray( $art.elements ); }
836
+ { this.checkExtensionDict( $art.elements ); }
858
837
  optionalSemi
859
838
  |
860
839
  ENUM '{' { $art.enum = this.createDict(); }
861
- enumSymbolDef[ $art ]*
862
- '}' { this.setDictEndLocation( $art.enum ); }
840
+ enumSymbolDef[ $art ]* // TODO: no EXTEND in enum? (ok, would just allow annos)
841
+ '}' { this.finalizeDictOrArray( $art.enum ); }
863
842
  optionalSemi
864
843
  )
865
844
  )
866
845
  ;
867
846
 
868
- extendWithOptElements[ art, annos ]
847
+ extendWithOptElements[ art ]
869
848
  :
870
- WITH { this.noSemicolonHere(); this.docComment( $annos ); }
871
- annotationAssignment_ll1[ $annos ]*
849
+ WITH { this.noSemicolonHere(); this.docComment( $art ); }
850
+ annotationAssignment_ll1[ $art ]*
872
851
  (
873
- includeRef[ $art ]
852
+ includeRef[ $art ] ( ',' includeRef[ $art ] )*
874
853
  requiredSemi
875
854
  |
876
855
  '{' { $art.elements = this.createDict(); }
877
856
  elementDefOrExtend[ $art ]*
878
- '}' { this.setDictEndLocation( $art.elements ); }
857
+ '}' { this.finalizeDictOrArray( $art.elements ); }
858
+ { this.checkExtensionDict( $art.elements ); }
879
859
  optionalSemi
880
860
  |
881
861
  requiredSemi
882
862
  )
883
863
  |
884
- { this.docComment( $annos ); }
885
- annotationAssignment_ll1[ $annos ]*
864
+ { this.docComment( $art ); }
865
+ annotationAssignment_ll1[ $art ]*
886
866
  (
887
867
  '{' { $art.elements = this.createDict(); }
888
868
  elementDefOrExtend[ $art ]*
889
- '}' { this.setDictEndLocation( $art.elements ); }
869
+ '}' { this.finalizeDictOrArray( $art.elements ); }
870
+ { this.checkExtensionDict( $art.elements ); }
890
871
  optionalSemi
891
872
  |
892
873
  requiredSemi
893
874
  )
894
875
  ;
895
876
 
896
- annotateArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
897
- @after { this.attachLocation($art); }
877
+ annotateArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
878
+ @after { this.attachLocation( $art ); }
898
879
  :
899
880
  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
-
881
+ ( ':' simplePath[ $elemName, 'Element'] )?
882
+ { this.addExtension( $art, $outer, 'annotate', $name, $elemName.path ); }
911
883
  ( WITH { this.noSemicolonHere(); } )?
912
- { this.docComment( $annos ); }
913
- annotationAssignment_ll1[ $annos ]*
884
+ { this.docComment( $art ); }
885
+ annotationAssignment_ll1[ $art ]*
914
886
  (
915
887
  '{' { $art.elements = this.createDict(); }
916
888
  annotateElement[ $art ]*
917
- '}' { this.setDictEndLocation( $art.elements ); }
889
+ '}' { this.finalizeDictOrArray( $art.elements ); }
890
+ { this.checkExtensionDict( $art.elements ); }
918
891
  (
919
892
  ACTIONS
920
893
  '{' { $art.actions = this.createDict(); }
921
894
  annotateAction[ $art ]*
922
- '}' { this.setDictEndLocation( $art.actions ); }
895
+ '}' { this.finalizeDictOrArray( $art.actions ); }
896
+ { this.checkExtensionDict( $art.actions ); }
923
897
  )?
924
898
  optionalSemi
925
899
  |
926
900
  ACTIONS
927
901
  '{' { $art.actions = this.createDict(); }
928
902
  annotateAction[ $art ]*
929
- '}' { this.setDictEndLocation( $art.actions ); }
903
+ '}' { this.finalizeDictOrArray( $art.actions ); }
904
+ { this.checkExtensionDict( $art.actions ); }
930
905
  optionalSemi
931
906
  |
932
907
  '(' { $art.params = this.createDict(); }
@@ -934,12 +909,14 @@ annotateArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
934
909
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
935
910
  annotateParam[ $art ]
936
911
  )*
937
- ')' { this.setDictEndLocation( $art.params ); }
912
+ ')' { this.finalizeDictOrArray( $art.params ); }
913
+ { this.checkExtensionDict( $art.params ); }
938
914
  (
939
915
  RETURNS { $art['$'+'syntax'] = 'returns'; }
940
916
  '{' { $art.elements = this.createDict(); }
941
917
  annotateElement[ $art ]*
942
- '}' { this.setDictEndLocation( $art.elements ); }
918
+ '}' { this.finalizeDictOrArray( $art.elements ); }
919
+ { this.checkExtensionDict( $art.elements ); }
943
920
  optionalSemi
944
921
  |
945
922
  requiredSemi
@@ -948,7 +925,8 @@ 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 ); }
929
+ { this.checkExtensionDict( $art.elements ); }
952
930
  optionalSemi
953
931
 
954
932
  |
@@ -956,74 +934,77 @@ annotateArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
956
934
  )
957
935
  ;
958
936
 
959
- annotateElement[ outer ] locals[ art, annos = [] ]
960
- @after{ this.attachLocation($art); }
937
+ annotateElement[ outer ] locals[ art = {} ]
938
+ @after{ this.attachLocation( $art ); }
961
939
  :
962
- { this.docComment( $annos ); }
963
- annotationAssignment_ll1[ $annos ]*
940
+ { $art.location = this.startLocation();; this.docComment( $art ); }
941
+ annotationAssignment_ll1[ $art ]*
964
942
  name=ident['Element']
965
- { $art = this.addDef( $outer, 'elements', 'annotate', $name.id, $annos );
966
- this.docComment( $annos ); }
967
- annotationAssignment_ll1[ $annos ]*
943
+ { this.addDef( $art, $outer, 'elements', 'annotate', $name.id );
944
+ this.docComment( $art ); }
945
+ annotationAssignment_ll1[ $art ]*
968
946
  (
969
947
  '{' { $art.elements = this.createDict(); }
970
948
  annotateElement[ $art ]*
971
- '}' { this.setDictEndLocation( $art.elements ); }
949
+ '}' { this.finalizeDictOrArray( $art.elements ); }
950
+ { this.checkExtensionDict( $art.elements ); }
972
951
  optionalSemi
973
952
  |
974
953
  requiredSemi
975
954
  )
976
955
  ;
977
956
 
978
- annotateAction [ outer ] locals [ art, annos = [] ]
979
- @after{ this.attachLocation($art); }
957
+ annotateAction [ outer ] locals [ art = {} ]
958
+ @after{ this.attachLocation( $art ); }
980
959
  :
981
- { this.docComment( $annos ); }
982
- annotationAssignment_ll1[ $annos ]*
960
+ { $art.location = this.startLocation();; this.docComment( $art ); }
961
+ annotationAssignment_ll1[ $art ]*
983
962
  name=ident['BoundAction']
984
- { $art = this.addDef( $outer, 'actions', 'annotate', $name.id, $annos );
985
- this.docComment( $annos ); }
986
- annotationAssignment_ll1[ $annos ]*
963
+ { this.addDef( $art, $outer, 'actions', 'annotate', $name.id );
964
+ this.docComment( $art ); }
965
+ annotationAssignment_ll1[ $art ]*
987
966
  (
988
967
  '(' { $art.params = this.createDict(); }
989
968
  annotateParam[ $art ]
990
969
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
991
970
  annotateParam[ $art ]
992
971
  )*
993
- ')' { this.setDictEndLocation( $art.params ); }
972
+ ')' { this.finalizeDictOrArray( $art.params ); }
973
+ { this.checkExtensionDict( $art.params ); }
994
974
  )?
995
975
  (
996
976
  RETURNS '{' { $art.elements = this.createDict(); }
997
977
  annotateElement[ $art ]*
998
- '}' { this.setDictEndLocation( $art.elements ); }
978
+ '}' { this.finalizeDictOrArray( $art.elements ); }
979
+ { this.checkExtensionDict( $art.elements ); }
999
980
  optionalSemi
1000
981
  |
1001
982
  requiredSemi
1002
983
  )
1003
984
  ;
1004
985
 
1005
- annotateParam [ outer ] locals [ art, annos = [] ]
1006
- @after{ this.attachLocation($art); }
986
+ annotateParam [ outer ] locals [ art = {} ]
987
+ @after{ this.attachLocation( $art ); }
1007
988
  :
1008
- { this.docComment( $annos ); }
1009
- annotationAssignment_ll1[ $annos ]*
989
+ { $art.location = this.startLocation();; this.docComment( $art ); }
990
+ annotationAssignment_ll1[ $art ]*
1010
991
  param=ident['Param']
1011
- { $art = this.addDef( $outer, 'params', 'annotate', $param.id, $annos );
1012
- this.docComment( $annos ); }
1013
- annotationAssignment_ll1[ $annos ]*
992
+ { this.addDef( $art, $outer, 'params', 'annotate', $param.id );
993
+ this.docComment( $art ); }
994
+ annotationAssignment_ll1[ $art ]*
1014
995
  ;
1015
996
 
1016
997
  // Element definition and its helpers ----------------------------------------
1017
998
 
1018
- enumSymbolDef[ outer ] locals[ art, annos = [] ]
1019
- @after { this.attachLocation($art); }
999
+ enumSymbolDef[ outer ] locals[ art = {} ]
1000
+ @after { this.attachLocation( $art ); }
1020
1001
  :
1021
- { this.docComment( $annos ); }
1022
- annotationAssignment_ll1[ $annos ]*
1002
+ { $art.location = this.startLocation();; this.docComment( $art ); }
1003
+ annotationAssignment_ll1[ $art ]*
1023
1004
  name=ident['Enum']
1024
- { $art = this.addDef( $outer, 'enum', 'enum', $name.id, $annos );
1025
- this.docComment( $annos ); }
1026
- annotationAssignment_ll1[ $annos ]*
1005
+ { this.addDef( $art, $outer, 'enum', 'enum', $name.id );
1006
+ this.docComment( $art ); }
1007
+ annotationAssignment_ll1[ $art ]*
1027
1008
  ( '='
1028
1009
  { this.excludeExpected( ['Boolean', 'QuotedLiteral', "'#'", 'NULL'] ); }
1029
1010
  (
@@ -1033,8 +1014,8 @@ enumSymbolDef[ outer ] locals[ art, annos = [] ]
1033
1014
  ( plus='+' | min='-' ) num=Number
1034
1015
  { $art.value = this.numberLiteral( $num, $plus||$min ); }
1035
1016
  )
1036
- { this.docComment( $annos ); }
1037
- annotationAssignment_ll1[ $annos ]*
1017
+ { this.docComment( $art ); }
1018
+ annotationAssignment_ll1[ $art ]*
1038
1019
  )?
1039
1020
  requiredSemi
1040
1021
  ;
@@ -1045,37 +1026,35 @@ defaultValue[ art ] locals[ elem, elements = {} ]
1045
1026
  DEFAULT expr=expression { $art.default = $expr.expr; }
1046
1027
  ;
1047
1028
 
1048
- elementDefOrExtend[ outer ] locals[ annos = [] ]
1049
- @after { /* #ATN 1 */ if ($ctx.art) this.attachLocation($art.art); }
1050
- // tool complains if I test for ($art)
1029
+ elementDefOrExtend[ outer ] locals[ art = {} ]
1030
+ @after { /* #ATN 1 */ } // if ($art) this.attachLocation( $art ); }
1051
1031
  :
1052
- { this.docComment( $annos ); }
1053
- annotationAssignment_ll1[ $annos ]*
1032
+ { $art.location = this.startLocation();; this.docComment( $art ); }
1033
+ annotationAssignment_ll1[ $art ]*
1054
1034
  // #ATN: element name for definition can be EXTEND
1055
1035
  (
1056
1036
  EXTEND
1057
- extendElement[ $outer, this.startLocation(), $annos ]
1037
+ extendElement[ $art, $outer ]
1058
1038
  |
1059
- art = elementDefInner[ $outer, this.startLocation(), $annos, true ]
1039
+ elementDefInner[ $art, $outer, true ]
1060
1040
  )
1061
1041
  ;
1062
1042
 
1063
- elementDef[ outer ] locals[ annos = [] ]
1064
- @after { this.attachLocation($art.art); }
1043
+ elementDef[ outer ] locals[ $art = {} ]
1065
1044
  :
1066
- { this.docComment( $annos ); }
1067
- annotationAssignment_ll1[ $annos ]*
1068
- art = elementDefInner[ $outer, this.startLocation(), $annos, false ]
1045
+ { $art.location = this.startLocation();; this.docComment( $art ); }
1046
+ annotationAssignment_ll1[ $art ]*
1047
+ elementDefInner[ $art, $outer, false ]
1069
1048
  ;
1070
1049
 
1071
1050
  // Actually, this is a subset if elementDefInner...
1072
1051
  // TODO: the corresponding restrictions must also be checked in the core
1073
1052
  // compiler, as the mixin element could come via CSN
1074
- mixinElementDef[ outer ] locals[ art ]
1053
+ mixinElementDef[ outer ] locals[ art = {} ]
1075
1054
  @after { /* #ATN 2 */ this.attachLocation($art); }
1076
1055
  :
1077
1056
  name=ident['Mixin']
1078
- { $art = this.addDef( $outer, 'mixin', 'mixin', $name.id ); }
1057
+ { this.addDef( $art, $outer, 'mixin', 'mixin', $name.id ); }
1079
1058
  (
1080
1059
  ':'
1081
1060
  // #ATN: referenced type name can be ASSOCIATION or COMPOSITION
@@ -1097,33 +1076,30 @@ mixinElementDef[ outer ] locals[ art ]
1097
1076
  requiredSemi
1098
1077
  ;
1099
1078
 
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 */ }
1079
+ elementDefInner[ art, outer, allowEq ]
1080
+ @after{ /* #ATN 5 */ this.attachLocation( $art ); }
1111
1081
  :
1112
1082
  // TODO: it would be excellent to remove ELEMENT...
1113
1083
  // or have a special ident rule without the ELEMENT
1114
1084
  // Reason: it would be good for error recovery to start a major block without LL1 ambiguity
1115
1085
  // VIRTUAL is keyword, except if before the following tokens texts:
1116
1086
  { this.setLocalToken( 'VIRTUAL', 'VIRTUAL', /^[:{@=}]$/ ); }
1117
- virtual=VIRTUAL? key=KEY?
1087
+ ( virtual=VIRTUAL { $art.virtual = this.valueWithTokenLocation( true, $virtual ); } )?
1088
+ ( key=KEY { $art.key = this.valueWithTokenLocation( true, $key ); } )?
1118
1089
  // #ATN: element name can be MASKED or ELEMENT (2x)
1119
- masked=MASKED? // TODO: order?
1090
+ ( masked=MASKED
1091
+ {
1092
+ $art.masked = this.valueWithTokenLocation( true, $masked ) ;
1093
+ this.message( 'syntax-invalid-masked', $masked, { keyword: 'masked' },
1094
+ 'Keyword $(KEYWORD) not supported' );
1095
+ }
1096
+ )?
1097
+ // TODO: order?
1120
1098
  ELEMENT?
1121
1099
  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 ]*
1100
+ { this.addDef( $art, $outer, 'elements', 'element', $name.id );
1101
+ this.docComment( $art ); }
1102
+ annotationAssignment_fix[ $art ]*
1127
1103
  // TODO: we can think of making the typeSpec optional and do checks instead:
1128
1104
  // type optional with '=', type required otherwise
1129
1105
  (
@@ -1138,7 +1114,6 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1138
1114
  (
1139
1115
  typeStruct[ $art ]
1140
1116
  nullability[ $art ]?
1141
- misplacedAnnotations[ $annos, 'syntax-anno-after-struct' ]?
1142
1117
  requiredSemi
1143
1118
  |
1144
1119
  typeAssociationBase[ $art, true ]
@@ -1155,11 +1130,11 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1155
1130
  typeCompoStruct[ $art.target ] optionalSemi
1156
1131
  |
1157
1132
  // we do not support `Composition of many { e }` - ambiguity ad-hoc target versus foreign keys!
1158
- typeToMany[ $art ] typeAssociationElementCont[ $art, $annos ]
1133
+ typeToMany[ $art ] typeAssociationElementCont[ $art ]
1159
1134
  |
1160
- typeToOne[ $art ] typeAssociationElementCont[ $art, $annos ]
1135
+ typeToOne[ $art ] typeAssociationElementCont[ $art ]
1161
1136
  |
1162
- simplePath[ $art.target, 'artref' ] typeAssociationElementCont[ $art, $annos ]
1137
+ simplePath[ $art.target, 'artref' ] typeAssociationElementCont[ $art ]
1163
1138
  )
1164
1139
  |
1165
1140
  (
@@ -1171,52 +1146,55 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1171
1146
  // #ATN: typeRefOptArgs can start with TYPE
1172
1147
  ( typeStruct[ $art.items ]
1173
1148
  nullability[ $art.items ]?
1174
- misplacedAnnotations[ $annos, 'syntax-anno-after-struct' ]?
1175
1149
  | typeTypeOf[ $art.items ]
1176
1150
  nullability[ $art.items ]?
1177
- { this.docComment( $annos ); }
1178
- annotationAssignment_ll1[ $annos ]*
1151
+ { this.docComment( $art ); }
1152
+ annotationAssignment_ll1[ $art ]*
1179
1153
  | typeRefOptArgs[ $art.items ]
1180
- nullability[ $art.items ]?
1181
- { this.docComment( $annos ); }
1182
- annotationAssignment_ll1[ $annos ]*
1154
+ nullability[ $art.items ]? // only if not followed by `enum`
1155
+ { this.docComment( $art ); }
1156
+ annotationAssignment_ll1[ $art ]*
1183
1157
  (
1158
+ { if ($art.items.notNull) {
1159
+ this.message( 'syntax-unexpected-null', $art.items.notNull.location,
1160
+ { keyword: $art.items.notNull.val ? 'not null' : 'null' } );
1161
+ }
1162
+ }
1184
1163
  ENUM '{' { $art.items.enum = this.createDict(); }
1185
1164
  enumSymbolDef[ $art.items ]*
1186
- '}' { this.setDictEndLocation( $art.items.enum ); }
1187
- misplacedAnnotations[ $annos, 'syntax-anno-after-enum' ]?
1165
+ '}' { this.finalizeDictOrArray( $art.items.enum ); }
1166
+ nullability[ $art.items ]?
1188
1167
  )?
1189
1168
  )
1190
1169
  requiredSemi // also req after struct/enum
1191
1170
  |
1192
1171
  typeTypeOf[ $art ] elementProperties[ $art ]?
1193
- { this.docComment( $annos ); }
1194
- annotationAssignment_ll1[ $annos ]*
1172
+ { this.docComment( $art ); }
1173
+ annotationAssignment_ll1[ $art ]*
1195
1174
  requiredSemi // also req after foreign key spec
1196
1175
  |
1197
1176
  l=LOCALIZED { $art.localized = this.valueWithTokenLocation( true, $l ); }
1198
1177
  typeRefOptArgs[ $art ]
1199
- { this.docComment( $annos ); }
1200
- annotationAssignment_ll1[ $annos ]*
1178
+ { this.docComment( $art ); }
1179
+ annotationAssignment_ll1[ $art ]*
1201
1180
  ( elementProperties[ $art ]
1202
- { this.docComment( $annos ); }
1203
- annotationAssignment_ll1[ $annos ]*
1181
+ { this.docComment( $art ); }
1182
+ annotationAssignment_ll1[ $art ]*
1204
1183
  )?
1205
1184
  requiredSemi
1206
1185
  |
1207
1186
  typeRefOptArgs[ $art ]
1208
- { this.docComment( $annos ); }
1209
- annotationAssignment_ll1[ $annos ]*
1187
+ { this.docComment( $art ); }
1188
+ annotationAssignment_ll1[ $art ]*
1210
1189
  (
1211
1190
  ENUM '{' { $art.enum = this.createDict(); }
1212
1191
  enumSymbolDef[ $art ]*
1213
- '}' { this.setDictEndLocation( $art.enum ); }
1192
+ '}' { this.finalizeDictOrArray( $art.enum ); }
1214
1193
  elementProperties[ $art ]?
1215
- misplacedAnnotations[ $annos, 'syntax-anno-after-enum' ]?
1216
1194
  |
1217
1195
  elementProperties[ $art ]
1218
- { this.docComment( $annos ); }
1219
- annotationAssignment_ll1[ $annos ]*
1196
+ { this.docComment( $art ); }
1197
+ annotationAssignment_ll1[ $art ]*
1220
1198
  )?
1221
1199
  requiredSemi // also req after enum spec
1222
1200
  )
@@ -1229,65 +1207,45 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1229
1207
  else if ($e.expr)
1230
1208
  $art.value = $e.expr;
1231
1209
  }
1232
- { this.docComment( $annos ); }
1233
- annotationAssignment_ll1[ $annos ]* // for enum symbol def via EXTEND
1210
+ { this.docComment( $art ); }
1211
+ annotationAssignment_ll1[ $art ]* // for enum symbol def via EXTEND
1234
1212
  requiredSemi
1235
1213
  )
1236
1214
  ;
1237
1215
 
1238
- extendElement[ outer, loc, annos ] locals[ art ]
1239
- @after{ /* #ATN 1 */ this.attachLocation($art); }
1216
+ extendElement[ art, outer ]
1217
+ @after{ /* #ATN 1 */ this.attachLocation( $art ); }
1240
1218
  :
1241
1219
  // #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
- '}'
1220
+ ( expected=ELEMENT { $art.expectedKind = 'element'; } )?
1221
+ name=ident['Element']
1222
+ { this.addDef( $art, $outer, 'elements', 'extend', $name.id ); }
1223
+ extendWithOptElements[ $art, $art ]
1260
1224
  ;
1261
1225
 
1262
- selectItemDef[ outer ] locals[ annos = [] ]
1263
- @after{ if ($ctx.art) this.attachLocation($art.art); }
1226
+ selectItemDef[ outer ] locals[ art ]
1227
+ @after{ if ($art) this.attachLocation( $art ); }
1264
1228
  :
1265
1229
  star='*'
1266
1230
  { $outer.push( this.valueWithTokenLocation( '*', $star ) ); }
1267
1231
  |
1268
- { this.docComment( $annos ); }
1269
- annotationAssignment_atn[ $annos ]*
1232
+ { $art = {};; this.docComment( $art ); }
1233
+ annotationAssignment_atn[ $art ]*
1270
1234
  // VIRTUAL is keyword, except if before the following tokens texts:
1271
1235
  { 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
- }
1236
+ ( virtual=VIRTUAL { $art.virtual = this.valueWithTokenLocation( true, $virtual ); } )?
1237
+ ( key=KEY { $art.key = this.valueWithTokenLocation( true, $key ); } )?
1238
+ selectItemDefBody[ $art, $outer ]
1279
1239
  ;
1280
1240
 
1281
- selectItemDefBody[ outer, annos ] returns[ art = {} ]
1282
- @after{ /* #ATN 2 */ this.attachLocation($art); }
1241
+ selectItemDefBody[ art, outer ]
1242
+ @after{ /* #ATN 2 */ }
1283
1243
  :
1244
+ { $outer.push( $art ); }
1284
1245
  (
1285
- e=expression
1246
+ e=expression { $art.value = $e.expr; }
1286
1247
  // we cannot use 'condition' instead, as long as we allow aliases without
1287
1248
  // AS (using rule 'ident' instead of 'identNoKeyword') -> ambiguities
1288
- {
1289
- $art = this.addItem( $outer, null, null, $annos, { value: $e.expr } );
1290
- }
1291
1249
  ( AS n1=ident['Item'] { $art.name = $n1.id }
1292
1250
  | n2=ident['Item'] { $art.name = this.fragileAlias( $n2.id, true ); }
1293
1251
  | { if (this.getCurrentToken().text !== '.') this.classifyImplicitName( 'Item', $e.expr ); }
@@ -1311,13 +1269,12 @@ selectItemDefBody[ outer, annos ] returns[ art = {} ]
1311
1269
  )
1312
1270
  )?
1313
1271
  |
1314
- { $art = this.addItem( $outer, null, null, $annos ); }
1315
1272
  selectItemInlineList[ $art, 'expand' ]
1316
1273
  excludingClause[ $art ]?
1317
1274
  AS n1=ident['Item'] { $art.name = $n1.id }
1318
1275
  )
1319
- { this.docComment( $annos ); }
1320
- annotationAssignment_fix[ $annos ]*
1276
+ { this.docComment( $art ); }
1277
+ annotationAssignment_fix[ $art ]*
1321
1278
  ( ':'
1322
1279
  // #ATN: typeRefOptArgs can start with TYPE, REDIRECTED
1323
1280
  ( re=REDIRECTED to=TO
@@ -1326,15 +1283,15 @@ selectItemDefBody[ outer, annos ] returns[ art = {} ]
1326
1283
  (
1327
1284
  typeAssociationCont[ $art ]
1328
1285
  |
1329
- { this.docComment( $annos ); }
1330
- annotationAssignment_ll1[ $annos ]*
1286
+ { this.docComment( $art ); }
1287
+ annotationAssignment_ll1[ $art ]*
1331
1288
  )
1332
1289
  | typeTypeOf[ $art ]
1333
- { this.docComment( $annos ); }
1334
- annotationAssignment_ll1[ $annos ]*
1335
- | typeRefOptArgs[ $art ] // TODO: annos here?
1336
- { this.docComment( $annos ); }
1337
- annotationAssignment_ll1[ $annos ]*
1290
+ { this.docComment( $art ); }
1291
+ annotationAssignment_ll1[ $art ]*
1292
+ | typeRefOptArgs[ $art ]
1293
+ { this.docComment( $art ); }
1294
+ annotationAssignment_ll1[ $art ]*
1338
1295
  |
1339
1296
  typeAssociationBase[ $art, false ]
1340
1297
  // #ATN: path could start with MANY or ONE - make sure a token follows in same rule!
@@ -1345,28 +1302,39 @@ selectItemDefBody[ outer, annos ] returns[ art = {} ]
1345
1302
  )?
1346
1303
  ;
1347
1304
 
1305
+ bracedSelectItemListDef[ query ]
1306
+ :
1307
+ '{' { $query.columns = this.createArray(); }
1308
+ (
1309
+ selectItemDef[ $query.columns ]
1310
+ ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
1311
+ selectItemDef[ $query.columns ]
1312
+ )*
1313
+ )?
1314
+ '}' { this.finalizeDictOrArray( $query.columns ); }
1315
+ ;
1316
+
1348
1317
  selectItemInlineList[ art, clause ]
1349
1318
  :
1350
- '{'
1351
- { $art[$clause] = []; }
1319
+ '{' { $art[$clause] = this.createArray(); }
1352
1320
  (
1353
1321
  selectItemInlineDef[ $art[$clause] ]
1354
1322
  ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
1355
1323
  selectItemInlineDef[ $art[$clause] ]
1356
1324
  )*
1357
1325
  )?
1358
- '}'
1326
+ '}' { this.finalizeDictOrArray( $art[$clause] ); }
1359
1327
  ;
1360
1328
 
1361
- selectItemInlineDef[ outer ] locals[ annos = [] ]
1362
- @after{ if ($ctx.art) this.attachLocation($art.art); }
1329
+ selectItemInlineDef[ outer ] locals[ art ]
1330
+ @after{ if ($art) this.attachLocation( $art ); }
1363
1331
  :
1364
1332
  star='*'
1365
1333
  { $outer.push( this.valueWithTokenLocation( '*', $star ) ); }
1366
1334
  |
1367
- { this.docComment( $annos ); }
1368
- annotationAssignment_atn[ $annos ]*
1369
- art=selectItemDefBody[ $outer, $annos ]
1335
+ { $art = {};; this.docComment( $art ); }
1336
+ annotationAssignment_atn[ $art ]*
1337
+ selectItemDefBody[ $art, $outer ]
1370
1338
  ;
1371
1339
 
1372
1340
  parameterListDef[ art ]
@@ -1380,51 +1348,22 @@ parameterListDef[ art ]
1380
1348
  parameterDef[ $art ]
1381
1349
  )*
1382
1350
  )?
1383
- ')' { this.setDictEndLocation( $art.params ); }
1351
+ ')' { this.finalizeDictOrArray( $art.params ); }
1384
1352
  ;
1385
1353
 
1386
- parameterDef[ outer ] locals[ art, annos = [] ]
1387
- @after { this.attachLocation($art); }
1354
+ parameterDef[ outer ] locals[ art = {} ]
1355
+ @after { this.attachLocation( $art ); }
1388
1356
  :
1389
- { this.docComment( $annos ); }
1390
- annotationAssignment_ll1[ $annos ]*
1357
+ { this.docComment( $art ); }
1358
+ annotationAssignment_ll1[ $art ]*
1391
1359
  name=ident['Param']
1392
- { $art = this.addDef( $outer, 'params', 'param', $name.id, $annos );
1393
- this.docComment( $annos ); }
1394
- annotationAssignment_fix[ $annos ]*
1360
+ { this.addDef( $art, $outer, 'params', 'param', $name.id );
1361
+ this.docComment( $art ); }
1362
+ annotationAssignment_fix[ $art ]*
1395
1363
  typeSpec[ $art ]
1396
1364
  defaultValue[ $art ]?
1397
- { this.docComment( $annos ); }
1398
- annotationAssignment_ll1[ $annos ]*
1399
- ;
1400
-
1401
- entityParameters[ art ]
1402
- :
1403
- '(' { $art.params = this.createDict(); }
1404
- // also empty param list (we might do some hacking later to allow reserved words)
1405
- // see annotationAssignment_paren
1406
- (
1407
- entityParameterDef[ $art ]
1408
- ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
1409
- entityParameterDef[ $art ]
1410
- )*
1411
- )?
1412
- ')' { this.setDictEndLocation( $art.params ); }
1413
- ;
1414
-
1415
- entityParameterDef[ outer ] locals[ art, annos = [] ]
1416
- @after { this.attachLocation($art); }
1417
- :
1418
- { this.docComment( $annos ); }
1419
- annotationAssignment_ll1[ $annos ]*
1420
- name=ident['Param']
1421
- { $art = this.addDef( $outer, 'params', 'param', $name.id, $annos );
1422
- this.docComment( $annos ); }
1423
- annotationAssignment_fix[ $annos ]*
1424
- typeSpec[ $art ]
1425
- defaultValue[ $art ]?
1426
- { this.docComment( $annos ); }
1427
- annotationAssignment_ll1[ $annos ]*
1365
+ { this.docComment( $art ); }
1366
+ annotationAssignment_ll1[ $art ]*
1428
1367
  ;
1429
1368
 
1430
1369
  nullability[ art ]
@@ -1451,21 +1390,25 @@ elementProperties[ elem ]
1451
1390
 
1452
1391
  // View definitions ----------------------------------------------------------
1453
1392
 
1454
- viewDef[ outer, loc, annos ] locals[ art, name = {} ]
1455
- @after { this.attachLocation($art); }
1393
+ viewDef[ art, outer ] locals[ name = {} ]
1394
+ @after { this.attachLocation( $art ); }
1456
1395
  :
1457
1396
  v=VIEW simplePath[ $name, 'Entity' ]
1458
- { $art = this.addDef( $outer, 'artifacts', 'entity', $name, $annos, { ['$'+'syntax']: 'view' }, $loc );
1459
- this.docComment( $annos ); }
1460
- annotationAssignment_fix[ $annos ]*
1397
+ { $art['$'+'syntax'] = 'view';
1398
+ this.addDef( $art, $outer, 'artifacts', 'entity', $name );
1399
+ this.docComment( $art ); }
1400
+ annotationAssignment_fix[ $art ]*
1461
1401
  (
1462
- entityParameters[ $art ]
1402
+ parameterListDef[ $art ]
1463
1403
  |
1464
- ( HideAlternatives | WITH ) PARAMETERS
1465
- entityParameterDef[ $art ]
1466
- ( ',' entityParameterDef[ $art ] )* // no optional final ',' here
1404
+ // TODO: warning deprecated?
1405
+ ( HideAlternatives | WITH ) { $art.params = this.createDict(); }
1406
+ PARAMETERS
1407
+ parameterDef[ $art ]
1408
+ ( ',' parameterDef[ $art ] )* // no optional final ',' here
1409
+ { this.finalizeDictOrArray( $art.params ); }
1467
1410
  )?
1468
- AS qe=queryExpression { $art.query = $qe.query; } // beta-mode test now in definer
1411
+ AS qe=queryExpression { $art.query = $qe.query; }
1469
1412
  // TODO check ANTLR: bad msg with 'view V as'<eof> but 'view V as FOO' is fine
1470
1413
  requiredSemi
1471
1414
  ;
@@ -1496,12 +1439,12 @@ typeSpec[ art ] // for params
1496
1439
  (
1497
1440
  ENUM '{' { $art.enum = this.createDict(); }
1498
1441
  enumSymbolDef[ $art ]*
1499
- '}' { this.setDictEndLocation( $art.enum ); }
1442
+ '}' { this.finalizeDictOrArray( $art.enum ); }
1500
1443
  )?
1501
1444
  )
1502
1445
  ;
1503
1446
 
1504
- returnTypeSpec[ art, annos ]
1447
+ returnTypeSpec[ art ]
1505
1448
  @after{ /* #ATN 1 */ }
1506
1449
  :
1507
1450
  ret=RETURNS { $art.returns = { location: this.tokenLocation( $ret ), kind: 'param' }; }
@@ -1517,17 +1460,15 @@ returnTypeSpec[ art, annos ]
1517
1460
  (
1518
1461
  ENUM '{' { $art.returns.enum = this.createDict(); }
1519
1462
  enumSymbolDef[ $art.returns ]*
1520
- '}' { this.setDictEndLocation( $art.returns.enum ); }
1521
- |
1522
- misplacedAnnotations[ $annos, 'syntax-anno-after-params' ]
1463
+ '}' { this.finalizeDictOrArray( $art.returns.enum ); }
1523
1464
  )?
1524
1465
  )
1525
1466
 
1526
- requiredSemi // currently for all - might change if we get rid of the misplaced annos
1467
+ requiredSemi // currently for all - might change if we get rid of the misplaced annos (TODO: Now removed)
1527
1468
  ;
1528
1469
 
1529
1470
 
1530
- typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1471
+ typeSpecSemi[ art ] // with 'includes', for type and annotation defs
1531
1472
  @after{ /* #ATN 3 */ }
1532
1473
  :
1533
1474
  typeStruct[ $art ]
@@ -1565,18 +1506,28 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1565
1506
  optionalSemi
1566
1507
  | typeTypeOf[ $art.items ]
1567
1508
  nullability[ $art.items ]?
1568
- { this.docComment( $annos ); }
1569
- annotationAssignment_ll1[ $annos ]*
1509
+ { this.docComment( $art ); }
1510
+ annotationAssignment_ll1[ $art ]*
1570
1511
  requiredSemi
1571
1512
  | typeRefOptArgs[ $art.items ]
1572
- nullability[ $art.items ]?
1573
- { this.docComment( $annos ); }
1574
- annotationAssignment_ll1[ $annos ]*
1513
+ nullability[ $art.items ]? // only if not followed by `enum`
1514
+ { this.docComment( $art ); }
1515
+ annotationAssignment_ll1[ $art ]*
1575
1516
  (
1517
+ { if ($art.items.notNull) {
1518
+ this.message( 'syntax-unexpected-null', $art.items.notNull.location,
1519
+ { keyword: $art.items.notNull.val ? 'not null' : 'null' } );
1520
+ }
1521
+ }
1576
1522
  ENUM '{' { $art.items.enum = this.createDict(); }
1577
1523
  enumSymbolDef[ $art.items ]*
1578
- '}' { this.setDictEndLocation( $art.items.enum ); }
1579
- optionalSemi
1524
+ '}' { this.finalizeDictOrArray( $art.items.enum ); }
1525
+ (
1526
+ nullability[ $art.items ]
1527
+ requiredSemi
1528
+ |
1529
+ optionalSemi
1530
+ )
1580
1531
  |
1581
1532
  requiredSemi
1582
1533
  )
@@ -1584,64 +1535,32 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1584
1535
  |
1585
1536
  typeTypeOf[ $art ]
1586
1537
  defaultValue[ $art ]?
1587
- { this.docComment( $annos ); }
1588
- annotationAssignment_ll1[ $annos ]* requiredSemi
1538
+ { this.docComment( $art ); }
1539
+ annotationAssignment_ll1[ $art ]* requiredSemi
1589
1540
  |
1590
1541
  l=LOCALIZED { $art.localized = this.valueWithTokenLocation( true, $l ); }
1591
1542
  typeRefOptArgs[ $art ]
1592
1543
  defaultValue[ $art ]?
1593
- { this.docComment( $annos ); }
1594
- annotationAssignment_ll1[ $annos ]*
1544
+ { this.docComment( $art ); }
1545
+ annotationAssignment_ll1[ $art ]*
1595
1546
  requiredSemi
1596
1547
  |
1597
1548
  // alt lookahead includes MANY '{'
1598
1549
  { $art.type = {}; }
1550
+ // Can't use typeRefOptArgs because of clash with include rule below (ATN would change)
1599
1551
  simplePath[ $art.type, 'artref' ]
1600
1552
  (
1601
- typeRefArgs[ $art ]
1602
- { this.docComment( $annos ); }
1603
- annotationAssignment_ll1[ $annos ]*
1604
- (
1605
- ENUM '{' { $art.enum = this.createDict(); }
1606
- enumSymbolDef[ $art ]*
1607
- '}' { this.setDictEndLocation( $art.enum ); }
1608
- (
1609
- optionalSemi
1610
- |
1611
- defaultValue[ $art ]
1612
- requiredSemi
1613
- )
1614
- |
1615
- defaultValue[ $art ]?
1616
- requiredSemi
1617
- )
1618
- |
1619
- ':' // with element, e.g. `type T : E:elem enum { ... }`
1620
- { $art.type.scope = $art.type.path.length; }
1621
- simplePath[ $art.type, 'ref']
1622
- { this.docComment( $annos ); }
1623
- annotationAssignment_ll1[ $annos ]*
1624
- (
1625
- ENUM '{' { $art.enum = this.createDict(); }
1626
- enumSymbolDef[ $art ]*
1627
- '}' { this.setDictEndLocation( $art.enum ); }
1628
- (
1629
- optionalSemi
1630
- |
1631
- defaultValue[ $art ]
1632
- requiredSemi
1633
- )
1634
- |
1635
- defaultValue[ $art ]?
1636
- requiredSemi
1637
- )
1638
- |
1639
- { this.docComment( $annos ); }
1640
- annotationAssignment_ll1[ $annos ]*
1553
+ ( typeRefArgs[ $art ]
1554
+ | ':' // with element, e.g. `type T : E:elem enum { ... }`
1555
+ { $art.type.scope = $art.type.path.length; }
1556
+ simplePath[ $art.type, 'ref']
1557
+ )?
1558
+ { this.docComment( $art ); }
1559
+ annotationAssignment_ll1[ $art ]*
1641
1560
  (
1642
1561
  ENUM '{' { $art.enum = this.createDict(); }
1643
1562
  enumSymbolDef[ $art ]*
1644
- '}' { this.setDictEndLocation( $art.enum ); }
1563
+ '}' { this.finalizeDictOrArray( $art.enum ); }
1645
1564
  (
1646
1565
  optionalSemi
1647
1566
  |
@@ -1669,7 +1588,7 @@ typeStruct[ art, attachLoc = false ]
1669
1588
  :
1670
1589
  '{' { $art.elements = this.createDict(); }
1671
1590
  elementDef[ $art ]*
1672
- '}' { this.setDictEndLocation( $art.elements ); }
1591
+ '}' { this.finalizeDictOrArray( $art.elements ); }
1673
1592
  ;
1674
1593
 
1675
1594
  typeCompoStruct[ art ]
@@ -1677,7 +1596,7 @@ typeCompoStruct[ art ]
1677
1596
  :
1678
1597
  COMPOSITIONofBRACE { $art.elements = this.createDict(); }
1679
1598
  elementDef[ $art ]*
1680
- '}' { this.setDictEndLocation( $art.elements ); }
1599
+ '}' { this.finalizeDictOrArray( $art.elements ); }
1681
1600
  ;
1682
1601
 
1683
1602
  typeArray[ art ]
@@ -1699,7 +1618,7 @@ typeArray[ art ]
1699
1618
  (
1700
1619
  ENUM '{' { $art.items.enum = this.createDict(); }
1701
1620
  enumSymbolDef[ $art.items ]*
1702
- '}' { this.setDictEndLocation( $art.items.enum ); }
1621
+ '}' { this.finalizeDictOrArray( $art.items.enum ); }
1703
1622
  )?
1704
1623
  )
1705
1624
  ;
@@ -1728,33 +1647,31 @@ typeAssociationCont[ art ]
1728
1647
  :
1729
1648
  (
1730
1649
  '{' { $art.foreignKeys = this.createDict(); }
1731
- { this.addDef( $art, 'foreignKeys' ); }
1732
1650
  (
1733
1651
  foreignKey[ $art ]
1734
1652
  ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
1735
1653
  foreignKey[ $art ]
1736
1654
  )*
1737
1655
  )?
1738
- '}' { this.setDictEndLocation( $art.foreignKeys ); }
1656
+ '}' { this.finalizeDictOrArray( $art.foreignKeys ); }
1739
1657
  |
1740
1658
  ON cond=condition
1741
1659
  { $art.on=$cond.cond; }
1742
1660
  )
1743
1661
  ;
1744
1662
 
1745
- typeAssociationElementCont[ art, annos ] // including Composition
1663
+ typeAssociationElementCont[ art ] // including Composition
1746
1664
  // optional NULL / NOT NULL for managed association only
1747
1665
  :
1748
1666
  (
1749
1667
  '{' { $art.foreignKeys = this.createDict(); }
1750
- { this.addDef( $art, 'foreignKeys' ); }
1751
1668
  (
1752
1669
  foreignKey[ $art ]
1753
1670
  ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
1754
1671
  foreignKey[ $art ]
1755
1672
  )*
1756
1673
  )?
1757
- '}' { this.setDictEndLocation( $art.foreignKeys ); }
1674
+ '}' { this.finalizeDictOrArray( $art.foreignKeys ); }
1758
1675
  nullability[ $art ]?
1759
1676
  |
1760
1677
  ON cond=condition
@@ -1762,8 +1679,8 @@ typeAssociationElementCont[ art, annos ] // including Composition
1762
1679
  |
1763
1680
  nullability[ $art ]
1764
1681
  )?
1765
- { this.docComment( $annos ); }
1766
- annotationAssignment_ll1[ $annos ]*
1682
+ { this.docComment( $art ); }
1683
+ annotationAssignment_ll1[ $art ]*
1767
1684
  requiredSemi // also req after foreign key spec
1768
1685
  ;
1769
1686
 
@@ -1817,10 +1734,9 @@ cardinality[ art ] locals[ card = {} ]
1817
1734
  foreignKey[ outer ] locals[ art = {}, elem = {} ]
1818
1735
  @after { this.attachLocation($art); }
1819
1736
  :
1820
- simplePath[ $elem, 'ref' ]
1737
+ simplePath[ $elem, 'ref' ] { $art.targetElement = $elem; }
1821
1738
  ( AS name=ident['Key'] )?
1822
- { $art = this.addDef( $outer, 'foreignKeys', 'key', ($ctx.name) ? $name.id : $elem.path,
1823
- undefined, { targetElement: $elem } ); }
1739
+ { this.addDef( $art, $outer, 'foreignKeys', 'key', ($ctx.name) ? $name.id : $elem.path ); }
1824
1740
  ;
1825
1741
 
1826
1742
  typeTypeOf[ art ] locals[ _sync = 'nop' ]
@@ -1852,11 +1768,11 @@ typeRefOptArgs[ art ]
1852
1768
 
1853
1769
  typeRefArgs[ art ]
1854
1770
  :
1855
- paren='('
1771
+ paren='(' { $art['$'+'typeArgs'] = this.createArray(); }
1856
1772
  (
1857
1773
  // unnamed arguments
1858
1774
  head=Number
1859
- { $art['$'+'typeArgs'] = [ this.numberLiteral( $head ) ]; }
1775
+ { $art['$'+'typeArgs'].push( this.numberLiteral( $head ) ); }
1860
1776
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
1861
1777
  (
1862
1778
  v=VARIABLE
@@ -1880,14 +1796,14 @@ typeRefArgs[ art ]
1880
1796
  typeNamedArg[ $art ]
1881
1797
  )*
1882
1798
  )
1883
- ')'
1799
+ ')'{ this.finalizeDictOrArray( $art['$'+'typeArgs']); }
1884
1800
  ;
1885
1801
 
1886
1802
  typeNamedArg[ art ] locals[ arg = '' ]
1887
1803
  :
1888
1804
  name=ident['paramname']
1889
1805
  ':'
1890
- { if (this.checkTypeFacet( $art, $name.id ))
1806
+ { if ($name.id && this.checkTypeFacet( $art, $name.id ))
1891
1807
  $arg = $name.id.id;
1892
1808
  }
1893
1809
  (
@@ -1924,10 +1840,10 @@ queryExpression returns[ query ] // QLSubqueryComplex, SubqueryComplex
1924
1840
  | op=MINUS q=DISTINCT?
1925
1841
  )
1926
1842
  qt=queryTerm
1927
- { $query = this.leftAssocBinaryOp( $query, $op, $q, $qt.query );; $ctx.q = null; }
1843
+ { if ($qt.query) $query = this.leftAssocBinaryOp( $query, $op, $q, $qt.query );; $ctx.q = null; }
1928
1844
  )*
1929
- ( ob=orderByClause[ $query ] { $query = $ob.query; } ) ?
1930
- ( lc=limitClause[ $query ] { $query = $lc.query; } ) ?
1845
+ ( ob=orderByClause[ $query ] { if ($ob.query) $query = $ob.query; } ) ?
1846
+ ( lc=limitClause[ $query ] { if ($lc.query) $query = $lc.query; } ) ?
1931
1847
  ;
1932
1848
 
1933
1849
  orderByClause[ inQuery ] returns [ query ]
@@ -2026,7 +1942,7 @@ overClause returns [ over ]
2026
1942
  @after { this.attachLocation( $over ); }
2027
1943
  :
2028
1944
  o=OVER { $over = { op: this.valueWithTokenLocation( 'over', $o ) , args: [] } }
2029
- '('
1945
+ '(' // TODO: check whether an extra location could be useful
2030
1946
  ( pb=partitionByClause { $over.args.push( $pb.expr ); } )?
2031
1947
  ( ob=overOrderByClause { $over.args.push( $ob.expr ); } )?
2032
1948
  ( wf=windowFrameClause { $over.args.push( $wf.wf ); } )?
@@ -2079,13 +1995,13 @@ queryPrimary returns[ query = {} ]
2079
1995
  (
2080
1996
  mixin=MIXIN '{' { $query.mixin = this.createDict(); }
2081
1997
  mixinElementDef[ $query ]*
2082
- '}' { this.setDictEndLocation( $query.mixin ); }
1998
+ '}' { this.finalizeDictOrArray( $query.mixin ); }
2083
1999
  INTO
2084
2000
  )?
2085
2001
  ( ad=( ALL | DISTINCT ) // TODO: or directly after SELECT ?
2086
2002
  { $query.quantifier = this.valueWithTokenLocation( $ad.text.toLowerCase(), $ad ); }
2087
2003
  )?
2088
- bracedSelectItemListDef[ $query ]?
2004
+ bracedSelectItemListDef[ $query, 'columns' ]?
2089
2005
  excludingClause[ $query ]?
2090
2006
  |
2091
2007
  ( ad=( ALL | DISTINCT ) // TODO: or directly after SELECT ?
@@ -2131,7 +2047,7 @@ tableExpression returns[ table ] // TableOrJoin
2131
2047
  ON cond=condition { $table.on = $cond.cond; }
2132
2048
  |
2133
2049
  crj=CROSS jn=JOIN tt=tableTerm
2134
- { $table = this.leftAssocBinaryOp( $table, $jn, $crj, $tt.table, 'join' ); }
2050
+ { if (!$table) { $table = {}; } $table = this.leftAssocBinaryOp( $table, $jn, $crj, $tt.table, 'join' ); }
2135
2051
  )*
2136
2052
  ;
2137
2053
 
@@ -2313,9 +2229,11 @@ conditionTerm returns [ cond ]
2313
2229
  |
2314
2230
  { $cond = { args: [ $expr.expr ] }; }
2315
2231
  NOT predicate[ $cond, true ]
2232
+ { if (!$cond.op) $cond = null; } // predicate failed to parse, avoid subseqential errors
2316
2233
  |
2317
2234
  { $cond = { args: [ $expr.expr ] }; }
2318
2235
  predicate[ $cond, false ]
2236
+ { if (!$cond.op) $cond = null; } // predicate failed to parse, avoid subseqential errors
2319
2237
  )? // optional: for conditions in parentheses
2320
2238
  ;
2321
2239
 
@@ -2429,7 +2347,9 @@ expressionTerm returns [ expr ] locals [ op, args = [] ]
2429
2347
  }
2430
2348
  )
2431
2349
  |
2432
- qm=( HideAlternatives | '?' )
2350
+ qm= '?' // is automatically not mentioned as CC candidate
2351
+ // if we have an HideAlternatives here, we would block it to use it in
2352
+ // parallel to an expression (would produce adaptivePredict() otherwise)
2433
2353
  { $expr = { param: this.valueWithTokenLocation( '?', $qm ), scope: 'param' };
2434
2354
  this.csnParseOnly( 'Dynamic parameter "?" is not supported', $qm );
2435
2355
  }
@@ -2457,39 +2377,12 @@ expressionTerm returns [ expr ] locals [ op, args = [] ]
2457
2377
  ;
2458
2378
 
2459
2379
  specialFunction returns [ ret = { } ] locals[ art = {} ]
2460
- @after{ /* #ATN 1 */ }
2461
2380
  :
2462
- fun=TRIM open='('
2463
- { $ret = this.functionAst( $fun, $open ); }
2464
- // #ATN: we do not want to reserve these three optional keywords
2465
- (
2466
- t=( LEADING | TRAILING | BOTH ) { $ret.args[0].args.push( $t.text ); }
2467
- ( e=expression { $ret.args[0].args.push( $e.expr ); } )?
2468
- t=FROM e=expression { $ret.args[0].args.push( $t.text, $e.expr ); }
2469
- |
2470
- e=expression
2471
- (
2472
- { $ret.args[0].args.push( $e.expr ); }
2473
- t=FROM e=expression
2474
- { $ret.args[0].args.push( $t.text, $e.expr ); }
2475
- |
2476
- { $ret.args[0] = $e.expr; }
2477
- )
2478
- )
2479
- ')'
2480
- |
2481
- fun=EXTRACT open='('
2482
- { $ret = this.functionAst( $fun, $open ); }
2483
- t=( YEAR | MONTH | DAY | HOUR | MINUTE | SECOND )
2484
- f=FROM e=expression
2485
- { $ret.args[0].args.push( $t.text, $f.text, $e.expr ); }
2486
- ')'
2487
- |
2488
- ca=CAST open='('
2381
+ ca=CAST '(' // see createArray() in action
2489
2382
  {
2490
2383
  $ret = {
2491
2384
  op: this.valueWithTokenLocation( 'cast', $ca ),
2492
- args: [ ],
2385
+ args: this.createArray(),
2493
2386
  location: this.tokenLocation( $ca )
2494
2387
  };
2495
2388
  }
@@ -2497,8 +2390,7 @@ specialFunction returns [ ret = { } ] locals[ art = {} ]
2497
2390
  {
2498
2391
  $ret.args.push( $e.expr );
2499
2392
  }
2500
- ')'
2501
- // TODO: ROUND - see also resolver.js
2393
+ ')' { this.finalizeDictOrArray( $ret.args ); }
2502
2394
  ;
2503
2395
 
2504
2396
  // query path includes aggregation:
@@ -2524,36 +2416,52 @@ valuePath[ category, location = null ] returns[ qp = { path: [] } ] locals[ _syn
2524
2416
  ;
2525
2417
 
2526
2418
  fromArguments[ pathStep ]
2419
+ @init{ if (!$pathStep) $pathStep = {}; } // grammar robustness, see test/negative/parser/NamedExpression.cds
2527
2420
  :
2528
- paren='('
2529
- namedExpression[ $pathStep ]
2421
+ '(' { $pathStep.args = this.createDict(); $pathStep['$'+'syntax'] = ':'; } // necessary?
2422
+ name=ident['paramname'] ':'
2423
+ namedExpression[ $pathStep, $name.id ]
2530
2424
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
2531
- namedExpression[ $pathStep ]
2425
+ name=ident['paramname'] ':'
2426
+ namedExpression[ $pathStep, $name.id ]
2532
2427
  )*
2533
- ')'
2428
+ ')' { this.finalizeDictOrArray( $pathStep.args ); }
2534
2429
  ;
2535
2430
 
2536
2431
  pathArguments[ pathStep, considerSpecial ]
2537
- @after{ /* #ATN 1 */ }
2432
+ @init{
2433
+ if (!$pathStep) $pathStep = {}; // grammar robustness, see test/negative/parser/NamedExpression.cds
2434
+ this.genericFunctionsStack.push( this['$'+'genericKeywords'] );
2435
+ }
2538
2436
  :
2539
2437
  { this.excludeExpected([ 'ORDER' ]); }
2540
- paren='('
2541
- { this.prepareGenericKeywords( $considerSpecial ); }
2542
- // ATN, LL2: Identifier can start both named arguments and the positional.
2438
+ '(' // dict or array, see below
2543
2439
  // Make sure that we do not introduce A:B paths in expressions!
2544
- (
2545
- namedExpression[ $pathStep ]
2440
+ // Need to avoid adaptPredict(), otherwise Generic keywords won't work in funcExpression
2441
+ //
2442
+ // For code completion, we need to handle generic tokens directly after the
2443
+ // '('. To avoid invalidating an assoc `trim` to an entity with parameter
2444
+ // `leading` (ok, a bit constructed), we do not do it with named parameters.
2445
+ { if (!this.setLocalTokenForId( { ':': 'HelperToken1', '=>': 'HelperToken2' } ))
2446
+ this.prepareGenericKeywords( $considerSpecial ); }
2447
+ (
2448
+ { $pathStep.args = this.createDict(); $pathStep['$'+'syntax'] = ':'; }
2449
+ id=HelperToken1 ':'
2450
+ namedExpression[ $pathStep, this.identAst( $id, 'paramname', true ) ]
2546
2451
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
2547
- namedExpression[ $pathStep ]
2452
+ name=ident['paramname'] ':'
2453
+ namedExpression[ $pathStep, $name.id ]
2548
2454
  )*
2549
2455
  |
2550
- { $pathStep.args = Object.create(null); } // TODO: XSN func path cleanup
2551
- arrowedExpression[ $pathStep ]
2456
+ { $pathStep.args = this.createDict(); } // TODO: XSN func path cleanup
2457
+ id=HelperToken2 '=>'
2458
+ namedExpression[ $pathStep, this.identAst( $id, 'paramname', true ) ]
2552
2459
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
2553
- arrowedExpression[ $pathStep ]
2460
+ name=ident['paramname'] '=>'
2461
+ namedExpression[ $pathStep, $name.id ]
2554
2462
  )*
2555
2463
  |
2556
- { $pathStep.args = []; }
2464
+ { $pathStep.args = this.createArray(); }
2557
2465
  funcExpression[ $pathStep, $considerSpecial ]
2558
2466
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
2559
2467
  funcExpression[ $pathStep, $considerSpecial ]
@@ -2566,47 +2474,82 @@ pathArguments[ pathStep, considerSpecial ]
2566
2474
  }
2567
2475
  )?
2568
2476
  |
2569
- a=ALL { $pathStep.quantifier = this.valueWithTokenLocation( 'all', $a ); }
2570
- e1=expression { $pathStep.args = [ $e1.expr ]; }
2571
- |
2572
- d=DISTINCT { $pathStep.quantifier = this.valueWithTokenLocation( 'distinct', $d ); }
2573
- e1=expression { $pathStep.args = [ $e1.expr ]; }
2574
- ( ',' e2=expression { $pathStep.args.push( $e2.expr ); } )*
2575
- |
2576
- star='*'
2577
- { $pathStep.args = [ { location: this.tokenLocation( $star ), val: '*', literal: 'token' } ]; }
2578
- |
2579
- { $pathStep.args = []; }
2477
+ { $pathStep.args = this.createArray(); }
2580
2478
  )
2581
- ')'
2479
+ ')' { this.finalizeDictOrArray( $pathStep.args ); }
2582
2480
  ;
2481
+ finally { // see @init
2482
+ if (!$pathStep.args) $pathStep.args = [];
2483
+ this['$'+'genericKeywords'] = this.genericFunctionsStack.pop();
2484
+ }
2583
2485
 
2584
- namedExpression[ pathStep ]
2486
+ namedExpression[ pathStep, id ]
2585
2487
  :
2586
- name=ident['paramname'] ':' elem=expression
2587
- { if ($pathStep && $name.id) {
2588
- this.addDef( $pathStep, 'args', 0, $name.id, true,
2589
- ($ctx.elem) ? $elem.expr : { location: $name.id.location } );
2590
- $pathStep['$'+'syntax'] = ':';
2488
+ elem=expression
2489
+ { if ($pathStep && $id) {
2490
+ this.addDef( ($ctx.elem) ? $elem.expr : { location: $id.location },
2491
+ $pathStep, 'args', 0, $id );
2591
2492
  }
2592
2493
  }
2593
2494
  ;
2594
2495
 
2595
- arrowedExpression[ pathStep ]
2596
- :
2597
- name=ident['paramname'] a='=>' elem=expression
2598
- { if ($name.id) this.addDef( $pathStep, 'args', 0, $name.id, true,
2599
- ($ctx.elem) ? $elem.expr : { location: $name.id.location } ); }
2600
- ;
2601
-
2602
- funcExpression[ pathStep, considerSpecial ]
2496
+ funcExpression[ pathStep, considerSpecial ] locals[ args ]
2603
2497
  @init { this.prepareGenericKeywords( $considerSpecial ); }
2604
2498
  :
2605
- only=GenericArgFull
2606
- { $pathStep.args.push( { location: this.tokenLocation($only), val: $only.text, literal: 'token' } ); }
2607
- |
2608
- expr=expression
2609
- { $pathStep.args.push( $expr.expr ); }
2499
+ (
2500
+ expr=expression
2501
+ { $pathStep.args.push( $expr.expr ); }
2502
+ |
2503
+ GenericExpr // keyword as replacement for expression, like '*'
2504
+ { $pathStep.args.push( this.xprToken() ); }
2505
+ |
2506
+ GenericIntro // keyword as introduction of expression, like DISTINCT
2507
+ { $pathStep.args.push( this.xprToken() ); }
2508
+ expr=expression
2509
+ { $args = this.setLastAsXpr( $pathStep.args );
2510
+ $args.push( $expr.expr ); }
2511
+ |
2512
+ // Rule 'pathArguments' makes a decision based on the first two lookahead
2513
+ // tokens of this rule → we need to list tokens which would be changed to
2514
+ // GenericExpr or GenericIntro, and are not already covered by 'expression'
2515
+ { this.reportErrorForGenericKeyword(); }
2516
+ ( HideAlternatives | '*' | ALL | DISTINCT )
2517
+ // now continue parsing like GenericExpr:
2518
+ { $pathStep.args.push( this.xprToken() ); }
2519
+ )
2520
+ (
2521
+ { if (!$args) $args = this.setLastAsXpr( $pathStep.args ); }
2522
+ (
2523
+ { this.prepareGenericKeywords( $considerSpecial, 'separator' ); }
2524
+ (
2525
+ GenericSeparator
2526
+ |
2527
+ // For ANTLR's lookahead calculations, we need to list tokens here
2528
+ // which could be changed to GenericSeparator. Do not invent a
2529
+ // keyword token which is just used here (Identifier does work
2530
+ // perfectly)! If we want, we could add all non-reserved keywords
2531
+ // except ORDER, and most reserved.
2532
+ { this.reportErrorForGenericKeyword(); }
2533
+ ( HideAlternatives | Identifier | FROM | IN | WITH | GROUP )
2534
+ )
2535
+ { $args.push( this.xprToken() );
2536
+ this.prepareGenericKeywords( $considerSpecial, 'expr' );
2537
+ }
2538
+ (
2539
+ expr=expression
2540
+ { $args.push( $expr.expr ); }
2541
+ |
2542
+ GenericExpr
2543
+ { $args.push( this.xprToken() ); }
2544
+ |
2545
+ { this.reportErrorForGenericKeyword(); }
2546
+ // Again, we need to list tokens which could make it to GenericExpr
2547
+ // and which do not start an expression
2548
+ ( HideAlternatives | ALL )
2549
+ { $args.push( this.xprToken() ); }
2550
+ )
2551
+ )+
2552
+ )?
2610
2553
  ;
2611
2554
 
2612
2555
  cardinalityAndFilter[ pathStep ] locals [ _sync = 'nop' ]
@@ -2648,32 +2591,41 @@ optionalWhereForFilter
2648
2591
 
2649
2592
  // Simple paths and values ---------------------------------------------------
2650
2593
 
2651
- annoValueBase returns[ val ] locals [ seenEllipsis = false ]
2652
- @after { this.attachLocation($val); }
2594
+ annoValue[ assignment ]
2653
2595
  :
2654
- { $val = { literal: 'struct', location: this.startLocation() }; }
2655
- '{'
2656
- { this.meltKeywordToIdentifier(); }
2657
- namedValue[ $val ]
2596
+ base=annoValueBase[ $assignment ]
2597
+ |
2598
+ // no docComment() here
2599
+ // this alternative is done with token rewrite in rule "annotationAssignment_atn"
2600
+ at='@'? annotationPath[ $assignment, 'ref', $at ]
2601
+ annotationPathVariant[ $assignment ]?
2602
+ ;
2603
+
2604
+ annoValueBase[ assignment ] locals [ seenEllipsis = false ]
2605
+ @after { this.attachLocation( $assignment ); }
2606
+ :
2607
+ '{' // no location here, we flatten
2608
+ { $assignment['$'+'flatten'] = []; this.meltKeywordToIdentifier(); }
2609
+ flattenedValue[ $assignment ]
2658
2610
  (
2659
2611
  ',' {
2660
2612
  this.meltKeywordToIdentifier();
2661
2613
  if (this.isStraightBefore("}")) break; // allow ',' before ')'
2662
2614
  }
2663
- namedValue[ $val ]
2615
+ flattenedValue[ $assignment ]
2664
2616
  )*
2665
2617
  '}'
2666
2618
  |
2667
- { $val = { literal: 'array', location: this.startLocation(), val: [] }; }
2668
- '['
2619
+ '[' // no need for createArray() here, $assignment.location is set
2620
+ { $assignment.val = []; $assignment.literal = 'array'; }
2669
2621
  (
2670
2622
  (
2671
- head=arrayValue { $val.val.push( $head.val ); }
2623
+ head=annoSubValue { $assignment.val.push( $head.val ); }
2672
2624
  |
2673
- e='...' ( UP TO upTo=arrayValue )?
2625
+ e='...' ( UP TO upTo=annoSubValue )?
2674
2626
  {{
2675
2627
  const item = { literal: 'token', val: '...', location: this.tokenLocation($e) };
2676
- $val.val.push( item );
2628
+ $assignment.val.push( item );
2677
2629
  if ($ctx.upTo) item.upTo = $upTo.val;
2678
2630
  $seenEllipsis = !$ctx.upTo || 'upTo';
2679
2631
  }}
@@ -2681,17 +2633,16 @@ annoValueBase returns[ val ] locals [ seenEllipsis = false ]
2681
2633
  (
2682
2634
  ',' { if (this.isStraightBefore(']')) break; } // allow ',' before ']'
2683
2635
  (
2684
- tail=arrayValue { $val.val.push( $tail.val ); }
2636
+ tail=annoSubValue { $assignment.val.push( $tail.val ); }
2685
2637
  |
2686
2638
  { $ctx.upTo = null; } // is not reset
2687
- e='...' ( UP TO upTo=arrayValue )?
2639
+ e='...' ( UP TO upTo=annoSubValue )?
2688
2640
  {{
2689
2641
  const item = { literal: 'token', val: '...', location: this.tokenLocation($e) };
2690
2642
  if ($ctx.upTo) item.upTo = $upTo.val;
2691
- $val.val.push( item );
2643
+ $assignment.val.push( item );
2692
2644
  if ($seenEllipsis === true) // TODO: adapt msg to UP TO
2693
- this.error( 'syntax-unexpected-ellipsis', $e, { code: '...' },
2694
- 'Expected no more than one $(CODE)' );
2645
+ this.error( 'syntax-unexpected-ellipsis', $e, { '#': 'std', code: '...' } );
2695
2646
  else
2696
2647
  $seenEllipsis = !$ctx.upTo || 'upTo';
2697
2648
  }}
@@ -2706,80 +2657,65 @@ annoValueBase returns[ val ] locals [ seenEllipsis = false ]
2706
2657
  'Expecting an array item $(NEWCODE) after an item with $(CODE)' );
2707
2658
  }
2708
2659
  |
2709
- v1=literalValue { $val = $v1.val; }
2660
+ v1=literalValue { Object.assign( $assignment, $v1.val ); }
2710
2661
  |
2711
2662
  ( plus='+' | min='-' ) num=Number
2712
- { $val = this.numberLiteral( $num, $plus||$min ); }
2663
+ { Object.assign( $assignment, this.numberLiteral( $num, $plus||$min ) ); }
2713
2664
  ;
2714
2665
 
2715
- annoValue returns[ val ]
2666
+ flattenedValue[ assignment ] locals[ val = { name: {} } ]
2716
2667
  :
2717
- base=annoValueBase { $val = $base.val }
2718
- |
2719
- { $val = {}; } // TODO: think about expression value representation
2720
- at='@'? annotationPath[ $val, 'ref', $at ]
2721
- annotationPathVariant[ $val ]?
2722
- ;
2723
-
2724
- namedValue[ struct ] locals[ namedVal = { name: {} } ]
2725
- :
2726
- at='@'? annotationPath[ $namedVal.name, 'name', $at ]
2727
- (
2728
- '#' { this.meltKeywordToIdentifier(); }
2729
- variant=ident['variant'] { $namedVal.name.variant = $variant.id; }
2730
- )?
2668
+ at='@'? annotationPath[ $val.name, 'name', $at ]
2669
+ ( annotationPathVariant[ $val.name ] )?
2731
2670
  (
2732
2671
  ':' { this.meltKeywordToIdentifier(true); } // allow path as anno value start with reserved
2733
- elem=annoValue
2672
+ annoValue[ $val ]
2734
2673
  )?
2735
- { this.addItem( $struct, '_struct', null, true, // TODO: re-check _struct
2736
- ($ctx.elem) ? Object.assign($namedVal, $elem.val) : $namedVal ); }
2674
+ { $assignment['$'+'flatten'].push( $val ); }
2737
2675
  ;
2738
2676
 
2739
- arrayValue returns[ val ]
2677
+ namedValue[ struct ] locals[ val = { name: {} } ]
2678
+ :
2679
+ at='@'? annotationPath[ $val.name, 'name', $at ]
2680
+ ( ':' sub=annoSubValue { Object.assign( $val, $sub.val ); } )?
2681
+ {
2682
+ if (!$val.location) $val.location = $val.name.location;
2683
+ this.addDef( $val, $struct, 'struct', null, $val.name ); // TODO: re-check name
2684
+ }
2685
+ ;
2686
+
2687
+ annoSubValue returns[ val = {} ]
2740
2688
  @after { this.attachLocation($val); }
2741
2689
  :
2742
- { $val = { literal: 'struct', location: this.startLocation() }; }
2743
- '{'
2690
+ '{' // no need for createDict() here, $val.location is set
2691
+ { $val.struct = Object.create(null); $val.literal = 'struct'; }
2744
2692
  { this.meltKeywordToIdentifier(); }
2745
- namedValueInArray[ $val ]
2693
+ namedValue[ $val ]
2746
2694
  ( ','
2747
2695
  {
2748
2696
  this.meltKeywordToIdentifier();
2749
2697
  if (this.isStraightBefore("}")) break; // allow ',' before '}'
2750
2698
  }
2751
- namedValueInArray[ $val ]
2699
+ namedValue[ $val ]
2752
2700
  )*
2753
2701
  '}'
2754
2702
  |
2755
- { $val = { literal: 'array', location: this.startLocation(), val: [] }; }
2756
- '['
2757
- ( head=arrayValue { $val.val.push( $head.val ); }
2703
+ '[' // no need for createArray() here, $val.location is set
2704
+ { $val.val = []; $val.literal = 'array'; }
2705
+ ( head=annoSubValue { $val.val.push( $head.val ); }
2758
2706
  ( ',' { if (this.isStraightBefore(']')) break; } // allow ',' before ']'
2759
- tail=arrayValue { $val.val.push( $tail.val ); }
2707
+ tail=annoSubValue { $val.val.push( $tail.val ); }
2760
2708
  )*
2761
2709
  )?
2762
2710
  ']'
2763
2711
  |
2764
- v1=literalValue { $val = $v1.val; }
2712
+ v1=literalValue { Object.assign( $val, $v1.val ); }
2765
2713
  |
2766
2714
  ( plus='+' | min='-' ) num=Number
2767
- { $val = this.numberLiteral( $num, $plus||$min ); }
2715
+ { Object.assign( $val, this.numberLiteral( $num, $plus||$min ) ); }
2768
2716
  |
2769
- { $val = {}; } // TODO: think about expression value representation
2770
2717
  at='@'? annotationPath[ $val, 'ref', $at ]
2771
- (
2772
- '#' { this.meltKeywordToIdentifier(); }
2773
- variant=ident['variant'] { $val.variant = $variant.id; }
2774
- )?
2775
- ;
2776
-
2777
- namedValueInArray[ struct ] locals[ name = {} ]
2778
- :
2779
- at='@'? annotationPath[ $name, 'name', $at ]
2780
- ( ':' elem=arrayValue )?
2781
- { this.addDef( $struct, 'struct', null, $name, true,
2782
- ($ctx.elem) ? $elem.val : { location: $name.location } ); }
2718
+ ( annotationPathVariant[ $val ] )?
2783
2719
  ;
2784
2720
 
2785
2721
  literalValue returns[ val ] locals[ tok ]
@@ -2837,12 +2773,12 @@ annotationPath[ art, category, headat = null ] locals[ _sync = 'nop' ]
2837
2773
  )*
2838
2774
  ;
2839
2775
 
2840
- annotationPathVariant[ art ]
2776
+ annotationPathVariant[ art ] locals[ variant = {} ]
2841
2777
  @after { this.attachLocation($art); }
2842
2778
  :
2843
- // TODO: warning for space before and after '#'
2779
+ // TODO: warning for space after '#'
2844
2780
  '#' { this.meltKeywordToIdentifier(); }
2845
- variant=ident['variant'] { $art.variant = $variant.id; }
2781
+ simplePath[ $variant, 'variant' ] { $art.variant = $variant; }
2846
2782
  ;
2847
2783
 
2848
2784
  // Identifier and non-reserved keywords --------------------------------------
@@ -2871,13 +2807,11 @@ ident[ category ] returns[ id ]
2871
2807
  | ASPECT
2872
2808
  | ASSOCIATION
2873
2809
  | BETWEEN
2874
- | BOTH
2875
2810
  | COLUMNS
2876
2811
  | COMPOSITION
2877
2812
  | CONTEXT
2878
2813
  | CROSS
2879
2814
  | CURRENT
2880
- | DAY
2881
2815
  | DEFAULT
2882
2816
  | DEFINE
2883
2817
  | DEFINITIONS
@@ -2901,14 +2835,12 @@ ident[ category ] returns[ id ]
2901
2835
  | FUNCTION
2902
2836
  | GROUP
2903
2837
  | HAVING
2904
- | HOUR
2905
2838
  | INNER
2906
2839
  | INTERSECT
2907
2840
  | INTO
2908
2841
  | IS
2909
2842
  | JOIN
2910
2843
  | LAST
2911
- | LEADING
2912
2844
  | LEFT
2913
2845
  | LIKE
2914
2846
  | LIMIT
@@ -2916,9 +2848,7 @@ ident[ category ] returns[ id ]
2916
2848
  | MANY
2917
2849
  | MASKED
2918
2850
  | MINUS
2919
- | MINUTE
2920
2851
  | MIXIN
2921
- | MONTH
2922
2852
  | NAMESPACE
2923
2853
  | NULLS
2924
2854
  | OFFSET
@@ -2935,10 +2865,8 @@ ident[ category ] returns[ id ]
2935
2865
  | RIGHT
2936
2866
  | ROW
2937
2867
  | ROWS
2938
- | SECOND
2939
2868
  | SERVICE
2940
2869
  | THEN
2941
- | TRAILING
2942
2870
  | UNION
2943
2871
  | UP
2944
2872
  | TO
@@ -2947,7 +2875,6 @@ ident[ category ] returns[ id ]
2947
2875
  | UNBOUNDED
2948
2876
  | VARIABLE
2949
2877
  | VIEW
2950
- | YEAR
2951
2878
  ;
2952
2879
 
2953
2880
  //----------------------------------------------------------------------------
@@ -3039,7 +2966,6 @@ CASE : [cC][aA][sS][eE] ;
3039
2966
  CAST : [cC][aA][sS][tT] ;
3040
2967
  DISTINCT : [dD][iI][sS][tT][iI][nN][cC][tT] ;
3041
2968
  EXISTS : [eE][xX][iI][sS][tT][sS] ;
3042
- EXTRACT : [eE][xX][tT][rR][aA][cC][tT] ;
3043
2969
  // FALSE: see Boolean
3044
2970
  FROM : [fF][rR][oO][mM] ;
3045
2971
  IN : [iI][nN] ;
@@ -3052,7 +2978,6 @@ ON : [oO][nN] ;
3052
2978
  SELECT : [sS][eE][lL][eE][cC][tT] ;
3053
2979
  SOME : [sS][oO][mM][eE] ;
3054
2980
  WHEN : [wW][hH][eE][nN] ;
3055
- TRIM : [tT][rR][iI][mM] ;
3056
2981
  // TRUE: see Boolean
3057
2982
  WHERE : [wW][hH][eE][rR][eE] ;
3058
2983
  WITH : [wW][iI][tT][hH] ;
@@ -3066,6 +2991,7 @@ Number // DO NOT RENAME OR MOVE THIS RULE !!!
3066
2991
  ;
3067
2992
 
3068
2993
  // Unreserved keywords (are case-insensitive): -------------------------------
2994
+ // Do not add keywords just for specialFunctions!
3069
2995
 
3070
2996
  ABSTRACT : [aA][bB][sS][tT][rR][aA][cC][tT] ;
3071
2997
  ACTION : [aA][cC][tT][iI][oO][nN] ;
@@ -3078,13 +3004,11 @@ ASC : [aA][sS][cC] ;
3078
3004
  ASPECT : [aA][sS][pP][eE][cC][tT] ;
3079
3005
  ASSOCIATION : [aA][sS][sS][oO][cC][iI][aA][tT][iI][oO][nN] ;
3080
3006
  BETWEEN : [bB][eE][tT][wW][eE][eE][nN] ;
3081
- BOTH : [bB][oO][tT][hH] ;
3082
3007
  COLUMNS : [cC][oO][lL][uU][mM][nN][sS];
3083
3008
  COMPOSITION : [cC][oO][mM][pP][oO][sS][iI][tT][iI][oO][nN] ;
3084
3009
  CONTEXT : [cC][oO][nN][tT][eE][xX][tT] ;
3085
3010
  CROSS : [cC][rR][oO][sS][sS] ;
3086
3011
  CURRENT : [cC][uU][rR][rR][eE][nN][tT] ;
3087
- DAY : [dD][aA][yY] ;
3088
3012
  DEFAULT : [dD][eE][fF][aA][uU][lL][tT] ;
3089
3013
  DEFINE : [dD][eE][fF][iI][nN][eE] ;
3090
3014
  DEFINITIONS : [dD][eE][fF][iI][nN][iI][tT][iI][oO][nN][sS] ;
@@ -3108,14 +3032,12 @@ FULL : [fF][uU][lL][lL] ;
3108
3032
  FUNCTION : [fF][uU][nN][cC][tT][iI][oO][nN] ;
3109
3033
  GROUP : [gG][rR][oO][uU][pP] ;
3110
3034
  HAVING : [hH][aA][vV][iI][nN][gG] ;
3111
- HOUR : [hH][oO][uU][rR] ;
3112
3035
  INNER : [iI][nN][nN][eE][rR] ;
3113
3036
  INTERSECT : [iI][nN][tT][eE][rR][sS][eE][cC][tT] ;
3114
3037
  INTO : [iI][nN][tT][oO] ;
3115
3038
  IS : [iI][sS] ;
3116
3039
  JOIN : [jJ][oO][iI][nN] ;
3117
3040
  LAST : [lL][aA][sS][tT] ;
3118
- LEADING : [lL][eE][aA][dD][iI][nN][gG] ;
3119
3041
  LEFT : [lL][eE][fF][tT] ;
3120
3042
  LIKE : [lL][iI][kK][eE] ;
3121
3043
  LIMIT : [lL][iI][mM][iI][tT] ;
@@ -3123,9 +3045,7 @@ LOCALIZED: [lL][oO][cC][aA][lL][iI][zZ][eE][dD];
3123
3045
  MANY : [mM][aA][nN][yY] ;
3124
3046
  MASKED : [mM][aA][sS][kK][eE][dD] ;
3125
3047
  MINUS : [mM][iI][nN][uU][sS] ;
3126
- MINUTE : [mM][iI][nN][uU][tT][eE] ;
3127
3048
  MIXIN : [mM][iI][xX][iI][nN] ;
3128
- MONTH : [mM][oO][nN][tT][hH] ;
3129
3049
  NAMESPACE : [nN][aA][mM][eE][sS][pP][aA][cC][eE] ;
3130
3050
  NULLS : [nN][uU][lL][lL][sS] ;
3131
3051
  OFFSET : [oO][fF][fF][sS][eE][tT] ;
@@ -3143,10 +3063,8 @@ RETURNS : [rR][eE][tT][uU][rR][nN][sS] ;
3143
3063
  RIGHT : [rR][iI][gG][hH][tT] ;
3144
3064
  ROW : [rR][oO][wW] ;
3145
3065
  ROWS : [rR][oO][wW][sS] ;
3146
- SECOND : [sS][eE][cC][oO][nN][dD] ;
3147
3066
  SERVICE : [sS][eE][rR][vV][iI][cC][eE] ;
3148
3067
  THEN : [tT][hH][eE][nN] ;
3149
- TRAILING : [tT][rR][aA][iI][lL][iI][nN][gG] ;
3150
3068
  TO : [tT][oO] ; // or make reserved? (is in SQL-92)
3151
3069
  TYPE : [tT][yY][pP][eE] ;
3152
3070
  UNION : [uU][nN][iI][oO][nN] ;
@@ -3156,7 +3074,6 @@ USING : [uU][sS][iI][nN][gG] ;
3156
3074
  VARIABLE : [vV][aA][rR][iI][aA][bB][lL][eE] ;
3157
3075
  VIEW : [vV][iI][eE][wW] ;
3158
3076
  // VIRTUAL: [vV][iI][rR][tT][uU][aA][lL] ; see tokens {}
3159
- YEAR : [yY][eE][aA][rR] ;
3160
3077
 
3161
3078
  // Identifiers, must BE LAST, DIRECTLY AFTER the unreserved keywords ---------
3162
3079