@sap/cds-compiler 2.15.4 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/CHANGELOG.md +33 -1590
  2. package/bin/cdsc.js +36 -33
  3. package/doc/CHANGELOG_ARCHIVE.md +1592 -0
  4. package/doc/CHANGELOG_BETA.md +3 -4
  5. package/doc/CHANGELOG_DEPRECATED.md +35 -1
  6. package/doc/{DeprecatedOptions.md → DeprecatedOptions_v2.md} +3 -1
  7. package/doc/Versioning.md +20 -1
  8. package/lib/api/.eslintrc.json +2 -2
  9. package/lib/api/main.js +220 -103
  10. package/lib/api/options.js +15 -85
  11. package/lib/api/validate.js +6 -10
  12. package/lib/base/keywords.js +216 -109
  13. package/lib/base/message-registry.js +60 -20
  14. package/lib/base/messages.js +65 -24
  15. package/lib/base/model.js +44 -2
  16. package/lib/checks/actionsFunctions.js +7 -5
  17. package/lib/checks/annotationsOData.js +1 -1
  18. package/lib/checks/cdsPersistence.js +1 -0
  19. package/lib/checks/elements.js +6 -6
  20. package/lib/checks/invalidTarget.js +1 -1
  21. package/lib/checks/nonexpandableStructured.js +1 -1
  22. package/lib/checks/queryNoDbArtifacts.js +2 -1
  23. package/lib/checks/selectItems.js +5 -1
  24. package/lib/checks/types.js +4 -2
  25. package/lib/checks/utils.js +2 -2
  26. package/lib/checks/validator.js +2 -1
  27. package/lib/compiler/assert-consistency.js +15 -10
  28. package/lib/compiler/builtins.js +87 -9
  29. package/lib/compiler/define.js +2 -2
  30. package/lib/compiler/extend.js +59 -11
  31. package/lib/compiler/finalize-parse-cdl.js +20 -9
  32. package/lib/compiler/index.js +25 -11
  33. package/lib/compiler/moduleLayers.js +7 -0
  34. package/lib/compiler/populate.js +13 -13
  35. package/lib/compiler/propagator.js +3 -3
  36. package/lib/compiler/resolve.js +193 -218
  37. package/lib/compiler/shared.js +47 -76
  38. package/lib/compiler/tweak-assocs.js +9 -10
  39. package/lib/compiler/utils.js +5 -0
  40. package/lib/edm/csn2edm.js +18 -21
  41. package/lib/edm/edmPreprocessor.js +25 -30
  42. package/lib/edm/edmUtils.js +10 -24
  43. package/lib/gen/language.checksum +1 -1
  44. package/lib/gen/language.interp +8 -30
  45. package/lib/gen/language.tokens +105 -114
  46. package/lib/gen/languageLexer.interp +1 -34
  47. package/lib/gen/languageLexer.js +889 -1007
  48. package/lib/gen/languageLexer.tokens +95 -106
  49. package/lib/gen/languageParser.js +20632 -22313
  50. package/lib/json/from-csn.js +56 -49
  51. package/lib/json/to-csn.js +10 -8
  52. package/lib/language/antlrParser.js +2 -2
  53. package/lib/language/docCommentParser.js +61 -38
  54. package/lib/language/errorStrategy.js +52 -40
  55. package/lib/language/genericAntlrParser.js +303 -229
  56. package/lib/language/language.g4 +573 -629
  57. package/lib/language/multiLineStringParser.js +14 -42
  58. package/lib/language/textUtils.js +44 -0
  59. package/lib/main.d.ts +27 -42
  60. package/lib/main.js +104 -81
  61. package/lib/model/csnRefs.js +1 -1
  62. package/lib/model/csnUtils.js +170 -283
  63. package/lib/model/revealInternalProperties.js +28 -8
  64. package/lib/model/sortViews.js +32 -31
  65. package/lib/optionProcessor.js +12 -21
  66. package/lib/render/.eslintrc.json +1 -1
  67. package/lib/render/DuplicateChecker.js +4 -7
  68. package/lib/render/manageConstraints.js +70 -2
  69. package/lib/render/toCdl.js +334 -339
  70. package/lib/render/toHdbcds.js +19 -15
  71. package/lib/render/toRename.js +44 -22
  72. package/lib/render/toSql.js +53 -51
  73. package/lib/render/utils/common.js +15 -1
  74. package/lib/render/utils/sql.js +20 -19
  75. package/lib/sql-identifier.js +6 -0
  76. package/lib/transform/db/.eslintrc.json +3 -2
  77. package/lib/transform/db/cdsPersistence.js +5 -15
  78. package/lib/transform/db/constraints.js +1 -1
  79. package/lib/transform/db/expansion.js +7 -6
  80. package/lib/transform/db/flattening.js +18 -19
  81. package/lib/transform/db/views.js +3 -3
  82. package/lib/transform/draft/.eslintrc.json +2 -2
  83. package/lib/transform/draft/db.js +6 -6
  84. package/lib/transform/draft/odata.js +6 -7
  85. package/lib/transform/forHanaNew.js +19 -22
  86. package/lib/transform/forOdataNew.js +10 -12
  87. package/lib/transform/localized.js +22 -16
  88. package/lib/transform/odata/toFinalBaseType.js +10 -10
  89. package/lib/transform/odata/typesExposure.js +3 -3
  90. package/lib/transform/odata/utils.js +1 -38
  91. package/lib/transform/transformUtilsNew.js +63 -77
  92. package/lib/transform/translateAssocsToJoins.js +2 -2
  93. package/lib/transform/universalCsn/.eslintrc.json +2 -2
  94. package/lib/transform/universalCsn/coreComputed.js +11 -6
  95. package/lib/transform/universalCsn/universalCsnEnricher.js +33 -5
  96. package/lib/utils/file.js +3 -3
  97. package/lib/utils/timetrace.js +20 -21
  98. package/package.json +35 -4
  99. package/doc/ApiMigration.md +0 -237
  100. package/doc/CommandLineMigration.md +0 -58
  101. package/doc/ErrorMessages.md +0 -175
  102. package/doc/FioriAnnotations.md +0 -94
  103. package/doc/ODataTransformation.md +0 -273
  104. package/lib/backends.js +0 -529
  105. 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 ]
389
+ | extendProjection[ $art, $outer ]
390
+ | extendType[ $art, $outer ]
391
+ | extendAspect[ $art, $outer ]
396
392
  // Streamlined Syntax
397
- | extendArtifact[ $outer, this.startLocation(), $annos ]
393
+ | extendArtifact[ $art, $outer ]
398
394
  )
399
395
  |
400
396
  annotate=ANNOTATE
401
- { if (defOnly) // this is a syntax restriction which is ensured in CSN in
402
- // another way
397
+ { if (defOnly)
403
398
  this.error( 'syntax-extend-context', $annotate,
404
399
  { code: 'ANNOTATE artifact', kind: defOnly },
405
400
  'No $(CODE) within $(KIND) extensions' );
406
401
  this.meltKeywordToIdentifier();
407
402
  }
408
- annotateArtifact[ $outer, this.startLocation(), $annos ] // not kind-specific
403
+ annotateArtifact[ $art, $outer ] // not kind-specific
409
404
  )
410
405
  ;
411
406
 
412
- contextDef[ outer, loc, annos, defOnly = false ] locals[ art, name = {} ]
413
- @after { this.attachLocation($art); }
407
+ contextDef[ art, outer, defOnly = false ] locals[ name = {} ]
408
+ @after { this.attachLocation( $art ); }
414
409
  :
415
410
  ( CONTEXT | service=SERVICE ) simplePath[ $name, $service ? 'Service' : 'Context' ]
416
- { $art = this.addDef( $outer, 'artifacts', $service ? 'service' : 'context', $name, $annos,
417
- {}, $loc );
418
- this.docComment( $annos ); }
419
- annotationAssignment_fix[ $annos ]*
411
+ { this.addDef( $art, $outer, 'artifacts', $service ? 'service' : 'context', $name );
412
+ this.docComment( $art ); }
413
+ annotationAssignment_fix[ $art ]*
420
414
  (
421
- '{' { $art.artifacts = this.createDict(); }
415
+ '{' { $art.artifacts = this.createDict(); $art.extensions = []; }
422
416
  artifactDef[ $art, defOnly ]*
423
- '}' { this.setDictEndLocation( $art.artifacts ); }
417
+ '}' { this.finalizeDictOrArray( $art.artifacts ); }
424
418
  optionalSemi
425
419
  |
426
420
  requiredSemi
427
421
  )
428
422
  ;
429
423
 
430
- extendContext[ outer, loc, annos ] locals[ art, name = {} ]
431
- @after { this.attachLocation($art); }
424
+ extendContext[ art, outer ] locals[ name = {} ]
425
+ @after { this.attachLocation( $art ); }
432
426
  :
433
- ( CONTEXT | service=SERVICE ) simplePath[ $name, $service ? 'Service' : 'Context' ] // not 'Extend' here
434
- { $art = this.addItem( $outer, 'extensions', 'extend', $annos,
435
- { name: $name, expectedKind: $service ? 'service' : 'context' },
436
- $loc ); }
427
+ ( CONTEXT { $art.expectedKind = 'context'; } | service=SERVICE { $art.expectedKind = 'service'; })
428
+ simplePath[ $name, $service ? 'Service' : 'Context' ] // not 'Extend' here
429
+ { $art.name = $name; this.addItem( $art, $outer, 'extensions', 'extend' ); }
437
430
  ( WITH { this.noSemicolonHere(); } )?
438
- { this.docComment( $annos ); }
439
- annotationAssignment_ll1[ $annos ]*
431
+ { this.docComment( $art ); }
432
+ annotationAssignment_ll1[ $art ]*
440
433
  (
441
434
  '{' { $art.artifacts = this.createDict(); }
442
435
  artifactDef[ $art, $service ? 'SERVICE' : 'CONTEXT' ]*
443
- '}' { this.setDictEndLocation( $art.artifacts ); }
436
+ '}' { this.finalizeDictOrArray( $art.artifacts ); }
444
437
  optionalSemi
445
438
  |
446
439
  requiredSemi
447
440
  )
448
441
  ;
449
442
 
450
- entityDef[ outer, loc, annos ] locals[ art, name = {} ]
451
- @after { this.attachLocation($art); }
443
+ entityDef[ art, outer ] locals[ name = {} ]
444
+ @after { this.attachLocation( $art ); }
452
445
  :
453
446
  ENTITY simplePath[ $name, 'Entity' ]
454
- { $art = this.addDef( $outer, 'artifacts', 'entity', $name, $annos, {}, $loc );
455
- this.docComment( $annos ); }
456
- annotationAssignment_fix[ $annos ]*
457
- entityParameters[ $art ]?
447
+ { this.addDef( $art, $outer, 'artifacts', 'entity', $name );
448
+ this.docComment( $art ); }
449
+ annotationAssignment_fix[ $art ]*
450
+ parameterListDef[ $art ]?
458
451
  (
459
452
  ( ':'
460
453
  includeRef[ $art ]
@@ -462,15 +455,14 @@ entityDef[ outer, loc, annos ] locals[ art, name = {} ]
462
455
  includeRef[ $art ]
463
456
  )*
464
457
  )?
465
- '{'
466
- { $art.elements = this.createDict(); } // better for include and annotate
458
+ '{' { $art.elements = this.createDict(); }
467
459
  elementDef[ $art ]*
468
- '}' { this.setDictEndLocation( $art.elements ); }
460
+ '}' { this.finalizeDictOrArray( $art.elements ); }
469
461
  // TODO: action definitions in a specific section?
470
462
  (
471
463
  ACTIONS '{' { $art.actions = this.createDict(); }
472
464
  actionFunctionDef[ $art ]*
473
- '}' { this.setDictEndLocation( $art.actions ); }
465
+ '}' { this.finalizeDictOrArray( $art.actions ); }
474
466
  )?
475
467
  optionalSemi
476
468
  |
@@ -480,7 +472,7 @@ entityDef[ outer, loc, annos ] locals[ art, name = {} ]
480
472
  (
481
473
  ACTIONS '{' { $art.actions = this.createDict(); }
482
474
  actionFunctionDef[ $art ]*
483
- '}' { this.setDictEndLocation( $art.actions ); }
475
+ '}' { this.finalizeDictOrArray( $art.actions ); }
484
476
  optionalSemi
485
477
  | requiredSemi
486
478
  )
@@ -490,7 +482,7 @@ entityDef[ outer, loc, annos ] locals[ art, name = {} ]
490
482
  (
491
483
  ACTIONS '{' { $art.actions = this.createDict(); }
492
484
  actionFunctionDef[ $art ]*
493
- '}' { this.setDictEndLocation( $art.actions ); }
485
+ '}' { this.finalizeDictOrArray( $art.actions ); }
494
486
  )?
495
487
  optionalSemi // TODO: not fully correct without columns or excluding
496
488
  )
@@ -514,7 +506,7 @@ projectionSpec returns[ query ] locals[ src ]
514
506
  ( AS aliasName=ident['FromAlias'] { $src.name = $aliasName.id } )?
515
507
  // ANTLR errors are better if we use ( A )? instead of ( A | ):
516
508
  { if (!$src.name) this.classifyImplicitName( $src.scope ? 'FromAlias' : 'Without' ); }
517
- bracedSelectItemListDef[ $query ]?
509
+ bracedSelectItemListDef[ $query, 'columns' ]?
518
510
  excludingClause[ $query ]?
519
511
  ;
520
512
 
