All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.drools.lang.DroolsParserExceptionFactory Maven / Gradle / Ivy

There is a newer version: 10.0.0
Show newest version
package org.drools.lang;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.Map.Entry;

import org.antlr.runtime.EarlyExitException;
import org.antlr.runtime.FailedPredicateException;
import org.antlr.runtime.MismatchedNotSetException;
import org.antlr.runtime.MismatchedSetException;
import org.antlr.runtime.MismatchedTokenException;
import org.antlr.runtime.MismatchedTreeNodeException;
import org.antlr.runtime.NoViableAltException;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.Token;
import org.drools.compiler.DroolsParserException;

/**
 * Helper class that generates DroolsParserException with user friendly error
 * messages.
 * 
 * @author porcelli
 * @see DroolsParserException
 */
public class DroolsParserExceptionFactory {
	public final static String MISMATCHED_TOKEN_MESSAGE_COMPLETE = "Line %1$d:%2$d mismatched input '%3$s' expecting '%4$s'%5$s";
	public final static String MISMATCHED_TOKEN_MESSAGE_PART = "Line %1$d:%2$d mismatched input '%3$s'%4$s";
	public final static String MISMATCHED_TREE_NODE_MESSAGE_COMPLETE = "Line %1$d:%2$d mismatched tree node '%3$s' expecting '%4$s'%5$s";
	public final static String MISMATCHED_TREE_NODE_MESSAGE_PART = "Line %1$d:%2$d mismatched tree node '%3$s'%4$s";
	public final static String NO_VIABLE_ALT_MESSAGE = "Line %1$d:%2$d no viable alternative at input '%3$s'%4$s";
	public final static String EARLY_EXIT_MESSAGE = "Line %1$d:%2$d required (...)+ loop did not match anything at input '%3$s'%4$s";
	public final static String MISMATCHED_SET_MESSAGE = "Line %1$d:%2$d mismatched input '%3$' expecting set '%4$s'%5$s.";
	public final static String MISMATCHED_NOT_SET_MESSAGE = "Line %1$d:%2$d mismatched input '%3$' expecting set '%4$s'%5$s";
	public final static String FAILED_PREDICATE_MESSAGE = "Line %1$d:%2$d rule '%3$s' failed predicate: {%4$s}?%5$s";
	public final static String TRAILING_SEMI_COLON_NOT_ALLOWED_MESSAGE = "Line %1$d:%2$d trailing semi-colon not allowed%3$s";
	public final static String PARSER_LOCATION_MESSAGE_COMPLETE = " in %1$s %2$s";
	public final static String PARSER_LOCATION_MESSAGE_PART = " in %1$s";

	private String[] tokenNames = null;
	private Stack> paraphrases = null;

	/**
	 * DroolsParserErrorMessages constructor.
	 * 
	 * @param tokenNames
	 *            tokenNames generated by ANTLR
	 * @param paraphrases
	 *            paraphrases parser structure
	 */
	public DroolsParserExceptionFactory(String[] tokenNames,
			Stack> paraphrases) {
		this.tokenNames = tokenNames;
		this.paraphrases = paraphrases;
	}

	/**
	 * This method creates a DroolsParserException for trailing semicolon
	 * exception, full of information.
	 * 
	 * @param line
	 *            line number
	 * @param column
	 *            column position
	 * @param offset
	 *            char offset
	 * @return DroolsParserException filled.
	 */
	public DroolsParserException createTrailingSemicolonException(int line,
			int column, int offset) {
		String message = String
				.format(
						DroolsParserExceptionFactory.TRAILING_SEMI_COLON_NOT_ALLOWED_MESSAGE,
						line, column, formatParserLocation());

		return new DroolsParserException("ERR 108", message, line, column,
				offset, null);
	}

	/**
	 * This method creates a DroolsParserException full of information.
	 * 
	 * @param e
	 *            original exception
	 * @return DroolsParserException filled.
	 */
	public DroolsParserException createDroolsException(RecognitionException e) {
		List codeAndMessage = createErrorMessage(e);
		return new DroolsParserException(codeAndMessage.get(1), codeAndMessage
				.get(0), e.line, e.charPositionInLine, e.index, e);
	}

