package translating;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import parser.ASTadditiveSetExpression;
import parser.ASTbasicSort;
import parser.ASTconcatenation;
import parser.ASTcondition;
import parser.ASTconstantTerm;
import parser.ASTconstantTermList;
import parser.ASTcurlyBrackets;
import parser.ASTfunctionalSymbol;
import parser.ASTidentifierRange;
import parser.ASTmultiplicativeSetExpression;
import parser.ASTnumericRange;
import parser.ASTsetExpression;
import parser.ASTsortExpression;
import parser.ASTsortExpressionList;
import parser.ASTsortName;
import parser.ASTunarySetExpression;
import parser.ParseException;
import parser.SimpleNode;
import parser.SparcTranslatorTreeConstants;
import sorts.Condition;
/**
* Generator of instances (strings) satisfying given sort expression
*/
public class InstanceGenerator {
ArrayList<GSort> generatedSorts; // generated and included into translation
// sorts
HashMap<String, ASTsortExpression> sortNameToExpression;
int ruleBeginLine;
int ruleBeginColumn;
HashSet<String> addedSorts;
public ArrayList<GSort> getGeneratedSorts() {
return generatedSorts;
}
/**
* Constructor
*
* @param sortNameToExpression
* a mapping from sort names to expressions assigned to them
*/
public InstanceGenerator(
HashMap<String, ASTsortExpression> sortNameToExpression) {
this.sortNameToExpression = sortNameToExpression;
generatedSorts = new ArrayList<GSort>();
}
/**
* Add new sort to the set of generated sorts
*
* @param sortName
* name of the sort
* @param expr
* expression to be assigned to the name
* @throws ParseException
* if the sort has too many instances (over limit)
*/
public void addSort(String sortName, ASTsortExpression expr,boolean generateSorts)
throws ParseException {
// check if sort was already generated
for (GSort s : generatedSorts) {
if (s.sortName.equals(sortName)) {
return;
}
}
// generate new sort
HashSet<String> instances = generateInstances_p(expr,generateSorts);
generatedSorts.add(new GSort(expr, sortName, instances));
}
public HashSet<String> generateInstances(ASTsortExpression expr,
boolean generateRecords) {
HashSet<String> result = null;
try {
result = generateInstances_p(expr, generateRecords);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
/**
* Get sort instances of given sort
*
* @param sortName
* of the sort
* @return list of instances
*/
public ArrayList<String> getSortInstances(String sortName) {
for (GSort sort : generatedSorts) {
if (sort.sortName.equals(sortName)) {
return new ArrayList<String>(sort.instances);
}
}
return null;
}
/**
* Intersection of two sets
*
* @param s1
* first set
* @param s2
* second set
* @return s1*s2
*/
private HashSet<String> intersectSets(HashSet<String> s1, HashSet<String> s2) {
HashSet<String> res = new HashSet<String>();
res.addAll(s1);
for (String s : s1) {
if (!s2.contains(s)) {
res.remove(s);
}
}
return res;
}
/**
* Intersection of sorts named by sort names.
*
* @param sortNames
* @return Set of strings each of which belongs to intersection.
*/
public HashSet<String> intersectGeneratedSorts(ArrayList<String> sortNames) {
HashSet<String> result = new HashSet<String>();
boolean initialized = false;
for (String sortName : sortNames) {
for (GSort candidateSort : generatedSorts) {
if (candidateSort.sortName.equals(sortName)) {
if (!initialized) {
initialized = true;
result.addAll(candidateSort.instances);
} else {
result = intersectSets(result, candidateSort.instances);
}
}
}
}
return result;
}
/**
* Move to a lower level of AST to produce all instances satisfying given
* sort expression
*
* @param se
* expression
* @param generateRecords
* records are generated if the flag is true
* @return set of instances satisfying expression
* @throws ParseException
* if se produces too many instances
*/
private HashSet<String> generateInstances_p(ASTsortExpression se,
boolean generateRecords) throws ParseException {
int id = ((SimpleNode) se.jjtGetChild(0)).getId();
switch (id) {
case SparcTranslatorTreeConstants.JJTSETEXPRESSION:
return generateInstances((ASTsetExpression) se.jjtGetChild(0),
generateRecords);
case SparcTranslatorTreeConstants.JJTNUMERICRANGE:
return generateInstances((ASTnumericRange) se.jjtGetChild(0));
case SparcTranslatorTreeConstants.JJTIDENTIFIERRANGE:
return generateInstances((ASTidentifierRange) se.jjtGetChild(0));
case SparcTranslatorTreeConstants.JJTCONCATENATION:
return generateInstances((ASTconcatenation) se.jjtGetChild(0));
case SparcTranslatorTreeConstants.JJTFUNCTIONALSYMBOL:
if (generateRecords)
return generateInstances((ASTfunctionalSymbol) se
.jjtGetChild(0));
else
return new HashSet<String>();
}
return generateInstances((ASTadditiveSetExpression) se.jjtGetChild(0),generateRecords);
}
private HashSet<String> generateInstances(ASTfunctionalSymbol funcSymbol)
throws ParseException {
ASTsortExpressionList elist = (ASTsortExpressionList) (funcSymbol
.jjtGetChild(0));
ArrayList<HashSet<String>> alist = new ArrayList<HashSet<String>>();
for (int i = 0; i < elist.jjtGetNumChildren(); i++) {
ASTsortName sname = (ASTsortName) elist.jjtGetChild(i);
alist.add(generateInstances_p(
sortNameToExpression.get(sname.toString()), true));
}
String initprefix = funcSymbol.image.substring(0,
funcSymbol.image.indexOf('('));
ASTcondition cond = null;
if (funcSymbol.jjtGetNumChildren() > 1) {
cond = (ASTcondition) funcSymbol.jjtGetChild(1);
}
return generateInstances(initprefix, null, alist, 0, cond);
}
/**
* Generate instances of the concatenation of basic sorts from sortlist
* starting from given index
*
* @param sortList
* list of basic sorts
* @param index
* starting index
* @return set of generated instances
* @throws ParseException
*/
private HashSet<String> generateInstances(ArrayList<ASTbasicSort> sortList,
int index) throws ParseException {
if (index == sortList.size()) {
return new HashSet<String>();
}
HashSet<String> instancesPrefix = generateInstances(sortList.get(index));
HashSet<String> instancesSuffix = generateInstances(sortList, index + 1);
if (instancesSuffix.size() == 0) {
return instancesPrefix;
} else {
HashSet<String> result = new HashSet<String>();
for (String prefix : instancesPrefix)
for (String suffix : instancesSuffix)
result.add(prefix + suffix);
return result;
}
}
/**
* Generate all instances of given basic sort
*
* @param asTbasicSort
* AST node represeting given basic sort
* @return set of generated instances
* @throws ParseException
*/
private HashSet<String> generateInstances(ASTbasicSort basicSortExp)
throws ParseException {
SimpleNode child = (SimpleNode) basicSortExp.jjtGetChild(0);
switch (child.getId()) {
case SparcTranslatorTreeConstants.JJTNUMERICRANGE:
return generateInstances((ASTnumericRange) basicSortExp
.jjtGetChild(0));
case SparcTranslatorTreeConstants.JJTIDENTIFIERRANGE:
return generateInstances((ASTidentifierRange) basicSortExp
.jjtGetChild(0));
case SparcTranslatorTreeConstants.JJTSORTNAME:
ASTsortExpression expr = sortNameToExpression
.get(child.image);
// from parsing phase we know that "expr" is restricted to basic
// sorts,
// but we still follow the general procedure
return generateInstances_p(expr,false);
case SparcTranslatorTreeConstants.JJTCONSTANTTERMLIST:
return generateInstances((ASTconstantTermList) basicSortExp
.jjtGetChild(0),false);
}
return null;
}
/**
* Generate all instances of concatenation
*
* @param jjtGetChild
* AST node describing the concatenation
* @return all the instances obtained by the concatenation
* @throws ParseException
*/
private HashSet<String> generateInstances(ASTconcatenation concatenationExpr)
throws ParseException {
ArrayList<ASTbasicSort> sortList = new ArrayList<ASTbasicSort>();
for (int i = 0; i < concatenationExpr.jjtGetNumChildren(); i++) {
sortList.add((ASTbasicSort) concatenationExpr.jjtGetChild(i));
}
return generateInstances(sortList, 0);
}
/**
* Generate lexicographically next string with length <=maxLength
*
* @param currentString
* @param maxLength
* @return
*/
String generateNextString(String currentString, int maxLength) {
int currentIndex = currentString.length() - 1;
while (currentIndex >= 0 && currentString.charAt(currentIndex) == 'z') {
currentIndex--;
}
if (currentIndex == -1) {
// need to increase length:
if (currentString.length() == maxLength) {
return null;
} else {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < maxLength + 1; i++) {
sb.append('a');
}
return sb.toString();
}
} else {
StringBuilder nextString = new StringBuilder();
if (currentIndex - 1 >= 0) {
nextString.append(currentString.substring(0, currentIndex));
}
nextString.append((char) (currentString.charAt(currentIndex) + 1));
for (int i = currentIndex + 1; i < currentString.length(); i++) {
nextString.append('a');
}
return nextString.toString();
}
}
/**
* Generate all strings s ,such that from<=s<=to and |from|<=|s|<=|to|
*
* @param from
* first string from the range
* @param to
* last string from the range
* @return set of generated strings
*/
public HashSet<String> generateStrings(String from, String to) {
HashSet<String> result = new HashSet<String>();
result.add(from);
String currentString = from;
int maxLength = to.length();
while ((currentString = generateNextString(currentString, maxLength)) != null && currentString.compareTo(to)<=0) {
result.add(currentString);
}
return result;
}
/**
* Generate all strings s of given identifier range from..to ,such that
* from<=s<=to and |from|<=|s|<=|to| @ * @return set of generated strings
*/
private HashSet<String> generateInstances(ASTidentifierRange identifierRange) {
String[] range = identifierRange.image.split(" ");
return generateStrings(range[0], range[1]);
}
/**
* Generate all instances of a set expression
*
* @param setExpr
* node of abstract syntax tree representing set expression
* @param generateRecords
* if the flag is true records are generated
* @return set of strings belonging to language described by se
* @throws ParseException
* if setExpr produces too many instances
*/
private HashSet<String> generateInstances(ASTsetExpression setExpr,
boolean generateRecords) throws ParseException {
return generateInstances(
(ASTadditiveSetExpression) setExpr.jjtGetChild(0),
generateRecords);
}
/**
* @param adde
* additive expression
* @return set of strings belonging to language described by se
* @param generateRecords
* if the flag is true records are generated
* @throws ParseException
* if se produces too many instances
*/
private HashSet<String> generateInstances(ASTadditiveSetExpression adde,
boolean generateRecords) throws ParseException {
// TODO Auto-generated method stub
HashSet<String> result = new HashSet<String>();
for (int i = 0; i < adde.jjtGetNumChildren(); i++) {
HashSet<String> newInstances = generateInstances(
(ASTmultiplicativeSetExpression) (adde.jjtGetChild(i)),
generateRecords);
if (newInstances == null) {
throw new ParseException("Rule at " + ruleBeginLine
+ ", column " + ruleBeginColumn
+ " requires too much memory to be processed, "
+ " shorten your sorts or avoid unsafety");
}
if (adde.image.charAt(i) == '+') {
result.addAll(newInstances);
} else {
result.removeAll(newInstances);
}
}
return result;
}
/**
* @param multe
* multiplicative expression
* @param generateRecords
* if the flag is true records are generated
* @return set of strings belonging to language described by multe
* @throws ParseException
* if se produces too many instances
*/
private HashSet<String> generateInstances(
ASTmultiplicativeSetExpression multe, boolean generateRecords)
throws ParseException {
HashSet<String> result = new HashSet<String>();
for (int i = 0; i < multe.jjtGetNumChildren(); i++) {
if (i == 0) {
result = generateInstances((ASTunarySetExpression) (multe
.jjtGetChild(i)),generateRecords);
} else {
result = intersectSets(result,
generateInstances((ASTunarySetExpression) (multe
.jjtGetChild(i)),generateRecords));
;
}
}
return result;
}
/**
* Create term string from provided predicate names and arguments
*
*/
private String createTermString(String termName, ArrayList<String> arguments) {
StringBuilder result = new StringBuilder();
result.append(termName);
if (arguments.size() != 0) {
result.append("(");
boolean first = true;
for (String argument : arguments) {
if (first) {
first = false;
} else {
result.append(',');
}
result.append(argument);
}
result.append(")");
}
return result.toString();
}
// TODO: Condition needs to be redone
/**
* Recursively generate strings with given prefix and suffix composed from
* all possible combinations of strings from alist ended by closing
* parenthesis
*
* @param prefix
* prefix to be added to every list
* @param alist
* list of possible strings
* @param index
* start index of alist from which strings will be taken
* @return set of generated strings
*/
private HashSet<String> generateInstances(String termName,
ArrayList<String> arguments, ArrayList<HashSet<String>> alist,
int index, ASTcondition cond) {
if (arguments == null)
arguments = new ArrayList<String>();
HashSet<String> result = new HashSet<String>();
// last element
if (index == alist.size() - 1) {
for (String s : alist.get(index)) {
// closing parenthesis
arguments.add(s);
if (cond == null || new Condition().check(cond, arguments)) {
result.add(createTermString(termName, arguments));
}
arguments.remove(index);
}
} else {
// recursive call
for (String s : alist.get(index)) {
arguments.add(s);
result.addAll(generateInstances(termName, arguments, alist,
index + 1, cond));
arguments.remove(index);
}
}
return result;
}
/**
* Generate set of strings described by expression une
*
* @param une
* unary expression
* @param generateRecords
* if the flag is true records are generated
* @return set of strings belonging to language described by une
* @throws ParseException
* there are too many instances
*/
private HashSet<String> generateInstances(ASTunarySetExpression une,boolean generateRecords)
throws ParseException {
// t=< POUND_SIGN > sortName()
// n=curlyBrackets()
// setExpression() < CP >
SimpleNode child = (SimpleNode) une.jjtGetChild(0);
if (child.getId() == SparcTranslatorTreeConstants.JJTSORTNAME) {
return generateInstances_p(sortNameToExpression.get(child
.toString()),generateRecords);
} else if (child.getId() == SparcTranslatorTreeConstants.JJTCURLYBRACKETS) {
ASTcurlyBrackets curlyBrackets = (ASTcurlyBrackets) child;
ASTconstantTermList termList = (ASTconstantTermList) curlyBrackets
.jjtGetChild(0);
return generateInstances(termList,generateRecords);
} else if(child.getId() == SparcTranslatorTreeConstants.JJTSETEXPRESSION) { // setExpression
return generateInstances((ASTsetExpression) child,generateRecords);
} else { //Functional symbol
if(generateRecords) {
return generateInstances((ASTfunctionalSymbol)child);
} else {
return new HashSet<String>();
}
}
}
public HashSet<String> generateInstances(ASTconstantTermList termList,boolean generateRecords) {
HashSet<String> result = new HashSet<String>();
for (int i = 0; i < termList.jjtGetNumChildren(); i++) {
ASTconstantTerm constantTerm = (ASTconstantTerm) termList
.jjtGetChild(i);
String constantString=constantTerm.toString();
boolean isRecord=constantString.indexOf('(')!=-1;
if(isRecord && generateRecords || !isRecord)
result.add(constantTerm.toString());
}
return result;
}
/**
* Generate instances of a numeric range
*
* @param r
* AST node describing the numeric range
* @return set of instances belonging to the sort
*/
HashSet<String> generateInstances(ASTnumericRange r) {
String[] range = r.image.split(" ");
int from = Integer.parseInt(range[0]);
int to = Integer.parseInt(range[1]);
return generateInstances(from, to);
}
/**
* Generate instances of a numeric range, consisting of consecutive numbers
* [from..to]
*
* @param from
* first number from numeric range
* @param to
* last number
* @return
*/
HashSet<String> generateInstances(int from, int to) {
HashSet<String> result = new HashSet<String>();
for (int i = from; i <= to; i++) {
result.add(Integer.toString(i));
}
return result;
}
/**
* class representing sort name and instances which belong to the sort
*/
class GSort {
ASTsortExpression se;
String sortName;
HashSet<String> instances;
public GSort(ASTsortExpression se, String sortName,
HashSet<String> instances) {
this.se = se;
this.sortName = sortName;
this.instances = instances;
}
}
}