@@ -343,7 +343,20 @@ object JavaParsers {
343
343
annots.toList
344
344
}
345
345
346
- /** Annotation ::= TypeName [`(` AnnotationArgument {`,` AnnotationArgument} `)`]
346
+ /** Annotation ::= TypeName [`(` [AnnotationArgument {`,` AnnotationArgument}] `)`]
347
+ * AnnotationArgument ::= ElementValuePair | ELementValue
348
+ * ElementValuePair ::= Identifier `=` ElementValue
349
+ * ElementValue ::= ConstExpressionSubset
350
+ * | ElementValueArrayInitializer
351
+ * | Annotation
352
+ * ElementValueArrayInitializer ::= `{` [ElementValue {`,` ElementValue}] [`,`] `}`
353
+ * ConstExpressionSubset ::= Literal
354
+ * | QualifiedName
355
+ * | ClassLiteral
356
+ *
357
+ * We support only subset of const expressions expected in this context by java.
358
+ * If we encounter expression that we cannot parse, we do not raise parsing error,
359
+ * but instead we skip entire annotation silently.
347
360
*/
348
361
def annotation (): Option [Tree ] = {
349
362
object LiteralT :
@@ -372,60 +385,64 @@ object JavaParsers {
372
385
)
373
386
else id
374
387
375
- def array (): Tree =
388
+ def array (): Option [ Tree ] =
376
389
accept(LBRACE )
377
- val buffer = ListBuffer [Tree ]()
378
- while ( in.token != RBRACE ) {
390
+ val buffer = ListBuffer [Option [ Tree ] ]()
391
+ while in.token != RBRACE do
379
392
buffer += argValue()
380
- if (in.token == COMMA ) in.nextToken() // using this instead of repsep allows us to handle trailing commas
381
- }
382
- val ok = ! buffer.contains(EmptyTree )
383
- in.token match {
384
- case RBRACE if ok =>
385
- accept(RBRACE )
386
- Apply (scalaDot(nme.Array ), buffer.toList)
387
- case _ =>
388
- skipTo(RBRACE )
389
- EmptyTree
393
+ if in.token == COMMA then
394
+ in.nextToken() // using this instead of repsep allows us to handle trailing commas
395
+ accept(RBRACE )
396
+ Option .unless(buffer contains None ) {
397
+ Apply (scalaDot(nme.Array ), buffer.flatten.toList)
390
398
}
391
399
392
- def argValue (): Tree =
393
- in.token match {
400
+ def argValue (): Option [ Tree ] =
401
+ val tree = in.token match {
394
402
case LiteralT (c) =>
395
403
val tree = atSpan(in.offset)(Literal (c))
396
404
in.nextToken()
397
- tree
405
+ Some ( tree)
398
406
case AT =>
399
407
in.nextToken()
400
- annotation().get
401
- case IDENTIFIER => classOrId()
408
+ annotation()
409
+ case IDENTIFIER => Some ( classOrId() )
402
410
case LBRACE => array()
403
- case _ => EmptyTree
411
+ case _ => None
404
412
}
413
+ if in.token == COMMA || in.token == RBRACE || in.token == RPAREN then
414
+ tree
415
+ else
416
+ skipTo(COMMA , RBRACE , RPAREN )
417
+ None
405
418
406
- def annArg (): Tree =
407
- if (in.token == IDENTIFIER && in.lookaheadToken == EQUALS )
408
- val name = ident()
419
+ def annArg (): Option [ Tree ] =
420
+ val name = if (in.token == IDENTIFIER && in.lookaheadToken == EQUALS )
421
+ val n = ident()
409
422
accept(EQUALS )
410
- val argv = argValue()
411
- NamedArg (name, argv)
412
-
423
+ n
413
424
else
414
- NamedArg (nme.value, argValue())
425
+ nme.value
426
+ argValue().map(NamedArg (name, _))
415
427
416
428
417
429
val id = convertToTypeId(qualId())
418
- val args = if in.token == LPAREN then
430
+ val args = ListBuffer [Option [Tree ]]()
431
+ if in.token == LPAREN then
419
432
in.nextToken()
420
- val args = repsep(annArg, COMMA )
433
+ if in.token != RPAREN then
434
+ args += annArg()
435
+ while in.token == COMMA do
436
+ in.nextToken()
437
+ args += annArg()
421
438
accept(RPAREN )
422
- args
423
- else Nil
424
439
425
- Some (Apply (
426
- Select (New (id), nme.CONSTRUCTOR ),
427
- args
428
- ))
440
+ Option .unless(args contains None ) {
441
+ Apply (
442
+ Select (New (id), nme.CONSTRUCTOR ),
443
+ args.flatten.toList
444
+ )
445
+ }
429
446
}
430
447
431
448
def modifiers (inInterface : Boolean ): Modifiers = {
0 commit comments