package coreVisitors;
import java.util.ArrayList;
import java.util.List;
import tools.Map;
import ast.ExpCore;
import ast.ExpCore.Block.Dec;
import ast.ExpCore.ClassB.Member;
import ast.ExpCore.Loop;
import ast.ExpCore.*;
import ast.Ast.*;
import ast.Ast.Type.*;
public class CloneVisitor implements Visitor<ExpCore>{
protected <T extends ExpCore>T lift(T e){
@SuppressWarnings("unchecked")
T result= (T)e.accept(this);
//assert result.getClass().equals(e.getClass());
//no, I would like to assert on T, that is a supertype of getClass()
return result;
}
protected Path liftP(Path p){return p;}
protected Type liftT(Type t){
return t.match(
nt->(Type)new NormType(nt.getMdf(),liftP(nt.getPath()),liftDoc(nt.getDoc())),
ht->(Type)new HistoricType(
liftP(ht.getPath()),
liftSXs(ht.getSelectors()),liftDoc(ht.getDoc()))
);
}
protected List<MethodSelectorX> liftSXs(List<MethodSelectorX> selectors) {
return Map.of(this::liftSX,selectors);
}
protected MethodSelectorX liftSX(MethodSelectorX selector) {
MethodSelector ms1=selector.getMs();
MethodSelector ms2=liftMs(ms1);
if(selector.getX().isEmpty() || selector.getX().equals("this")){return selector.withMs(ms2);}
int pos=ms1.getNames().indexOf(selector.getX());
assert pos!=-1:selector;
return selector.withMs(ms2).withX(ms2.getNames().get(pos));
}
protected MethodSelector liftMs(MethodSelector ms){return ms;}
protected ExpCore.Block.On liftO(ExpCore.Block.On on){
return new ExpCore.Block.On(on.getKind(),on.getX(),liftT(on.getT()),lift(on.getInner()),on.getP());
}
/*protected Header liftH(Header h) {
return h.match(ch->new ConcreteHeader(
ch.getMdf(),ch.getName(), Map.of(this::liftF,ch.getFs())
), th->th, ih->ih);
}*/
/*protected FieldDec liftF(FieldDec f) {
return new FieldDec(f.isVar(),liftT(f.getT()),f.getName(),f.getDocs());
}*/
protected Block.Dec liftDec(Block.Dec f) {
return new Block.Dec(liftT(f.getT()),f.getX(),lift(f.getInner()));
}
protected Doc liftDoc(Doc doc) {
return doc.withAnnotations(Map.of(ann->{
if(ann instanceof Path){return liftP((Path)ann);}
return ann;},doc.getAnnotations()));
}
protected Member liftM(Member m) {
return m.match(
nc->visit(nc),
mi->visit(mi),
mt->visit(mt)
);
}
public ClassB.NestedClass visit(ClassB.NestedClass nc){return new ClassB.NestedClass(liftDoc(nc.getDoc()),nc.getName(),lift(nc.getInner()),nc.getP());}
public ClassB.MethodImplemented visit(ClassB.MethodImplemented mi){
return new ClassB.MethodImplemented(liftDoc(mi.getDoc()), liftMsInMetDec(mi.getS()), lift(mi.getInner()),mi.getP());
}
public ClassB.MethodWithType visit(ClassB.MethodWithType mt){
return new ClassB.MethodWithType(liftDoc(mt.getDoc()),liftMsInMetDec(this.liftMs(mt.getMs())),liftMT(mt.getMt()), Map.of(this::lift,mt.get_inner()),mt.getP());
}
protected MethodType liftMT(MethodType mt) {
return new MethodType(mt.isRefine(),mt.getMdf(),Map.of(this::liftT,mt.getTs()),liftT(mt.getReturnType()),Map.of(this::liftT,mt.getExceptions()));
}
@Override public ExpCore visit(EPath s) {return s.withInner(liftP(s.getInner()));}
public ExpCore visit(X s) { return s;}
public ExpCore visit(_void s) {return s;}
public ExpCore visit(WalkBy s) {return s;}
public ExpCore visit(Using s) {
return new Using(liftP(s.getPath()),liftMs(s.getS()),liftDoc(s.getDoc()),Map.of(this::lift,s.getEs()),lift(s.getInner()));
}
public ExpCore visit(Signal s) {
return new Signal(s.getKind(),lift(s.getInner()),
s.getTypeOut()==null?null:liftT(s.getTypeOut()).getNT(),
s.getTypeIn()==null?null:liftT(s.getTypeIn()).getNT()
);
}
public ExpCore visit(MCall s) {
return new MCall(lift(s.getInner()),liftMs(s.getS()),liftDoc(s.getDoc()),Map.of(this::lift,s.getEs()),s.getP());
}
public ExpCore visit(Block s) {
return new Block(liftDoc(s.getDoc()),liftDecs(s.getDecs()),lift(s.getInner()),Map.of(this::liftO,s.getOns()),s.getP());
}
protected List<Dec> liftDecs(List<Dec> s) {
return Map.of(this::liftDec,s);
}
public ExpCore visit(ClassB s) {
List<Type> sup = liftSup(s.getSupertypes());
List<Member> ms = liftMembers(s.getMs());
return new ClassB(
liftDoc(s.getDoc1()),
s.isInterface(),
sup,
ms,
s.getP(),
s.getPhase(),
s.getUniqueId());
}
public List<Member> liftMembers(List<Member> s) {
return Map.of(this::liftM,s);
}
protected List<Type> liftSup(List<Type> supertypes) {
return Map.of(this::liftT,supertypes);
}
@Override
public ExpCore visit(Loop s) {
return new Loop(lift(s.getInner()));
}
protected MethodSelector liftMsInMetDec(MethodSelector ms) {
return ms;
}
}