	/**
	 * This will take a RecognitionException, and create a sensible error
	 * message out of it
	 */
	private List createErrorMessage(RecognitionException e) {
		List codeAndMessage = new ArrayList(2);
		String message = "";
		if (e instanceof MismatchedTokenException) {
			MismatchedTokenException mte = (MismatchedTokenException) e;
			if (tokenNames != null && mte.expecting >= 0 && mte.expecting < tokenNames.length) {
				message = String
						.format(
								DroolsParserExceptionFactory.MISMATCHED_TOKEN_MESSAGE_COMPLETE,
								e.line, e.charPositionInLine,
								getBetterToken(e.token),
								getBetterToken(mte.expecting),
								formatParserLocation());
				codeAndMessage.add(message);
				codeAndMessage.add("ERR 101");
			} else {
				message = String
						.format(
								DroolsParserExceptionFactory.MISMATCHED_TOKEN_MESSAGE_PART,
								e.line, e.charPositionInLine,
								getBetterToken(e.token), formatParserLocation());
				codeAndMessage.add(message);
				codeAndMessage.add("ERR 101");
			}
		} else if (e instanceof MismatchedTreeNodeException) {
			MismatchedTreeNodeException mtne = (MismatchedTreeNodeException) e;
			if (mtne.expecting >= 0 && mtne.expecting < tokenNames.length) {
				message = String
						.format(
								DroolsParserExceptionFactory.MISMATCHED_TREE_NODE_MESSAGE_COMPLETE,
								e.line, e.charPositionInLine,
								getBetterToken(e.token),
								getBetterToken(mtne.expecting),
								formatParserLocation());
				codeAndMessage.add(message);
				codeAndMessage.add("ERR 102");
			} else {
				message = String
						.format(
								DroolsParserExceptionFactory.MISMATCHED_TREE_NODE_MESSAGE_PART,
								e.line, e.charPositionInLine,
								getBetterToken(e.token), formatParserLocation());
				codeAndMessage.add(message);
				codeAndMessage.add("ERR 102");
			}
		} else if (e instanceof NoViableAltException) {
			// NoViableAltException nvae = (NoViableAltException) e;
			message = String.format(
					DroolsParserExceptionFactory.NO_VIABLE_ALT_MESSAGE, e.line,
					e.charPositionInLine, getBetterToken(e.token),
					formatParserLocation());
			codeAndMessage.add(message);
			codeAndMessage.add("ERR 103");
		} else if (e instanceof EarlyExitException) {
			// EarlyExitException eee = (EarlyExitException) e;
			message = String.format(
					DroolsParserExceptionFactory.EARLY_EXIT_MESSAGE, e.line,
					e.charPositionInLine, getBetterToken(e.token),
					formatParserLocation());
			codeAndMessage.add(message);
			codeAndMessage.add("ERR 104");
		} else if (e instanceof MismatchedSetException) {
			MismatchedSetException mse = (MismatchedSetException) e;
			message = String.format(
					DroolsParserExceptionFactory.MISMATCHED_SET_MESSAGE,
					e.line, e.charPositionInLine, getBetterToken(e.token),
					mse.expecting, formatParserLocation());
			codeAndMessage.add(message);
			codeAndMessage.add("ERR 105");
		} else if (e instanceof MismatchedNotSetException) {
			MismatchedNotSetException mse = (MismatchedNotSetException) e;
			message = String.format(
					DroolsParserExceptionFactory.MISMATCHED_NOT_SET_MESSAGE,
					e.line, e.charPositionInLine, getBetterToken(e.token),
					mse.expecting, formatParserLocation());
			codeAndMessage.add(message);
			codeAndMessage.add("ERR 106");
		} else if (e instanceof FailedPredicateException) {
			FailedPredicateException fpe = (FailedPredicateException) e;
			message = String.format(
					DroolsParserExceptionFactory.FAILED_PREDICATE_MESSAGE,
					e.line, e.charPositionInLine, fpe.ruleName,
					fpe.predicateText, formatParserLocation());
			codeAndMessage.add(message);
			codeAndMessage.add("ERR 107");
		}
		if (codeAndMessage.get(0).length() == 0) {
			codeAndMessage.add("?????");
		}
		return codeAndMessage;
	}