@@ -541,25 +533,26 @@ excludingClause[ query ]
541
533
  ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
542
534
  projectionExclusion[ $query ]
543
535
  )*
544
- '}' { this.setDictEndLocation( $query.excludingDict ); }
536
+ '}' { this.finalizeDictOrArray( $query.excludingDict ); }
545
537
  ;
546
538
 
547
- projectionExclusion[ outer ] locals[ art ]
539
+ projectionExclusion[ outer ] locals[ art = {} ]
548
540
  @after { this.attachLocation($art); }
549
541
  :
550
542
  name=ident['ref']
551
- { $art = this.addDef( $outer, 'excludingDict', '', $name.id ); }
543
+ { this.addDef( $art, $outer, 'excludingDict', '', $name.id ); }
552
544
  ;
553
545
 
554
- extendEntity[ outer, loc, annos ] locals[ art, name = {} ]
555
- @after { /* #ATN 1 */ this.attachLocation($art); }
546
+ extendEntity[ art, outer ] locals[ name = {} ]
547
+ @after { /* #ATN 1 */ this.attachLocation( $art ); }
556
548
  :
557
549
  ENTITY simplePath[ $name, 'Extend' ]
558
- { $art = this.addItem( $outer, 'extensions', 'extend', $annos,
559
- { name: $name, expectedKind: 'entity' }, $loc ); }
550
+ { $art.expectedKind = 'entity'; $art.name = $name;
551
+ this.addItem( $art, $outer, 'extensions', 'extend' );
552
+ }
560
553
  (
561
- WITH { this.noSemicolonHere(); this.docComment( $annos ); }
562
- annotationAssignment_ll1[ $annos ]*
554
+ WITH { this.noSemicolonHere(); this.docComment( $art ); }
555
+ annotationAssignment_ll1[ $art ]*
563
556
  // ATN: the ref can start with ACTIONS
564
557
  (
565
558
  includeRef[ $art ]
@@ -568,8 +561,8 @@ extendEntity[ outer, loc, annos ] locals[ art, name = {} ]
568
561
  extendForEntity[ $art ]
569
562
  )
570
563
  |
571
- { this.docComment( $annos ); }
572
- annotationAssignment_ll1[ $annos ]*
564
+ { this.docComment( $art ); }
565
+ annotationAssignment_ll1[ $art ]*
573
566
  extendForEntity[ $art ]
574
567
  )
575
568
  ;
@@ -578,33 +571,32 @@ extendForEntity[ art ]
578
571
  :
579
572
  '{' { $art.elements = this.createDict(); }
580
573
  elementDefOrExtend[ $art ]*
581
- '}' { this.setDictEndLocation( $art.elements ); }
574
+ '}' { this.finalizeDictOrArray( $art.elements ); }
582
575
  (
583
576
  ACTIONS '{' { $art.actions = this.createDict(); }
584
577
  actionFunctionDef[ $art ]*
585
- '}' { this.setDictEndLocation( $art.actions ); }
578
+ '}' { this.finalizeDictOrArray( $art.actions ); }
586
579
  )?
587
580
  optionalSemi
588
581
  |
589
582
  ACTIONS '{' { $art.actions = this.createDict(); }
590
583
  actionFunctionDef[ $art ]*
591
- '}' { this.setDictEndLocation( $art.actions ); }
584
+ '}' { this.finalizeDictOrArray( $art.actions ); }
592
585
  optionalSemi
593
586
  |
594
587
  requiredSemi
595
588
  ;
596
589
 
597
- extendProjection[ outer, loc, annos ] locals[ art, name = {} ]
598
- @after { this.attachLocation($art); }
590
+ extendProjection[ art, outer ] locals[ name = {} ]
591
+ @after { this.attachLocation( $art ); }
599
592
  :
600
593
  expected=PROJECTION simplePath[ $name, 'Extend' ]
601
- {
602
- $art = this.addItem( $outer, 'extensions', 'extend', $annos,
603
- { name: $name, expectedKind: 'entity' }, // or 'projection'?
604
- $loc ); }
594
+ { $art.expectedKind = 'entity'; $art.name = $name;
595
+ this.addItem( $art, $outer, 'extensions', 'extend' );
596
+ }
605
597
  ( WITH { this.noSemicolonHere(); } )?
606
- { this.docComment( $annos ); }
607
- annotationAssignment_ll1[ $annos ]*
598
+ { this.docComment( $art ); }
599
+ annotationAssignment_ll1[ $art ]*
608
600
  (
609
601
  '{' { $art.columns = []; }
610
602
  (
@@ -617,13 +609,13 @@ extendProjection[ outer, loc, annos ] locals[ art, name = {} ]
617
609
  (
618
610
  ACTIONS '{' { $art.actions = this.createDict(); }
619
611
  actionFunctionDef[ $art ]*
620
- '}' { this.setDictEndLocation( $art.actions ); }
612
+ '}' { this.finalizeDictOrArray( $art.actions ); }
621
613
  )?
622
614
  optionalSemi
623
615
  |
624
616
  ACTIONS '{' { $art.actions = this.createDict(); }
625
617
  actionFunctionDef[ $art ]*
626
- '}' { this.setDictEndLocation( $art.actions ); }
618
+ '}' { this.finalizeDictOrArray( $art.actions ); }
627
619
  optionalSemi
628
620
  |
629
621
  requiredSemi
@@ -631,53 +623,53 @@ extendProjection[ outer, loc, annos ] locals[ art, name = {} ]
631
623
  ;
632
624
 
633
625
  // TODO: no action extension?
634
- actionFunctionDef[ outer ] locals[ art, annos = [] ]
635
- @after { this.attachLocation($art); }
626
+ actionFunctionDef[ outer ] locals[ art = {} ]
627
+ @after { this.attachLocation( $art ); }
636
628
  :
637
- { this.docComment( $annos ); }
638
- annotationAssignment_ll1[ $annos ]*
629
+ { $art.location = this.startLocation();; this.docComment( $art ); }
630
+ annotationAssignment_ll1[ $art ]*
639
631
  (
640
632
  ACTION name=ident['BoundAction']
641
- { $art = this.addDef( $outer, 'actions', 'action', $name.id, $annos );
642
- this.docComment( $annos ); }
643
- annotationAssignment_fix[ $annos ]*
633
+ { this.addDef( $art, $outer, 'actions', 'action', $name.id );
634
+ this.docComment( $art ); }
635
+ annotationAssignment_fix[ $art ]*
644
636
  parameterListDef[ $art ]
645
- ( returnTypeSpec[ $art, $annos ] | requiredSemi )
637
+ ( returnTypeSpec[ $art ] | requiredSemi )
646
638
  |
647
639
  FUNCTION name=ident['BoundAction']
648
- { $art = this.addDef( $outer, 'actions', 'function', $name.id, $annos );
649
- this.docComment( $annos ); }
650
- annotationAssignment_fix[ $annos ]*
640
+ { this.addDef( $art, $outer, 'actions', 'function', $name.id );
641
+ this.docComment( $art ); }
642
+ annotationAssignment_fix[ $art ]*
651
643
  parameterListDef[ $art ]
652
- returnTypeSpec[ $art, $annos ]
644
+ returnTypeSpec[ $art ]
653
645
  )
654
646
  ;
655
647
 
656
- actionFunctionMainDef[ outer, loc, annos ] locals[ art, name = {} ]
657
- @after { this.attachLocation($art); }
648
+ actionFunctionMainDef[ art, outer ] locals[ name = {} ]
649
+ @after { this.attachLocation( $art ); }
658
650
  :
659
651
  ACTION simplePath[ $name, 'Action' ]
660
- { $art = this.addDef( $outer, 'artifacts', 'action', $name, $annos, {}, $loc );
661
- this.docComment( $annos ); }
662
- annotationAssignment_fix[ $annos ]*
652
+ { this.addDef( $art, $outer, 'artifacts', 'action', $name );
653
+ this.docComment( $art ); }
654
+ annotationAssignment_fix[ $art ]*
663
655
  parameterListDef[ $art ]
664
- ( returnTypeSpec[ $art, $annos ] | requiredSemi )
656
+ ( returnTypeSpec[ $art ] | requiredSemi )
665
657
  |
666
658
  FUNCTION simplePath[ $name, 'Action' ]
667
- { $art = this.addDef( $outer, 'artifacts', 'function', $name, $annos, {}, $loc );
668
- this.docComment( $annos ); }
669
- annotationAssignment_fix[ $annos ]*
659
+ { this.addDef( $art, $outer, 'artifacts', 'function', $name );
660
+ this.docComment( $art ); }
661
+ annotationAssignment_fix[ $art ]*
670
662
  parameterListDef[ $art ]
671
- returnTypeSpec[ $art, $annos ]
663
+ returnTypeSpec[ $art ]
672
664
  ;
673
665
 
674
- eventDef[ outer, loc, annos ] locals[ art, name = {} ]
675
- @after { /* #ATN 1 */ this.attachLocation($art); }
666
+ eventDef[ art, outer ] locals[ name = {} ]
667
+ @after { /* #ATN 1 */ this.attachLocation( $art ); }
676
668
  :
677
669
  EVENT simplePath[ $name, 'Event' ]
678
- { $art = this.addDef( $outer, 'artifacts', 'event', $name, $annos, {}, $loc );
679
- this.docComment( $annos ); }
680
- annotationAssignment_fix[ $annos ]*
670
+ { this.addDef( $art, $outer, 'artifacts', 'event', $name );
671
+ this.docComment( $art ); }
672
+ annotationAssignment_fix[ $art ]*
681
673
  (
682
674
  typeStruct[ $art ] optionalSemi
683
675
  |
@@ -693,8 +685,8 @@ eventDef[ outer, loc, annos ] locals[ art, name = {} ]
693
685
  )*
694
686
  typeStruct[ $art ] optionalSemi
695
687
  |
696
- { this.docComment( $annos ); }
697
- annotationAssignment_ll1[ $annos ]*
688
+ { this.docComment( $art ); }
689
+ annotationAssignment_ll1[ $art ]*
698
690
  requiredSemi
699
691
  )
700
692
  |
@@ -708,18 +700,18 @@ eventDef[ outer, loc, annos ] locals[ art, name = {} ]
708
700
  )
709
701
  ;
710
702
 
711
- aspectDef[ outer, loc, annos ] locals[ art, name = {} ]
712
- @after { this.attachLocation($art); }
703
+ aspectDef[ art, outer ] locals[ name = {} ]
704
+ @after { this.attachLocation( $art ); }
713
705
  :
714
706
  ( ASPECT | ( abs=ABSTRACT | HideAlternatives ) ent=ENTITY )
715
707
  simplePath[ $name, 'Type' ]
716
- { $art = this.addDef( $outer, 'artifacts', 'aspect', $name, $annos, {}, $loc );
708
+ { this.addDef( $art, $outer, 'artifacts', 'aspect', $name );
717
709
  // backends do not like ['$'+'syntax']: ($ent ? 'entity' : 'aspect')
718
710
  if ($ent)
719
711
  this.warning( 'syntax-deprecated-abstract', this.tokenLocation( $abs, $ent ), {},
720
712
  'Abstract entity definitions are deprecated; use aspect definitions instead' );
721
- this.docComment( $annos ); }
722
- annotationAssignment_fix[ $annos ]*
713
+ this.docComment( $art ); }
714
+ annotationAssignment_fix[ $art ]*
723
715
  ( ':'
724
716
  (
725
717
  includeRef[ $art ]
@@ -730,99 +722,93 @@ aspectDef[ outer, loc, annos ] locals[ art, name = {} ]
730
722
  )?
731
723
  '{' { $art.elements = this.createDict(); }
732
724
  ( elementDef[ $art ]* )
733
- '}' { this.setDictEndLocation( $art.elements ); }
725
+ '}' { this.finalizeDictOrArray( $art.elements ); }
734
726
  // TODO: action definitions in a specific section?
735
727
  (
736
728
  ACTIONS '{' { $art.actions = this.createDict(); }
737
729
  actionFunctionDef[ $art ]*
738
- '}' { this.setDictEndLocation( $art.actions ); }
730
+ '}' { this.finalizeDictOrArray( $art.actions ); }
739
731
  )?
740
732
  optionalSemi
741
733
  ;
742
734
 
743
- typeDef[ outer, loc, annos ] locals[ art, name = {} ]
744
- @after { this.attachLocation($art); }
735
+ typeDef[ art, outer ] locals[ name = {} ]
736
+ @after { this.attachLocation( $art ); }
745
737
  :
746
738
  TYPE simplePath[ $name, 'Type' ]
747
- { $art = this.addDef( $outer, 'artifacts', 'type', $name, $annos, {}, $loc );
748
- this.docComment( $annos ); }
749
- annotationAssignment_fix[ $annos ]*
750
- typeSpecSemi[ $art, $annos ]
739
+ { this.addDef( $art, $outer, 'artifacts', 'type', $name );
740
+ this.docComment( $art ); }
741
+ annotationAssignment_fix[ $art ]*
742
+ typeSpecSemi[ $art ]
751
743
  ;
752
744
 
753
- extendType[ outer, loc, annos ] locals[ art, name = {} ]
754
- @after { this.attachLocation($art); }
745
+ extendType[ art, outer ] locals[ name = {} ]
746
+ @after { this.attachLocation( $art ); }
755
747
  :
756
748
  // aspects are types, i.e. kind is 'type' for aspects
757
749
  TYPE simplePath[ $name, 'Extend' ]
758
- { $art = this.addItem( $outer, 'extensions', 'extend', $annos,
759
- { name: $name, expectedKind: 'type' },
760
- $loc ); }
761
- extendWithOptElements[ $art, $annos ]
750
+ { $art.expectedKind = 'type'; $art.name = $name;
751
+ this.addItem( $art, $outer, 'extensions', 'extend' );
752
+ }
753
+ extendWithOptElements[ $art, $art ]
762
754
  ;
763
755
 
764
- extendAspect[ outer, loc, annos ] locals[ art, name = {} ]
765
- @after { this.attachLocation($art); }
756
+ extendAspect[ art, outer ] locals[ name = {} ]
757
+ @after { this.attachLocation( $art ); }
766
758
  :
767
759
  // aspects are types, i.e. kind is 'type' for aspects
768
760
  ASPECT simplePath[ $name, 'Extend' ]
769
- { $art = this.addItem( $outer, 'extensions', 'extend', $annos,
770
- { name: $name, expectedKind: 'aspect' },
771
- $loc ); }
772
- extendWithOptElements[ $art, $annos ]
761
+ { $art.expectedKind = 'aspect'; $art.name = $name;
762
+ this.addItem( $art, $outer, 'extensions', 'extend' );
763
+ }
764
+ extendWithOptElements[ $art, $art ]
773
765
  ;
774
766
 
775
- annotationDef[ outer, loc, annos ] locals[ art, name = {} ]
776
- @after { this.attachLocation($art); }
767
+ annotationDef[ art, outer ] locals[ name = {} ]
768
+ @after { this.attachLocation( $art ); }
777
769
  :
778
770
  annotation=ANNOTATION simplePath[ $name, 'AnnoDef' ]
779
771
  { if ($outer.kind !== 'source') { // this is a syntax restriction to avoid confusion
780
- this.error( 'syntax-no-inner-vocabulary', $annotation, {},
781
- 'Annotation definitions can\'t be defined inside contexts or services' );
772
+ this.error( 'syntax-unexpected-vocabulary', $annotation, { '#': $outer.kind } );
782
773
  $art = {}; }
783
- else
784
- $art = this.addDef( $outer, 'vocabularies', 'annotation', $name, $annos, {}, $loc );
785
- this.docComment( $annos ); }
786
- annotationAssignment_fix[ $annos ]*
787
- typeSpecSemi[ $art, $annos ] // also 'includes'...
774
+ else {
775
+ if (!$outer.vocabularies) $outer.vocabularies = Object.create(null);
776
+ this.addDef( $art, $outer, 'vocabularies', 'annotation', $name );
777
+ }
778
+ this.docComment( $art ); }
779
+ annotationAssignment_fix[ $art ]*
780
+ typeSpecSemi[ $art ] // also 'includes'...
788
781
  ;
