package typechecking;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import parser.ASTarithmeticTerm;
import parser.ASTsymbolicTerm;
import parser.ASTterm;
import parser.ASTtermList;
import parser.ParseException;
import parser.SimpleNode;
import parser.SparcTranslator;
import parser.SparcTranslatorConstants;
import parser.SparcTranslatorTreeConstants;
/**
* Class for unification(matching) between terms with variables and ground
* terms. Used for typechecking purposes
*
*/
public class Unifier {
TypeChecker typechecker;
public Unifier(TypeChecker tc) {
this.typechecker = tc;
}
/**
* Unify(match) term with each of string constants from the list (without
* variables)
*
* @param term
* term with variables
* @param constants
* list of constants
* @return true if at least one of the unifications succeeds
*/
public boolean unify(ASTterm term, ArrayList<String> constants) {
boolean result = false;
// try to unify every constant from the list
for (String s : constants) {
if (unify(term, s)) {
result = true; // result is true, if unification succeeds
break;
}
}
return result;
}
/**
* Unify(match) term with variables with given string s, representing ground
* term
*
* @param termWithVariables
* @param s
* , string, representing constant ground term
* @return true if there is a substitution for variables from
* termWithVariables which makes the term equal to s.
*/
private boolean unify(ASTterm termWithVariables, String s) {
ASTterm groundTerm = createTerm(s);
groundTerm.toString();
return unify(termWithVariables, groundTerm);
}
/**
* Unify(match) term with variables with given term without variables,
*
* @param termWithVariables
* @param groundterm
* @return true if there exists a substitution for term with variables which
* makes it equivalent to ground term.
*/
private boolean unify(ASTterm termWithVariables, ASTterm groundTerm) {
// TODO Auto-generated method stub
if (((SimpleNode) termWithVariables.jjtGetChild(0)).getId() == SparcTranslatorTreeConstants.JJTVAR) {
return true;
} else if (((SimpleNode) termWithVariables.jjtGetChild(0)).getId() == SparcTranslatorTreeConstants.JJTSYMBOLICTERM) {
if (((SimpleNode) groundTerm.jjtGetChild(0)).getId() == SparcTranslatorTreeConstants.JJTSYMBOLICTERM) {
return unify(
(ASTsymbolicTerm) termWithVariables.jjtGetChild(0),
(ASTsymbolicTerm) groundTerm.jjtGetChild(0));
} else { // arithmetic term
return unify(
(ASTsymbolicTerm) termWithVariables.jjtGetChild(0),
(ASTarithmeticTerm) groundTerm.jjtGetChild(0));
}
} else { // term with variables is arithmetic
if (((SimpleNode) groundTerm.jjtGetChild(0)).getId() == SparcTranslatorTreeConstants.JJTSYMBOLICTERM) {
return unify(
(ASTarithmeticTerm) termWithVariables.jjtGetChild(0),
(ASTsymbolicTerm) groundTerm.jjtGetChild(0));
} else { // ground term is arithmetic
return unify(
(ASTarithmeticTerm) termWithVariables.jjtGetChild(0),
(ASTarithmeticTerm) groundTerm.jjtGetChild(0));
}
}
}
/**
* Unify(match) arithmetic term with variables with arithmetic term without
* variables,
*
* @param termWithVariables
* @param groundterm
* @return true if there exists a substitution for term with variables which
* makes it equivalent to ground term.
*/
private boolean unify(ASTarithmeticTerm termWithVariables,
ASTarithmeticTerm groundTerm) {
// we assume arithmetic terms are always unifiable
return true;
}
/**
* Unify(match) arithmetic term with variables with ground symbolic term
*
* @param termWithVariables
* @param groundTerm
* symbolic ground term
* @return false (terms are always not unifiable)
*/
private boolean unify(ASTarithmeticTerm termWithVariables,
ASTsymbolicTerm groundTerm) {
// we can never get a symbolic constant out of arithmetic term
return false;
}
/**
* Unify(match) symbolic term with variables with arithmetic term without
* variables,
*
* @param termWithVariables
* @param groundterm
* @return true if there exists a substitution for term with variables which
* makes it equivalent to ground term.
*/
private boolean unify(ASTsymbolicTerm termWithVariables,
ASTarithmeticTerm groundTerm) {
SimpleNode child1 = (SimpleNode) termWithVariables.jjtGetChild(0);
TermEvaluator tEval = new TermEvaluator(groundTerm);
String value = null;
try {
value = Long.toString(tEval.evaluate());
} catch (ParseException e) {
e.printStackTrace();
}
if (child1.getId() == SparcTranslatorTreeConstants.JJTSYMBOLICFUNCTION) {
return false;
} else {
if (typechecker.constantsMapping.containsKey(termWithVariables
.toString())) {
return typechecker.constantsMapping.get(
termWithVariables.toString()).equals(value);
} else {
return false;
}
}
}
/**
* Unify(match) symbolic term with variables with symbolic term without
* variables,
*
* @param termWithVariables
* @param groundterm
* @return true if there exists a substitution for term with variables which
* makes it equivalent to ground term.
*/
private boolean unify(ASTsymbolicTerm termWithVariables,
ASTsymbolicTerm groundTerm) {
SimpleNode child1 = (SimpleNode) termWithVariables.jjtGetChild(0);
SimpleNode child2 = (SimpleNode) groundTerm.jjtGetChild(0);
// either both of the terms start from functional symbol or both of them
// are
// constants
if (child1.getId() != child2.getId()) {
return false;
} else if (child1.getId() == SparcTranslatorTreeConstants.JJTSYMBOLICCONSTANT) {
return child1.image.equals(child2.image);
} else { // both are symbolic functions:
if (!child1.image.equals(child2.image)) {
return false;
}
SimpleNode termList1 = (ASTtermList) termWithVariables
.jjtGetChild(1);
SimpleNode termList2 = (ASTtermList) groundTerm.jjtGetChild(1);
return unifyTermLists(termList1, termList2);
}
}
/**
* Unify(match) two list of terms
*
* @param termList1
* @param termList2
* @return true if all corresponding elements of two lists are unifiable)
*/
private boolean unifyTermLists(SimpleNode termList1, SimpleNode termList2) {
if (termList1.jjtGetNumChildren() != termList2.jjtGetNumChildren()) {
return false;
} else {
boolean result = true;
for (int index = 0; index < termList1.jjtGetNumChildren(); index++) {
ASTterm t1 = (ASTterm) termList1.jjtGetChild(index);
ASTterm t2 = (ASTterm) termList2.jjtGetChild(index);
if (!unify(t1, t2)) {
result = false;
break;
}
}
return result;
}
}
/**
* Create a term from given string
*
* @param content
* given string
* @return Abstract Syntax Tree Node representing the term
*/
private ASTterm createTerm(String content) {
Reader sr = new StringReader(content);
SparcTranslator p = new SparcTranslator(sr);
p.token_source.SwitchTo(SparcTranslatorConstants.IN_PROGRAM_RULES);
ASTterm result = null;
try {
result = (ASTterm) p.term();
} catch (ParseException e) {
e.printStackTrace();
}
return result;
}
}