package translating;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import parser.ASTadditiveSetExpression;
import parser.ASTaggregateElement;
import parser.ASTatom;
import parser.ASTbody;
import parser.ASTchoice_element;
import parser.ASTdisjunction;
import parser.ASTextendedNonRelAtom;
import parser.ASTextendedSimpleAtomList;
import parser.ASThead;
import parser.ASTmultiplicativeSetExpression;
import parser.ASTnonRelAtom;
import parser.ASTpredSymbol;
import parser.ASTprogramRule;
import parser.ASTsimpleAtom;
import parser.ASTsortExpression;
import parser.ASTsortExpressionList;
import parser.ASTterm;
import parser.ASTtermList;
import parser.ASTunarySetExpression;
import parser.ASTunlabeledProgramCrRule;
import parser.ASTunlabeledProgramRule;
import parser.SparcTranslatorConstants;
import parser.SimpleNode;
import parser.SparcTranslatorTreeConstants;
/**
* Term fetcher finds all terms in given AST node (which may be a rule, body,
* head, atom.etc) and returns a mapping from terms to sort expression they
* should satisfy in order to obey sort definitions
*/
public class TermFetcher {
// mapping from sort names to sort expressions assigned to the sorts
// mapping from predicate names to a list of names of sorts describing
// arguments
private HashMap<String, ArrayList<String>> predicateArgumentSorts;
// mapping from sort names to sort expressions assigned to the sorts
// this map is needed for optimization purposes to avoid generation of certain sorts
private HashMap<String, ASTsortExpression> sortNameToExpression;
/**
* Constructor
*
* @param sortNameToExpression
* @param predicateArgumentSorts
*/
public TermFetcher(
HashMap<String, ArrayList<String>> predicateArgumentSorts,
HashMap<String, ASTsortExpression> sortNameToExpression) {
this.predicateArgumentSorts = predicateArgumentSorts;
this.sortNameToExpression = sortNameToExpression;
}
/**
* Fetch sorts for terms in program rule given by AST node
*
* @param rule
* ASTnode to explore
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
public HashMap<ASTterm, String> fetchTermSorts(ASTprogramRule rule) {
if (((SimpleNode) (rule.jjtGetChild(0))).getId() == SparcTranslatorTreeConstants.JJTUNLABELEDPROGRAMRULE) {
return fetchTermSorts((ASTunlabeledProgramRule) (rule
.jjtGetChild(0)));
} else {
return fetchTermSorts((ASTunlabeledProgramCrRule) (rule
.jjtGetChild(0)));
}
}
/**
* Put all key-value pairs from src map to dest map
*
* @param dest
* first map
* @param src
* second map
*/
private void unionMaps(HashMap<ASTterm, String> dest,
HashMap<ASTterm, String> src) {
for (ASTterm term : src.keySet()) {
dest.put(term, src.get(term));
}
}
/**
* Fetch variables from unlabeled program rule given by AST node
*
* @param rule
* ASTnode to explore
* @return variable->sort_expression mapping, where sort expression
* describes a language of string each of which may be used as a
* substitution for given variable
*/
public HashMap<ASTterm, String> fetchTermSorts(ASTunlabeledProgramRule rule) {
HashMap<ASTterm, String> result = new HashMap<ASTterm, String>();
String weakSep = SparcTranslatorConstants.tokenImage[SparcTranslatorConstants.WEAKSEP];
// remove quotes:
weakSep = weakSep.substring(1, weakSep.length() - 1);
if (rule.image.equals(weakSep)) {
// weak constraint can only have body
unionMaps(result, fetchTermSorts((ASTbody) (rule.jjtGetChild(0))));
} else if (rule.jjtGetNumChildren() > 0
&& ((SimpleNode) rule.jjtGetChild(0)).getId() == SparcTranslatorTreeConstants.JJTPREDSYMBOL) {
// fact of the form f(n1..n2).
return result;
} else if (rule.jjtGetNumChildren() > 1) {
// program rule consists of at most one head and at most one body
unionMaps(result, fetchTermSorts((ASThead) (rule.jjtGetChild(0))));
unionMaps(result, fetchTermSorts((ASTbody) (rule.jjtGetChild(1))));
} else if (((SimpleNode) rule.jjtGetChild(0)).getId() == SparcTranslatorTreeConstants.JJTHEAD) {
unionMaps(result, fetchTermSorts((ASThead) (rule.jjtGetChild(0))));
} else {
unionMaps(result, fetchTermSorts((ASTbody) (rule.jjtGetChild(0))));
}
return result;
}
/**
* Fetch sorts for terms in rule's body given by AST node
*
* @param rule
* ASTnode to explore
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
private HashMap<ASTterm, String> fetchTermSorts(ASTbody body) {
HashMap<ASTterm, String> result = new HashMap<ASTterm, String>();
for (int i = 0; i < body.jjtGetNumChildren(); i++) {
unionMaps(result, fetchTermSorts((ASTatom) (body.jjtGetChild(i))));
}
return result;
}
/**
* Fetch sorts for terms occurring in the atom given by AST node
*
* @param rule
* ASTnode to explore
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
private HashMap<ASTterm, String> fetchTermSorts(ASTatom atom) {
HashMap<ASTterm, String> result = new HashMap<ASTterm, String>();
if (((SimpleNode) atom.jjtGetChild(0)).getId() == SparcTranslatorTreeConstants.JJTEXTENDEDNONRELATOM) {
unionMaps(result,
fetchTermSorts((ASTextendedNonRelAtom) atom.jjtGetChild(0)));
}
return result;
}
/**
* Fetch sorts for terms occurring in the extended non-relational atom given by AST node
*
* @param rule
* ASTnode to explore
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
private HashMap<ASTterm, String> fetchTermSorts(
ASTextendedNonRelAtom atom) {
ASTpredSymbol pred = (ASTpredSymbol) atom.jjtGetChild(0);
if (atom.jjtGetNumChildren() == 1) { // 0-arity
return new HashMap<ASTterm,String>();
}
return fetchTermSorts((ASTtermList) (atom.jjtGetChild(1)), (pred.hasPoundSign()? "#":"") + pred.image);
}
/**
* Check if given sort is defined by a sort expression which is a union of disjoint records
* (see the details below)
* @param sort sort name
* @return true iff sort is defined by an expression of the form #sort= expr_1 + ...expr_n,
* where 1) each of expr_1,...,expr_n is either of the form fi(#si_1,...,#si_ki), or is a sort #si
* defined as #si = fi(#si_1,...,#si_ki),
* 2) fi are pairwise distinct
*
*/
private boolean isSumOfDisjointRecordSorts(String sort) {
ASTsortExpression expr = sortNameToExpression.get(sort);
SimpleNode exprChild = (SimpleNode) expr.jjtGetChild(0);
if(exprChild.getId()!=SparcTranslatorTreeConstants.JJTSETEXPRESSION)
return false;
// from now on we can assume childExpr is a set expression!
ASTadditiveSetExpression addExpr = (ASTadditiveSetExpression) exprChild.jjtGetChild(0);
if(addExpr.image.indexOf('-')!=-1)
return false; // we should only have additions!
// collect record names from the sort definition in this set
// this set is used to check if the record names are pairwise distinct
HashSet<String> recordNames = new HashSet<String>();
for(int i=0;i<addExpr.jjtGetNumChildren();i++) {
ASTmultiplicativeSetExpression multExpr = (ASTmultiplicativeSetExpression) addExpr.jjtGetChild(i);
ASTunarySetExpression unaryExpr = (ASTunarySetExpression)multExpr.jjtGetChild(0);
SimpleNode unarExprChild = (SimpleNode)unaryExpr.jjtGetChild(0);
String recordName = null;
if(unarExprChild.getId() == SparcTranslatorTreeConstants.JJTSORTNAME) {
String argSort = unarExprChild.image;
ASTsortExpression argSortExpression = sortNameToExpression.get(argSort);
SimpleNode argExprChild = (SimpleNode) argSortExpression.jjtGetChild(0);
if(argExprChild.getId()!=SparcTranslatorTreeConstants.JJTSETEXPRESSION)
return false;
// from now on we can assume argExprChild is a set expression!
ASTadditiveSetExpression argAddExpr = (ASTadditiveSetExpression) argExprChild.jjtGetChild(0);
// we must have exactly one child:
if(argAddExpr.jjtGetNumChildren()!=1)
return false;
// and this child should be a record
ASTmultiplicativeSetExpression argMultExpr = (ASTmultiplicativeSetExpression) argAddExpr.jjtGetChild(0);
ASTunarySetExpression argUnaryExpr = (ASTunarySetExpression)argMultExpr.jjtGetChild(0);
SimpleNode argUnarExprChild = (SimpleNode)argUnaryExpr.jjtGetChild(0);
if(argUnarExprChild.getId()!=SparcTranslatorTreeConstants.JJTFUNCTIONALSYMBOL)
return false;
if(argUnarExprChild.jjtGetNumChildren()!=1)// if we have a condition, generate the entire sort
return false;
recordName = argUnarExprChild.image.substring(0, argUnarExprChild.image.indexOf('('));
} else if(unarExprChild.getId() == SparcTranslatorTreeConstants.JJTFUNCTIONALSYMBOL) {
if(unarExprChild.jjtGetNumChildren()!=1) // if we have a condition, generate the entire sort
return false;
recordName = unarExprChild.image.substring(0, unarExprChild.image.indexOf('('));
} else {
return false;
}
// check for pairwise distinction:
if(recordNames.contains(recordName))
return false;
recordNames.add(recordName);
}
return true;
}
/**
* @param sort
* @param recordName
* @param arity
* @return if isSumOfDisjointRecordSorts(sort), and fi(#s1,...,sn) is a part of the sort definition,
* such that n = arity, and f = recordName, then return [#s1,...,#sn]
* otherwise, return null
*/
private ArrayList<String> getRecordSorts(String sort , String recordName, int arity) {
if(!isSumOfDisjointRecordSorts(sort))
return null;
ASTsortExpression expr = sortNameToExpression.get(sort);
SimpleNode exprChild = (SimpleNode) expr.jjtGetChild(0);
ASTadditiveSetExpression addExpr = (ASTadditiveSetExpression) exprChild.jjtGetChild(0);
// a variable to store the list of sort expression for record's arguments:
ASTsortExpressionList sortExprList = null;
for(int i=0;i<addExpr.jjtGetNumChildren();i++) {
ASTmultiplicativeSetExpression multExpr = (ASTmultiplicativeSetExpression) addExpr.jjtGetChild(i);
ASTunarySetExpression unaryExpr = (ASTunarySetExpression)multExpr.jjtGetChild(0);
SimpleNode unarExprChild = (SimpleNode)unaryExpr.jjtGetChild(0);
if(unarExprChild.getId() == SparcTranslatorTreeConstants.JJTSORTNAME) {
String argSort = unarExprChild.image;
ASTsortExpression argSortExpression = sortNameToExpression.get(argSort);
SimpleNode argExprChild = (SimpleNode) argSortExpression.jjtGetChild(0);
ASTadditiveSetExpression argAddExpr = (ASTadditiveSetExpression) argExprChild.jjtGetChild(0);
ASTmultiplicativeSetExpression argMultExpr = (ASTmultiplicativeSetExpression) argAddExpr.jjtGetChild(0);
ASTunarySetExpression argUnaryExpr = (ASTunarySetExpression)argMultExpr.jjtGetChild(0);
SimpleNode argUnarExprChild = (SimpleNode)argUnaryExpr.jjtGetChild(0);
String sortRecordName = argUnarExprChild.image.substring(0, argUnarExprChild.image.indexOf('('));
if(recordName.equals(sortRecordName)) {
sortExprList = (ASTsortExpressionList)argUnarExprChild.jjtGetChild(0);
}
} else if(unarExprChild.getId() == SparcTranslatorTreeConstants.JJTFUNCTIONALSYMBOL) {
String sortRecordName = unarExprChild.image.substring(0, unarExprChild.image.indexOf('('));
if(recordName.equals(sortRecordName)) {
sortExprList = (ASTsortExpressionList)unarExprChild.jjtGetChild(0);
}
}
}
if(sortExprList.jjtGetNumChildren()!=arity)
return null;
return sortExprList.getSortNames();
}
/**
* Fetch sorts for terms with variables occurring in the predicate
*
* @param termList
* list of terms which are arguments of the predicate
* @param predicateName
* name of the predicate
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
private HashMap<ASTterm, String> fetchTermSorts(
ASTtermList termList, String predicateName) {
HashMap<ASTterm, String> result = new HashMap<ASTterm, String>();
ArrayList<String> argumentSortList=predicateArgumentSorts.get(predicateName);
for (int i=0;i<termList.jjtGetNumChildren();i++) {
ASTterm term=(ASTterm)termList.jjtGetChild(i);
if(term.hasVariables()) {
// add new atoms sort(term) iff it is not the same as original atom predicateName(term).
if(!predicateName.startsWith("#")) {
// if the term t is of the form f(t1,...,tn) and the sort is of the form
// #s = #s1 + ...#sn,
// where 1) each of #s1,...,sn is either of the form fi(#si_1,...,#si_ki), or is defined as
// #si = fi(#si_1,...,#si_ki),
// 2) the records fi are pairwise distinct
// and there exists fi in {f1,...,fn} s.t, fi = f and n = ki
// then add the sort atoms si_1(f1),...si_n(fn) to the body!
String sort = argumentSortList.get(i);
// a variable that will store #si_1,..#s_in, in case all the conditions are satisfied:
ArrayList<String> recordSorts;
if(isSumOfDisjointRecordSorts(sort) && term.isRecord() &&
((recordSorts = getRecordSorts(sort, term.getRecordName(), term.getRecordArgs().size())) !=null)) {
ArrayList<ASTterm> recordArgTerms = term.getRecordArgs();
for(int j=0; j < recordArgTerms.size() ;j++) {
result.put(recordArgTerms.get(j), recordSorts.get(j));
}
}
else {// add #s(#t) to the body
result.put(term,sort);
}
}
}
}
return result;
}
/**
* Fetch sorts for terms with variables occurring in the aggregate Element
*
* @param agr
* element to explore
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
//public HashMap<ASTterm,String> fetchTermSorts(
// ASTaggregate agr) {
// for (int i = 0; i < agr.jjtGetNumChildren(); i++) {
// if (((SimpleNode) (agr.jjtGetChild(i))).getId() == SparcTranslatorTreeConstants.JJTAGGREGATEELEMENTS) {
// return fetchTermSorts((ASTaggregateElements) (agr
// .jjtGetChild(i)));
// }
// }
// return null;// we should never be here!
//}
/**
* Fetch sorts for terms with variables occurring in the aggregate Elements
* //assuming all local variables are properly renamed
* @param agrelems
* elements to explore
*
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
//private HashMap<ASTterm,String> fetchTermSorts(
// ASTaggregateElements agrelems) {/
// HashMap<ASTterm,String> result = new HashMap<ASTterm,String>();
// for (int i = 0; i < agrelems.jjtGetNumChildren(); i++) {
// unionMaps(result,
// fetchTermSorts((ASTaggregateElement) (agrelems
// .jjtGetChild(i))));
// }
//return result;
// }
/**
* Fetch sorts for terms with variables occurring in the aggregate Element
* /assuming all local variables are properly renamed
* @param agrelem
* element to explore
* /
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
public HashMap<ASTterm,String> fetchTermSorts(
ASTaggregateElement argelem) {
HashMap<ASTterm,String> result = new HashMap<ASTterm,String>();
for (int i = 0; i < argelem.jjtGetNumChildren(); i++) {
if (((SimpleNode) (argelem.jjtGetChild(i))).getId() == SparcTranslatorTreeConstants.JJTEXTENDEDSIMPLEATOMLIST) {
unionMaps(result,
fetchTermSorts((ASTextendedSimpleAtomList) argelem
.jjtGetChild(i)));
}
}
return result;
}
/**
* Fetch sorts for terms with variables occurring in the extended simple atoms(see grammar) given by
* AST node
*
* @param exList
* AST node to explore
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
private HashMap<ASTterm,String> fetchTermSorts(
ASTextendedSimpleAtomList exList) {
HashMap<ASTterm,String> result = new HashMap<ASTterm,String>();
for (int i = 0; i < exList.jjtGetNumChildren(); i++) {
unionMaps(result,
fetchTermSorts((ASTsimpleAtom) exList.jjtGetChild(i)));
}
return result;
}
/**
* Fetch sorts for terms with variables occurring in the simple atom(see grammar) given by
* AST node
*
* @param atom
* AST node to explore
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
private HashMap<ASTterm,String> fetchTermSorts(
ASTsimpleAtom atom) {
HashMap<ASTterm,String> result = new HashMap<ASTterm,String>();
if (((SimpleNode) atom.jjtGetChild(0)).getId() == SparcTranslatorTreeConstants.JJTEXTENDEDNONRELATOM) {
unionMaps(result,
fetchTermSorts((ASTextendedNonRelAtom) atom.jjtGetChild(0)));
}
return result;
}
/**
* Fetch sorts for terms with variables occurring in the non-relational atom given by AST node.
* Relational atoms are atoms of the form [term1] [relation][term2]
*
* @param nonRelAtom
* AST node to explore
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
private HashMap<ASTterm,String>fetchTermSorts(
ASTnonRelAtom nonRelAtom) {
ASTpredSymbol pred = (ASTpredSymbol) nonRelAtom.jjtGetChild(0);
if (nonRelAtom.jjtGetNumChildren() == 1) { // 0-arity
return new HashMap<ASTterm,String>();
}
return fetchTermSorts((ASTtermList) (nonRelAtom.jjtGetChild(1)),
pred.image);
}
/**
* Fetch sorts for terms with variables occurring in the head given by AST node
*
* @param head
* ASTnode to explore
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
private HashMap<ASTterm,String> fetchTermSorts(ASThead head) {
if (((SimpleNode) (head.jjtGetChild(0))).getId() == SparcTranslatorTreeConstants.JJTDISJUNCTION) {
return fetchTermSorts((ASTdisjunction) (head.jjtGetChild(0)));
} else {
return new HashMap<ASTterm,String>();
}
}
/**
* Fetch sorts for terms with variables occurring in the choice rule given by AST node
*
* @param choice_rule
* ASTnode to explore
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
// public HashMap<ASTterm,String> fetchTermSorts(
// ASTchoice_rule choice_rule) {
//
// for (int i = 0; i < choice_rule.jjtGetNumChildren(); i++) {
// if (((SimpleNode) (choice_rule.jjtGetChild(i))).getId() == SparcTranslatorTreeConstants.JJTCHOICE_ELEMENTS) {
// return fetchTermSorts((ASTchoice_elements) (choice_rule
// .jjtGetChild(i)));
// }
// }
// return null; // DEAD CODE!
// }
/**
* Fetch sorts for terms with variables occurring in the choice rule elements given by AST node
*
* @param choice_elements
* elements to explore
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
// private HashMap<ASTterm,String> fetchTermSorts(
// ASTchoice_elements choice_elements) {
// HashMap<ASTterm,String> result = new HashMap<ASTterm,String>();
//
// for (int i = 0; i < choice_elements.jjtGetNumChildren(); i++) {
// unionMaps(result,
// fetchTermSorts((ASTchoice_element) (choice_elements
// .jjtGetChild(i))));
// }
// return result;
// }
/**
* Fetch sorts for terms with variables occurring in the choice rule element given by AST node
*
* @param choice_element
* element to explore
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
public HashMap<ASTterm,String> fetchTermSorts(
ASTchoice_element choice_element) {
HashMap<ASTterm,String> result = new HashMap<ASTterm,String>();
for (int i = 0; i < choice_element.jjtGetNumChildren(); i++) {
if (((SimpleNode) (choice_element.jjtGetChild(i))).getId() == SparcTranslatorTreeConstants.JJTNONRELATOM) {
unionMaps(result,
fetchTermSorts((ASTnonRelAtom) choice_element
.jjtGetChild(i)));
} else if (((SimpleNode) (choice_element.jjtGetChild(i))).getId() == SparcTranslatorTreeConstants.JJTEXTENDEDSIMPLEATOMLIST) {
unionMaps(
result,
fetchTermSorts((ASTextendedSimpleAtomList) choice_element
.jjtGetChild(i)));
}
}
return result;
}
/**
* Fetch sorts for terms with variables occurring in the disjunction given by AST node
*
* @param disjunction
* ASTnode to explore
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
private HashMap<ASTterm,String> fetchTermSorts(
ASTdisjunction disjunction) {
HashMap<ASTterm,String> result = new HashMap<ASTterm,String>();
for (int i = 0; i < disjunction.jjtGetNumChildren(); i++) {
unionMaps(result,
fetchTermSorts((ASTnonRelAtom) disjunction.jjtGetChild(i)));
}
return result;
}
/**
* Fetch sorts for terms occurring in the consistency restoring rule given by AST node
*
* @param crrule
* rule to explore
* @return term->sort_name mapping, where sort_name is a name of sort which
* describes a set of strings this term, being grounded, must belong to in order to
* obey sort definitions
*/
public HashMap<ASTterm,String> fetchTermSorts(
ASTunlabeledProgramCrRule crrule) {
HashMap<ASTterm,String> result = new HashMap<ASTterm,String>();
for (int i = 0; i < crrule.jjtGetNumChildren(); i++) {
if (((SimpleNode) (crrule.jjtGetChild(i))).getId() == SparcTranslatorTreeConstants.JJTHEAD) {
unionMaps(result,
fetchTermSorts((ASThead) crrule.jjtGetChild(i)));
} else {// body
unionMaps(result,
fetchTermSorts((ASTbody) crrule.jjtGetChild(i)));
}
}
return result;
}
}