789
782
 
790
- extendArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
791
- @after{ /* #ATN 1 */ this.attachLocation($art); }
783
+ extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
784
+ @after{ /* #ATN 1 */ this.attachLocation( $art ); }
792
785
  :
793
786
  simplePath[ $name, 'Extend' ]
787
+ ( ':' simplePath[ $elemName, 'Element'] )?
788
+ { this.addExtension( $art, $outer, 'extend', $name, $elemName.path ); }
794
789
  (
795
- { $art = this.addItem( $outer, 'extensions', 'extend', $annos, { name: $name }, $loc ); }
796
- |
797
- ':'
798
- simplePath[ $elemName, 'ref']
799
- {{
800
- const def = this.addItem( $outer, 'extensions', 'extend', null, { name: $name }, $loc );
801
- $art = this.artifactForElementAnnotateOrExtend( 'extend', def, $elemName.path, $annos, $loc );
802
- }}
803
- )
804
- (
805
- { this.docComment( $annos ); }
806
- annotationAssignment_ll1[ $annos ]*
790
+ { this.docComment( $art ); }
791
+ annotationAssignment_ll1[ $art ]*
807
792
  (
808
793
  '{' { $art.elements = this.createDict(); }
809
794
  elementDefOrExtend[ $art ]*
810
- '}' { this.setDictEndLocation( $art.elements ); }
795
+ '}' { this.finalizeDictOrArray( $art.elements ); }
811
796
  optionalSemi
812
797
  |
813
798
  requiredSemi
814
799
  )
815
800
  |
816
- WITH { this.noSemicolonHere(); this.docComment( $annos ); }
817
- annotationAssignment_ll1[ $annos ]*
801
+ WITH { this.noSemicolonHere(); this.docComment( $art ); }
802
+ annotationAssignment_ll1[ $art ]*
818
803
  // #ATN: DEFINITIONS, COLUMNS, ACTIONS etc are not reserved and could be identifiers (ref).
804
+ // TODO: exclude "expected" according to disallowElementExtension()
819
805
  (
820
806
  includeRef[ $art ]
821
807
  requiredSemi
822
808
  |
823
809
  '{' { $art.elements = this.createDict(); }
824
810
  elementDefOrExtend[ $art ]*
825
- '}' { this.setDictEndLocation( $art.elements ); }
811
+ '}' { this.finalizeDictOrArray( $art.elements ); }
826
812
  optionalSemi
827
813
  |
828
814
  requiredSemi
@@ -831,7 +817,7 @@ extendArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
831
817
  DEFINITIONS
832
818
  '{' { $art.artifacts = this.createDict(); }
833
819
  artifactDef[ $art, true ]*
834
- '}' { this.setDictEndLocation( $art.artifacts ); }
820
+ '}' { this.finalizeDictOrArray( $art.artifacts ); }
835
821
  optionalSemi
836
822
  |
837
823
  { this.disallowElementExtension( $elemName, $outer, 'columns' ); }
@@ -849,84 +835,75 @@ extendArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
849
835
  { this.disallowElementExtension( $elemName, $outer, 'actions' ); }
850
836
  ACTIONS '{' { $art.actions = this.createDict(); }
851
837
  actionFunctionDef[ $art ]*
852
- '}' { this.setDictEndLocation( $art.actions ); }
838
+ '}' { this.finalizeDictOrArray( $art.actions ); }
853
839
  optionalSemi
854
840
  |
855
841
  ELEMENTS '{' { $art.elements = this.createDict(); }
856
842
  elementDefOrExtend[ $art ]*
857
- '}' { this.setDictEndLocation( $art.elements ); }
843
+ '}' { this.finalizeDictOrArray( $art.elements ); }
858
844
  optionalSemi
859
845
  |
860
846
  ENUM '{' { $art.enum = this.createDict(); }
861
847
  enumSymbolDef[ $art ]*
862
- '}' { this.setDictEndLocation( $art.enum ); }
848
+ '}' { this.finalizeDictOrArray( $art.enum ); }
863
849
  optionalSemi
864
850
  )
865
851
  )
866
852
  ;
867
853
 
868
- extendWithOptElements[ art, annos ]
854
+ extendWithOptElements[ art ]
869
855
  :
870
- WITH { this.noSemicolonHere(); this.docComment( $annos ); }
871
- annotationAssignment_ll1[ $annos ]*
856
+ WITH { this.noSemicolonHere(); this.docComment( $art ); }
857
+ annotationAssignment_ll1[ $art ]*
872
858
  (
873
859
  includeRef[ $art ]
874
860
  requiredSemi
875
861
  |
876
862
  '{' { $art.elements = this.createDict(); }
877
863
  elementDefOrExtend[ $art ]*
878
- '}' { this.setDictEndLocation( $art.elements ); }
864
+ '}' { this.finalizeDictOrArray( $art.elements ); }
879
865
  optionalSemi
880
866
  |
881
867
  requiredSemi
882
868
  )
883
869
  |
884
- { this.docComment( $annos ); }
885
- annotationAssignment_ll1[ $annos ]*
870
+ { this.docComment( $art ); }
871
+ annotationAssignment_ll1[ $art ]*
886
872
  (
887
873
  '{' { $art.elements = this.createDict(); }
888
874
  elementDefOrExtend[ $art ]*
889
- '}' { this.setDictEndLocation( $art.elements ); }
875
+ '}' { this.finalizeDictOrArray( $art.elements ); }
890
876
  optionalSemi
891
877
  |
892
878
  requiredSemi
893
879
  )
894
880
  ;
895
881
 
896
- annotateArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
897
- @after { this.attachLocation($art); }
882
+ annotateArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
883
+ @after { this.attachLocation( $art ); }
898
884
  :
899
885
  simplePath[ $name, 'Annotate' ]
900
- (
901
- { $art = this.addItem( $outer, 'extensions', 'annotate', $annos, { name: $name }, $loc ); }
902
- |
903
- ':'
904
- simplePath[ $elemName, 'ref']
905
- {{
906
- const def = this.addItem( $outer, 'extensions', 'annotate', null, { name: $name }, $loc );
907
- $art = this.artifactForElementAnnotateOrExtend( 'annotate', def, $elemName.path, $annos, $loc );
908
- }}
909
- )
910
-
886
+ ( ':' simplePath[ $elemName, 'Element'] )?
887
+ { this.addExtension( $art, $outer, 'annotate', $name, $elemName.path ); }
911
888
  ( WITH { this.noSemicolonHere(); } )?
912
- { this.docComment( $annos ); }
913
- annotationAssignment_ll1[ $annos ]*
889
+ { this.docComment( $art ); }
890
+ annotationAssignment_ll1[ $art ]*
914
891
  (
915
892
  '{' { $art.elements = this.createDict(); }
916
893
  annotateElement[ $art ]*
917
- '}' { this.setDictEndLocation( $art.elements ); }
894
+ '}' { this.finalizeDictOrArray( $art.elements ); }
918
895
  (
919
896
  ACTIONS
920
897
  '{' { $art.actions = this.createDict(); }
921
898
  annotateAction[ $art ]*
922
- '}' { this.setDictEndLocation( $art.actions ); }
899
+ '}' { this.finalizeDictOrArray( $art.actions ); }
923
900
  )?
924
901
  optionalSemi
925
902
  |
926
903
  ACTIONS
927
904
  '{' { $art.actions = this.createDict(); }
928
905
  annotateAction[ $art ]*
929
- '}' { this.setDictEndLocation( $art.actions ); }
906
+ '}' { this.finalizeDictOrArray( $art.actions ); }
930
907
  optionalSemi
931
908
  |
932
909
  '(' { $art.params = this.createDict(); }
@@ -934,12 +911,12 @@ annotateArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
934
911
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
935
912
  annotateParam[ $art ]
936
913
  )*
937
- ')' { this.setDictEndLocation( $art.params ); }
914
+ ')' { this.finalizeDictOrArray( $art.params ); }
938
915
  (
939
916
  RETURNS { $art['$'+'syntax'] = 'returns'; }
940
917
  '{' { $art.elements = this.createDict(); }
941
918
  annotateElement[ $art ]*
942
- '}' { this.setDictEndLocation( $art.elements ); }
919
+ '}' { this.finalizeDictOrArray( $art.elements ); }
943
920
  optionalSemi
944
921
  |
945
922
  requiredSemi
@@ -948,7 +925,7 @@ annotateArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
948
925
  RETURNS { $art['$'+'syntax'] = 'returns'; }
949
926
  '{' { $art.elements = this.createDict(); }
950
927
  annotateElement[ $art ]*
951
- '}' { this.setDictEndLocation( $art.elements ); }
928
+ '}' { this.finalizeDictOrArray( $art.elements ); }
952
929
  optionalSemi
953
930
 
954
931
  |
@@ -956,74 +933,74 @@ annotateArtifact[ outer, loc, annos ] locals[ art, name = {}, elemName = {} ]
956
933
  )
957
934
  ;
958
935
 
959
- annotateElement[ outer ] locals[ art, annos = [] ]
960
- @after{ this.attachLocation($art); }
936
+ annotateElement[ outer ] locals[ art = {} ]
937
+ @after{ this.attachLocation( $art ); }
961
938
  :
962
- { this.docComment( $annos ); }
963
- annotationAssignment_ll1[ $annos ]*
939
+ { $art.location = this.startLocation();; this.docComment( $art ); }
940
+ annotationAssignment_ll1[ $art ]*
964
941
  name=ident['Element']
965
- { $art = this.addDef( $outer, 'elements', 'annotate', $name.id, $annos );
966
- this.docComment( $annos ); }
967
- annotationAssignment_ll1[ $annos ]*
942
+ { this.addDef( $art, $outer, 'elements', 'annotate', $name.id );
943
+ this.docComment( $art ); }
944
+ annotationAssignment_ll1[ $art ]*
968
945
  (
969
946
  '{' { $art.elements = this.createDict(); }
970
947
  annotateElement[ $art ]*
971
- '}' { this.setDictEndLocation( $art.elements ); }
948
+ '}' { this.finalizeDictOrArray( $art.elements ); }
972
949
  optionalSemi
973
950
  |
974
951
  requiredSemi
975
952
  )
976
953
  ;
977
954
 
978
- annotateAction [ outer ] locals [ art, annos = [] ]
979
- @after{ this.attachLocation($art); }
955
+ annotateAction [ outer ] locals [ art = {} ]
956
+ @after{ this.attachLocation( $art ); }
980
957
  :
981
- { this.docComment( $annos ); }
982
- annotationAssignment_ll1[ $annos ]*
958
+ { $art.location = this.startLocation();; this.docComment( $art ); }
959
+ annotationAssignment_ll1[ $art ]*
983
960
  name=ident['BoundAction']
