/*
* *************************************************************************************
* Copyright (C) 2008 EsperTech, Inc. All rights reserved. *
* http://esper.codehaus.org *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
* *************************************************************************************
*/
package com.espertech.esper.epl.parse;
import com.espertech.esper.client.EPStatementSyntaxException;
import com.espertech.esper.client.PropertyAccessException;
import com.espertech.esper.collection.UniformPair;
import com.espertech.esper.epl.generated.EsperEPL2Ast;
import com.espertech.esper.epl.generated.EsperEPL2GrammarParser;
import org.antlr.runtime.*;
import java.util.Set;
import java.util.Stack;
/**
* Converts recognition exceptions.
*/
public class ExceptionConvertor
{
/**
* Converts from a syntax error to a nice statement exception.
* @param e is the syntax error
* @param expression is the expression text
* @param parser the parser that parsed the expression
* @param addPleaseCheck indicates to add "please check" paraphrases
* @return syntax exception
*/
public static EPStatementSyntaxException convertStatement(RecognitionException e, String expression, boolean addPleaseCheck, EsperEPL2GrammarParser parser)
{
UniformPair<String> pair = convert(e, expression, addPleaseCheck, parser);
return new EPStatementSyntaxException(pair.getFirst(), pair.getSecond());
}
/**
* Converts from a syntax error to a nice property exception.
* @param e is the syntax error
* @param expression is the expression text
* @param parser the parser that parsed the expression
* @param addPleaseCheck indicates to add "please check" paraphrases
* @return syntax exception
*/
public static PropertyAccessException convertProperty(RecognitionException e, String expression, boolean addPleaseCheck, EsperEPL2GrammarParser parser)
{
UniformPair<String> pair = convert(e, expression, addPleaseCheck, parser);
return new PropertyAccessException(pair.getFirst(), pair.getSecond());
}
/**
* Converts from a syntax error to a nice exception.
* @param e is the syntax error
* @param expression is the expression text
* @param parser the parser that parsed the expression
* @param addPleaseCheck indicates to add "please check" paraphrases
* @return syntax exception
*/
public static UniformPair<String> convert(RecognitionException e, String expression, boolean addPleaseCheck, EsperEPL2GrammarParser parser)
{
if (expression.trim().length() == 0)
{
String message = "Unexpected end of input";
return new UniformPair<String>(message, expression);
}
Token t;
Token tBefore = null;
Token tAfter = null;
if (e.index < parser.getTokenStream().size())
{
t = parser.getTokenStream().get(e.index);
if ((e.index + 1) < parser.getTokenStream().size())
{
tAfter = parser.getTokenStream().get(e.index + 1);
}
if (e.index - 1 >= 0)
{
tBefore = parser.getTokenStream().get(e.index - 1);
}
}
else
{
if (parser.getTokenStream().size() >= 2) {
tBefore = parser.getTokenStream().get(parser.getTokenStream().size() - 2);
}
t = parser.getTokenStream().get(parser.getTokenStream().size() - 1);
}
Token tEnd = null;
if (parser.getTokenStream().size() > 0) {
tEnd = parser.getTokenStream().get(parser.getTokenStream().size() - 1);
}
String positionInfo = getPositionInfo(t);
String token = "'" + t.getText() + "'";
Stack stack = parser.getParaphrases();
String check = "";
if ((stack.size() > 0) && addPleaseCheck)
{
String delimiter = "";
StringBuilder checkList = new StringBuilder();
checkList.append(", please check the ");
while(stack.size() != 0)
{
checkList.append(delimiter);
checkList.append(stack.pop());
delimiter = " within the ";
}
check = checkList.toString();
}
// check if token is a reserved keyword
Set<String> keywords = parser.getKeywords();
if (keywords.contains(token.toLowerCase()))
{
token += " (a reserved keyword)";
}
else
{
if ((tBefore != null) &&
(tAfter != null) &&
(keywords.contains("'" + tBefore.getText().toLowerCase() + "'")) &&
(keywords.contains("'" + tAfter.getText().toLowerCase() + "'")))
{
token += " ('" + tBefore.getText() + "' and '" + tAfter.getText() + "' are a reserved keyword)";
}
else if ((tBefore != null) &&
(keywords.contains("'" + tBefore.getText().toLowerCase() + "'")))
{
token += " ('" + tBefore.getText() + "' is a reserved keyword)";
}
else if (tEnd != null && keywords.contains("'" + tEnd.getText().toLowerCase() + "'")) {
token += " ('" + tEnd.getText() + "' is a reserved keyword)";
}
}
String message = "Incorrect syntax near " + token + positionInfo + check;
if (e instanceof NoViableAltException)
{
NoViableAltException nvae = (NoViableAltException) e;
if (nvae.token.getType() == -1)
{
message = "Unexpected end of input near " + token + positionInfo + check;
}
else
{
if (parser.getParserTokenParaphrases().get(nvae.token.getType()) != null)
{
message = "Incorrect syntax near " + token + positionInfo + check;
}
else
{
// find next keyword in the next 3 tokens
int currentIndex = e.index + 1;
while ((currentIndex > 0) &&
(currentIndex < parser.getTokenStream().size() - 1) &&
(currentIndex < e.index + 3))
{
Token next = parser.getTokenStream().get(currentIndex);
currentIndex++;
String quotedToken = "'" + next.getText() + "'";
if (parser.getKeywords().contains(quotedToken))
{
check += " near reserved keyword '" + next.getText() + "'";
break;
}
}
message = "Incorrect syntax near " + token + positionInfo + check;
}
}
}
if (e instanceof MismatchedTokenException)
{
MismatchedTokenException mismatched = (MismatchedTokenException) e;
String expected = "end of input";
if ((mismatched.expecting >= 0) && (mismatched.expecting < parser.getTokenNames().length))
{
expected = parser.getTokenNames()[mismatched.expecting];
}
if (parser.getLexerTokenParaphrases().get(mismatched.expecting) != null)
{
expected = parser.getLexerTokenParaphrases().get(mismatched.expecting);
}
if (parser.getParserTokenParaphrases().get(mismatched.expecting) != null)
{
expected = parser.getParserTokenParaphrases().get(mismatched.expecting);
}
String unexpected;
if ((mismatched.getUnexpectedType() < 0) || (mismatched.getUnexpectedType() >= parser.getTokenNames().length))
{
unexpected = "end of input";
}
else
{
unexpected = parser.getTokenNames()[mismatched.getUnexpectedType()];
}
if (parser.getLexerTokenParaphrases().get(mismatched.getUnexpectedType()) != null)
{
unexpected = parser.getLexerTokenParaphrases().get(mismatched.getUnexpectedType());
}
if (parser.getParserTokenParaphrases().get(mismatched.getUnexpectedType()) != null)
{
unexpected = parser.getParserTokenParaphrases().get(mismatched.getUnexpectedType());
}
String expecting = " expecting " + expected.trim() + " but found " + unexpected.trim();
message = "Incorrect syntax near " + token + expecting + positionInfo + check;
}
if (e instanceof EarlyExitException)
{
EarlyExitException ee = (EarlyExitException) e;
char c = (char) ee.c;
if (c == 65535) {
message = "Unexpected end of input string, check for an invalid identifier or missing additional keywords near " + token + positionInfo + " ";
}
else {
message = "Incorrect syntax near " + token + positionInfo + " unexpected character '" + c + "', check for an invalid identifier or missing additional keywords";
}
}
return new UniformPair<String>(message, expression);
}
/**
* Converts from a syntax error to a nice statement exception.
* @param e is the syntax error
* @param expression is the expression text
* @param treeWalker the tree walker that walked the tree
* @return syntax exception
*/
public static EPStatementSyntaxException convert(RecognitionException e, String expression, EsperEPL2Ast treeWalker)
{
String positionInfo = getPositionInfo(e.token);
String tokenName = "end of input";
if ((e.token != null) && (e.token.getType() >= 0) && (e.token.getType() < treeWalker.getTokenNames().length))
{
tokenName = treeWalker.getTokenNames()[e.token.getType()];
}
String message = "Unexpected error processing statement near token " + tokenName + positionInfo;
if (e instanceof MismatchedTokenException)
{
MismatchedTokenException mismatched = (MismatchedTokenException) e;
String expected = "end of input";
if ((mismatched.expecting >= 0) && (mismatched.expecting < treeWalker.getTokenNames().length))
{
expected = treeWalker.getTokenNames()[mismatched.expecting];
}
String unexpected;
if ((mismatched.getUnexpectedType() < 0) || (mismatched.getUnexpectedType() >= treeWalker.getTokenNames().length))
{
unexpected = "end of input";
}
else
{
unexpected = treeWalker.getTokenNames()[mismatched.getUnexpectedType()];
}
String expecting = " expecting " + expected.trim() + " but found " + unexpected.trim();
message = "Unexpected error processing statement near token " + tokenName + expecting + positionInfo;
}
return new EPStatementSyntaxException(message, expression);
}
/**
* Returns the position information string for a parser exception.
* @param t the token to return the information for
* @return is a string with line and column information
*/
private static String getPositionInfo(Token t)
{
return t.getLine() > 0 && t.getCharPositionInLine() > 0
? " at line " + t.getLine() + " column " + t.getCharPositionInLine()
: "";
}
}