package programReduction; import java.util.ArrayList; import java.util.List; import ast.Ast.Path; import ast.Ast.Position; import ast.ExpCore; import ast.ExpCore.Block; import ast.ExpCore.Block.Dec; import ast.ExpCore.Block.On; import ast.ExpCore.ClassB; 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 coreVisitors.IsCompiled; import tools.Assertions; import tools.Map; public interface CtxC { ExpCore fillHole(ExpCore hole); ExpCore originalHole(); CtxC divide(ExpCore all); static CtxC split (ExpCore e){return e.accept(new CtxSplitter());} static CtxC hole(ExpCore original){return new CtxSplitter.Hole(original);} default String _toString() {return "CtxC["+sugarVisitors.ToFormattedText.of(this.fillHole(new ExpCore.X(Position.noInfo,"_HOLE_")))+",originalHole:"+sugarVisitors.ToFormattedText.of(this.originalHole())+"]";} default int _hashCode() {return this.fillHole(new ExpCore.WalkBy()).hashCode();} default boolean _equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; CtxC other = (CtxC) obj; ExpCore oE=other.fillHole(new ExpCore.WalkBy()); ExpCore thisE=this.fillHole(new ExpCore.WalkBy()); return thisE.equals(oE); } } //utility class to create CtxCs that point somewhere in a list abstract class CtxCAbsPos<T> implements CtxC{ @Override public String toString() {return _toString();}//limitation of Java8 requires methods of object @Override public int hashCode() {return this._hashCode();} //to be reimplemented :( @Override public boolean equals(Object obj) {return this._equals(obj);} T origin;int pos;CtxC ctx; CtxCAbsPos(T origin,int pos, CtxC ctx){ this.origin=origin;this.pos=pos;this.ctx=ctx; } public ExpCore originalHole() {return ctx.originalHole();} } //generic class allowing to contexts in a subexpression "main expression" (like the method receiver) class CtxCInner<T extends ExpCore.WithInner<T> & ExpCore> implements CtxC{ @Override public String toString() {return _toString();}//limitation of Java8 requires methods of object @Override public int hashCode() {return this._hashCode();} //to be reimplemented :( @Override public boolean equals(Object obj) {return this._equals(obj);} T origin;CtxC ctx; CtxCInner(T origin,CtxC ctx) {this.origin=origin;this.ctx=ctx;} public ExpCore originalHole() {return ctx.originalHole();} public T fillHole(ExpCore hole) {return origin.withInner(ctx.fillHole(hole));} public CtxC divide(ExpCore all) { assert origin.getClass().equals(all.getClass()); @SuppressWarnings("unchecked") //safe here T _all=(T)all; CtxC ctxInner=ctx.divide(_all.getInner()); return new CtxCInner<T>(_all,ctxInner); } } class CtxSplitter implements coreVisitors.Visitor<CtxC>{ //those are never reached by the visit public CtxC visit(ExpCore.EPath s) {throw Assertions.codeNotReachable();} public CtxC visit(X s) {throw Assertions.codeNotReachable();} public CtxC visit(_void s) {throw Assertions.codeNotReachable();} //this case should eventually disappear public CtxC visit(WalkBy s) {throw new AssertionError();} //expressions that just wrap another public CtxC visit(Signal s) {return new CtxCInner<Signal>(s, s.getInner().accept(this));} public CtxC visit(Loop s) { return new CtxCInner<Loop>(s, s.getInner().accept(this));} //method call: define class for pointing in parameters private static class CtxCMCallPos extends CtxCAbsPos<MCall>{ CtxCMCallPos(MCall origin,int pos,CtxC ctx) {super(origin,pos,ctx);} public ExpCore fillHole(ExpCore hole) {return origin.withEsi(pos,ctx.fillHole(hole));} public CtxC divide(ExpCore all) { MCall _all=(MCall)all; CtxC ctxInner=ctx.divide(_all.getEs().get(pos)); return new CtxCMCallPos(_all,pos,ctxInner); } } //method call: if receiver, otherwise a point in parameters public CtxC visit(MCall s) { ExpCore r=s.getInner(); if (!IsCompiled.of(r)){return new CtxCInner<MCall>(s,r.accept(this));} int pos=firstNotCompiled(s.getEs()); return new CtxCMCallPos(s,pos,s.getEs().get(pos).accept(this)); } //from now on we just repeat this pattern //using: define class for pointing in parameters private static class CtxCUsingPos extends CtxCAbsPos<Using>{ CtxCUsingPos(Using origin,int pos,CtxC ctx) {super(origin,pos,ctx);} public ExpCore fillHole(ExpCore hole) {return origin.withEsi(pos,ctx.fillHole(hole));} public CtxC divide(ExpCore all) { Using _all=(Using)all; CtxC ctxInner=ctx.divide(_all.getEs().get(pos)); return new CtxCUsingPos(_all,pos,ctxInner); } } //using: if parameters, otherwise the main expression public CtxC visit(Using s) { int pos=firstNotCompiled(s.getEs()); if (pos<s.getEs().size()){ return new CtxCUsingPos(s,pos,s.getEs().get(pos).accept(this)); } assert !IsCompiled.of(s.getInner()); return new CtxCInner<Using>(s,s.getInner().accept(this)); } //block is more complex since it has two sets of es: //one nested in the decs, and one nested in the ons; so we define two classes private static class CtxCBlock1Pos extends CtxCAbsPos<Block>{ CtxCBlock1Pos(Block origin,int pos,CtxC ctx) {super(origin,pos,ctx);} public ExpCore fillHole(ExpCore hole) { List<Dec> ds=new ArrayList<>(origin.getDecs()); ds.set(pos, ds.get(pos).withInner(ctx.fillHole(hole))); return origin.withDecs(ds); } public CtxC divide(ExpCore all) { Block _all=(Block)all; CtxC ctxInner=ctx.divide(_all.getDecs().get(pos).getInner()); return new CtxCBlock1Pos(_all,pos,ctxInner); } } private static class CtxCBlock2Pos extends CtxCAbsPos<Block>{ CtxCBlock2Pos(Block origin,int pos,CtxC ctx) {super(origin,pos,ctx);} public ExpCore fillHole(ExpCore hole) { List<On> os=new ArrayList<>(origin.getOns()); os.set(pos, os.get(pos).withInner(ctx.fillHole(hole))); return origin.withOns(os); } public CtxC divide(ExpCore all) { Block _all=(Block)all; CtxC ctxInner=ctx.divide(_all.getDecs().get(pos).getInner()); return new CtxCBlock1Pos(_all,pos,ctxInner); } } //block: first in the decs, then in the ons, than in the main public CtxC visit(Block s) {{//to scope variables List<ExpCore> es=Map.of(d->d.getInner(),s.getDecs()); int pos=firstNotCompiled(es); if (pos<es.size()){ return new CtxCBlock1Pos(s,pos,es.get(pos).accept(this)); } }{ List<ExpCore> es=Map.of(o->o.getInner(),s.getOns()); int pos=firstNotCompiled(es); if (pos<es.size()){ return new CtxCBlock2Pos(s,pos,es.get(pos).accept(this)); } }{ return new CtxCInner<Block>(s,s.getInner().accept(this)); }} //finally: case for L, where the hole will be static class Hole implements CtxC{ @Override public String toString() {return _toString();} @Override public int hashCode() {return 0;} @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; return true;//all holes are equals, and ignore the original content } ExpCore original; Hole(ExpCore original){this.original=original;} public ExpCore fillHole(ExpCore hole) {return hole;} public ExpCore originalHole() {return original;} public CtxC divide(ExpCore all) {return new Hole(all);} } public CtxC visit(ClassB s) { assert !IsCompiled.of(s); return new Hole(s); } //utility method static int firstNotCompiled(List<ExpCore> es) { for(int i=0;i<es.size();i++){ if(!IsCompiled.of(es.get(i))){return i;} } return es.size(); } }