org.eclipse.persistence.internal.jpa.parsing.jpql.JPQLParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.eclipse.persistence.core Show documentation
Show all versions of org.eclipse.persistence.core Show documentation
EclipseLink build based upon Git transaction ecdf3c32c4
/*
* Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.internal.jpa.parsing.jpql;
import java.util.ArrayList;
import java.util.List;
//toplink imports
import org.eclipse.persistence.exceptions.JPQLException;
import org.eclipse.persistence.internal.jpa.parsing.JPQLParseTree;
import org.eclipse.persistence.internal.jpa.parsing.NodeFactory;
import org.eclipse.persistence.internal.jpa.parsing.NodeFactoryImpl;
import org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParserBuilder;
// Third party (ANLTR) stuff
import org.eclipse.persistence.internal.libraries.antlr.runtime.MismatchedTokenException;
import org.eclipse.persistence.internal.libraries.antlr.runtime.NoViableAltException;
import org.eclipse.persistence.internal.libraries.antlr.runtime.RecognitionException;
import org.eclipse.persistence.internal.libraries.antlr.runtime.RecognizerSharedState;
import org.eclipse.persistence.internal.libraries.antlr.runtime.Token;
import org.eclipse.persistence.internal.libraries.antlr.runtime.TokenStream;
/**
* EJBQLParser is the superclass of the ANTLR generated parser.
*/
public abstract class JPQLParser extends org.eclipse.persistence.internal.libraries.antlr.runtime.Parser {
/** List of errors. */
private List errors = new ArrayList();
/** The name of the query being compiled.
* The variable is null for dynamic queries.
*/
private String queryName = null;
/** The text of the query being compiled. */
private String queryText = null;
/** The factory to create parse tree nodes. */
protected NodeFactory factory;
protected JPQLParser(TokenStream stream) {
super(stream);
}
public JPQLParser(TokenStream input, RecognizerSharedState state) {
super(input, state);
}
/**
* INTERNAL
* Returns the ANTLR version currently used.
*/
public static String ANTLRVersion() throws Exception {
return "3.5.2";
}
/**
* INTERNAL
* Builds a parser, parses the specified query string and returns the
* parse tree. Any error in the query text results in an JPQLException.
* This method is used for dynamic queries.
*/
public static JPQLParseTree buildParseTree(String queryText)
throws JPQLException {
return buildParseTree(null, queryText);
}
/**
* INTERNAL
* Builds a parser, parses the specified query string and returns the
* parse tree. Any error in the query text results in an JPQLException.
*/
public static JPQLParseTree buildParseTree(String queryName, String queryText)
throws JPQLException {
JPQLParser parser = buildParserFor(queryName, queryText);
return parser.parse();
}
/**
* INTERNAL
* Creates a parser for the specified query string. The query string is
* not parsed (see method parse).
* This method is used for dynamic queries.
*/
public static JPQLParser buildParserFor(String queryText)
throws JPQLException {
return buildParserFor(null, queryText);
}
/**
* INTERNAL
* Creates a parser for the specified query string. The query string is
* not parsed (see method parse).
*/
public static JPQLParser buildParserFor(String queryName, String queryText)
throws JPQLException {
try {
JPQLParser parser = JPQLParserBuilder.buildParser(queryText);
parser.setQueryName(queryName);
parser.setQueryText(queryText);
parser.setNodeFactory(new NodeFactoryImpl(parser.getQueryInfo()));
return parser;
} catch (Exception ex) {
throw JPQLException.generalParsingException(queryText, ex);
}
}
/**
* INTERNAL
* Parse the query string that was specified on parser creation.
*/
public JPQLParseTree parse()
throws JPQLException {
try {
document();
} catch (Exception e) {
addError(e);
}
// Handle any errors generated by the Parser
if (hasErrors()) {
throw generateException();
}
// return the parser tree
return getParseTree();
}
/**
* INTERNAL
* Returns the parse tree created by a successful run of the parse
* method.
*/
public JPQLParseTree getParseTree() {
return (JPQLParseTree)getRootNode();
}
/**
* INTERNAL
* Return the text of the current query being compiled.
*/
public String getQueryText() {
return queryText;
}
/**
* INTERNAL
* Set the text of the current query being compiled.
* Please note, setting the query text using this method is for error
* handling and debugging purposes.
*/
public void setQueryText(String queryText) {
this.queryText = queryText;
}
/**
* INTERNAL
* Return the name of the current query being compiled. This method returns
* null
if the current query is a dynamic query and not a named
* query.
*/
public String getQueryName() {
return queryText;
}
/**
* INTERNAL
* Set the name of the current query being compiled.
* Please note, setting the query name using this method is for error
* handling and debugging purposes.
*/
public void setQueryName(String queryName) {
this.queryName = queryName;
}
/**
* INTERNAL
* Return the the query text prefixed by the query name in case of a
* named query. The method returns just the query text in case of a dynamic
* query.
*/
public String getQueryInfo() {
return (queryName == null) ? queryText :
queryName + ": " + queryText;
}
/**
* INTERNAL
* Set the factory used by the parser to create a parse tree and parse
* tree nodes.
*/
public void setNodeFactory(NodeFactory factory) {
this.factory = factory;
}
/**
* INTERNAL
* Returns the factory used by the parser to create a parse tree and parse
* tree nodes.
*/
public NodeFactory getNodeFactory() {
return factory;
}
/**
* INTERNAL
* Returns the list of errors found during the parsing process.
*/
public List getErrors() {
return errors;
}
/**
* INTERNAL
* Returns true if there were errors during the parsing process.
*/
public boolean hasErrors() {
return !getErrors().isEmpty();
}
/**
* INTERNAL
* Add the exception to the list of errors.
*/
public void addError(Exception e) {
if (e instanceof RecognitionException) {
e = handleRecognitionException((RecognitionException)e);
} else if (!(e instanceof JPQLException)) {
e = JPQLException.generalParsingException(getQueryInfo(), e);
}
errors.add(e);
}
/**
* INTERNAL
* Generate an exception which encapsulates all the exceptions generated
* by this parser. Special case where the first exception is an
* JPQLException.
*/
protected JPQLException generateException() {
//Handle exceptions we expect (such as expressionSotSupported)
Exception firstException = (Exception)getErrors().get(0);
if (firstException instanceof JPQLException) {
return (JPQLException)firstException;
}
//Handle general exceptions, such as NPE
JPQLException exception =
JPQLException.generalParsingException(getQueryInfo());
exception.setInternalExceptions(getErrors());
return exception;
}
/**
* INTERNAL
* Map an exception thrown by the ANTLR generated code to an
* JPQLException.
*/
//gf1166 Wrap ANTLRException inside JPQLException
protected JPQLException handleRecognitionException(RecognitionException ex) {
JPQLException result = null;
// TODO: figure out the equivalent
/* if (ex instanceof MismatchedCharException) {
MismatchedCharException mismatched = (MismatchedCharException)ex;
if (mismatched.foundChar == EOF_CHAR) {
result = JPQLException.unexpectedEOF(getQueryInfo(),
mismatched.getLine(), mismatched.getColumn(), ex);
} else if (mismatched.mismatchType == MismatchedCharException.CHAR) {
result = JPQLException.expectedCharFound(getQueryInfo(),
mismatched.getLine(), mismatched.getColumn(),
String.valueOf((char)mismatched.expecting),
String.valueOf((char)mismatched.foundChar),
ex);
}
}
else*/
if (ex instanceof MismatchedTokenException) {
MismatchedTokenException mismatched = (MismatchedTokenException)ex;
Token token = mismatched.token;
if (token != null) {
if (token.getType() == Token.EOF) {
result = JPQLException.unexpectedEOF(getQueryInfo(),
mismatched.line, mismatched.charPositionInLine, ex);
}
else {
result = JPQLException.syntaxErrorAt(getQueryInfo(),
mismatched.line, mismatched.charPositionInLine,
token.getText(), ex);
}
}
}
else if (ex instanceof NoViableAltException) {
NoViableAltException noviable = (NoViableAltException)ex;
Token token = noviable.token;
if (token != null) {
if (token.getType() == Token.EOF) {
result = JPQLException.unexpectedEOF(getQueryInfo(),
noviable.line, noviable.charPositionInLine, ex);
}
else {
result = JPQLException.unexpectedToken(getQueryInfo(),
noviable.line, noviable.charPositionInLine,
token.getText(), ex);
}
}
} else if (ex instanceof InvalidIdentifierException){
InvalidIdentifierException invalid = (InvalidIdentifierException)ex;
Token token = invalid.getToken();
if (token != null) {
if (token.getType() == Token.EOF) {
result = JPQLException.unexpectedEOF(getQueryInfo(),
token.getLine(), token.getCharPositionInLine(), ex);
}
else {
result = JPQLException.unexpectedToken(getQueryInfo(),
token.getLine(), token.getCharPositionInLine(),
token.getText(), ex);
}
}
} else if (ex instanceof InvalidIdentifierStartException) {
InvalidIdentifierStartException invalid = (InvalidIdentifierStartException)ex;
result = JPQLException.unexpectedChar(getQueryInfo(),
invalid.line, invalid.charPositionInLine,
String.valueOf((char)invalid.c), ex);
}
/*
else if (ex instanceof TokenStreamRecognitionException) {
result = handleANTLRException(((TokenStreamRecognitionException)ex).recog);
}*/
if (result == null) {
// no special handling from aboves matches the exception if this
// line is reached => make it a syntax error
result = JPQLException.syntaxError(getQueryInfo(), ex);
}
return result;
}
/**
* Method called by the ANTLR generated code in case of an error.
*/
@Override
public void reportError(RecognitionException ex) {
addError(ex);
}
/**
* This is the parser start method. It will be implemented by the ANTLR
* generated subclass.
*/
public abstract void document() throws RecognitionException;
/**
* Returns the root node after representing the parse tree for the current
* query string. It will be implemented by the ANTLR generated subclass.
*/
public abstract Object getRootNode();
}