Cleanup grammar

This commit is contained in:
Clément Fournier
2019-04-03 14:48:48 +02:00
committed by Andreas Dangel
parent e83ae65dad
commit 1966a7648c
4 changed files with 30 additions and 54 deletions

View File

@ -479,6 +479,17 @@ public class JavaParser {
}
}
private void forceTypeContext() {
Node top = jjtree.peekNode();
if (top instanceof ASTAmbiguousName) {
// see doc on the method
Node replacement = ((ASTAmbiguousName) top).forceTypeContext();
jjtree.popNode();
jjtree.pushNode(replacement);
}
}
}
PARSER_END(JavaParser)
@ -2040,13 +2051,6 @@ void ArrayTypeDim():
void ReferenceType() #void:
{}
{
// TODO TypeVariable is ambiguous with ClassOrInterfaceType
// but I think it would be good to have a node for it nevertheless
// to help typeres, since TypeVariables have special types (intersection types)
// This could be handled in a rewrite phase, which is necessary for
// disambiguation. Since type parameters shadow anything, their disambiguation
// is stable regardless of classpath config.
( PrimitiveType() Dims() ) #ArrayType
| ( ClassOrInterfaceType() [ LOOKAHEAD(2) Dims() ] ) #ArrayType(>1)
}
@ -2059,20 +2063,12 @@ void ReferenceType() #void:
void ClassOrInterfaceType() #void:
{}
{
/*
FIXME We gobble up all identifiers until we find
either type arguments or annotations, because
it may be a FQCN, e.g. java.util.List is a single node.
But java.util.Map.Entry should be two nodes ((java.util.Map).Entry)
I would have said this doesn't matter but the other fixme comment just
below shows we need a rewrite phase anyway
*/
/*
First, gobble up all identifiers until the first type arguments
or annotation is found. The name is ambiguous between package or
@ -2095,10 +2091,9 @@ void ClassOrInterfaceType() #void:
/*
Now if there are other segments, either the previous segment specified type
arguments, or the next has an annotation.
Each of the following segments is its own ClassOrInterfaceType which encloses the
previous one. The resulting structure appears left-recursive, but the parser just
arguments, or the next has an annotation. Either way we know that all the
following segments is a type name. Each segment is parsed as its own ClassOrInterfaceType
which encloses the previous one. The resulting structure appears left-recursive, but the parser just
executes a loop. That scheme preserves the position of type arguments and annotations.
See #1150.
*/
@ -2111,14 +2106,7 @@ void ClassOrInterfaceType() #void:
[ LOOKAHEAD( "<" ) TypeArguments() ]
) #ClassOrInterfaceType
)*
{
Node top = jjtree.peekNode();
if (top instanceof ASTAmbiguousName) {
Node replacement = ((ASTAmbiguousName) top).forceTypeContext();
jjtree.popNode();
jjtree.pushNode(replacement);
}
}
{ forceTypeContext(); }
}
@ -2231,19 +2219,7 @@ void Expression() #AssignmentExpression(>1):
AssignmentOp AssignmentOperator() #void:
{}
{
( "="
| "*="
| "/="
| "%="
| "+="
| "-="
| "<<="
| ">>="
| ">>>="
| "&="
| "^="
| "|="
)
( "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | ">>>=" | "&=" | "^=" | "|=" )
{return AssignmentOp.fromImage(getToken(0).getImage());}
}
@ -3232,8 +3208,10 @@ String VoidName() #void:
}
// This is used to get JJTree to generate a node.
// Since variable references are most of the time ambiguous, they're
// not created directly by the parser
// Variable references are always ambiguous
// when they're parsed, so they're not created
// normally by jjtree, but rather by the disambiguation
// hooks spread across the parser
//noinspection JavaCCJccUnusedProduction
void VariableReference():
{}

View File

@ -39,8 +39,9 @@ import net.sourceforge.pmd.lang.java.xpath.SemanticAmbiguityChecker;
*
* <blockquote>
* A name is syntactically classified as an ExpressionName in these contexts:
* ...
* - As the qualifying expression in a qualified class instance creation expression (§15.9)*
* ...
* - As the qualifying expression in a qualified class instance creation
* expression (§15.9)
* </blockquote>
*
* We don't know at the moment the name is parsed that it will be
@ -49,13 +50,15 @@ import net.sourceforge.pmd.lang.java.xpath.SemanticAmbiguityChecker;
* expression. In that case, the name can be reclassified, and e.g. if
* it's a simple name be promoted to {@link ASTVariableReference}. This
* type of immediate disambiguation is carried out by the {@link AbstractJavaNode#jjtClose()}
* method of those nodes that can be pushed.
* method of those nodes that do force a specific context on their
* left-hand side. See also {@link LeftRecursiveNode}.
*
* <p>Another mechanism is {@link #forceExprContext()} and {@link #forceTypeContext()},
* which are called by the parser to promote an ambiguous name to an
* expression or a type when it's sure they must be one.
* expression or a type when exiting from the {@link JavaParser#PrimaryExpression()}
* production or {@link JavaParser#ClassOrInterfaceType()}.
*
* <p>These two mechanisms perform the first classification step, the
* <p>Those two mechanisms perform the first classification step, the
* one that only depends on the syntactic context and not on semantic
* information. A second pass on the AST after building the symbol tables
* would allow us to remove all the remaining ambiguous names.
@ -100,6 +103,7 @@ public final class ASTAmbiguousName extends AbstractJavaTypeNode implements ASTR
return getImage();
}
public List<String> getSegments() {
return Arrays.asList(getImage().split("\\."));
}

View File

@ -11,7 +11,6 @@ package net.sourceforge.pmd.lang.java.ast;
*
* <p>This is only relevant to node construction and is package private.
*
*
* @author Clément Fournier
*/
interface LeftRecursiveNode {

View File

@ -30,12 +30,7 @@ public final class SemanticAmbiguityChecker {
}
public static SemanticAmbiguityResult semanticCheck(Node node) {
if (!(node instanceof ASTAmbiguousName)) {
return null;
}
ASTAmbiguousName name = (ASTAmbiguousName) node;
public static SemanticAmbiguityResult semanticCheck(ASTAmbiguousName name) {
if (name.jjtGetParent() instanceof ASTExpression) {