package sugarVisitors; import java.util.ArrayList; import java.util.List; import java.util.Optional; import tools.Map; import ast.Ast.Doc; import ast.Ast.MethodSelector; import ast.Ast.Parameters; import ast.Ast; import ast.Ast.ConcreteHeader; import ast.Ast.FieldDec; import ast.Ast.Header; import ast.Ast.HistoricType; import ast.Ast.MethodType; import ast.Ast.NormType; import ast.Ast.Path; import ast.Ast.Type; import ast.Ast.VarDec; import ast.Expression; import ast.Expression.ClassB.Member; import ast.Expression.*; import ast.Expression.ClassB.*; public class CloneVisitor implements Visitor<Expression>{ protected <T extends Expression>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() //assert L42.checkWellFormedness(e); //assert L42.checkWellFormedness(result); 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()),Map.of(this::liftMsX, ht.getSelectors()),liftDoc(ht.getDoc())) ); } protected Expression.Catch liftK(Expression.Catch k){ if (k instanceof DesugarCatchDefault.CatchToComplete){ k = this.liftK(((DesugarCatchDefault.CatchToComplete) k).catch1); return new DesugarCatchDefault.CatchToComplete((Catch1) k); } return k.match(k1->new Expression.Catch1(k1.getP(), k1.getKind(), liftT(k1.getT()), k1.getX(), lift(k1.getInner()) ), kM->new Expression.CatchMany(kM.getP(),kM.getKind(), Map.of(this::liftT,kM.getTs()) , lift(kM.getInner())), kP->new Expression.CatchProp(kP.getP(),kP.getKind(), Map.of(this::liftT,kP.getTs()) , lift(kP.getInner())) ); } protected Expression.With.On liftO(Expression.With.On on){ return new Expression.With.On(Map.of(this::liftT,on.getTs()),lift(on.getInner())); } protected Header liftH(Header h) { return h.match(ch->new ConcreteHeader( ch.getMdf(),ch.getName(), Map.of(this::liftF,ch.getFs()),ch.getP() ), th->th, ih->ih); } protected FieldDec liftF(FieldDec f) { return new FieldDec(f.isVar(),liftT(f.getT()),f.getName(),liftDoc(f.getDoc())); } protected Doc liftDoc(Doc doc) { return doc.withAnnotations(Map.of(ann->{ if(ann instanceof Path){return this.liftP((Path)ann);} return ann;},doc.getAnnotations())); } protected Expression.BlockContent liftBC(Expression.BlockContent c) { List<VarDec> liftVarDecs = liftVarDecs(c.getDecs()); List<Expression.Catch> liftK = this.liftKs(c.get_catch()); return new Expression.BlockContent(liftVarDecs,liftK); } protected List<Catch> liftKs(List<Catch> ks) { List<Catch> result=new ArrayList<>(); for(Catch k:ks){result.add(liftK(k));} return result; } protected List<ast.Ast.VarDec> liftVarDecs(List<ast.Ast.VarDec> ds) { return Map.of(this::liftVarDec, ds); } protected ast.Ast.VarDec liftVarDec(ast.Ast.VarDec d) { return d.match( this::liftVarDecXE, this::liftVarDecE, this::liftVarDecCE); } protected ast.Ast.VarDecXE liftVarDecXE(ast.Ast.VarDecXE d) { return new ast.Ast.VarDecXE(d.isVar(),Map.of(this::liftT,d.getT()),d.getX(),lift(d.getInner())); } protected ast.Ast.VarDecE liftVarDecE(ast.Ast.VarDecE d) { return new ast.Ast.VarDecE(lift(d.getInner())); } protected ast.Ast.VarDecCE liftVarDecCE(ast.Ast.VarDecCE d) { return new ast.Ast.VarDecCE(this.visit(d.getInner())); } protected Member liftM(Member m) { return m.match( nc->visit(nc), mi->visit(mi), mt->visit(mt) ); } public NestedClass visit(NestedClass nc){return new NestedClass(liftDoc(nc.getDoc()),nc.getName(),lift(nc.getInner()),null);} public MethodImplemented visit(MethodImplemented mi){return new ClassB.MethodImplemented(liftDoc(mi.getDoc()), liftMs(mi.getS()), lift(mi.getInner()),null);} public MethodWithType visit(MethodWithType mt){ return new ClassB.MethodWithType(liftDoc(mt.getDoc()), liftMs(mt.getMs()), liftMT(mt.getMt()), Map.of(this::lift,mt.getInner()),mt.getP());} protected MethodSelector liftMs(MethodSelector ms) { return ms; } protected Ast.MethodSelectorX liftMsX(Ast.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 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())); } public Expression visit(Expression.EPath s) {return s.withInner(liftP(s.getInner()));} public Expression visit(X s) { return s;} public Expression visit(_void s) {return s;} public Expression visit(WalkBy s) {return s;} public Expression visit(Using s) { return new Using(liftP(s.getPath()),s.getName(),liftDoc(s.getDocs()),liftPs(s.getPs()),lift(s.getInner())); } protected Parameters liftPs(Parameters ps) { return new Parameters( Map.of(this::lift, ps.getE()), ps.getXs(), Map.of(this::lift, ps.getEs()) ); } public Expression visit(Signal s) { return new Signal(s.getKind(),lift(s.getInner())); } public Expression visit(Loop s) { return new Loop(lift(s.getInner())); } public Expression visit(MCall s) { return new MCall(lift(s.getReceiver()),s.getName(),liftDoc(s.getDoc()),liftPs(s.getPs()),s.getP()); } public Expression visit(ClassB s) { Header h = liftH(s.getH()); List<FieldDec> fs=Map.of(this::liftF,s.getFields()); List<Type> superT = Map.of(this::liftT,s.getSupertypes()); List<Member> ms = Map.of(this::liftM,s.getMs()); return new ClassB(liftDoc(s.getDoc1()),h,fs,superT,ms,s.getP()); } @Override public Expression visit(If s) { return new If(s.getP(),lift(s.getCond()),lift(s.getThen()),Map.of(this::lift,s.get_else())); } @Override public Expression visit(While s) { return new While(s.getP(),lift(s.getCond()),lift(s.getThen())); } @Override public Expression visit(With s) { return new With(s.getP(),s.getXs(),Map.of(this::liftVarDecXE, s.getIs()),Map.of(this::liftVarDecXE, s.getDecs()),Map.of(this::liftO,s.getOns()),Map.of(this::lift, s.getDefaultE())); } @Override public Expression visit(BinOp s) { return new BinOp(s.getP(),lift(s.getLeft()),s.getOp(),lift(s.getRight())); } @Override public Expression visit(DocE s) { return new DocE(lift(s.getInner()),liftDoc(s.getDoc())); } @Override public Expression visit(UnOp s) { return new UnOp(s.getP(),s.getOp(),lift(s.getInner())); } @Override public Expression visit(FCall s) { return new FCall(s.getP(),lift(s.getReceiver()),liftDoc(s.getDoc()),liftPs(s.getPs())); } @Override public Expression visit(SquareCall s) { return new SquareCall(s.getP(),lift(s.getReceiver()),liftDoc(s.getDoc()),Map.of(this::liftDoc,s.getDocs()),Map.of(this::liftPs,s.getPss())); } @Override public Expression visit(SquareWithCall s) { return new SquareWithCall(s.getP(),lift(s.getReceiver()),lift(s.getWith())); } @Override public Expression visit(UseSquare s) { return new UseSquare(lift(s.getInner())); } @Override public Expression visit(RoundBlock s) { List<BlockContent> content = Map.of(this::liftBC,s.getContents()); Expression inner = lift(s.getInner()); Expression result= new RoundBlock(s.getP(),liftDoc(s.getDoc()), inner,content); //assert L42.checkWellFormedness(s); //assert L42.checkWellFormedness(result); return result; } @Override public Expression visit(CurlyBlock s) { Expression result= new CurlyBlock(s.getP(),liftDoc(s.getDoc()),Map.of(this::liftBC,s.getContents())); //assert L42.checkWellFormedness(s); //assert L42.checkWellFormedness(result); return result; } @Override public Expression visit(DotDotDot s) { return s; } @Override public Expression visit(Literal s) { return new Literal(s.getP(),lift(s.getReceiver()),s.getInner(),s.isNumber()); } @Override public Expression visit(ClassReuse s) { //assert s.getUrlFetched()==null; return new ClassReuse(lift(s.getInner()),s.getUrl(),s.getUrlFetched()); } @Override public Expression visit(ContextId s) { return s; } }