@sap/cds-compiler 2.15.2 → 3.0.2

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