984
- { $art = this.addDef( $outer, 'actions', 'annotate', $name.id, $annos );
985
- this.docComment( $annos ); }
986
- annotationAssignment_ll1[ $annos ]*
961
+ { this.addDef( $art, $outer, 'actions', 'annotate', $name.id );
962
+ this.docComment( $art ); }
963
+ annotationAssignment_ll1[ $art ]*
987
964
  (
988
965
  '(' { $art.params = this.createDict(); }
989
966
  annotateParam[ $art ]
990
967
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
991
968
  annotateParam[ $art ]
992
969
  )*
993
- ')' { this.setDictEndLocation( $art.params ); }
970
+ ')' { this.finalizeDictOrArray( $art.params ); }
994
971
  )?
995
972
  (
996
973
  RETURNS '{' { $art.elements = this.createDict(); }
997
974
  annotateElement[ $art ]*
998
- '}' { this.setDictEndLocation( $art.elements ); }
975
+ '}' { this.finalizeDictOrArray( $art.elements ); }
999
976
  optionalSemi
1000
977
  |
1001
978
  requiredSemi
1002
979
  )
1003
980
  ;
1004
981
 
1005
- annotateParam [ outer ] locals [ art, annos = [] ]
1006
- @after{ this.attachLocation($art); }
982
+ annotateParam [ outer ] locals [ art = {} ]
983
+ @after{ this.attachLocation( $art ); }
1007
984
  :
1008
- { this.docComment( $annos ); }
1009
- annotationAssignment_ll1[ $annos ]*
985
+ { $art.location = this.startLocation();; this.docComment( $art ); }
986
+ annotationAssignment_ll1[ $art ]*
1010
987
  param=ident['Param']
1011
- { $art = this.addDef( $outer, 'params', 'annotate', $param.id, $annos );
1012
- this.docComment( $annos ); }
1013
- annotationAssignment_ll1[ $annos ]*
988
+ { this.addDef( $art, $outer, 'params', 'annotate', $param.id );
989
+ this.docComment( $art ); }
990
+ annotationAssignment_ll1[ $art ]*
1014
991
  ;
1015
992
 
1016
993
  // Element definition and its helpers ----------------------------------------
1017
994
 
1018
- enumSymbolDef[ outer ] locals[ art, annos = [] ]
1019
- @after { this.attachLocation($art); }
995
+ enumSymbolDef[ outer ] locals[ art = {} ]
996
+ @after { this.attachLocation( $art ); }
1020
997
  :
1021
- { this.docComment( $annos ); }
1022
- annotationAssignment_ll1[ $annos ]*
998
+ { $art.location = this.startLocation();; this.docComment( $art ); }
999
+ annotationAssignment_ll1[ $art ]*
1023
1000
  name=ident['Enum']
1024
- { $art = this.addDef( $outer, 'enum', 'enum', $name.id, $annos );
1025
- this.docComment( $annos ); }
1026
- annotationAssignment_ll1[ $annos ]*
1001
+ { this.addDef( $art, $outer, 'enum', 'enum', $name.id );
1002
+ this.docComment( $art ); }
1003
+ annotationAssignment_ll1[ $art ]*
1027
1004
  ( '='
1028
1005
  { this.excludeExpected( ['Boolean', 'QuotedLiteral', "'#'", 'NULL'] ); }
1029
1006
  (
@@ -1033,8 +1010,8 @@ enumSymbolDef[ outer ] locals[ art, annos = [] ]
1033
1010
  ( plus='+' | min='-' ) num=Number
1034
1011
  { $art.value = this.numberLiteral( $num, $plus||$min ); }
1035
1012
  )
1036
- { this.docComment( $annos ); }
1037
- annotationAssignment_ll1[ $annos ]*
1013
+ { this.docComment( $art ); }
1014
+ annotationAssignment_ll1[ $art ]*
1038
1015
  )?
1039
1016
  requiredSemi
1040
1017
  ;
@@ -1045,37 +1022,35 @@ defaultValue[ art ] locals[ elem, elements = {} ]
1045
1022
  DEFAULT expr=expression { $art.default = $expr.expr; }
1046
1023
  ;
1047
1024
 
1048
- elementDefOrExtend[ outer ] locals[ annos = [] ]
1049
- @after { /* #ATN 1 */ if ($ctx.art) this.attachLocation($art.art); }
1050
- // tool complains if I test for ($art)
1025
+ elementDefOrExtend[ outer ] locals[ art = {} ]
1026
+ @after { /* #ATN 1 */ } // if ($art) this.attachLocation( $art ); }
1051
1027
  :
1052
- { this.docComment( $annos ); }
1053
- annotationAssignment_ll1[ $annos ]*
1028
+ { $art.location = this.startLocation();; this.docComment( $art ); }
1029
+ annotationAssignment_ll1[ $art ]*
1054
1030
  // #ATN: element name for definition can be EXTEND
1055
1031
  (
1056
1032
  EXTEND
1057
- extendElement[ $outer, this.startLocation(), $annos ]
1033
+ extendElement[ $art, $outer ]
1058
1034
  |
1059
- art = elementDefInner[ $outer, this.startLocation(), $annos, true ]
1035
+ elementDefInner[ $art, $outer, true ]
1060
1036
  )
1061
1037
  ;
1062
1038
 
1063
- elementDef[ outer ] locals[ annos = [] ]
1064
- @after { this.attachLocation($art.art); }
1039
+ elementDef[ outer ] locals[ $art = {} ]
1065
1040
  :
1066
- { this.docComment( $annos ); }
1067
- annotationAssignment_ll1[ $annos ]*
1068
- art = elementDefInner[ $outer, this.startLocation(), $annos, false ]
1041
+ { $art.location = this.startLocation();; this.docComment( $art ); }
1042
+ annotationAssignment_ll1[ $art ]*
1043
+ elementDefInner[ $art, $outer, false ]
1069
1044
  ;
1070
1045
 
1071
1046
  // Actually, this is a subset if elementDefInner...
1072
1047
  // TODO: the corresponding restrictions must also be checked in the core
1073
1048
  // compiler, as the mixin element could come via CSN
1074
- mixinElementDef[ outer ] locals[ art ]
1049
+ mixinElementDef[ outer ] locals[ art = {} ]
1075
1050
  @after { /* #ATN 2 */ this.attachLocation($art); }
1076
1051
  :
1077
1052
  name=ident['Mixin']
1078
- { $art = this.addDef( $outer, 'mixin', 'mixin', $name.id ); }
1053
+ { this.addDef( $art, $outer, 'mixin', 'mixin', $name.id ); }
1079
1054
  (
1080
1055
  ':'
1081
1056
  // #ATN: referenced type name can be ASSOCIATION or COMPOSITION
@@ -1097,33 +1072,30 @@ mixinElementDef[ outer ] locals[ art ]
1097
1072
  requiredSemi
1098
1073
  ;
1099
1074
 
1100
- misplacedAnnotations[ annos, messageId ]
1101
- :
1102
- // No docComment() here
1103
- annotationAssignment_ll1[ $annos ]+
1104
- { if ($messageId) // issue specified in central registry
1105
- this.message( messageId, this.tokenLocation( $ctx.start, this.getCurrentToken() ) );
1106
- }
1107
- ;
1108
-
1109
- elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1110
- @after{ /* #ATN 5 */ }
1075
+ elementDefInner[ art, outer, allowEq ]
1076
+ @after{ /* #ATN 5 */ this.attachLocation( $art ); }
1111
1077
  :
1112
1078
  // TODO: it would be excellent to remove ELEMENT...
1113
1079
  // or have a special ident rule without the ELEMENT
1114
1080
  // Reason: it would be good for error recovery to start a major block without LL1 ambiguity
1115
1081
  // VIRTUAL is keyword, except if before the following tokens texts:
1116
1082
  { this.setLocalToken( 'VIRTUAL', 'VIRTUAL', /^[:{@=}]$/ ); }
1117
- virtual=VIRTUAL? key=KEY?
1083
+ ( virtual=VIRTUAL { $art.virtual = this.valueWithTokenLocation( true, $virtual ); } )?
1084
+ ( key=KEY { $art.key = this.valueWithTokenLocation( true, $key ); } )?
1118
1085
  // #ATN: element name can be MASKED or ELEMENT (2x)
1119
- masked=MASKED? // TODO: order?
1086
+ ( masked=MASKED
1087
+ {
1088
+ $art.masked = this.valueWithTokenLocation( true, $masked ) ;
1089
+ this.message( 'syntax-invalid-masked', $masked, { keyword: 'masked' },
1090
+ 'Keyword $(KEYWORD) not supported' );
1091
+ }
1092
+ )?
1093
+ // TODO: order?
1120
1094
  ELEMENT?
1121
1095
  name=ident['Element']
1122
- { $art = this.addDef( $outer, 'elements', 'element', $name.id, $annos,
1123
- { virtual: $virtual, key: $key, masked: $masked },
1124
- $loc );
1125
- this.docComment( $annos ); }
1126
- annotationAssignment_fix[ $annos ]*
1096
+ { this.addDef( $art, $outer, 'elements', 'element', $name.id );
1097
+ this.docComment( $art ); }
1098
+ annotationAssignment_fix[ $art ]*
1127
1099
  // TODO: we can think of making the typeSpec optional and do checks instead:
1128
1100
  // type optional with '=', type required otherwise
1129
1101
  (
@@ -1138,7 +1110,6 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1138
1110
  (
1139
1111
  typeStruct[ $art ]
1140
1112
  nullability[ $art ]?
1141
- misplacedAnnotations[ $annos, 'syntax-anno-after-struct' ]?
1142
1113
  requiredSemi
1143
1114
  |
1144
1115
  typeAssociationBase[ $art, true ]
@@ -1155,11 +1126,11 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1155
1126
  typeCompoStruct[ $art.target ] optionalSemi
1156
1127
  |
1157
1128
  // we do not support `Composition of many { e }` - ambiguity ad-hoc target versus foreign keys!
1158
- typeToMany[ $art ] typeAssociationElementCont[ $art, $annos ]
1129
+ typeToMany[ $art ] typeAssociationElementCont[ $art ]
1159
1130
  |
1160
- typeToOne[ $art ] typeAssociationElementCont[ $art, $annos ]
1131
+ typeToOne[ $art ] typeAssociationElementCont[ $art ]
1161
1132
  |
1162
- simplePath[ $art.target, 'artref' ] typeAssociationElementCont[ $art, $annos ]
1133
+ simplePath[ $art.target, 'artref' ] typeAssociationElementCont[ $art ]
1163
1134
  )
1164
1135
  |
1165
1136
  (
@@ -1171,52 +1142,55 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1171
1142
  // #ATN: typeRefOptArgs can start with TYPE
1172
1143
  ( typeStruct[ $art.items ]
1173
1144
  nullability[ $art.items ]?
1174
- misplacedAnnotations[ $annos, 'syntax-anno-after-struct' ]?
1175
1145
  | typeTypeOf[ $art.items ]
1176
1146
  nullability[ $art.items ]?
1177
- { this.docComment( $annos ); }
1178
- annotationAssignment_ll1[ $annos ]*
1147
+ { this.docComment( $art ); }
1148
+ annotationAssignment_ll1[ $art ]*
1179
1149
  | typeRefOptArgs[ $art.items ]
1180
- nullability[ $art.items ]?
1181
- { this.docComment( $annos ); }
1182
- annotationAssignment_ll1[ $annos ]*
1150
+ nullability[ $art.items ]? // only if not followed by `enum`
1151
+ { this.docComment( $art ); }
1152
+ annotationAssignment_ll1[ $art ]*
1183
1153
  (
1154
+ { if ($art.items.notNull) {
1155
+ this.message( 'syntax-unexpected-null', $art.items.notNull.location,
1156
+ { keyword: $art.items.notNull.val ? 'not null' : 'null' } );
1157
+ }
1158
+ }
1184
1159
  ENUM '{' { $art.items.enum = this.createDict(); }
1185
1160
  enumSymbolDef[ $art.items ]*
1186
- '}' { this.setDictEndLocation( $art.items.enum ); }
1187
- misplacedAnnotations[ $annos, 'syntax-anno-after-enum' ]?
1161
+ '}' { this.finalizeDictOrArray( $art.items.enum ); }
1162
+ nullability[ $art.items ]?
1188
1163
  )?
1189
1164
  )
1190
1165
  requiredSemi // also req after struct/enum
1191
1166
  |
1192
1167
  typeTypeOf[ $art ] elementProperties[ $art ]?
1193
- { this.docComment( $annos ); }
1194
- annotationAssignment_ll1[ $annos ]*
1168
+ { this.docComment( $art ); }
1169
+ annotationAssignment_ll1[ $art ]*
1195
1170
  requiredSemi // also req after foreign key spec
1196
1171
  |
1197
1172
  l=LOCALIZED { $art.localized = this.valueWithTokenLocation( true, $l ); }
1198
1173
  typeRefOptArgs[ $art ]
1199
- { this.docComment( $annos ); }
1200
- annotationAssignment_ll1[ $annos ]*
1174
+ { this.docComment( $art ); }
1175
+ annotationAssignment_ll1[ $art ]*
1201
1176
  ( elementProperties[ $art ]
1202
- { this.docComment( $annos ); }
1203
- annotationAssignment_ll1[ $annos ]*
1177
+ { this.docComment( $art ); }
1178
+ annotationAssignment_ll1[ $art ]*
1204
1179
  )?
1205
1180
  requiredSemi
1206
1181
  |
1207
1182
  typeRefOptArgs[ $art ]
1208
- { this.docComment( $annos ); }
1209
- annotationAssignment_ll1[ $annos ]*
1183
+ { this.docComment( $art ); }
1184
+ annotationAssignment_ll1[ $art ]*
1210
1185
  (
1211
1186
  ENUM '{' { $art.enum = this.createDict(); }
1212
1187
  enumSymbolDef[ $art ]*
1213
- '}' { this.setDictEndLocation( $art.enum ); }
1188
+ '}' { this.finalizeDictOrArray( $art.enum ); }
1214
1189
  elementProperties[ $art ]?
1215
- misplacedAnnotations[ $annos, 'syntax-anno-after-enum' ]?
1216
1190
  |
1217
1191
  elementProperties[ $art ]
1218
- { this.docComment( $annos ); }
1219
- annotationAssignment_ll1[ $annos ]*
1192
+ { this.docComment( $art ); }
1193
+ annotationAssignment_ll1[ $art ]*
1220
1194
  )?
1221
1195
  requiredSemi // also req after enum spec
1222
1196
  )
@@ -1229,65 +1203,45 @@ elementDefInner[ outer, loc, annos, allowEq ] returns[ art ]
1229
1203
  else if ($e.expr)
1230
1204
  $art.value = $e.expr;
1231
1205
  }
1232
- { this.docComment( $annos ); }
1233
- annotationAssignment_ll1[ $annos ]* // for enum symbol def via EXTEND
1206
+ { this.docComment( $art ); }
1207
+ annotationAssignment_ll1[ $art ]* // for enum symbol def via EXTEND
1234
1208
  requiredSemi
1235
1209
  )
