/**
* SPINdle (version 2.2.2)
* Copyright (C) 2009-2012 NICTA Ltd.
*
* This file is part of SPINdle project.
*
* SPINdle is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SPINdle is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SPINdle. If not, see <http://www.gnu.org/licenses/>.
*
* @author H.-P. Lam (oleklam@gmail.com), National ICT Australia - Queensland Research Laboratory
*/
package spindle.io.parser;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.app.utils.Converter;
import spindle.core.dom.AppConstant;
import spindle.core.dom.AppConstants;
import spindle.core.dom.DomConst;
import spindle.core.dom.LiteralVariable;
import spindle.core.dom.DomConst.Literal;
import spindle.core.dom.impl.Duration;
import spindle.core.dom.impl.Val;
import spindle.io.ComponentMismatchException;
import spindle.io.ParserException;
import spindle.io.outputter.DflTheoryConst;
import spindle.sys.InvalidArgumentException;
import spindle.sys.message.ErrorMessage;
/**
* Theory parser utilities class.
*
* @author H.-P. Lam (oleklam@gmail.com), National ICT Australia - Queensland Research Laboratory
* @version 2011.07.26
* @since version 2.1.0
* @deprecated As of version 2.1.0, the DFL theory parser class {@link spindle.io.parser.DflTheoryParser} is replaced by
* {@link spindle.io.parser.DflTheoryParser2}. The theory parser utilities class will no longer be used
* anymore.
*/
@Deprecated
public class TheoryParserUtilities {
private static TheoryParserUtilities INSTANCE = null;
public static TheoryParserUtilities getInstance() {
if (null == INSTANCE) INSTANCE = new TheoryParserUtilities();
return INSTANCE;
}
private AppConstants appConstants = null;
protected AppConstants getAppConstants() {
if (null == appConstants) appConstants = AppConstants.getInstance(null);
return appConstants;
}
private static enum LiteralComponent {
THEORY_FUNCTION_START(DflTheoryConst.LITERAL_BOOLEAN_FUNCTION_PREFIX), //
MODE_START(DflTheoryConst.MODE_START), //
MODE_END(DflTheoryConst.MODE_END), //
NAME_START(""), //
NAME_END(""), //
PREDICATE_START(DflTheoryConst.PREDICATE_START), //
PREDICATE_END(DflTheoryConst.PREDICATE_END), //
TEMPORAL_START(DflTheoryConst.TIMESTAMP_START), //
TEMPORAL_END(DflTheoryConst.TIMESTAMP_END), //
THEORY_FUNCTION_END(DflTheoryConst.LITERAL_BOOLEAN_FUNCTION_POSTFIX);
private String symbol;
LiteralComponent(String symbol) {
setSymbol(symbol);
}
LiteralComponent(char symbol) {
setSymbol(symbol);
}
protected void setSymbol(char _symbol) {
symbol = "" + _symbol;
}
protected void setSymbol(String _symbol) {
symbol = _symbol;
}
public String getSymbol() {
return symbol;
}
};
private void verifyComponentStart(Stack<LiteralComponent> componentStack, LiteralComponent componentToCheck,
String literalName) throws ComponentMismatchException {
if (componentStack.size() == 0) {
if (componentToCheck.compareTo(LiteralComponent.NAME_START) > 0) throw new ComponentMismatchException(
ErrorMessage.LITERAL_NAME_MISSING);
} else {
LiteralComponent lastComponent = componentStack.peek();
if (lastComponent.equals(LiteralComponent.NAME_START)
&& componentToCheck.compareTo(LiteralComponent.NAME_END) > 0) {
if ("".equals(literalName)) throw new ComponentMismatchException(ErrorMessage.LITERAL_NAME_MISSING);
lastComponent = LiteralComponent.NAME_END;
componentStack.push(lastComponent);
}
if (lastComponent.ordinal() % 2 != 0) throw new ComponentMismatchException(
ErrorMessage.LITERAL_COMPONENT_MISMATCH, new Object[] { "" + lastComponent.getSymbol() + ":::::"
+ componentToCheck.getSymbol() });
else if (lastComponent.compareTo(componentToCheck) >= 0) throw new ComponentMismatchException(
ErrorMessage.LITERAL_COMPONENT_MISORDERED, new Object[] { componentToCheck.getSymbol() });
}
componentStack.push(componentToCheck);
}
private void verifyComponentEnd(Stack<LiteralComponent> componentStack, LiteralComponent componentToCheck,
String literalName, String arguments) throws ComponentMismatchException {
if (componentStack.size() == 0) throw new ComponentMismatchException(ErrorMessage.LITERAL_NAME_MISSING);
else {
LiteralComponent lastComponent = componentStack.peek();
if (lastComponent.ordinal() % 2 == 0 && componentToCheck.equals(LiteralComponent.THEORY_FUNCTION_END)) {
if ("".equals(literalName)) throw new ComponentMismatchException(ErrorMessage.LITERAL_NAME_MISSING);
} else if (lastComponent.ordinal() % 2 == 0) {
throw new ComponentMismatchException(ErrorMessage.LITERAL_COMPONENT_MISMATCH,
new Object[] { componentToCheck.getSymbol() });
} else if (lastComponent.ordinal() + 1 != componentToCheck.ordinal()) {
throw new ComponentMismatchException(ErrorMessage.LITERAL_COMPONENT_MISMATCH,
new Object[] { componentToCheck.getSymbol() });
} else {
switch (componentToCheck) {
case NAME_END:
if ("".equals(literalName)) throw new ComponentMismatchException(ErrorMessage.LITERAL_NAME_MISSING);
break;
case MODE_END:
if ("".equals(arguments)) throw new ComponentMismatchException(
ErrorMessage.LITERAL_MODE_ARGUMENT_MISSING);
break;
case TEMPORAL_END:
if ("".equals(arguments)) throw new ComponentMismatchException(
ErrorMessage.LITERAL_TEMPORAL_ARGUMENT_MISSING);
break;
default:
}
}
}
componentStack.push(componentToCheck);
}
private int getBalancedPredciateEndLocation(String literalString, int locStart) throws ComponentMismatchException {
int bracketCount = 0;
int currLoc = locStart;
while (currLoc < literalString.length() && literalString.charAt(currLoc) != DflTheoryConst.PREDICATE_START) {
currLoc++;
}
if (literalString.charAt(currLoc) != DflTheoryConst.PREDICATE_START) throw new ComponentMismatchException(
"no start predicate found");
do {
switch (literalString.charAt(currLoc)) {
case DflTheoryConst.PREDICATE_START:
bracketCount++;
break;
case DflTheoryConst.PREDICATE_END:
bracketCount--;
break;
default:
}
if (bracketCount == 0) return currLoc;
} while (currLoc++ < literalString.length());
throw new ComponentMismatchException("no end predicate found, literalString=" + literalString);
}
public List<String> parseLiteralString(final String literalString) throws ComponentMismatchException,
ParserException {
List<String> literals = new ArrayList<String>();
if (null == literalString || "".equals(literalString.trim())) return literals;
String literalStr = literalString.replaceAll("\\s\\r\\n", "");
literalStr = literalStr.trim() + DflTheoryConst.LITERAL_SEPARATOR;
String literalName = "", arguments = "";
int literalStart = 0;
int dollarSignCount = 0;
Stack<LiteralComponent> componentStack = new Stack<LiteralComponent>();
int i = 0;
try {
for (i = 0; i < literalStr.length(); i++) {
char c = literalStr.charAt(i);
LiteralComponent lc = (componentStack.size() == 0) ? null : componentStack.peek();
switch (c) {
case DflTheoryConst.LITERAL_BOOLEAN_FUNCTION_PREFIX:
if (dollarSignCount++ % 2 == 0) {
if (componentStack.size() > 0) throw new ComponentMismatchException(
ErrorMessage.LITERAL_STRING_INCORRECT_FORMAT,
new Object[] { "literal boolean fucntion should start at the beginning" });
verifyComponentStart(componentStack, LiteralComponent.THEORY_FUNCTION_START, literalName);
} else {
if (componentStack.get(0).equals(LiteralComponent.THEORY_FUNCTION_START)) {
if (lc.equals(LiteralComponent.NAME_START)) componentStack.push(LiteralComponent.NAME_END);
verifyComponentEnd(componentStack, LiteralComponent.THEORY_FUNCTION_END, literalName,
arguments);
} else throw new ComponentMismatchException(ErrorMessage.LITERAL_STRING_INCORRECT_FORMAT,
new Object[] { "literal boolean fucntion should start at the beginning" });
}
break;
case DflTheoryConst.MODE_START:
verifyComponentStart(componentStack, LiteralComponent.MODE_START, literalName);
break;
case DflTheoryConst.MODE_END:
verifyComponentEnd(componentStack, LiteralComponent.MODE_END, literalName, arguments);
componentStack.push(LiteralComponent.NAME_START);
break;
case DflTheoryConst.PREDICATE_START:
verifyComponentStart(componentStack, LiteralComponent.PREDICATE_START, literalName);
boolean abstractLiteralVariableStart = getAppConstants().containsAbstractLiteralInPredicate(
literalName);
if (abstractLiteralVariableStart) {
int bracketEnd = getBalancedPredciateEndLocation(literalStr, i);
String abstractLiteralPredicateString = literalStr.substring(i + 1, bracketEnd);
List<String> pList = parseLiteralString(abstractLiteralPredicateString);
for (int ii = 0; ii < pList.size(); ii++) {
if (ii > 0) arguments += ",";
arguments += pList.get(ii);
}
i = bracketEnd - 1;
}
break;
case DflTheoryConst.PREDICATE_END:
verifyComponentEnd(componentStack, LiteralComponent.PREDICATE_END, literalName, arguments);
break;
case DflTheoryConst.TIMESTAMP_START:
verifyComponentStart(componentStack, LiteralComponent.TEMPORAL_START, literalName);
break;
case DflTheoryConst.TIMESTAMP_END:
verifyComponentEnd(componentStack, LiteralComponent.TEMPORAL_END, literalName, arguments);
break;
case DflTheoryConst.LITERAL_SEPARATOR:
if (componentStack.size() == 0 || lc.equals(LiteralComponent.NAME_START)
|| lc.equals(LiteralComponent.PREDICATE_END) || lc.equals(LiteralComponent.TEMPORAL_END)
|| lc.equals(LiteralComponent.THEORY_FUNCTION_END)) {
if ("".equals(literalName) || literalName.equals("" + DflTheoryConst.LITERAL_VARIABLE_PREFIX)) throw new ComponentMismatchException(
ErrorMessage.LITERAL_NAME_MISSING);
String literal = literalStr.substring(literalStart, i);
literals.add(literal);
literalStart = i + 1;
literalName = "";
arguments = "";
componentStack.clear();
} else {
switch (lc) {
case MODE_START:
case MODE_END:
case NAME_END:
throw new ComponentMismatchException(ErrorMessage.LITERAL_STRING_INCORRECT_FORMAT);
case TEMPORAL_START:
if (arguments.contains("" + DflTheoryConst.LITERAL_SEPARATOR)) throw new ComponentMismatchException(
ErrorMessage.LITERAL_STRING_INCORRECT_FORMAT);
default:
if (componentStack.get(0).equals(LiteralComponent.THEORY_FUNCTION_START)
&& (!(lc.equals(LiteralComponent.PREDICATE_START) || lc
.equals(LiteralComponent.TEMPORAL_START)))) throw new ComponentMismatchException(
ErrorMessage.LITERAL_STRING_INCORRECT_FORMAT, new Object[] { "1.2" });
if ("".equals(arguments)) throw new ComponentMismatchException(
ErrorMessage.LITERAL_TEMPORAL_ARGUMENT_MISSING);
}
arguments += c;
}
break;
default:
if (componentStack.size() == 0 || lc.equals(LiteralComponent.THEORY_FUNCTION_START)) componentStack
.push(LiteralComponent.NAME_START);
if (componentStack.peek().equals(LiteralComponent.NAME_START)) literalName += c;
else arguments += c;
}
}
} catch (ComponentMismatchException e) {
System.out.println(literals.toString());
System.out.println("literalString=" + literalString);
System.out.println("literalName=" + literalName);
System.out.println("componentStack=" + componentStack);
System.out.println("arguments=" + arguments);
int ex = i;
if (ex > literalStr.length()) ex = literalStr.length();
throw new ParserException(literalStr + ", i=" + i + ", c=" + literalStr.charAt(i), e);
}
return literals;
}
public synchronized String formalizeLiteralBooleanFunctionString(final String literalVariableStr,
Map<LiteralVariable, LiteralVariable> literalVariableMapping,
Map<LiteralVariable, String> literalBooleanFunctionAnswers, boolean isSubstituteWithJavaCode)
throws ParserException {
if (null == literalVariableStr || "".equals(literalVariableStr.trim())) return "";
String originalStr = literalVariableStr.replaceAll("\\s", "");
int l = originalStr.length();
if (originalStr.charAt(0) != DflTheoryConst.LITERAL_BOOLEAN_FUNCTION_PREFIX) throw new ParserException(
ErrorMessage.LITERAL_BOOLEAN_FUNCTION_PREFIX_MISMATCH, new Object[] { ""
+ DflTheoryConst.LITERAL_BOOLEAN_FUNCTION_PREFIX });
if (originalStr.charAt(l - 1) != DflTheoryConst.LITERAL_BOOLEAN_FUNCTION_POSTFIX) throw new ParserException(
ErrorMessage.LITERAL_BOOLEAN_FUNCTION_POSTFIX_MISMATCH, new Object[] { ""
+ DflTheoryConst.LITERAL_BOOLEAN_FUNCTION_POSTFIX });
try {
List<String> tokens = tokenizeBooleanFunctionString(originalStr, 0, literalVariableMapping,
literalBooleanFunctionAnswers, isSubstituteWithJavaCode, 0);
StringBuilder sb = new StringBuilder();
for (String s : tokens) {
sb.append(s);
}
return sb.toString();
} catch (ParserException e) {
throw e;
} catch (Exception e) {
throw new ParserException(ErrorMessage.LITERAL_BOOLEAN_FUNCTION_COMPONENT_MISMATCH,
new String[] { originalStr }, e);
}
}
private static final String DUMMY_START = "(.*)(";
private static final String DUMMY_END = ")(.*)";
private static final String PATTERN_BRACKETS = "(\\$(.*)\\$|\\((.*)\\)|\\[(.*)]|\\{(.*)})";
private static final Pattern patternOutterBrackets = Pattern.compile("^" + PATTERN_BRACKETS + "$");
private static final String PATTERN_OR_AND_COMPARATORS = "\\|\\||&&|==|!=|\\>=|\\<=";
private static final Pattern patternOutterOrAndComparators = Pattern.compile(DUMMY_START
+ PATTERN_OR_AND_COMPARATORS + DUMMY_END);
private static final String PATTERH_MATH_OPERATORS1 = "([^\\>\\<]*)([\\>\\<&&[^,-]])(.*)";
private static final Pattern patternMathOperators1 = Pattern.compile(PATTERH_MATH_OPERATORS1);
private static final String PATTERH_MATH_OPERATORS2 = "([^\\+/\\*\\|!]*)([&\\+/\\*\\|!%&&[^,]])(.*)";
private static final Pattern patternMathOperators2 = Pattern.compile(PATTERH_MATH_OPERATORS2);
private static final String PATTERH_MATH_OPERATORS3 = "([^-]*)(-)(.*)";
private static final Pattern patternMathOperators3 = Pattern.compile(PATTERH_MATH_OPERATORS3);
private static final String LEFT_ITEM_EXCEMPTED_OPERATORS = "-!";
public synchronized List<String> tokenizeBooleanFunctionString(final String origStr, int startLoc,
Map<LiteralVariable, LiteralVariable> literalVariableMapping,
Map<LiteralVariable, String> literalBooleanFunctionAnswers, boolean isSubstituteWithJavaCode, int level)
throws ParserException {
List<String> tokens = new ArrayList<String>();
if (null == origStr || "".equals(origStr)) return tokens;
List<String> tTokens = null, ttTokens = null;
if ((tTokens = extractPatternString(origStr, patternOutterBrackets)) != null) {
if ((ttTokens = verifyBracketTokens(tTokens)) != null) {
tokens.add(ttTokens.get(0));
String item = ttTokens.get(1);
if ("".equals(item)) throw new ParserException(
ErrorMessage.LITERAL_BOOLEAN_FUNCTION_COMPONENT_MISMATCH, new Object[] { origStr });
tokens.addAll(tokenizeBooleanFunctionString(item, startLoc + tTokens.get(0).length(),
literalVariableMapping, literalBooleanFunctionAnswers, isSubstituteWithJavaCode, level + 1));
tokens.add(ttTokens.get(2));
} else throw new ParserException(ErrorMessage.LITERAL_BOOLEAN_FUNCTION_RIGHT_ITEM_MISSING, new Object[] {
"" + origStr.charAt(0), "" + (startLoc + 1) });
} else {
if ((tTokens = extractPatternString(origStr, patternOutterOrAndComparators)) != null) {
// System.out.println("p1");
} else if ((tTokens = extractPatternString(origStr, patternMathOperators1)) != null) {
// System.out.println("p2");
} else if ((tTokens = extractPatternString(origStr, patternMathOperators2)) != null) {
// System.out.println("p3");
} else {
// System.out.println("p4");
tTokens = extractPatternString(origStr, patternMathOperators3);
}
if (null != tTokens) {
String leftItem = tTokens.get(1);
String operator = tTokens.get(2);
String rightItem = tTokens.get(3);
if ("".equals(leftItem)) {
if (LEFT_ITEM_EXCEMPTED_OPERATORS.contains(operator)) {
if (operator.equals("-")) {
operator = "";
rightItem = DflTheoryConst.SYMBOL_NEGATION + rightItem;
}
} else {
throw new ParserException(ErrorMessage.LITERAL_BOOLEAN_FUNCTION_LEFT_ITEM_MISSING,
new Object[] { operator, "" + startLoc });
}
}
int lLoc = startLoc;
int rLoc = startLoc + leftItem.length() + operator.length();
if ("".equals(rightItem)) throw new ParserException(
ErrorMessage.LITERAL_BOOLEAN_FUNCTION_RIGHT_ITEM_MISSING, new Object[] { operator, "" + rLoc });
tokens.addAll(tokenizeBooleanFunctionString(leftItem, lLoc, literalVariableMapping,
literalBooleanFunctionAnswers, isSubstituteWithJavaCode, level + 1));
if ("".equals(operator)) {
try {
tokens.add(generateFunctionString(rightItem, literalVariableMapping));
} catch (ParserException e) {
throw e;
} catch (Exception e) {
tokens.add(rightItem);
}
} else {
tokens.add(operator);
tokens.addAll(tokenizeBooleanFunctionString(rightItem, rLoc, literalVariableMapping,
literalBooleanFunctionAnswers, isSubstituteWithJavaCode, level + 1));
}
} else {
try {
tokens.add(generateFunctionString(origStr, literalVariableMapping));
} catch (ParserException e) {
throw e;
} catch (Exception e) {
tokens.add(origStr);
}
}
}
return tokens;
}
private String generateFunctionString(String origStr,//
Map<LiteralVariable, LiteralVariable> literalVariableMapping) throws ParserException {
try {
LiteralVariable lv = DflTheoryParser2.extractLiteralVariable(origStr);
if (null != literalVariableMapping && literalVariableMapping.containsKey(lv)) {
lv = literalVariableMapping.get(lv);
} else if (getAppConstants().isAppConstant(lv)) lv = getAppConstants().getAppConstantAsLiteralVariable(lv);
return lv.toString();
} catch (ParserException e) {
throw e;
} catch (Exception e) {
throw new ParserException(e);
}
}
private List<String> verifyBracketTokens(List<String> tokens) throws ParserException {
List<String> newTokens = new ArrayList<String>();
int bracketType = -1;
String[] brackets = null;
for (int i = 2; i < tokens.size() && bracketType < 0; i++) {
if (!"".equals(tokens.get(i))) bracketType = i;
}
switch (bracketType) {
case 2:
brackets = new String[] { "$", "$" };
break;
case 3:
brackets = new String[] { "(", ")" };
break;
case 4:
brackets = new String[] { "[", "]" };
break;
case 5:
brackets = new String[] { "{", "}" };
break;
default:
return null;
}
String tokenString = tokens.get(bracketType);
newTokens.add(brackets[0]);
newTokens.add(tokenString);
newTokens.add(brackets[1]);
return newTokens;
}
private List<String> extractPatternString(String str, Pattern pattern) {
Matcher matcher = pattern.matcher(str);
if (!matcher.find()) return null;
List<String> tokens = new ArrayList<String>();
do {
for (int i = 0; i < matcher.groupCount() + 1; i++) {
if (null == matcher.group(i)) tokens.add("");
else tokens.add(matcher.group(i));
}
} while (matcher.find());
return tokens;
}
/**
* @param str
* @return a formatted string for theory application constant if the inputed string represent a system defined
* application constant; or the original string otherwise
* @throws InvalidArgumentException
*/
public String formatLiteralVariableString(final String str) throws InvalidArgumentException {
if (null == str || "".equals(str.trim())) throw new InvalidArgumentException(
ErrorMessage.LITERAL_VARIABLE_DEFINITION_NOT_FOUND);
if (str.charAt(0) == DomConst.Literal.LITERAL_VARIABLE_PREFIX
|| str.charAt(0) == DomConst.Literal.LITERAL_BOOLEAN_FUNCTION_PREFIX) return str;
AppConstant appConstant = null;
try {
Integer.parseInt(str);
appConstant = getAppConstants().getAppConstant(Val.LABEL);
} catch (Exception e) {
try {
Converter.timeString2long(str);
appConstant = getAppConstants().getAppConstant(Duration.LABEL);
} catch (Exception e1) {
}
}
if (null == appConstant) return str;
String newStr = appConstant.getLabel() + Literal.PREDICATE_START + str + Literal.PREDICATE_END;
return newStr;
}
}