package is.L42.connected.withSafeOperators; import ast.Ast; import ast.Ast.Doc; import ast.Ast.Mdf; import ast.Ast.MethodSelector; import ast.Ast.MethodType; import ast.ExpCore; import ast.ExpCore.ClassB; import ast.ExpCore.ClassB.Member; import ast.ExpCore.ClassB.MethodWithType; import ast.Util.PathMx; import auxiliaryGrammar.Functions; import programReduction.Program; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import ast.Ast.Path; import ast.Ast.Type; import ast.Ast.NormType; import ast.ErrorMessage.TwoDifferentImplementedInterfacesDeclareMethod; import ast.ExpCore.*; import coreVisitors.CloneWithPath; import coreVisitors.From; import platformSpecific.javaTranslation.Resources; import tools.Map; public class ExtractInfo { static class IsUsed extends CloneWithPath{ Path target;IsUsed(Path target){ assert target.outerNumber()==0:"only for used internal paths"; this.target=target; } Set<Path> whereUsed=new HashSet<>(); @Override protected Path liftP(Path s) { List<Ast.C> path = this.getLocator().getClassNamesPath(); if(s.isPrimitive()){return s;} if(path.size()<s.outerNumber()){return s;} //List<String> unexploredPath=path.subList(0,path.size()-s.outerNumber()); //if(unexploredPath.contains(null)){return super.visit(s);} if(path.contains(null)){return super.liftP(s);} Path localP=Path.outer(0,path); boolean isSame=From.fromP(s, localP).equals(target); if(isSame){ whereUsed.add(localP); } return super.liftP(s); } public static Set<Path> of(ClassB cb,Path path){ IsUsed iu=new IsUsed(path); cb.accept(iu); return iu.whereUsed; } } static class IsUsedAsPath extends IsUsed{ IsUsedAsPath(Path target){super(target);} protected List<Type> liftSup(List<Type> supertypes) {return supertypes;} protected Type liftT(Type t){return t;} public static Set<Path> of(ClassB cb,Path path){ IsUsedAsPath iu=new IsUsedAsPath(path); cb.accept(iu); return iu.whereUsed; } } static class IsImplemented extends CloneWithPath{ Path target;IsImplemented(Path target){this.target=target;} Set<Path> whereUsed=new HashSet<>(); public ExpCore visit(ClassB s) { Path localP=Path.outer(0,this.getLocator().getClassNamesPath()); for(Path ip:s.getSuperPaths()){ if(From.fromP(ip, localP).equals(target)){ whereUsed.add(localP); } } return super.visit(s); } public static Set<Path> of(ClassB cb,Path path){ IsImplemented iu=new IsImplemented(path); cb.accept(iu); return iu.whereUsed; } } //path member is not a nestedclass //path is used public static boolean checkBox(ClassB top,ClassB cb,List<Ast.C> path,boolean justFalse) throws Resources.Error/*NotBox*/{ List<MethodSelector> meth = collectDeclaredMethods(cb); Set<Path> used = ExtractInfo.IsUsed.of(top,Path.outer(0,path)); if(meth.isEmpty()&& used.isEmpty() && !cb.isInterface() && cb.getSupertypes().isEmpty()){return true;} if(justFalse){return false;} throw Errors42.errorNotBox(cb, meth, used,classKind(cb,Collections.emptyList(),cb,false,null,null)); } private static List<MethodSelector> collectDeclaredMethods(ClassB cb) { List<MethodSelector> meth=new ArrayList<>(); for(ClassB.Member m:cb.getMs()){ m.match(nc->false, mi->meth.add(mi.getS()), mt->meth.add(mt.getMs())); } return meth; } public static void checkBox(ClassB top,ClassB cb,List<Ast.C> path) throws Resources.Error/*NotBox*/{ checkBox(top,cb, path,false);} public static boolean isBox(ClassB top,ClassB cb,List<Ast.C> path){return checkBox(top, cb,path,true);} public static boolean isNeverImplemented(ClassB top,List<Ast.C> path){ Set<Path> used = ExtractInfo.IsImplemented.of(top,Path.outer(0,path)); if(used.isEmpty()){ return true;} return false; } public static String memberKind(Member m){ return m.match( nc->"NestedClass", mi->"InterfaceImplementedMethod", mt->(mt.get_inner().isPresent())?"ImplementedMethod":"AbstractMethod"); } public static enum ClassKind{ //Box, Interface("interface"), //FreeInterface, ClosedClass("closedClass"), OpenClass("openClass"), Template("template")/*,PureRecord*/, FreeTemplate("freeTemplate"); //Module, //TemplateModule, //Interface_FreeInterface, //Box_TemplateModule public final String name42; ClassKind(String name42){this.name42=name42;} } //top can be null, in this case we can return the mixed kinds public static ClassKind classKind(ClassB top, List<Ast.C> current,ClassB cb,Boolean isFree,Boolean isPrivateState,Boolean isNoImplementation){//9 options assert (top==null)==(current==null); if(cb.isInterface()){ return ClassKind.Interface; } if(isPrivateState==null){isPrivateState=hasPrivateState(cb);} if(isPrivateState){return ClassKind.ClosedClass;} if(isNoImplementation==null){isNoImplementation=isNoImplementation(cb);} if(!isNoImplementation){return ClassKind.OpenClass;} if(isFree==null && current!=null ){isFree=ExtractInfo.isFree(top,current);} if(isFree!=null &&isFree){return ClassKind.FreeTemplate;} return ClassKind.Template; } public static boolean isFree(ClassB top, List<Ast.C> current) { assert current!=null; Set<Path> used = ExtractInfo.IsUsedAsPath.of(top,Path.outer(0,current)); if(used.isEmpty()){ return true;} return false; } static List<String> showMembers(List<Member> ms){ List<String>result=new ArrayList<>(); for(Member m:ms){ result.add(""+m.match(nc->nc.getName(), mi->mi.getS(), mt->mt.getMs())); } return result; } static Ast.Doc showPaths(List<Path> ps){ Ast.Doc result=Doc.empty(); for(Path pi:ps){ result=result.sum(Errors42.formatPath(pi)); } return result.formatNewLinesAsList(); } public static boolean hasPrivateState(ClassB cb) { for(Member m:cb.getMs()){ if(!(m instanceof MethodWithType)){continue;} MethodWithType mwt=(MethodWithType)m; if(mwt.get_inner().isPresent()){continue;} if(mwt.getMs().isUnique()){return true;} } return false; } public static boolean isNoImplementation(ClassB cb){ for(Member m:cb.getMs()){ boolean isImpl=m.match( nc->false, mi->{ return true ;}, mt->mt.get_inner().isPresent() ); if(isImpl){return false;} } return true; } public static boolean isModule(ClassB cb) { for(Member m:cb.getMs()){ if(!(m instanceof MethodWithType)){continue;} MethodWithType mwt=(MethodWithType)m; if(mwt.getMt().getMdf()!=Mdf.Class){return false;} Type rt = mwt.getMt().getReturnType(); if(!(rt instanceof NormType)){continue;} NormType nt=(NormType)rt; if(nt.getPath().equals(Path.outer(0))){return false;} } return true; } /* private static Set<MethodSelector> intersection(Collection<MethodSelector>ams, Collection<MethodSelector>bms){ if( ams==null || ams.isEmpty() || bms==null || bms.isEmpty()){return Collections.emptySet();} Set<MethodSelector> result = new HashSet<>(ams); result.retainAll(bms); return result; }*/ static void accumulateCb(java.util.Map<Path,List<MethodSelector>> accumulator,Path path,ClassB cb){ assert cb.isInterface(); if(accumulator.containsKey(path)){return;} List<MethodSelector> defined=new ArrayList<>(); for(Member m:cb.getMs()){ if(!(m instanceof MethodWithType)){continue;} defined.add(((MethodWithType)m).getMs()); } accumulator.put(path, defined); } /* static java.util.Map<Path,List<MethodSelector>> implementedInterfacesMethods(Program p,Path path){ java.util.Map<Path,List<MethodSelector>> accumulator=new HashMap<>(); fillImplementedInterfacesMethods(accumulator,p,path); return accumulator; } static void fillImplementedInterfacesMethods(java.util.Map<Path,List<MethodSelector>> accumulator,Program p,Path path){ //assume p have all the cb present,we do not use ct here ClassB cb=p.extractCb(path); if(cb.isInterface()){accumulateCb(accumulator,path,cb);} for(Path pi:cb.getSupertypes()){ pi=From.fromP(pi,path); fillImplementedInterfacesMethods(accumulator, p, pi); } } */ static List<Integer> isParTypeOk(MethodWithType mta, MethodWithType mtb) { List<Integer>res=new ArrayList<>(); int maxLen=Math.max(mta.getMt().getTs().size(),mtb.getMt().getTs().size()); for(int i=0;i<maxLen;i++){ Type ta; Type tb; try{ ta = mta.getMt().getTs().get(i); tb=mtb.getMt().getTs().get(i); }catch(ArrayIndexOutOfBoundsException out){res.add(i);continue;} if(!ta.equals(tb)){res.add(i);} } return res; } static boolean isExceptionOk(MethodWithType mta, MethodWithType mtb) { Set<Path> pa=new HashSet<>(Map.of(t->t.getNT().getPath(), mta.getMt().getExceptions())); Set<Path> pb=new HashSet<>(Map.of(t->t.getNT().getPath(),mtb.getMt().getExceptions())); Set<Path> pc=new HashSet<>(pa); pc.retainAll(pb); if(mta.get_inner().isPresent() && !pc.containsAll(pa)){ return false;} if(mtb.get_inner().isPresent() && !pc.containsAll(pb)){ return false;} return true; } static List<PathMx> collectPrivateMethodsOfPublicPaths(ClassB cb, List<Ast.C> path) { List<PathMx> result=new ArrayList<>(); cb=cb.getClassB(path); auxCollectPrivateMethodsOfPublicPaths(cb,result,path); return result; } private static void auxCollectPrivateMethodsOfPublicPaths(ClassB cb,List<PathMx> accumulator, List<Ast.C> prefix) { for(Member m:cb.getMs()){m.match( nc->{ if(nc.getName().isUnique()){return null;} List<Ast.C> newPrefix=new ArrayList<>(prefix); newPrefix.add(nc.getName()); auxCollectPrivateMethodsOfPublicPaths((ClassB)nc.getInner(),accumulator,newPrefix); return null; },mi->null, mt->{ if (!mt.getMs().isUnique()){return null;} accumulator.add(new PathMx(Path.outer(0,prefix),mt.getMs())); return null; });} } private static void auxCollectPrivatePathsAndSubpaths(ClassB cb,List<Path> accumulator, List<Ast.C> prefix, boolean collectAll) { for(Member m:cb.getMs()){m.match( nc->{ List<Ast.C> newPrefix=new ArrayList<>(prefix); newPrefix.add(nc.getName()); boolean newCollectAll=collectAll || nc.getName().isUnique(); auxCollectPrivatePathsAndSubpaths((ClassB)nc.getInner(),accumulator,newPrefix,newCollectAll); if(newCollectAll){accumulator.add(Path.outer(0,newPrefix));} return null; },mi->null, mt->null);} } static List<Path> collectPrivatePathsAndSubpaths(ClassB cb, List<Ast.C> path) { List<Path> result=new ArrayList<>(); cb=cb.getClassB(path); auxCollectPrivatePathsAndSubpaths(cb,result,path ,false); return result; } public static boolean isPrefix(List<Ast.C> a, List<Ast.C> b) { List<Ast.C> la=a; List<Ast.C> lb=b; while (!la.isEmpty() && !lb.isEmpty()){ Ast.C ai=la.get(0); Ast.C bi=lb.get(0); if(!ai.equals(bi)){return false;} la=la.subList(1, la.size()); lb=lb.subList(1, lb.size()); } assert la.isEmpty() || lb.isEmpty(); return true; } }