1236
1210
  ;
1237
1211
 
1238
- extendElement[ outer, loc, annos ] locals[ art ]
1239
- @after{ /* #ATN 1 */ this.attachLocation($art); }
1212
+ extendElement[ art, outer ]
1213
+ @after{ /* #ATN 1 */ this.attachLocation( $art ); }
1240
1214
  :
1241
1215
  // #ATN: element name can be ELEMENT
1242
- expected=ELEMENT? name=ident['Element']
1243
- { $art = this.addDef( $outer, 'elements', 'extend', $name.id, $annos,
1244
- { expectedKind: $expected && 'element' },
1245
- $loc ); }
1246
- extendWithOptElements[ $art, $annos ]
1247
- ;
1248
-
1249
- bracedSelectItemListDef[ query ]
1250
- :
1251
- '{'
1252
- { if (!$query.columns) $query.columns = []; } // set it early to avoid "wildcard" errors
1253
- (
1254
- selectItemDef[ $query.columns ]
1255
- ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
1256
- selectItemDef[ $query.columns ]
1257
- )*
1258
- )?
1259
- '}'
1216
+ ( expected=ELEMENT { $art.expectedKind = 'element'; } )?
1217
+ name=ident['Element']
1218
+ { this.addDef( $art, $outer, 'elements', 'extend', $name.id ); }
1219
+ extendWithOptElements[ $art, $art ]
1260
1220
  ;
1261
1221
 
1262
- selectItemDef[ outer ] locals[ annos = [] ]
1263
- @after{ if ($ctx.art) this.attachLocation($art.art); }
1222
+ selectItemDef[ outer ] locals[ art ]
1223
+ @after{ if ($art) this.attachLocation( $art ); }
1264
1224
  :
1265
1225
  star='*'
1266
1226
  { $outer.push( this.valueWithTokenLocation( '*', $star ) ); }
1267
1227
  |
1268
- { this.docComment( $annos ); }
1269
- annotationAssignment_atn[ $annos ]*
1228
+ { $art = {};; this.docComment( $art ); }
1229
+ annotationAssignment_atn[ $art ]*
1270
1230
  // VIRTUAL is keyword, except if before the following tokens texts:
1271
1231
  { this.setLocalToken( 'VIRTUAL', 'VIRTUAL', /^([,.:\[@]|as)$/i ) ; } // not '{'
1272
- virtual=VIRTUAL?
1273
- key=KEY?
1274
- art=selectItemDefBody[ $outer, $annos ]
1275
- {
1276
- if ($virtual) $art.art.virtual = this.valueWithTokenLocation( true, $virtual );
1277
- if ($key) $art.art.key = this.valueWithTokenLocation( true, $key );
1278
- }
1232
+ ( virtual=VIRTUAL { $art.virtual = this.valueWithTokenLocation( true, $virtual ); } )?
1233
+ ( key=KEY { $art.key = this.valueWithTokenLocation( true, $key ); } )?
1234
+ selectItemDefBody[ $art, $outer ]
1279
1235
  ;
1280
1236
 
1281
- selectItemDefBody[ outer, annos ] returns[ art = {} ]
1282
- @after{ /* #ATN 2 */ this.attachLocation($art); }
1237
+ selectItemDefBody[ art, outer ]
1238
+ @after{ /* #ATN 2 */ }
1283
1239
  :
1240
+ { $outer.push( $art ); }
1284
1241
  (
1285
- e=expression
1242
+ e=expression { $art.value = $e.expr; }
1286
1243
  // we cannot use 'condition' instead, as long as we allow aliases without
1287
1244
  // AS (using rule 'ident' instead of 'identNoKeyword') -> ambiguities
1288
- {
1289
- $art = this.addItem( $outer, null, null, $annos, { value: $e.expr } );
1290
- }
1291
1245
  ( AS n1=ident['Item'] { $art.name = $n1.id }
1292
1246
  | n2=ident['Item'] { $art.name = this.fragileAlias( $n2.id, true ); }
1293
1247
  | { if (this.getCurrentToken().text !== '.') this.classifyImplicitName( 'Item', $e.expr ); }
@@ -1311,13 +1265,12 @@ selectItemDefBody[ outer, annos ] returns[ art = {} ]
1311
1265
  )
1312
1266
  )?
1313
1267
  |
1314
- { $art = this.addItem( $outer, null, null, $annos ); }
1315
1268
  selectItemInlineList[ $art, 'expand' ]
1316
1269
  excludingClause[ $art ]?
1317
1270
  AS n1=ident['Item'] { $art.name = $n1.id }
1318
1271
  )
1319
- { this.docComment( $annos ); }
1320
- annotationAssignment_fix[ $annos ]*
1272
+ { this.docComment( $art ); }
1273
+ annotationAssignment_fix[ $art ]*
1321
1274
  ( ':'
1322
1275
  // #ATN: typeRefOptArgs can start with TYPE, REDIRECTED
1323
1276
  ( re=REDIRECTED to=TO
@@ -1326,15 +1279,15 @@ selectItemDefBody[ outer, annos ] returns[ art = {} ]
1326
1279
  (
1327
1280
  typeAssociationCont[ $art ]
1328
1281
  |
1329
- { this.docComment( $annos ); }
1330
- annotationAssignment_ll1[ $annos ]*
1282
+ { this.docComment( $art ); }
1283
+ annotationAssignment_ll1[ $art ]*
1331
1284
  )
1332
1285
  | typeTypeOf[ $art ]
1333
- { this.docComment( $annos ); }
1334
- annotationAssignment_ll1[ $annos ]*
1335
- | typeRefOptArgs[ $art ] // TODO: annos here?
1336
- { this.docComment( $annos ); }
1337
- annotationAssignment_ll1[ $annos ]*
1286
+ { this.docComment( $art ); }
1287
+ annotationAssignment_ll1[ $art ]*
1288
+ | typeRefOptArgs[ $art ]
1289
+ { this.docComment( $art ); }
1290
+ annotationAssignment_ll1[ $art ]*
1338
1291
  |
1339
1292
  typeAssociationBase[ $art, false ]
1340
1293
  // #ATN: path could start with MANY or ONE - make sure a token follows in same rule!
@@ -1345,28 +1298,39 @@ selectItemDefBody[ outer, annos ] returns[ art = {} ]
1345
1298
  )?
1346
1299
  ;
1347
1300
 
1301
+ bracedSelectItemListDef[ query ]
1302
+ :
1303
+ '{' { $query.columns = this.createArray(); }
1304
+ (
1305
+ selectItemDef[ $query.columns ]
1306
+ ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
1307
+ selectItemDef[ $query.columns ]
1308
+ )*
1309
+ )?
1310
+ '}' { this.finalizeDictOrArray( $query.columns ); }
1311
+ ;
1312
+
1348
1313
  selectItemInlineList[ art, clause ]
1349
1314
  :
1350
- '{'
1351
- { $art[$clause] = []; }
1315
+ '{' { $art[$clause] = this.createArray(); }
1352
1316
  (
1353
1317
  selectItemInlineDef[ $art[$clause] ]
1354
1318
  ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
1355
1319
  selectItemInlineDef[ $art[$clause] ]
1356
1320
  )*
1357
1321
  )?
1358
- '}'
1322
+ '}' { this.finalizeDictOrArray( $art[$clause] ); }
1359
1323
  ;
1360
1324
 
1361
- selectItemInlineDef[ outer ] locals[ annos = [] ]
1362
- @after{ if ($ctx.art) this.attachLocation($art.art); }
1325
+ selectItemInlineDef[ outer ] locals[ art ]
1326
+ @after{ if ($art) this.attachLocation( $art ); }
1363
1327
  :
1364
1328
  star='*'
1365
1329
  { $outer.push( this.valueWithTokenLocation( '*', $star ) ); }
1366
1330
  |
1367
- { this.docComment( $annos ); }
1368
- annotationAssignment_atn[ $annos ]*
1369
- art=selectItemDefBody[ $outer, $annos ]
1331
+ { $art = {};; this.docComment( $art ); }
1332
+ annotationAssignment_atn[ $art ]*
1333
+ selectItemDefBody[ $art, $outer ]
1370
1334
  ;
1371
1335
 
1372
1336
  parameterListDef[ art ]
@@ -1380,51 +1344,22 @@ parameterListDef[ art ]
1380
1344
  parameterDef[ $art ]
1381
1345
  )*
1382
1346
  )?
1383
- ')' { this.setDictEndLocation( $art.params ); }
1347
+ ')' { this.finalizeDictOrArray( $art.params ); }
1384
1348
  ;
1385
1349
 
1386
- parameterDef[ outer ] locals[ art, annos = [] ]
1387
- @after { this.attachLocation($art); }
1350
+ parameterDef[ outer ] locals[ art = {} ]
1351
+ @after { this.attachLocation( $art ); }
1388
1352
  :
1389
- { this.docComment( $annos ); }
1390
- annotationAssignment_ll1[ $annos ]*
1353
+ { this.docComment( $art ); }
1354
+ annotationAssignment_ll1[ $art ]*
1391
1355
  name=ident['Param']
1392
- { $art = this.addDef( $outer, 'params', 'param', $name.id, $annos );
1393
- this.docComment( $annos ); }
1394
- annotationAssignment_fix[ $annos ]*
1356
+ { this.addDef( $art, $outer, 'params', 'param', $name.id );
1357
+ this.docComment( $art ); }
1358
+ annotationAssignment_fix[ $art ]*
1395
1359
  typeSpec[ $art ]
1396
1360
  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 ]*
1361
+ { this.docComment( $art ); }
1362
+ annotationAssignment_ll1[ $art ]*
1428
1363
  ;
1429
1364
 
1430
1365
  nullability[ art ]
@@ -1451,21 +1386,25 @@ elementProperties[ elem ]
1451
1386
 
1452
1387
  // View definitions ----------------------------------------------------------
1453
1388
 
1454
- viewDef[ outer, loc, annos ] locals[ art, name = {} ]
1455
- @after { this.attachLocation($art); }
1389
+ viewDef[ art, outer ] locals[ name = {} ]
1390
+ @after { this.attachLocation( $art ); }
1456
1391
  :
1457
1392
  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 ]*
1393
+ { $art['$'+'syntax'] = 'view';
1394
+ this.addDef( $art, $outer, 'artifacts', 'entity', $name );
1395
+ this.docComment( $art ); }
1396
+ annotationAssignment_fix[ $art ]*
1461
1397
  (
1462
- entityParameters[ $art ]
1398
+ parameterListDef[ $art ]
1463
1399
  |
1464
- ( HideAlternatives | WITH ) PARAMETERS
1465
- entityParameterDef[ $art ]
1466
- ( ',' entityParameterDef[ $art ] )* // no optional final ',' here
1400
+ // TODO: warning deprecated?
1401
+ ( HideAlternatives | WITH ) { $art.params = this.createDict(); }
1402
+ PARAMETERS
1403
+ parameterDef[ $art ]
1404
+ ( ',' parameterDef[ $art ] )* // no optional final ',' here
1405
+ { this.finalizeDictOrArray( $art.params ); }
1467
1406
  )?
1468
- AS qe=queryExpression { $art.query = $qe.query; } // beta-mode test now in definer
1407
+ AS qe=queryExpression { $art.query = $qe.query; }
1469
1408
  // TODO check ANTLR: bad msg with 'view V as'<eof> but 'view V as FOO' is fine
1470
1409
  requiredSemi
1471
1410
  ;
@@ -1496,12 +1435,12 @@ typeSpec[ art ] // for params
1496
1435
  (
1497
1436
  ENUM '{' { $art.enum = this.createDict(); }
1498
1437
  enumSymbolDef[ $art ]*
1499
- '}' { this.setDictEndLocation( $art.enum ); }
1438
+ '}' { this.finalizeDictOrArray( $art.enum ); }
1500
1439
  )?
1501
1440
  )
1502
1441
  ;
1503
1442
 
1504
- returnTypeSpec[ art, annos ]
1443
+ returnTypeSpec[ art ]
1505
1444
  @after{ /* #ATN 1 */ }
