You know that in C++ a template instatiation like:
Foo<Bar<Baz>>
is problematic to parse. Nevertheless, Java seems to repeat history and chosed the same simbols for it's generics, but nobody seems to complain about it. Do you happen to know why?
I sat for a moment to think about it, consulted the Java Language Specification , and it turns out a Type is defined as follows:
Type: Identifier [TypeArguments]{ . Identifier [TypeArguments]} {[]} BasicType TypeArguments: < TypeArgument {, TypeArgument} > TypeArgument: Type ? [( extends |super ) Type]
Note that as a TypeArgument, only another Type is allowed. This gives us the clue about why this problem is much easier to solve in C++: arguments to generic types are always types, never expressions.
So if a C++ parser already read
Foo<Bar<Baz>>
it may be that Baz resolves to an integer, that Bar is a template that receives an integer as an argument, and so the parser doesn't know if Baz is the argument of Bar, or if Baz >> somethingElse (which the parser didn't already read, that is, Baz right shift something else) is it's argument.
In Java, if the parser is in the same situation, by simply using a stack of previously encountered generic types, this is very easy to solve. Debugging JDT's code I found these lines:
// when consuming a rule... case 538: if (DEBUG) { System.out.println( "ReferenceType2 ::= ReferenceType RIGHT_SHIFT"); } consumeReferenceType2(); break; case 544: if (DEBUG) { System.out.println( "ReferenceType3 ::= ReferenceType UNSIGNED_RIGHT_SHIFT"); } consumeReferenceType3(); break;
As you can see, the case where a type is encountered followed by a right shift is built in the parser, and the consumeReferenceTypeN() methods simply check their generic types stack to see if everything is ok.