package platformSpecific.javaTranslation;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.IntStream;
import platformSpecific.fakeInternet.PluginType;
import tools.Assertions;
import tools.StringBuilders;
import ast.Ast.NormType;
import ast.Ast.Path;
import ast.Ast.Position;
import ast.Ast.SignalKind;
import ast.Ast.Stage;
import ast.ErrorMessage;
import ast.ExpCore;
import ast.ExpCore.Block;
import ast.ExpCore.Block.Dec;
import ast.ExpCore.Block.On;
import ast.ExpCore.ClassB;
import ast.ExpCore.ClassB.Phase;
import ast.ExpCore.Loop;
import ast.ExpCore.MCall;
import ast.ExpCore.Signal;
import ast.ExpCore.Using;
import ast.ExpCore.WalkBy;
import ast.ExpCore.X;
import ast.ExpCore._void;
import auxiliaryGrammar.Functions;
import programReduction.Program;
import coreVisitors.IsCompiled;
/*class A{ A m(A a){return a;}
A mm(){
A a=new A();
a.m(B.block(()->{A a1=new A(); return a1.m(a1);}));
return B.block(()->{throw Assertions.codeNotReachable();});
}
}
class B{public static <T> T block(java.util.function.Supplier<T> p){return p.get();}}
*/
public class TranslateExpression implements coreVisitors.Visitor<Void>{
public static void of(ExpCore expCore,StringBuilder res) {
TranslateExpression tr=new TranslateExpression(res);
if(expCore instanceof Block){
tr.produceNestedBlock((Block)expCore," return ");
return;}
res.append("{return ");
expCore.accept(tr);
res.append(";}");
}
private static Set<String> labels=new HashSet<String>();
StringBuilder res;
Set<String> undeclared=new HashSet<String>();
TranslateExpression(StringBuilder res){this.res=res;}
@Override //not a propagator visitor.
public Void visit(ExpCore.EPath s) {
Path ss=s.getInner();
if(ss.isPrimitive()){
if(ss.equals(Path.Any())){res.append("platformSpecific.javaTranslation.Resources.Any.type");}
if(ss.equals(Path.Library())){res.append("platformSpecific.javaTranslation.Resources.Library.type");}
if(ss.equals(Path.Void())){res.append("platformSpecific.javaTranslation.Resources.Void.type");}
return null;
}
ClassB cbs=Resources.getP().extractClassB(ss);
if(cbs.getPhase()==Phase.Coherent && IsCompiled.of(cbs)){
res.append(Resources.nameOf(ss)+".type ");
}
else{
Position pos=Resources.getP().get(ss.outerNumber()).getP();
int hash=System.identityHashCode(pos);
String cs=s.toString();
int dotPos=cs.indexOf(".");
assert dotPos>=0;
cs=cs.substring(dotPos);
res.append(
"platformSpecific.javaTranslation.Resources.fromHash("+hash+",\""+cs+"\")");
}
return null;
}
@Override
public Void visit(X s) {
if(s.getInner().equals("this")){res.append("this");return null;}
if(undeclared.contains(s.getInner())){res.append("PH"+s.getInner());}
else{res.append("P"+s.getInner());}
return null;
}
@Override
public Void visit(_void s) {
res.append("platformSpecific.javaTranslation.Resources.Void.instance");
return null;
}
@Override
public Void visit(WalkBy s) {
throw Assertions.codeNotReachable();
}
@Override
public Void visit(Using s) {
List<String> es=new ArrayList<>();
StringBuilder resOld=res;
res=new StringBuilder();
s.getInner().accept(this);
String e=res.toString();
for(ExpCore ei:s.getEs()){
res=new StringBuilder();
ei.accept(this);
es.add(res.toString());
}
res=resOld;
PluginType pt=platformSpecific.fakeInternet.OnLineCode.plugin(Resources.getP(),s);
res.append(pt.executableJ(Resources.getP(),s, e, es, TranslateExpression.labels));
return null;
}
@Override
public Void visit(Signal s) {
res.append("platformSpecific.javaTranslation.Resources.block(()->{");
produceThrow(s);
res.append("})");
return null;
}
public Void produceThrow(Signal s){
res.append("throw new platformSpecific.javaTranslation.Resources.");
res.append(s.getKind().name());
res.append("(");
s.getInner().accept(this);
res.append(");\n");
return null;
}
@Override
public Void visit(MCall s) {
res.append("(");
s.getInner().accept(this);
res.append(")."+Resources.nameOf(s.getS().nameToS(),s.getS().getNames())+"(");
StringBuilders.formatSequence(res,s.getEs().iterator(),
", ", ei->ei.accept(this));
res.append(")");
return null;
}
@Override
public Void visit(Block s) {
res.append("platformSpecific.javaTranslation.Resources.block(()->");
produceNestedBlock(s,"return ");
res.append(")");
return null;
}
public void produceNestedBlock(Block s,String asReturn){
String kVar=" L"+Functions.freshName("lab",TranslateExpression.labels);
res.append("{"+kVar+":{");
Set<String> domPhs=declareVarsAndPh(s.getDecs());
if(!s.getOns().isEmpty()){
res.append("try{\n");
initializeVars(domPhs,s.getDecs(),kVar);
res.append("\n}");
getCatches(s.getOns(),asReturn,kVar);
}
else{initializeVars(domPhs,s.getDecs(),kVar);}
//if(s.getInner()instanceof Block){
// produceNestedBlock((Block)s.getInner(),asReturn);
//}else{//This change the semantic... :?
if(s.getInner()instanceof Signal){
if(asReturn.contains("="))res.append("if(true)");
produceThrow((Signal)s.getInner());
}else{
res.append(asReturn);
s.getInner().accept(this);
res.append(";");
}
res.append("}}");
}
private void getCatches(List<On> c,String asReturn,String kLab) {
assert !c.isEmpty();
SignalKind kind = c.get(0).getKind();
boolean allEq=true;
for(On on:c){ if(on.getKind()!=kind){allEq=false;}}
assert allEq;//TODO: for now ok, then we will capture a more general exception on need.
String kVar=Functions.freshName("K",TranslateExpression.labels);
res.append("catch(platformSpecific.javaTranslation.Resources."+kind.name()+" "+kVar);
res.append("){\n");
for(On on:c){getCatch(kVar,on,asReturn,kLab);}
res.append("{}/*ensure termination*/throw "+kVar);
res.append(";\n}\n");
}
private void getCatch(String kVar,On on,String asReturn,String kLab) {
Path p=((NormType)on.getT()).getPath();
String tn=Resources.nameOf(p);
if(p.equals(Path.Library())){
res.append(getCatchHeaderForLibrary(kVar));
}
else if(!p.isPrimitive() && tn.equals("Object")){
res.append(getCatchHeaderForPathNotStar(kVar,p));
}
else {
res.append("if("+kVar+".unbox instanceof "+tn+"){\n");
}
res.append(" "+tn+" P"+on.getX()+"=("+tn+")"+kVar+".unbox;\n");
res.append(asReturn);
on.getInner().accept(this);
res.append(";");
if(asReturn.contains("=")){ res.append("break "+kLab+";"); }
res.append("\n }\nelse ");
}
//TODO: this is problematic for plugins with Part
//for now, we may leave it broken that Library capture all as much as any?
private Object getCatchHeaderForLibrary(String xName) {
String iOf=xName+".unbox instanceof ";
return "if(!("+iOf+"platformSpecific.javaTranslation.Resources.Revertable)){\n";
/* return "if("
+iOf+" String ||"
+iOf+" Integer ||"
+iOf+" ast.ExpCore.ClassB||"//Will break if ClassB implements Revertable
+iOf+" ast.Ast.Doc"
+"){\n";*/
}
private Object getCatchHeaderForPathNotStar(String xName,Path path) {
String cond="((platformSpecific.javaTranslation.Resources.Revertable)"+xName+".unbox).revert().toString().equals(\""+path.toString()+"\")";
return "if("+cond+"){\n";
}
private void initializeVars(Set<String> domPhs, List<Dec> decs,String kVar) {
//insertComment(domPhs);
this.undeclared.addAll(domPhs);
for(Dec d:decs){//declare all vars;
/*if(*/initializeSingleVar(d);/*){return true;}*/
undeclared.remove(d.getX());
if(domPhs.contains(d.getX())){
res.append("PH"+d.getX()+".commit(P"+d.getX()+");\n");
}
}
//return false;
}
public void initializeSingleVar(Dec d) {
if(d.getInner() instanceof ExpCore.Signal){
res.append("if(true)");
produceThrow((ExpCore.Signal)d.getInner());
return;
}
if(d.getInner() instanceof ExpCore.Block && d.getT().getNT().getPath().equals(Path.Void())){
//speeds up compilation time
/*boolean isThrow=*/produceNestedBlock((Block)d.getInner(),"P"+d.getX()+"=");
res.append("\n");
//if(isThrow){return true;}
}
else{
res.append("P"+d.getX()+"=");
d.getInner().accept(this);
res.append(";\n");
}
}
public void insertComment(Object domPhs) {
res.append("//");
res.append(domPhs.toString());
res.append("\n");
}
public Set<String> declareVarsAndPh(List<Dec> decs) {
Set<String> unDeclared=new HashSet<>();
for(Dec d:decs){//declare all vars;
res.append(Resources.nameOf(d.getT()));
res.append(" P"+d.getX()+";\n");
unDeclared.add(d.getX());
}
Set<String> domPhs=new HashSet<>();
for(Dec d:decs){
Set<String> fvei = coreVisitors.FreeVariables.of(d.getInner());
fvei.retainAll(unDeclared);
if(!fvei.isEmpty()){domPhs.addAll(fvei);}
unDeclared.remove(d.getX());
}
assert unDeclared.isEmpty();
for(Dec d:decs){
if(domPhs.contains(d.getX())){//declare placeholder
res.append(Resources.nameOf(d.getT())+".Ph");
res.append(" PH"+d.getX()+"=new "+Resources.nameOf(d.getT())+".Ph();\n");
}
}
return domPhs;
}
@Override
public Void visit(ClassB s) {
String k=Resources.submitRes(s);
res.append("platformSpecific.javaTranslation.Resources.getRes(\""+k+"\""+Resources.pKeysString()+")");
return null;
}
@Override
public Void visit(Loop s) {
res.append("platformSpecific.javaTranslation.Resources.block(()->{while(true){\n");
res.append("platformSpecific.javaTranslation.Resources.unused=");
s.getInner().accept(this);
res.append(";\n}})\n");
return null;
}
}