1506
1445
  :
1507
1446
  ret=RETURNS { $art.returns = { location: this.tokenLocation( $ret ), kind: 'param' }; }
@@ -1517,17 +1456,15 @@ returnTypeSpec[ art, annos ]
1517
1456
  (
1518
1457
  ENUM '{' { $art.returns.enum = this.createDict(); }
1519
1458
  enumSymbolDef[ $art.returns ]*
1520
- '}' { this.setDictEndLocation( $art.returns.enum ); }
1521
- |
1522
- misplacedAnnotations[ $annos, 'syntax-anno-after-params' ]
1459
+ '}' { this.finalizeDictOrArray( $art.returns.enum ); }
1523
1460
  )?
1524
1461
  )
1525
1462
 
1526
- requiredSemi // currently for all - might change if we get rid of the misplaced annos
1463
+ requiredSemi // currently for all - might change if we get rid of the misplaced annos (TODO: Now removed)
1527
1464
  ;
1528
1465
 
1529
1466
 
1530
- typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1467
+ typeSpecSemi[ art ] // with 'includes', for type and annotation defs
1531
1468
  @after{ /* #ATN 3 */ }
1532
1469
  :
1533
1470
  typeStruct[ $art ]
@@ -1565,18 +1502,28 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1565
1502
  optionalSemi
1566
1503
  | typeTypeOf[ $art.items ]
1567
1504
  nullability[ $art.items ]?
1568
- { this.docComment( $annos ); }
1569
- annotationAssignment_ll1[ $annos ]*
1505
+ { this.docComment( $art ); }
1506
+ annotationAssignment_ll1[ $art ]*
1570
1507
  requiredSemi
1571
1508
  | typeRefOptArgs[ $art.items ]
1572
- nullability[ $art.items ]?
1573
- { this.docComment( $annos ); }
1574
- annotationAssignment_ll1[ $annos ]*
1509
+ nullability[ $art.items ]? // only if not followed by `enum`
1510
+ { this.docComment( $art ); }
1511
+ annotationAssignment_ll1[ $art ]*
1575
1512
  (
1513
+ { if ($art.items.notNull) {
1514
+ this.message( 'syntax-unexpected-null', $art.items.notNull.location,
1515
+ { keyword: $art.items.notNull.val ? 'not null' : 'null' } );
1516
+ }
1517
+ }
1576
1518
  ENUM '{' { $art.items.enum = this.createDict(); }
1577
1519
  enumSymbolDef[ $art.items ]*
1578
- '}' { this.setDictEndLocation( $art.items.enum ); }
1579
- optionalSemi
1520
+ '}' { this.finalizeDictOrArray( $art.items.enum ); }
1521
+ (
1522
+ nullability[ $art.items ]
1523
+ requiredSemi
1524
+ |
1525
+ optionalSemi
1526
+ )
1580
1527
  |
1581
1528
  requiredSemi
1582
1529
  )
@@ -1584,14 +1531,14 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1584
1531
  |
1585
1532
  typeTypeOf[ $art ]
1586
1533
  defaultValue[ $art ]?
1587
- { this.docComment( $annos ); }
1588
- annotationAssignment_ll1[ $annos ]* requiredSemi
1534
+ { this.docComment( $art ); }
1535
+ annotationAssignment_ll1[ $art ]* requiredSemi
1589
1536
  |
1590
1537
  l=LOCALIZED { $art.localized = this.valueWithTokenLocation( true, $l ); }
1591
1538
  typeRefOptArgs[ $art ]
1592
1539
  defaultValue[ $art ]?
1593
- { this.docComment( $annos ); }
1594
- annotationAssignment_ll1[ $annos ]*
1540
+ { this.docComment( $art ); }
1541
+ annotationAssignment_ll1[ $art ]*
1595
1542
  requiredSemi
1596
1543
  |
1597
1544
  // alt lookahead includes MANY '{'
@@ -1599,12 +1546,12 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1599
1546
  simplePath[ $art.type, 'artref' ]
1600
1547
  (
1601
1548
  typeRefArgs[ $art ]
1602
- { this.docComment( $annos ); }
1603
- annotationAssignment_ll1[ $annos ]*
1549
+ { this.docComment( $art ); }
1550
+ annotationAssignment_ll1[ $art ]*
1604
1551
  (
1605
1552
  ENUM '{' { $art.enum = this.createDict(); }
1606
1553
  enumSymbolDef[ $art ]*
1607
- '}' { this.setDictEndLocation( $art.enum ); }
1554
+ '}' { this.finalizeDictOrArray( $art.enum ); }
1608
1555
  (
1609
1556
  optionalSemi
1610
1557
  |
@@ -1619,12 +1566,12 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1619
1566
  ':' // with element, e.g. `type T : E:elem enum { ... }`
1620
1567
  { $art.type.scope = $art.type.path.length; }
1621
1568
  simplePath[ $art.type, 'ref']
1622
- { this.docComment( $annos ); }
1623
- annotationAssignment_ll1[ $annos ]*
1569
+ { this.docComment( $art ); }
1570
+ annotationAssignment_ll1[ $art ]*
1624
1571
  (
1625
1572
  ENUM '{' { $art.enum = this.createDict(); }
1626
1573
  enumSymbolDef[ $art ]*
1627
- '}' { this.setDictEndLocation( $art.enum ); }
1574
+ '}' { this.finalizeDictOrArray( $art.enum ); }
1628
1575
  (
1629
1576
  optionalSemi
1630
1577
  |
@@ -1636,12 +1583,12 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
1636
1583
  requiredSemi
1637
1584
  )
1638
1585
  |
1639
- { this.docComment( $annos ); }
1640
- annotationAssignment_ll1[ $annos ]*
1586
+ { this.docComment( $art ); }
1587
+ annotationAssignment_ll1[ $art ]*
1641
1588
  (
1642
1589
  ENUM '{' { $art.enum = this.createDict(); }
1643
1590
  enumSymbolDef[ $art ]*
1644
- '}' { this.setDictEndLocation( $art.enum ); }
1591
+ '}' { this.finalizeDictOrArray( $art.enum ); }
1645
1592
  (
1646
1593
  optionalSemi
1647
1594
  |
@@ -1669,7 +1616,7 @@ typeStruct[ art, attachLoc = false ]
1669
1616
  :
1670
1617
  '{' { $art.elements = this.createDict(); }
1671
1618
  elementDef[ $art ]*
1672
- '}' { this.setDictEndLocation( $art.elements ); }
1619
+ '}' { this.finalizeDictOrArray( $art.elements ); }
1673
1620
  ;
1674
1621
 
1675
1622
  typeCompoStruct[ art ]
@@ -1677,7 +1624,7 @@ typeCompoStruct[ art ]
1677
1624
  :
1678
1625
  COMPOSITIONofBRACE { $art.elements = this.createDict(); }
1679
1626
  elementDef[ $art ]*
1680
- '}' { this.setDictEndLocation( $art.elements ); }
1627
+ '}' { this.finalizeDictOrArray( $art.elements ); }
1681
1628
  ;
1682
1629
 
1683
1630
  typeArray[ art ]
@@ -1699,7 +1646,7 @@ typeArray[ art ]
1699
1646
  (
1700
1647
  ENUM '{' { $art.items.enum = this.createDict(); }
1701
1648
  enumSymbolDef[ $art.items ]*
1702
- '}' { this.setDictEndLocation( $art.items.enum ); }
1649
+ '}' { this.finalizeDictOrArray( $art.items.enum ); }
1703
1650
  )?
1704
1651
  )
1705
1652
  ;
@@ -1728,33 +1675,31 @@ typeAssociationCont[ art ]
1728
1675
  :
1729
1676
  (
1730
1677
  '{' { $art.foreignKeys = this.createDict(); }
1731
- { this.addDef( $art, 'foreignKeys' ); }
1732
1678
  (
1733
1679
  foreignKey[ $art ]
1734
1680
  ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
1735
1681
  foreignKey[ $art ]
1736
1682
  )*
1737
1683
  )?
1738
- '}' { this.setDictEndLocation( $art.foreignKeys ); }
1684
+ '}' { this.finalizeDictOrArray( $art.foreignKeys ); }
1739
1685
  |
1740
1686
  ON cond=condition
1741
1687
  { $art.on=$cond.cond; }
1742
1688
  )
1743
1689
  ;
1744
1690
 
1745
- typeAssociationElementCont[ art, annos ] // including Composition
1691
+ typeAssociationElementCont[ art ] // including Composition
1746
1692
  // optional NULL / NOT NULL for managed association only
1747
1693
  :
1748
1694
  (
1749
1695
  '{' { $art.foreignKeys = this.createDict(); }
1750
- { this.addDef( $art, 'foreignKeys' ); }
1751
1696
  (
1752
1697
  foreignKey[ $art ]
1753
1698
  ( ',' { if (this.isStraightBefore("}")) break; } // allow ',' before '}'
1754
1699
  foreignKey[ $art ]
1755
1700
  )*
1756
1701
  )?
1757
- '}' { this.setDictEndLocation( $art.foreignKeys ); }
1702
+ '}' { this.finalizeDictOrArray( $art.foreignKeys ); }
1758
1703
  nullability[ $art ]?
1759
1704
  |
1760
1705
  ON cond=condition
@@ -1762,8 +1707,8 @@ typeAssociationElementCont[ art, annos ] // including Composition
1762
1707
  |
1763
1708
  nullability[ $art ]
1764
1709
  )?
1765
- { this.docComment( $annos ); }
1766
- annotationAssignment_ll1[ $annos ]*
1710
+ { this.docComment( $art ); }
1711
+ annotationAssignment_ll1[ $art ]*
1767
1712
  requiredSemi // also req after foreign key spec
1768
1713
  ;
1769
1714
 
@@ -1817,10 +1762,9 @@ cardinality[ art ] locals[ card = {} ]
1817
1762
  foreignKey[ outer ] locals[ art = {}, elem = {} ]
1818
1763
  @after { this.attachLocation($art); }
1819
1764
  :
1820
- simplePath[ $elem, 'ref' ]
1765
+ simplePath[ $elem, 'ref' ] { $art.targetElement = $elem; }
1821
1766
  ( AS name=ident['Key'] )?
1822
- { $art = this.addDef( $outer, 'foreignKeys', 'key', ($ctx.name) ? $name.id : $elem.path,
1823
- undefined, { targetElement: $elem } ); }
1767
+ { this.addDef( $art, $outer, 'foreignKeys', 'key', ($ctx.name) ? $name.id : $elem.path ); }
1824
1768
  ;
1825
1769
 
1826
1770
  typeTypeOf[ art ] locals[ _sync = 'nop' ]
@@ -1852,11 +1796,11 @@ typeRefOptArgs[ art ]
1852
1796
 
1853
1797
  typeRefArgs[ art ]
1854
1798
  :
1855
- paren='('
1799
+ paren='(' { $art['$'+'typeArgs'] = this.createArray(); }
1856
1800
  (
1857
1801
  // unnamed arguments
1858
1802
  head=Number
1859
- { $art['$'+'typeArgs'] = [ this.numberLiteral( $head ) ]; }
1803
+ { $art['$'+'typeArgs'].push( this.numberLiteral( $head ) ); }
1860
1804
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
1861
1805
  (
1862
1806
  v=VARIABLE
@@ -1880,7 +1824,7 @@ typeRefArgs[ art ]
1880
1824
  typeNamedArg[ $art ]
1881
1825
  )*
1882
1826
  )
1883
- ')'
1827
+ ')'{ this.finalizeDictOrArray( $art['$'+'typeArgs']); }
1884
1828
  ;
1885
1829
 
1886
1830
  typeNamedArg[ art ] locals[ arg = '' ]
@@ -2026,7 +1970,7 @@ overClause returns [ over ]
2026
1970
  @after { this.attachLocation( $over ); }
2027
1971
  :
2028
1972
  o=OVER { $over = { op: this.valueWithTokenLocation( 'over', $o ) , args: [] } }
2029
- '('
1973
+ '(' // TODO: check whether an extra location could be useful
2030
1974
  ( pb=partitionByClause { $over.args.push( $pb.expr ); } )?
2031
1975
  ( ob=overOrderByClause { $over.args.push( $ob.expr ); } )?
2032
1976
  ( wf=windowFrameClause { $over.args.push( $wf.wf ); } )?
@@ -2079,13 +2023,13 @@ queryPrimary returns[ query = {} ]
2079
2023
  (
2080
2024
  mixin=MIXIN '{' { $query.mixin = this.createDict(); }
2081
2025
  mixinElementDef[ $query ]*
2082
- '}' { this.setDictEndLocation( $query.mixin ); }
2026
+ '}' { this.finalizeDictOrArray( $query.mixin ); }
2083
2027
  INTO
2084
2028
  )?
2085
2029
  ( ad=( ALL | DISTINCT ) // TODO: or directly after SELECT ?
2086
2030
  { $query.quantifier = this.valueWithTokenLocation( $ad.text.toLowerCase(), $ad ); }
2087
2031
  )?
2088
- bracedSelectItemListDef[ $query ]?
2032
+ bracedSelectItemListDef[ $query, 'columns' ]?
2089
2033
  excludingClause[ $query ]?
2090
2034
  |
2091
2035
  ( ad=( ALL | DISTINCT ) // TODO: or directly after SELECT ?
@@ -2429,7 +2373,9 @@ expressionTerm returns [ expr ] locals [ op, args = [] ]
2429
2373
  }
2430
2374
  )
2431
2375
  |
2432
- qm=( HideAlternatives | '?' )
2376
+ qm= '?' // is automatically not mentioned as CC candidate
2377
+ // if we have an HideAlternatives here, we would block it to use it in
2378
+ // parallel to an expression (would produce adaptivePredict() otherwise)
2433
2379
  { $expr = { param: this.valueWithTokenLocation( '?', $qm ), scope: 'param' };
2434
2380
  this.csnParseOnly( 'Dynamic parameter "?" is not supported', $qm );
2435
2381
  }
@@ -2457,39 +2403,12 @@ expressionTerm returns [ expr ] locals [ op, args = [] ]
2457
2403
  ;
2458
2404
 
2459
2405
  specialFunction returns [ ret = { } ] locals[ art = {} ]
2460
- @after{ /* #ATN 1 */ }
2461
2406
  :
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='('
2407
+ ca=CAST '(' // see createArray() in action
2489
2408
  {
2490
2409
  $ret = {
2491
2410
  op: this.valueWithTokenLocation( 'cast', $ca ),
2492
- args: [ ],
2411
+ args: this.createArray(),
2493
2412
  location: this.tokenLocation( $ca )
2494
2413
  };
2495
2414
  }
@@ -2497,8 +2416,7 @@ specialFunction returns [ ret = { } ] locals[ art = {} ]
2497
2416
  {
2498
2417
  $ret.args.push( $e.expr );
2499
2418
  }
2500
- ')'
2501
- // TODO: ROUND - see also resolver.js
2419
+ ')' { this.finalizeDictOrArray( $ret.args ); }
2502
2420
  ;
2503
2421
 
2504
2422
  // query path includes aggregation:
@@ -2524,36 +2442,47 @@ valuePath[ category, location = null ] returns[ qp = { path: [] } ] locals[ _syn
2524
2442
  ;
2525
2443
 
2526
2444
  fromArguments[ pathStep ]
2445
+ @init{ if (!$pathStep) $pathStep = {}; } // grammar robustness, see test/negative/parser/NamedExpression.cds
2527
2446
  :
2528
- paren='('
2529
- namedExpression[ $pathStep ]
2447
+ '(' { $pathStep.args = this.createDict(); $pathStep['$'+'syntax'] = ':'; } // necessary?
2448
+ name=ident['paramname'] ':'
2449
+ namedExpression[ $pathStep, $name.id ]
2530
2450
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
2531
- namedExpression[ $pathStep ]
2451
+ name=ident['paramname'] ':'
2452
+ namedExpression[ $pathStep, $name.id ]
2532
2453
  )*
2533
- ')'
2454
+ ')' { this.finalizeDictOrArray( $pathStep.args ); }
2534
2455
  ;
2535
2456
 
2536
2457
  pathArguments[ pathStep, considerSpecial ]
2537
- @after{ /* #ATN 1 */ }
2458
+ @init{
2459
+ if (!$pathStep) $pathStep = {}; // grammar robustness, see test/negative/parser/NamedExpression.cds
2460
+ this.genericFunctionsStack.push( this['$'+'genericKeywords'] );
2461
+ }
2538
2462
  :
2539
2463
  { this.excludeExpected([ 'ORDER' ]); }
2540
- paren='('
2541
- { this.prepareGenericKeywords( $considerSpecial ); }
2542
- // ATN, LL2: Identifier can start both named arguments and the positional.
2464
+ '(' // dict or array, see below
2543
2465
  // Make sure that we do not introduce A:B paths in expressions!
2466
+ // Need to avoid adaptPredict(), otherwise Generic keywords won't work in funcExpression
2467
+ { this.setLocalTokenForId( { ':': 'HelperToken1', '=>': 'HelperToken2' } ); }
2544
2468
  (
2545
- namedExpression[ $pathStep ]
2469
+ { $pathStep.args = this.createDict(); $pathStep['$'+'syntax'] = ':'; }
2470
+ id=HelperToken1 ':'
2471
+ namedExpression[ $pathStep, this.identAst( $id, 'paramname', true ) ]
2546
2472
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
2547
- namedExpression[ $pathStep ]
2473
+ name=ident['paramname'] ':'
2474
+ namedExpression[ $pathStep, $name.id ]
2548
2475
  )*
2549
2476
  |
2550
- { $pathStep.args = Object.create(null); } // TODO: XSN func path cleanup
2551
- arrowedExpression[ $pathStep ]
2477
+ { $pathStep.args = this.createDict(); } // TODO: XSN func path cleanup
2478
+ id=HelperToken2 '=>'
2479
+ namedExpression[ $pathStep, this.identAst( $id, 'paramname', true ) ]
2552
2480
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
2553
- arrowedExpression[ $pathStep ]
2481
+ name=ident['paramname'] '=>'
2482
+ namedExpression[ $pathStep, $name.id ]
2554
2483
  )*
2555
2484
  |
2556
- { $pathStep.args = []; }
2485
+ { $pathStep.args = this.createArray(); }
2557
2486
  funcExpression[ $pathStep, $considerSpecial ]
2558
2487
  ( ',' { if (this.isStraightBefore(')')) break; } // allow ',' before ')'
2559
2488
  funcExpression[ $pathStep, $considerSpecial ]
@@ -2566,47 +2495,82 @@ pathArguments[ pathStep, considerSpecial ]
2566
2495
  }
2567
2496
  )?
2568
2497
  |
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 = []; }
2498
+ { $pathStep.args = this.createArray(); }
2580
2499
  )