	/**
	 * This will take Paraphrases stack, and create a sensible location
	 */
	private String formatParserLocation() {
		StringBuilder sb = new StringBuilder();
		if (paraphrases != null){
			for (Map map : paraphrases) {
				for (Entry activeEntry : map
						.entrySet()) {
					if (activeEntry.getValue().length() == 0) {
						sb.append(String.format(PARSER_LOCATION_MESSAGE_PART,
								getLocationName(activeEntry.getKey())));
					} else {
						sb.append(String.format(PARSER_LOCATION_MESSAGE_COMPLETE,
								getLocationName(activeEntry.getKey()), activeEntry
										.getValue()));
					}
				}
			}			
		}
		return sb.toString();
	}

	/**
	 * Returns a string based on Paraphrase Type
	 * 
	 * @param type
	 *            Paraphrase Type
	 * @return a string representing the
	 */
	private String getLocationName(DroolsParaphraseTypes type) {
		switch (type) {
		case PACKAGE:
			return "package";
		case IMPORT:
			return "import";
		case FUNCTION_IMPORT:
			return "function import";
		case GLOBAL:
			return "global";
		case FUNCTION:
			return "function";
		case QUERY:
			return "query";
		case TEMPLATE:
			return "template";
		case RULE:
			return "rule";
		case RULE_ATTRIBUTE:
			return "rule attribute";
		case PATTERN:
			return "pattern";
		default:
			return "";
		}
	}

	/**
	 * Helper method that creates a user friendly token definition
	 * 
	 * @param token
	 *            token
	 * @return user friendly token definition
	 */
	private String getBetterToken(Token token) {
		if (token == null){
			return "";
		}
		return getBetterToken(token.getType(), token.getText());
	}

	/**
	 * Helper method that creates a user friendly token definition
	 * 
	 * @param tokenType
	 *            token type
	 * @return user friendly token definition
	 */
	private String getBetterToken(int tokenType) {
		return getBetterToken(tokenType, null);
	}

	/**
	 * Helper method that creates a user friendly token definition
	 * 
	 * @param tokenType
	 *            token type
	 * @param defaultValue
	 *            default value for identifier token, may be null
	 * @return user friendly token definition
	 */
	private String getBetterToken(int tokenType, String defaultValue) {
		switch (tokenType) {
		case DRLLexer.INT:
			return defaultValue == null ? "int" : defaultValue;
		case DRLLexer.FLOAT:
			return defaultValue == null ? "float" : defaultValue;
		case DRLLexer.STRING:
			return defaultValue == null ? "string" : defaultValue;
		case DRLLexer.BOOL:
			return defaultValue == null ? "boolean" : defaultValue;
		case DRLLexer.NULL:
			return "null";
		case DRLLexer.THEN:
			return "then";
		case DRLLexer.END:
			return "end";
		case DRLLexer.GRAVE_ACCENT:
			return "`";
		case DRLLexer.SEMICOLON:
			return ";";
		case DRLLexer.DOT_STAR:
			return ".*";
		case DRLLexer.COLON:
			return ":";
		case DRLLexer.EQUAL:
			return "==";
		case DRLLexer.NOT_EQUAL:
			return "!=";
		case DRLLexer.GREATER:
			return ">";
		case DRLLexer.GREATER_EQUAL:
			return ">=";
		case DRLLexer.LESS:
			return "<";
		case DRLLexer.LESS_EQUAL:
			return "<=";
		case DRLLexer.ARROW:
			return "->";
		case DRLLexer.ID:
			return defaultValue == null ? "identifier" : defaultValue;
		case DRLLexer.LEFT_PAREN:
			return "(";
		case DRLLexer.RIGHT_PAREN:
			return ")";
		case DRLLexer.LEFT_SQUARE:
			return "[";
		case DRLLexer.RIGHT_SQUARE:
			return "]";
		case DRLLexer.LEFT_CURLY:
			return "{";
		case DRLLexer.RIGHT_CURLY:
			return "}";
		case DRLLexer.COMMA:
			return ",";
		case DRLLexer.DOT:
			return ".";
		case DRLLexer.DOUBLE_AMPER:
			return "&&";
		case DRLLexer.DOUBLE_PIPE:
			return "||";
		case DRLLexer.MISC:
			return defaultValue == null ? "misc" : defaultValue;
		case DRLLexer.EOF:
			return "";
		default:
			return tokenType > tokenNames.length ? "unknown"
					: tokenNames[tokenType];
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy