package is.L42.connected.withSafeOperators;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import ast.Ast;
import ast.ExpCore;
import ast.Ast.Doc;
import ast.Ast.MethodSelector;
import ast.Ast.MethodSelectorX;
import ast.Ast.NormType;
import ast.Ast.Path;
import ast.Ast.Type;
import ast.ErrorMessage.NormImpossible;
import ast.ExpCore.Block;
import ast.ExpCore.ClassB;
import ast.ExpCore.MCall;
import auxiliaryGrammar.Functions;
import ast.ExpCore.Block.Dec;
import ast.ExpCore.Block.On;
import ast.ExpCore.ClassB.Member;
import ast.ExpCore.ClassB.MethodImplemented;
import ast.ExpCore.ClassB.MethodWithType;
import ast.ExpCore.ClassB.Phase;
import programReduction.Program;
import coreVisitors.From;
import facade.Configuration;
import newTypeSystem.TIn;
import tools.Assertions;
import tools.Map;
abstract public class MethodPathCloneVisitor extends RenameMembers {
public HashMap<String, NormType> varEnv=new HashMap<>();
public final ClassB visitStart;
public final Program p;
public MethodPathCloneVisitor(ClassB visitStart,CollectedLocatorsMap maps,Program p) {
super(maps);
this.visitStart=visitStart;
this.p=p.evilPush(visitStart);
}
ClassB getLastCb(){
if(this.getLocator().size()==0){return visitStart;}
return this.getLocator().getLastCb();
}
public abstract MethodSelector visitMS(MethodSelector original,Path src);
public ClassB.NestedClass visit(ClassB.NestedClass nc){
HashMap<String, Ast.NormType> aux =this.varEnv;
this.varEnv=new HashMap<>();
try{return super.visit(nc);}
finally{this.varEnv=aux;}
}
public ClassB.MethodImplemented visit(ClassB.MethodImplemented mi){
HashMap<String, Ast.NormType> aux =this.varEnv;
Program ep=p;for(ClassB cbi:this.getLocator().getCbs()){ep=ep.evilPush(cbi);}
this.varEnv=getVarEnvOf(ep,mi.getS(),this.getLastCb());
try{ return super.visit(mi); }
finally{this.varEnv=aux;}
}
public ClassB.MethodWithType visit(ClassB.MethodWithType mt){
HashMap<String, Ast.NormType> aux =this.varEnv;
Program ep=p;for(ClassB cbi:this.getLocator().getCbs()){ep=ep.evilPush(cbi);}
this.varEnv=getVarEnvOf(ep,mt.getMs(),this.getLastCb());
try{ return super.visit(mt);}
finally{this.varEnv=aux;}
}
private Ast.MethodType getMt(Program p,MethodSelector s,ClassB cb){
assert p.top()==cb;
Optional<Member> mOpt = Functions.getIfInDom(cb.getMs(),s);
assert mOpt.isPresent();
if(mOpt.get() instanceof MethodWithType){return ((MethodWithType)mOpt.get()).getMt();}
assert mOpt.get() instanceof MethodImplemented;
MethodWithType mwt=(MethodWithType) cb._getMember(s);
return mwt.getMt();
}
private HashMap<String, Ast.NormType> getVarEnvOf(Program p,MethodSelector s,ClassB cb) {
assert p.top()==cb;
Ast.MethodType mt=getMt(p,s,cb);
HashMap<String,Ast.NormType> result=new HashMap<>();
{int i=-1;for(String n:s.getNames()){i+=1;
//NormType nt=Norm.of(p,mt.getTs().get(i));
result.put(n,mt.getTs().get(i).getNT());
}}
result.put("this",new NormType(mt.getMdf(),Path.outer(0),Doc.empty()));
return result;
}
public ExpCore visit(Block s) {
HashMap<String, Ast.NormType> aux = new HashMap<>(this.varEnv);
try{
for(Dec d:s.getDecs()){
this.varEnv.put(d.getX(),d.getT().getNT()
//Functions.forceNormType(s,d.getT())
//Norm.of(p, d.getT())
);
}
List<Dec> newDecs = liftDecs(s.getDecs());
List<On> newOns=new ArrayList<>();
for(On on:s.getOns()){
this.varEnv.put(on.getX(),on.getT().getNT());
newOns.add(liftO(on));
this.varEnv.remove(on.getX());
}
return new Block(s.getDoc(),newDecs,lift(s.getInner()),newOns,s.getP());
}
finally{this.varEnv=aux;}
}
public Ast.Type liftT(Ast.Type t){
if(!(t instanceof Ast.HistoricType)){return super.liftT(t);}
Ast.HistoricType ht=(Ast.HistoricType)t;
Path last=ht.getPath();
List<MethodSelectorX>sels=new ArrayList<>();
for(MethodSelectorX sel:ht.getSelectors()){
MethodSelector ms2=visitMS(sel.getMs(),last);
if(ms2.equals(sel.getMs())){sels.add(sel);}
else{sels.add(new MethodSelectorX(ms2,sel.getX()));}
Ast.HistoricType hti=new Ast.HistoricType(last,Collections.singletonList(sel),Doc.empty());
Program ep=p;for(ClassB cbi:this.getLocator().getCbs()){ep=ep.evilPush(cbi);}
NormType nt=programReduction.Norm.resolve(ep, hti);
last=nt.getPath();
}
Ast.HistoricType ht2=ht.withSelectors(sels);
return super.liftT(ht2);//this renames the initial path
}
public ExpCore visit(MCall s) {
Program ep=p;for(ClassB cbi:this.getLocator().getCbs()){
if(cbi!=null){ep=ep.evilPush(cbi);}
}
MethodSelector ms=s.getS();
Path guessed=null;
try{
TIn in=TIn.top(Phase.Typed, ep, s.getInner());
in=in.withG(varEnv);
guessed=newTypeSystem.GuessTypeCore.of(in,s.getInner()).getPath();
assert guessed!=null;
}
catch(NormImpossible ignored){return super.visit(s);}
MethodSelector ms2=visitMS(ms,guessed);
if(ms2.equals(ms)){return super.visit(s);}
s=new MCall(s.getInner(),ms2,s.getDoc(),s.getEs(),s.getP());
return super.visit(s);
}
@Override protected MethodSelector liftMsInMetDec(MethodSelector ms){return visitMS(ms,Path.outer(0));}
}