package programReduction; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map.Entry; import java.util.stream.Collectors; import java.util.Set; import ast.Ast; import ast.Ast.MethodSelector; import ast.Ast.Path; import ast.ExpCore.ClassB; import ast.ExpCore.ClassB.Member; import ast.ExpCore.ClassB.MethodWithType; import coreVisitors.From; import tools.Map; public abstract class Methods implements Program{ static private List<Ast.Path> push(List<Ast.Path>ps,Ast.Path newThis){ List<Ast.Path>res=new ArrayList<>(); res.add(Path.outer(0)); for(Ast.Path pi:ps){res.add(From.fromP(pi,newThis));} return res; } static private <T> List<T> mergeUnique(T p,List<T>before, List<T>after){ List<T>res=new ArrayList<T>(); if(!after.contains(p)){res.add(p);} for(T e:before){if(!after.contains(e)){res.add(e);}} res.addAll(after); return res; } public static List<Ast.Path> collect(Program p,List<Ast.Path> p0ps){ List<Path> res = collect(p,p0ps,new ArrayList<>()); return res; //TODO: do we need somehow to remove duplicates? } static List<Ast.Path> collect(Program p,List<Ast.Path> p0ps,List<Ast.Path> visited){ if( p0ps.isEmpty()){return p0ps;} Ast.Path p0=p0ps.get(0); List<Ast.Path> ps=p0ps.subList(1,p0ps.size()); if (visited.contains(p0)){ throw new ast.ErrorMessage.CircularImplements(push(visited,p0)); } if(p0.isPrimitive()){return collect(p,ps,visited);} ClassB l=p.extractClassB(p0); List<Path>superPaths=l.getSuperPaths(); List<Ast.Path> recP0=collect(p.navigate(p0),superPaths,push(visited,p0)); recP0=Map.of(pi->From.fromP(pi,p0),recP0); List<Ast.Path> recPs=collect(p,ps,visited); return mergeUnique(p0, recP0, recPs); } static MethodWithType addRefine(MethodWithType mwt){ return mwt.withMt(mwt.getMt().withRefine(true)); } // -methods(p,P0)=M1'..Mk' // p(P0)={interface? implements Ps Ms} public List<MethodWithType> methods(Ast.Path p0){ if (p0.isPrimitive()){return Collections.emptyList();} Program p=this; ClassB cb0=p.extractClassB(p0); List<Ast.Path> ps=cb0.getSuperPaths(); // P1..Pn=collect(p,Ps[from P0]), error unless forall i, p(Pi) is an interface List<Ast.Path> p1n=collect(p,Map.of(pi->From.fromP(pi,p0), ps)); List<ClassB> cb1n=Map.of(pi->p.extractClassB(pi), p1n); {int i=-1;for(ClassB cbi:cb1n){i++;if (!cbi.isInterface()){ throw new ast.ErrorMessage.NonInterfaceImplements(p0,p1n.get(i));} }} // ms1..msk={ms|p(Pi)(ms) is defined} HashMap<Ast.MethodSelector,List<ClassB.Member>> ms1k=new LinkedHashMap<>(); for(ClassB.Member mij:cb0.getMs()){mij.match( nc->null, mi->add(true,ms1k,mi.getS(),From.from(mij,p0)), mt->add(true,ms1k,mt.getMs(),From.from(mij,p0)) );} for(Ast.Path pi:p1n){//call the memoized methods for(ClassB.Member mij:p.methods(pi)){mij.match( nc->null, mi->add(false,ms1k,mi.getS(),mij), mt->add(false,ms1k,mt.getMs(),mij) );} } //members in cb0 are now first (may be null), thanks to the add function // forall ms in ms1..msk, there is exactly 1 j in 0..n // such that p(Pj)(ms)=mh e? //no refine for(Entry<MethodSelector, List<Member>> ei: ms1k.entrySet()){ if(!exactly1NoRefine(ei.getValue())){ throw new ast.ErrorMessage.NotExaclyOneMethodOrigin(p0,ei.getKey(),ei.getValue()); } } List<ClassB.MethodWithType> ms=new ArrayList<>(); // //i comes from k in ms1..msk // Mi= p(P0)(msi)[from P0] if it is of form refine? mh e?, // otherwise // Mi=addRefine(methods(p,Pj)(msi)) // for the smallest j in 1..k such that methods(p,Pj)(msi) of form refine? mh for(Entry<MethodSelector, List<Member>> ei : ms1k.entrySet()){ List<Member> memsi=ei.getValue(); if(memsi.get(0)!=null && memsi.get(0) instanceof MethodWithType){ ms.add((MethodWithType)memsi.get(0));continue; } ClassB.MethodImplemented mem0=(ClassB.MethodImplemented)memsi.get(0); for(Member mj:memsi){// 0 will fail instanceof if (mj==null || !(mj instanceof MethodWithType)){continue;} // Mi'=Mi[with e=p(P0)(msi).e[from P0]] if defined, // otherwise // Mi'=Mi if(mem0!=null){mj=mj.withInner(mem0.getE());} ms.add(addRefine((MethodWithType) mj)); break; } } return ms; } static private Void add(boolean isFirst,HashMap<Ast.MethodSelector,List<ClassB.Member>> ms1k,Ast.MethodSelector ms,ClassB.Member m){ List<Member> list = ms1k.get(ms); if(list==null){ ms1k.put(ms,list=new ArrayList<>()); if(!isFirst){list.add(null);} } list.add(m); return null; } static private boolean exactly1NoRefine(List<Member> memsAll) { int count=0; for(Member m:memsAll){ if(m==null){continue;} if(!(m instanceof ClassB.MethodWithType)){continue;} ClassB.MethodWithType mwt=(ClassB.MethodWithType)m; if(!mwt.getMt().isRefine()){count++;} } return count==1; } }