package auxiliaryGrammar; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import sugarVisitors.CloneVisitor; import sugarVisitors.ToFormattedText; import tools.Assertions; import tools.Map; import tools.Match; import ast.Ast; import ast.Ast.C; import ast.Ast.Doc; import ast.Ast.HistoricType; import ast.Ast.Mdf; import ast.Ast.MethodSelector; import ast.Ast.NormType; import ast.Ast.Path; import ast.Ast.Position; import ast.Ast.Stage; import ast.Ast.Type; import ast.ErrorMessage; import ast.ExpCore; import ast.ExpCore.*; import ast.ExpCore.ClassB.*; import ast.Expression.ClassReuse; import ast.Expression; import ast.Util.InvalidMwtAsState; import ast.Util.PathMwt; import coreVisitors.Dec; import coreVisitors.FreeVariables; import coreVisitors.From; import coreVisitors.IsCompiled; import coreVisitors.IsValue; import coreVisitors.ReplaceCtx; import facade.Configuration; import facade.L42; import programReduction.Program; public class Functions { public static Optional<Member> getIfInDom(List<ExpCore.ClassB.Member> map, Ast.C elem){ for(ExpCore.ClassB.Member m: map){ if(m.match(nc->nc.getName().equals(elem), mi->false, mt->false)){return Optional.of(m);} } return Optional.empty(); } public static Optional<Member> getIfInDom(List<ExpCore.ClassB.Member> map, ast.Ast.MethodSelector elem){ //remember: the are no docs to make method selectors different. for(ExpCore.ClassB.Member m: map){ if(m.match(nc->false,mi->mi.getS().equals(elem) ,mt->mt.getMs().equals(elem))){return Optional.of(m);} } return Optional.empty(); } public static Optional<Member> getIfInDom(List<ExpCore.ClassB.Member> map, ExpCore.ClassB.Member elem){ return elem.match(nc->getIfInDom(map,nc.getName()), mi->getIfInDom(map,mi.getS()),mt->getIfInDom(map,mt.getMs())); } public static void removeIfInDom(List<Member> ms,MethodSelector sel){ for(Member memi:ms){ boolean res=memi.match( nc->false, mi->{if(mi.getS().equals(sel)){ms.remove(mi);return true;}return false;}, mt->{if(mt.getMs().equals(sel)){ms.remove(mt);return true;}return false;}); if(res){break;} } } public static void removeIfInDom(List<Member> ms,String sel){ for(Member memi:ms){ boolean res=memi.match( nc->{if(nc.getName().equals(sel)){ms.remove(nc);return true;}return false;}, mi->false, mt->false); if(res){break;} } } public static void replaceIfInDom(List<Member> ms,Member m){ Object matchRes=m.match( nc->{for(Member mi:ms){if (!(mi instanceof NestedClass)){continue;} if (!nc.getName().equals(((NestedClass)mi).getName())){continue;} return ms.set(ms.indexOf(mi), m);//swap to keep order }return null;}, mImpl->{for(Member mi:ms){if (!(mi instanceof MethodImplemented)){continue;} if (!mImpl.getS().equals(((MethodImplemented)mi).getS())){continue;} return ms.set(ms.indexOf(mi), m);//swap to keep order }return null;}, mt->{for(Member mi:ms){if (!(mi instanceof MethodWithType)){continue;} if (!mt.getMs().equals(((MethodWithType)mi).getMs())){continue;} return ms.set(ms.indexOf(mi), m);//swap to keep order }return null;}); if(matchRes==null){ms.add(m);} } public static ClassB.NestedClass encapsulateIn(List<Ast.C> cBar,ClassB elem,Doc doc) { //Notice: encapsulation do not do the from. It must be done //on the call side as in "redirectDefinition" assert !cBar.isEmpty(); List<Ast.C> cBar2 = cBar.subList(1,cBar.size()); if(cBar2.isEmpty()){return new ClassB.NestedClass(doc,cBar.get(0),elem,null);} List<Member> ms=new ArrayList<>(); ms.add(encapsulateIn(cBar2,elem,doc)); ClassB cb= ClassB.membersClass(ms,Position.noInfo,elem.getPhase()); return new ClassB.NestedClass(Doc.empty(),cBar.get(0),cb,null); } public static Path originDecOf(Program p,MethodSelector ms,ClassB cb/*normalized*/){ assert cb.getPhase().subtypeEq(Phase.Norm); for(Path pi:cb.getSuperPaths()){ ClassB cbi=p.extractClassB(pi); MethodWithType m = (MethodWithType) cbi._getMember(ms); if(m!=null && !m.getMt().isRefine()){return pi;} } throw Assertions.codeNotReachable(); } public static Path add1Outer(Path p) { if( p.isPrimitive()){return p;} return p.setNewOuter(p.outerNumber()+1); } public static boolean isSubtype(Mdf mdf1, Mdf m) { if(mdf1==m){return true;} switch(mdf1){ case Class: return false; case Capsule: return m!=Mdf.Class; case Immutable: return m==Mdf.Readable || m==Mdf.ImmutablePFwd || m==Mdf.ImmutableFwd;//imm<=read,fwd%Imm //,fwdImm case Mutable: return m==Mdf.Lent || m==Mdf.MutablePFwd ||m==Mdf.Readable|| m==Mdf.MutableFwd;//mut<=lent,fwd%Mut //,read,fwdMut case Lent: return m==Mdf.Readable;//lent<=read case MutablePFwd: return m==Mdf.MutableFwd;//fwd%Mut<=fwdMut case ImmutablePFwd:return m==Mdf.ImmutableFwd;//fwd%Imm<=fwdImm default: return false; } } public static NormType sharedAndLentToReadable(NormType that){ Mdf mdf=that.getMdf(); if(mdf==Mdf.Mutable){mdf=Mdf.Readable;} if(mdf==Mdf.Lent){mdf=Mdf.Readable;} return that.withMdf(mdf); } public static Block garbage(Block e, int n) { //try to see witch of the dvs in 0..i can be trashed HashSet<String> needX=neededX(e,n); HashSet<Integer> needKeep=new HashSet<Integer>(); while(iterateAddNeeded(e, n, needX, needKeep)); List<ast.ExpCore.Block.Dec> decs1 = e.getDecs(); List<ast.ExpCore.Block.Dec> decs2 = new ArrayList<>(); for(int i=0;i<e.getDecs().size();i++){ if(i<n&&!needKeep.contains(i)){continue;} decs2.add(decs1.get(i)); } return new Block(e.getDoc(),decs2,e.getInner(),e.getOns(),e.getP()); } private static boolean iterateAddNeeded(Block e, int n, HashSet<String> needX, HashSet<Integer> needKeep) { int size=needKeep.size(); for(int i: needKeep){ ExpCore ei=e.getDecs().get(i).getInner(); needX.addAll(FreeVariables.of(ei)); } for(int i=0;i<n;i++){ if(!needX.contains(e.getDecs().get(i).getX())){continue;} needKeep.add(i); } assert size<=needKeep.size(); return size!=needKeep.size(); } private static HashSet<String> neededX(Block e,int n){ HashSet<String> neededX=new HashSet<String>(); for(int i=n;i<e.getDecs().size();i++){ ExpCore ei=e.getDecs().get(i).getInner(); neededX.addAll(FreeVariables.of(ei)); } for(int i=n;i<e.getDecs().size();i++){ neededX.remove(e.getDecs().get(i).getX()); } neededX.addAll(FreeVariables.of(e.getInner())); return neededX; } public static String freshName(String pathR, Set<String> usedNames) { while(Character.isDigit(pathR.charAt(pathR.length()-1))){ pathR=pathR.substring(0,pathR.length()-1); } if(!usedNames.contains(pathR) && !keywords.contains(pathR)){ usedNames.add(pathR); return pathR; } int i=0; while(true){ String res=pathR+i; if(usedNames.contains(res)){i++;continue;} usedNames.add(res); return res; } } public static Path freshPathName(Path pathR, Set<String> usedNames) { String p=null; if(pathR.isPrimitive()){p=freshName(pathR.toString(),usedNames);} else if(pathR.getCBar().isEmpty()){p=freshName("This",usedNames);} else{ Ast.C last=pathR.getCBar().get(pathR.getCBar().size()-1); if (last.isUnique()){return pathR.popC().pushC(last.withUniqueNum(L42.freshPrivate()));} p=last.toString(); p=freshName(p,usedNames); } return pathR.popC().pushC(C.of(p)); } public static String freshName(Path pathR, Set<String> usedNames) { String p=null; if(pathR.isPrimitive()){p=freshName(pathR.toString(),usedNames);} else if(pathR.getCBar().isEmpty()){p=freshName("This",usedNames);} else{ p=pathR.getCBar().get(pathR.getCBar().size()-1).toString(); p=freshName(p,usedNames); } p=p.substring(0,1).toLowerCase() +p.substring(1); return freshName(p,usedNames); } public static final HashSet<String>keywords=new HashSet<String>(); static{ //keywords.add("Void"); //keywords.add("Any"); //keywords.add("Library"); keywords.add("void"); keywords.add("case"); keywords.add("class"); keywords.add("mut"); keywords.add("read"); keywords.add("lent"); keywords.add("capsule"); keywords.add("if"); keywords.add("else"); keywords.add("while"); keywords.add("loop"); keywords.add("with"); keywords.add("on"); keywords.add("in"); keywords.add("catch"); keywords.add("var"); keywords.add("default"); keywords.add("interface"); keywords.add("method"); keywords.add("use"); keywords.add("check"); } public static List<Block.Dec> replace(List<Block.Dec> dvs,MCall mc){ String x=((ExpCore.X)mc.getInner()).getInner(); List<Block.Dec> result=new ArrayList<>(); for(Block.Dec dv: dvs){ if(!dv.getX().equals(x)){result.add(dv);continue;} MCall inner=(MCall)dv.getInner(); String fieldName=mc.getS().nameToS(); int mIndex=inner.getS().getNames().indexOf(fieldName); assert mIndex!=-1 :fieldName+" / "+ToFormattedText.of(inner); List<ExpCore> es2 = new ArrayList<>(inner.getEs()); ExpCore parameterAtom = mc.getEs().get(0); es2.set(mIndex,parameterAtom); result.add(dv.withInner(inner.withEs(es2))); } return result; } public static Member firstIncomplete(ClassB cb){ for(Member m: cb.getMs()){ if(IsCompiled.of(m)){continue;} return m; } throw Assertions.codeNotReachable(); } public static List<Path> remove1OuterAndPrimitives(Collection<Path> paths){ List<Path> result=new ArrayList<>(); for(Path p:paths){ if(p.isPrimitive()){continue;} int n=p.outerNumber(); if(n>0){result.add(p.setNewOuter(n-1));} } return result; } /* public static Path classOf(Program p, ExpCore ctxVal,List<ast.ExpCore.Block.Dec> decs, ExpCore inner) { Position pos=null;if(inner instanceof Ast.HasPos){pos=((Ast.HasPos)inner).getP();} Block b=new Block(Doc.empty(),decs,new WalkBy(),Collections.emptyList(),pos); ctxVal=ReplaceCtx.of(ctxVal, b); return classOf(p,ctxVal,inner); } */ public static NormType toPartial(NormType that) { switch (that.getMdf()){ case Capsule: return that; case Class: return that; case Immutable: return that.withMdf(Mdf.ImmutablePFwd); case ImmutableFwd: return that; case ImmutablePFwd: return that; case Lent: return that; case Mutable: return that.withMdf(Mdf.MutablePFwd); case MutableFwd: return that; case MutablePFwd: return that; case Readable: return that; } throw Assertions.codeNotReachable(); } public static boolean isComplete(NormType that){ switch (that.getMdf()){ case Capsule: return true; case Class: return true; case Immutable: return true; case ImmutableFwd: return false; case ImmutablePFwd: return false; case Lent: return true; case Mutable: return true; case MutableFwd: return false; case MutablePFwd: return false; case Readable: return true; } throw Assertions.codeNotReachable(); } public static NormType toPh(NormType that){ switch (that.getMdf()){ case Capsule: return that; case Class: return that; case Immutable: return that.withMdf(Mdf.ImmutableFwd); case ImmutableFwd: return that; case ImmutablePFwd: return that.withMdf(Mdf.ImmutableFwd); case Lent: return that; case Mutable: return that.withMdf(Mdf.MutableFwd); case MutableFwd: return that; case MutablePFwd: return that.withMdf(Mdf.MutableFwd); case Readable: return that; } throw Assertions.codeNotReachable(); } public static NormType toComplete(NormType that){ switch (that.getMdf()){ case Capsule: return that; case Class: return that; case Immutable: return that; case ImmutableFwd: return that.withMdf(Mdf.Immutable); case ImmutablePFwd: return that.withMdf(Mdf.Immutable); case Lent: return that; case Mutable: return that; case MutableFwd: return that.withMdf(Mdf.Mutable); case MutablePFwd: return that.withMdf(Mdf.Mutable); case Readable: return that; } throw Assertions.codeNotReachable(); } public static HashMap<String, NormType> complete(HashMap<String, NormType> varEnv) { HashMap<String, NormType> result= new HashMap<String, NormType>(); for(String s: varEnv.keySet()){ if(isComplete(varEnv.get(s))){result.put(s,varEnv.get(s));} } return result; } public static HashMap<String, NormType> nonComplete(HashMap<String, NormType> varEnv) { HashMap<String, NormType> result= new HashMap<String, NormType>(); for(String s: varEnv.keySet()){ if(!isComplete(varEnv.get(s))){result.put(s,varEnv.get(s));} } return result; } public static HashMap<String, NormType> toPh(HashMap<String, NormType> varEnv) { HashMap<String, NormType> result= new HashMap<String, NormType>(); for(String s: varEnv.keySet()){result.put(s,toPh(varEnv.get(s)));} return result; } public static HashMap<String, NormType> toPartial(HashMap<String, NormType> varEnv) { HashMap<String, NormType> result= new HashMap<String, NormType>(); for(String s: varEnv.keySet()){result.put(s,toPartial(varEnv.get(s)));} return result; } public static NormType sharedToLent(NormType nt) { if(nt.getMdf()!=Mdf.Mutable){return nt;} return nt.withMdf(Mdf.Lent); } public static boolean isSuperTypeOfMut(Mdf mdf){ return mdf==Mdf.Mutable ||mdf==Mdf.Lent ||mdf==Mdf.Readable; } public static boolean isInterface(Program p, Path path) { if (path.equals(Path.Any())){return true;} if(path.isPrimitive()){return false;} return p.extractClassB(path).isInterface();//in typing, this is guaranteed to be there } public static boolean checkCore(Expression result) { result.accept(new CloneVisitor(){ @Override protected Path liftP(Path p){assert p.isCore() || p.isPrimitive():p;return p;} protected <T extends Expression>T lift(T e){//exists just to breakpoint try{return super.lift(e);} catch(AssertionError err){ throw err; //throw new AssertionError(ToFormattedText.of(e),err); } }}); return true; } }