2581
- ')'
2500
+ ')' { this.finalizeDictOrArray( $pathStep.args ); }
2582
2501
  ;
2502
+ finally { // see @init
2503
+ if (!$pathStep.args) $pathStep.args = [];
2504
+ this['$'+'genericKeywords'] = this.genericFunctionsStack.pop();
2505
+ }
2583
2506
 
2584
- namedExpression[ pathStep ]
2507
+ namedExpression[ pathStep, id ]
2585
2508
  :
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'] = ':';
2509
+ elem=expression
2510
+ { if ($pathStep && $id) {
2511
+ this.addDef( ($ctx.elem) ? $elem.expr : { location: $id.location },
2512
+ $pathStep, 'args', 0, $id );
2591
2513
  }
2592
2514
  }
2593
2515
  ;
2594
2516
 
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 ]
2517
+ funcExpression[ pathStep, considerSpecial ] locals[ args ]
2603
2518
  @init { this.prepareGenericKeywords( $considerSpecial ); }
2604
2519
  :
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 ); }
2520
+ (
2521
+ expr=expression
2522
+ { $pathStep.args.push( $expr.expr ); }
2523
+ |
2524
+ GenericExpr // keyword as replacement for expression, like '*'
2525
+ { $pathStep.args.push( this.xprToken() ); }
2526
+ |
2527
+ GenericIntro // keyword as introduction of expression, like DISTINCT
2528
+ { $pathStep.args.push( this.xprToken() ); }
2529
+ expr=expression
2530
+ { $args = this.setLastAsXpr( $pathStep.args );
2531
+ $args.push( $expr.expr ); }
2532
+ |
2533
+ // Rule 'pathArguments' makes a decision based on the first two lookahead
2534
+ // tokens of this rule → we need to list tokens which would be changed to
2535
+ // GenericExpr or GenericIntro, and are not already covered by 'expression'
2536
+ { this.reportErrorForGenericKeyword(); }
2537
+ ( HideAlternatives | '*' | ALL | DISTINCT )
2538
+ // now continue parsing like GenericExpr:
2539
+ { $pathStep.args.push( this.xprToken() ); }
2540
+ )
2541
+ (
2542
+ { if (!$args) $args = this.setLastAsXpr( $pathStep.args ); }
2543
+ (
2544
+ { this.prepareGenericKeywords( $considerSpecial, 'separator' ); }
2545
+ (
2546
+ GenericSeparator
2547
+ |
2548
+ // For ANTLR's lookahead calculations, we need to list tokens here
2549
+ // which could be changed to GenericSeparator. Do not invent a
2550
+ // keyword token which is just used here (Identifier does work
2551
+ // perfectly)! If we want, we could add all non-reserved keywords
2552
+ // except ORDER, and most reserved.
2553
+ { this.reportErrorForGenericKeyword(); }
2554
+ ( HideAlternatives | Identifier | FROM | IN | WITH | GROUP )
2555
+ )
2556
+ { $args.push( this.xprToken() );
2557
+ this.prepareGenericKeywords( $considerSpecial, 'expr' );
2558
+ }
2559
+ (
2560
+ expr=expression
2561
+ { $args.push( $expr.expr ); }
2562
+ |
2563
+ GenericExpr
2564
+ { $args.push( this.xprToken() ); }
2565
+ |
2566
+ { this.reportErrorForGenericKeyword(); }
2567
+ // Again, we need to list tokens which could make it to GenericExpr
2568
+ // and which do not start an expression
2569
+ ( HideAlternatives | ALL )
2570
+ { $args.push( this.xprToken() ); }
2571
+ )
2572
+ )+
2573
+ )?
2610
2574
  ;
2611
2575
 
2612
2576
  cardinalityAndFilter[ pathStep ] locals [ _sync = 'nop' ]
@@ -2648,32 +2612,41 @@ optionalWhereForFilter
2648
2612
 
2649
2613
  // Simple paths and values ---------------------------------------------------
2650
2614
 
2651
- annoValueBase returns[ val ] locals [ seenEllipsis = false ]
2652
- @after { this.attachLocation($val); }
2615
+ annoValue[ assignment ]
2653
2616
  :
2654
- { $val = { literal: 'struct', location: this.startLocation() }; }
2655
- '{'
2656
- { this.meltKeywordToIdentifier(); }
2657
- namedValue[ $val ]
2617
+ base=annoValueBase[ $assignment ]
2618
+ |
2619
+ // no docComment() here
2620
+ // this alternative is done with token rewrite in rule "annotationAssignment_atn"
2621
+ at='@'? annotationPath[ $assignment, 'ref', $at ]
2622
+ annotationPathVariant[ $assignment ]?
2623
+ ;
2624
+
2625
+ annoValueBase[ assignment ] locals [ seenEllipsis = false ]
2626
+ @after { this.attachLocation( $assignment ); }
2627
+ :
2628
+ '{' // no location here, we flatten
2629
+ { $assignment['$'+'flatten'] = []; this.meltKeywordToIdentifier(); }
2630
+ flattenedValue[ $assignment ]
2658
2631
  (
2659
2632
  ',' {
2660
2633
  this.meltKeywordToIdentifier();
2661
2634
  if (this.isStraightBefore("}")) break; // allow ',' before ')'
2662
2635
  }
2663
- namedValue[ $val ]
2636
+ flattenedValue[ $assignment ]
2664
2637
  )*
2665
2638
  '}'
2666
2639
  |
