package printer;
import java.io.BufferedWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import speclistener.SpecBaseListener;
import symboltable.ASTNode;
import symboltable.Constructor;
import symboltable.ContainsProperties;
import symboltable.Entity;
import symboltable.Enumeration;
import symboltable.Property;
import static util.PrintUtil.writeToFile;
/**
*
* @author kostasferles
*/
public class PrintLogicQLSchema extends SpecBaseListener{
private final char lbNodeName = 'n';
private final char propertyName = 'v';
private final char indexName = 'i';
private BufferedWriter outputFile;
private String getPropertyFullName(Property pr){
return new StringBuilder().append(pr.getParent().getName()).
append(':').
append(pr.getName()).
toString();
}
private String printPropertyToString(Property pr){
StringBuilder rv = new StringBuilder();
ContainsProperties node = pr.getParent();
Property.Type prType = pr.getType();
String nodeName = node.getName();
String propertyFullName = getPropertyFullName(pr);
rv = rv.append(propertyFullName);
switch(prType){
case ManyToMany:
if(!pr.isOrdered()){
rv.append('(').
append(this.lbNodeName).
append(',').
append(this.propertyName).
append(')');
}
else{
rv.append("(").
append(lbNodeName).
append(",").
append(indexName).
append(",").
append(propertyName).append(")");
}
break;
case ManyToOne:
case OneToOne:
rv.append('(').
append(this.lbNodeName).
append(',').
append(this.propertyName).append(')');
break;
case OneToMany:
if(!pr.isOrdered()){
rv.append('(').
append(this.propertyName).
append(',').
append(this.lbNodeName).
append(')');
}
else{
rv.append('(').
append(propertyName).
append(',').
append(indexName).
append(",").
append(lbNodeName).append(")");
}
break;
case Existential:
rv.append("(").
append(this.lbNodeName).
append(")");
break;
default:
assert false;
}
rv.append(" -> ").
append(nodeName).
append('(').
append(this.lbNodeName).
append(')');
if(!(prType == Property.Type.Existential)){
rv.append(", ").
append(pr.getRangeTypeName()).
append('(').
append(this.propertyName).
append(")");
}
if(pr.isOrdered())
rv.append(", int(").append(indexName).append(")");
rv.append(".");
/* Temporary deactivate the constraint,
* if it makes performance worse, then
* we do not need it
* if(prType == Property.Type.OneToOne){
rv = rv.append('\n').
append(propertyFullName).
append("[n1] = v, ").
append(propertyFullName).
append("[n2] = v -> n1 = n2.");
}*/
return rv.toString();
}
private String handleElementWithProps(ContainsProperties elem){
writeToFile(this.outputFile, "\n");
StringBuilder rv = new StringBuilder();
String name = elem.getName();
rv = rv.append(name).append("(x) -> ");
ContainsProperties parentNode = elem.getSuper();
if(parentNode != null)
rv = rv.append(parentNode.getName()).append("(x)");
rv = rv.append(".");
if(!elem.hasSubClasses())
rv = rv.append("\nlang:isEntity[`").append(name).append("] = true.");
rv = rv.append("\n");
writeToFile(this.outputFile, rv.toString());
return rv.toString();
}
public PrintLogicQLSchema(BufferedWriter outputFile){
this.outputFile = outputFile;
}
@Override
public void enterProperty(Property p){
writeToFile(this.outputFile, this.printPropertyToString(p));
writeToFile(this.outputFile, "\n");
}
@Override
public void enterAstNode(ASTNode n){
handleElementWithProps(n);
}
@Override
public void enterEntity(Entity en){
handleElementWithProps(en);
}
@Override
public void enterEnumNode(Enumeration e){
StringBuilder rv = new StringBuilder();
String indexPrName = ":fromIndex";
Iterator<String> it = e.getEnumerators();
String enumName = e.getName();
rv = rv.append(enumName).
append("(n) -> .\n" ).
append(enumName).
append(indexPrName).
append("[i] = n -> int(i), ").
append(enumName).
append("(n).\n");
int i = 0;
while(it.hasNext()){
String enumerator = it.next();
String enumeratorLbName = enumName + ':' + enumerator;
rv = rv.append(enumeratorLbName).
append("[] = n -> ").
append(enumName).
append("(n).\n").
append("lang:isConstructor[`").
append(enumeratorLbName).
append("] = true.\n").
append(enumName).
append("(n), ").
append(enumName).
append(indexPrName).
append("[").append(i++).append("] = n").append(", ").
append(enumeratorLbName).
append("[] = n <- .\n");
}
writeToFile(this.outputFile, rv.toString());
writeToFile(this.outputFile, "\n");
}
@Override
public void enterConstructor(Constructor cons){
Iterator<Property> it = cons.getProperties();
StringBuilder rv = new StringBuilder();
ContainsProperties parent = cons.getParent();
String parentName = parent.getName();
String consName = parentName + ":cons";
Property pr = it.next();
List<String> typesOfCons = new ArrayList<>();
int vIndex = 1;
rv = rv.append(consName).
append('[').
append("v").
append(vIndex++);
typesOfCons.add(pr.getRangeTypeName());
while(it.hasNext()){
pr = it.next();
rv = rv.append(", v").
append(vIndex++);
typesOfCons.add(pr.getRangeTypeName());
}
rv.append("] = n -> ");
for(int i = 0 ; i < typesOfCons.size() ; i++){
rv = rv.append(typesOfCons.get(i)).
append("(v").
append(i+1).
append("), ");
}
rv = rv.append(parentName).
append("(n).\n");
rv = rv.append("lang:isConstructor[`").
append(consName).
append("] = true.\n");
writeToFile(this.outputFile, rv.toString());
}
}