2667
- { $val = { literal: 'array', location: this.startLocation(), val: [] }; }
2668
- '['
2640
+ '[' // no need for createArray() here, $assignment.location is set
2641
+ { $assignment.val = []; $assignment.literal = 'array'; }
2669
2642
  (
2670
2643
  (
2671
- head=arrayValue { $val.val.push( $head.val ); }
2644
+ head=annoSubValue { $assignment.val.push( $head.val ); }
2672
2645
  |
2673
- e='...' ( UP TO upTo=arrayValue )?
2646
+ e='...' ( UP TO upTo=annoSubValue )?
2674
2647
  {{
2675
2648
  const item = { literal: 'token', val: '...', location: this.tokenLocation($e) };
2676
- $val.val.push( item );
2649
+ $assignment.val.push( item );
2677
2650
  if ($ctx.upTo) item.upTo = $upTo.val;
2678
2651
  $seenEllipsis = !$ctx.upTo || 'upTo';
2679
2652
  }}
@@ -2681,17 +2654,16 @@ annoValueBase returns[ val ] locals [ seenEllipsis = false ]
2681
2654
  (
2682
2655
  ',' { if (this.isStraightBefore(']')) break; } // allow ',' before ']'
2683
2656
  (
2684
- tail=arrayValue { $val.val.push( $tail.val ); }
2657
+ tail=annoSubValue { $assignment.val.push( $tail.val ); }
2685
2658
  |
2686
2659
  { $ctx.upTo = null; } // is not reset
2687
- e='...' ( UP TO upTo=arrayValue )?
2660
+ e='...' ( UP TO upTo=annoSubValue )?
2688
2661
  {{
2689
2662
  const item = { literal: 'token', val: '...', location: this.tokenLocation($e) };
2690
2663
  if ($ctx.upTo) item.upTo = $upTo.val;
2691
- $val.val.push( item );
2664
+ $assignment.val.push( item );
2692
2665
  if ($seenEllipsis === true) // TODO: adapt msg to UP TO
2693
- this.error( 'syntax-unexpected-ellipsis', $e, { code: '...' },
2694
- 'Expected no more than one $(CODE)' );
2666
+ this.error( 'syntax-unexpected-ellipsis', $e, { '#': 'std', code: '...' } );
2695
2667
  else
2696
2668
  $seenEllipsis = !$ctx.upTo || 'upTo';
2697
2669
  }}
@@ -2706,67 +2678,66 @@ annoValueBase returns[ val ] locals [ seenEllipsis = false ]
2706
2678
  'Expecting an array item $(NEWCODE) after an item with $(CODE)' );
2707
2679
  }
2708
2680
  |
2709
- v1=literalValue { $val = $v1.val; }
2681
+ v1=literalValue { Object.assign( $assignment, $v1.val ); }
2710
2682
  |
2711
2683
  ( plus='+' | min='-' ) num=Number
2712
- { $val = this.numberLiteral( $num, $plus||$min ); }
2684
+ { Object.assign( $assignment, this.numberLiteral( $num, $plus||$min ) ); }
2713
2685
  ;
2714
2686
 
2715
- annoValue returns[ val ]
2687
+ flattenedValue[ assignment ] locals[ val = { name: {} } ]
2716
2688
  :
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 ]
2689
+ at='@'? annotationPath[ $val.name, 'name', $at ]
2727
2690
  (
2728
2691
  '#' { this.meltKeywordToIdentifier(); }
2729
- variant=ident['variant'] { $namedVal.name.variant = $variant.id; }
2692
+ variant=ident['variant'] { $val.name.variant = $variant.id; }
2730
2693
  )?
2731
2694
  (
2732
2695
  ':' { this.meltKeywordToIdentifier(true); } // allow path as anno value start with reserved
2733
- elem=annoValue
2696
+ annoValue[ $val ]
2734
2697
  )?
2735
- { this.addItem( $struct, '_struct', null, true, // TODO: re-check _struct
2736
- ($ctx.elem) ? Object.assign($namedVal, $elem.val) : $namedVal ); }
2698
+ { $assignment['$'+'flatten'].push( $val ); }
2737
2699
  ;
2738
2700
 
2739
- arrayValue returns[ val ]
2701
+ namedValue[ struct ] locals[ val = { name: {} } ]
2702
+ :
2703
+ at='@'? annotationPath[ $val.name, 'name', $at ]
2704
+ ( ':' sub=annoSubValue { Object.assign( $val, $sub.val ); } )?
2705
+ {
2706
+ if (!$val.location) $val.location = $val.name.location;
2707
+ this.addDef( $val, $struct, 'struct', null, $val.name ); // TODO: re-check name
2708
+ }
2709
+ ;
2710
+
2711
+ annoSubValue returns[ val = {} ]
2740
2712
  @after { this.attachLocation($val); }
2741
2713
  :
2742
- { $val = { literal: 'struct', location: this.startLocation() }; }
2743
- '{'
2714
+ '{' // no need for createDict() here, $val.location is set
2715
+ { $val.struct = Object.create(null); $val.literal = 'struct'; }
2744
2716
  { this.meltKeywordToIdentifier(); }
2745
- namedValueInArray[ $val ]
2717
+ namedValue[ $val ]
2746
2718
  ( ','
2747
2719
  {
2748
2720
  this.meltKeywordToIdentifier();
2749
2721
  if (this.isStraightBefore("}")) break; // allow ',' before '}'
2750
2722
  }
2751
- namedValueInArray[ $val ]
2723
+ namedValue[ $val ]
2752
2724
  )*
2753
2725
  '}'
2754
2726
  |
2755
- { $val = { literal: 'array', location: this.startLocation(), val: [] }; }
2756
- '['
2757
- ( head=arrayValue { $val.val.push( $head.val ); }
2727
+ '[' // no need for createArray() here, $val.location is set
2728
+ { $val.val = []; $val.literal = 'array'; }
2729
+ ( head=annoSubValue { $val.val.push( $head.val ); }
2758
2730
  ( ',' { if (this.isStraightBefore(']')) break; } // allow ',' before ']'
2759
- tail=arrayValue { $val.val.push( $tail.val ); }
2731
+ tail=annoSubValue { $val.val.push( $tail.val ); }
2760
2732
  )*
2761
2733
  )?
2762
2734
  ']'
2763
2735
  |
2764
- v1=literalValue { $val = $v1.val; }
2736
+ v1=literalValue { Object.assign( $val, $v1.val ); }
2765
2737
  |
2766
2738
  ( plus='+' | min='-' ) num=Number
2767
- { $val = this.numberLiteral( $num, $plus||$min ); }
2739
+ { Object.assign( $val, this.numberLiteral( $num, $plus||$min ) ); }
2768
2740
  |
2769
- { $val = {}; } // TODO: think about expression value representation
2770
2741
  at='@'? annotationPath[ $val, 'ref', $at ]
2771
2742
  (
2772
2743
  '#' { this.meltKeywordToIdentifier(); }
@@ -2774,14 +2745,6 @@ arrayValue returns[ val ]
2774
2745
  )?
2775
2746
  ;
2776
2747
 
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 } ); }
2783
- ;
2784
-
2785
2748
  literalValue returns[ val ] locals[ tok ]
2786
2749
  @init{ $tok = this.getCurrentToken(); }
2787
2750
  @after { this.attachLocation($val); }
@@ -2840,7 +2803,7 @@ annotationPath[ art, category, headat = null ] locals[ _sync = 'nop' ]
2840
2803
  annotationPathVariant[ art ]
2841
2804
  @after { this.attachLocation($art); }
2842
2805
  :
2843
- // TODO: warning for space before and after '#'
2806
+ // TODO: warning for space after '#'
2844
2807
  '#' { this.meltKeywordToIdentifier(); }
2845
2808
  variant=ident['variant'] { $art.variant = $variant.id; }
2846
2809
  ;
@@ -2871,13 +2834,11 @@ ident[ category ] returns[ id ]
2871
2834
  | ASPECT
2872
2835
  | ASSOCIATION
2873
2836
  | BETWEEN
2874
- | BOTH
2875
2837
  | COLUMNS
2876
2838
  | COMPOSITION
2877
2839
  | CONTEXT
2878
2840
  | CROSS
2879
2841
  | CURRENT
2880
- | DAY
2881
2842
  | DEFAULT
2882
2843
  | DEFINE
2883
2844
  | DEFINITIONS
@@ -2901,14 +2862,12 @@ ident[ category ] returns[ id ]
2901
2862
  | FUNCTION
2902
2863
  | GROUP
2903
2864
  | HAVING
2904
- | HOUR
2905
2865
  | INNER
2906
2866
  | INTERSECT
2907
2867
  | INTO
2908
2868
  | IS
2909
2869
  | JOIN
2910
2870
  | LAST
2911
- | LEADING
2912
2871
  | LEFT
2913
2872
  | LIKE
2914
2873
  | LIMIT
@@ -2916,9 +2875,7 @@ ident[ category ] returns[ id ]
2916
2875
  | MANY
2917
2876
  | MASKED
2918
2877
  | MINUS
2919
- | MINUTE
2920
2878
  | MIXIN
2921
- | MONTH
2922
2879
  | NAMESPACE
2923
2880
  | NULLS
2924
2881
  | OFFSET
@@ -2935,10 +2892,8 @@ ident[ category ] returns[ id ]
2935
2892
  | RIGHT
2936
2893
  | ROW
2937
2894
  | ROWS
2938
- | SECOND
2939
2895
  | SERVICE
2940
2896
  | THEN
2941
- | TRAILING
2942
2897
  | UNION
2943
2898
  | UP
2944
2899
  | TO
@@ -2947,7 +2902,6 @@ ident[ category ] returns[ id ]
2947
2902
  | UNBOUNDED
2948
2903
  | VARIABLE
2949
2904
  | VIEW
2950
- | YEAR
2951
2905
  ;
2952
2906
 
2953
2907
  //----------------------------------------------------------------------------
@@ -3039,7 +2993,6 @@ CASE : [cC][aA][sS][eE] ;
3039
2993
  CAST : [cC][aA][sS][tT] ;
3040
2994
  DISTINCT : [dD][iI][sS][tT][iI][nN][cC][tT] ;
3041
2995
  EXISTS : [eE][xX][iI][sS][tT][sS] ;
3042
- EXTRACT : [eE][xX][tT][rR][aA][cC][tT] ;
3043
2996
  // FALSE: see Boolean
3044
2997
  FROM : [fF][rR][oO][mM] ;
3045
2998
  IN : [iI][nN] ;
@@ -3052,7 +3005,6 @@ ON : [oO][nN] ;
3052
3005
  SELECT : [sS][eE][lL][eE][cC][tT] ;
3053
3006
  SOME : [sS][oO][mM][eE] ;
3054
3007
  WHEN : [wW][hH][eE][nN] ;
3055
- TRIM : [tT][rR][iI][mM] ;
3056
3008
  // TRUE: see Boolean
3057
3009
  WHERE : [wW][hH][eE][rR][eE] ;
3058
3010
  WITH : [wW][iI][tT][hH] ;
@@ -3066,6 +3018,7 @@ Number // DO NOT RENAME OR MOVE THIS RULE !!!
3066
3018
  ;
3067
3019
 
3068
3020
  // Unreserved keywords (are case-insensitive): -------------------------------
3021
+ // Do not add keywords just for specialFunctions!
3069
3022
 
3070
3023
  ABSTRACT : [aA][bB][sS][tT][rR][aA][cC][tT] ;
3071
3024
  ACTION : [aA][cC][tT][iI][oO][nN] ;
@@ -3078,13 +3031,11 @@ ASC : [aA][sS][cC] ;
3078
3031
  ASPECT : [aA][sS][pP][eE][cC][tT] ;
3079
3032
  ASSOCIATION : [aA][sS][sS][oO][cC][iI][aA][tT][iI][oO][nN] ;
3080
3033
  BETWEEN : [bB][eE][tT][wW][eE][eE][nN] ;
3081
- BOTH : [bB][oO][tT][hH] ;
3082
3034
  COLUMNS : [cC][oO][lL][uU][mM][nN][sS];
3083
3035
  COMPOSITION : [cC][oO][mM][pP][oO][sS][iI][tT][iI][oO][nN] ;
3084
3036
  CONTEXT : [cC][oO][nN][tT][eE][xX][tT] ;
3085
3037
  CROSS : [cC][rR][oO][sS][sS] ;
3086
3038
  CURRENT : [cC][uU][rR][rR][eE][nN][tT] ;
3087
- DAY : [dD][aA][yY] ;
3088
3039
  DEFAULT : [dD][eE][fF][aA][uU][lL][tT] ;
3089
3040
  DEFINE : [dD][eE][fF][iI][nN][eE] ;
3090
3041
  DEFINITIONS : [dD][eE][fF][iI][nN][iI][tT][iI][oO][nN][sS] ;
@@ -3108,14 +3059,12 @@ FULL : [fF][uU][lL][lL] ;
3108
3059
  FUNCTION : [fF][uU][nN][cC][tT][iI][oO][nN] ;
3109
3060
  GROUP : [gG][rR][oO][uU][pP] ;
3110
3061
  HAVING : [hH][aA][vV][iI][nN][gG] ;
3111
- HOUR : [hH][oO][uU][rR] ;
3112
3062
  INNER : [iI][nN][nN][eE][rR] ;
3113
3063
  INTERSECT : [iI][nN][tT][eE][rR][sS][eE][cC][tT] ;
3114
3064
  INTO : [iI][nN][tT][oO] ;
3115
3065
  IS : [iI][sS] ;
3116
3066
  JOIN : [jJ][oO][iI][nN] ;
3117
3067
  LAST : [lL][aA][sS][tT] ;
3118
- LEADING : [lL][eE][aA][dD][iI][nN][gG] ;
3119
3068
  LEFT : [lL][eE][fF][tT] ;
3120
3069
  LIKE : [lL][iI][kK][eE] ;
3121
3070
  LIMIT : [lL][iI][mM][iI][tT] ;
@@ -3123,9 +3072,7 @@ LOCALIZED: [lL][oO][cC][aA][lL][iI][zZ][eE][dD];
3123
3072
  MANY : [mM][aA][nN][yY] ;
3124
3073
  MASKED : [mM][aA][sS][kK][eE][dD] ;
3125
3074
  MINUS : [mM][iI][nN][uU][sS] ;
3126
- MINUTE : [mM][iI][nN][uU][tT][eE] ;
3127
3075
  MIXIN : [mM][iI][xX][iI][nN] ;
3128
- MONTH : [mM][oO][nN][tT][hH] ;
3129
3076
  NAMESPACE : [nN][aA][mM][eE][sS][pP][aA][cC][eE] ;
3130
3077
  NULLS : [nN][uU][lL][lL][sS] ;
3131
3078
  OFFSET : [oO][fF][fF][sS][eE][tT] ;
@@ -3143,10 +3090,8 @@ RETURNS : [rR][eE][tT][uU][rR][nN][sS] ;
3143
3090
  RIGHT : [rR][iI][gG][hH][tT] ;
3144
3091
  ROW : [rR][oO][wW] ;
3145
3092
  ROWS : [rR][oO][wW][sS] ;
3146
- SECOND : [sS][eE][cC][oO][nN][dD] ;
3147
3093
  SERVICE : [sS][eE][rR][vV][iI][cC][eE] ;
3148
3094
  THEN : [tT][hH][eE][nN] ;
3149
- TRAILING : [tT][rR][aA][iI][lL][iI][nN][gG] ;
3150
3095
  TO : [tT][oO] ; // or make reserved? (is in SQL-92)
3151
3096
  TYPE : [tT][yY][pP][eE] ;
3152
3097
  UNION : [uU][nN][iI][oO][nN] ;
@@ -3156,7 +3101,6 @@ USING : [uU][sS][iI][nN][gG] ;
3156
3101
  VARIABLE : [vV][aA][rR][iI][aA][bB][lL][eE] ;
3157
3102
  VIEW : [vV][iI][eE][wW] ;
3158
3103
  // VIRTUAL: [vV][iI][rR][tT][uU][aA][lL] ; see tokens {}
3159
- YEAR : [yY][eE][aA][rR] ;
3160
3104
 
3161
3105
  // Identifiers, must BE LAST, DIRECTLY AFTER the unreserved keywords ---------
3162
3106