package is.L42.connected.withSafeOperators; import platformSpecific.javaTranslation.Resources; import sugarVisitors.ToFormattedText; import tools.Map; import ast.Ast; import ast.ErrorMessage; import ast.Ast.Mdf; import ast.Ast.MethodSelectorX; import ast.Ast.Path; import ast.Ast.Type; import ast.ErrorMessage.NormImpossible; import ast.Ast.NormType; import ast.Ast.Doc; import ast.ExpCore.ClassB; import ast.ExpCore.ClassB.Member; import ast.ExpCore.ClassB.MethodWithType; import ast.ExpCore.ClassB.NestedClass; import ast.ExpCore.*; import auxiliaryGrammar.EncodingHelper; import auxiliaryGrammar.Functions; import programReduction.Program; import java.util.List; import java.util.ArrayList; import java.util.Arrays; import java.util.Optional; import coreVisitors.From; import facade.Configuration; public class Introspection {//TODO: we keep 5 methods, but we merge the PathReport and MemberReport content. public static List<Object> giveInfo(ClassB that,List<Ast.C> path){ Errors42.checkExistsPathMethod(that, path,Optional.empty()); Doc doc=null; ClassB current=that; if(!path.isEmpty()){ NestedClass nsCurrent=that.getNested(path); current= (ClassB) nsCurrent.getE(); doc=nsCurrent.getDoc(); } return Arrays.asList( "MemberKind","NestedClass", "MemberDoc",(doc==null)?"":liftDoc(path.subList(0,path.size()-1),doc,1), "Key",""+String.join(".",Map.of(ci->""+ci,path)), "AllAsString",current, "ClassKind",ExtractInfo.classKind(that, path, current,null, null,null).name(), "LibraryDoc",liftDoc(path,current.getDoc1(),1), "MemberNumber",""+current.getMs().size(), "ImplementedNumber",""+current.getSupertypes().size() );} public static ClassB giveInfoMember(ClassB that,List<Ast.C> path,int memberN){ assert memberN!=0; Errors42.checkExistsPathMethod(that, path,Optional.empty()); ClassB current = that.getClassB(path); if(current.getMs().size()<memberN){ throw Resources.notAct; } Member mN=current.getMs().get(memberN-1); ClassB[] result={null}; mN.match( nc->{ List<Ast.C> fullPath=new ArrayList<>(path); fullPath.add(nc.getName()); ClassB currentNc=(ClassB)nc.getInner(); result[0]=Resources.Error.multiPartStringClassB("MemberReport", "MemberKind","NestedClass", "MemberDoc",liftDoc(path,nc.getDoc(),1), "Key",String.join(".",Map.of(ci->""+ci, fullPath)), "AllAsString",ToFormattedText.of(nc.getInner()), "ClassKind",ExtractInfo.classKind(that, path,(ClassB) nc.getInner(),null, null,null).name(), "LibraryDoc",liftDoc(path,currentNc.getDoc1(),1), "MemberNumber",""+currentNc.getMs().size(), "ImplementedNumber",""+currentNc.getSupertypes().size() ); return null; }, mi->{//we want to use mi instead of mt of ct: even the number of members may change. result[0]=Resources.Error.multiPartStringClassB("MemberReport", "MemberKind",ExtractInfo.memberKind(mN), "MemberDoc",liftDoc(path,mi.getDoc(),1), "Key",""+mi.getS(),//Selector/Path "AllAsString",ToFormattedText.of(mi), "ParameterNumber",""+mi.getS().getNames().size() ); return null; }, mt->{ result[0]=Resources.Error.multiPartStringClassB("MemberReport", "MemberKind",ExtractInfo.memberKind(mN), "MemberDoc",liftDoc(path,mt.getDoc(),1), "ThisMdf",""+mt.getMt().getMdf().name(), "Key",""+mt.getMs(),//Selector/Path "AllAsString",ToFormattedText.of(mt), "ExceptionNumber",""+mt.getMt().getExceptions().size(), "ParameterNumber",""+mt.getMs().getNames().size() ); return null; }); //TODO: doc exceptions should become a doc for each exception return result[0]; } //static enum TypeKind{InternalNormal,ExternalNormal,InternalAlias,ExternalAlias, InternalAliasUnresolvable,ExternalAliasUnresolvable,InternalExternalAlias} static enum TypeKind{Normal,Alias,AliasUnresolvable} //if member ==0, talk about implemented interfaces, nested classes have no types public static ClassB giveInfoType(Path isExternal,Program p,ClassB that,List<Ast.C> path,int memberN,int typeN){ Errors42.checkExistsPathMethod(that, path,Optional.empty()); ClassB current = that.getClassB(path); if(current.getMs().size()<memberN){throw Resources.notAct;} if(memberN<0){throw Resources.notAct;}//TODO: is this a good idea? if(memberN==0){ if(typeN<=0){throw Resources.notAct;} if(current.getSupertypes().size()<typeN){throw Resources.notAct;} Type implN = current.getSupertypes().get(typeN-1); return typeReport(isExternal,p.evilPush(that), implN,path); } assert memberN>0; Member mi = current.getMs().get(memberN-1); if(!(mi instanceof MethodWithType)){throw Resources.notAct;} MethodWithType mwt=(MethodWithType)mi; Type ti = mwt.getMt().getReturnType(); if(typeN>mwt.getMt().getTs().size()){throw Resources.notAct;} if(typeN<-mwt.getMt().getExceptions().size()){throw Resources.notAct;} if(typeN>0){ ti=mwt.getMt().getTs().get(typeN-1); } if(typeN<0){ ti=mwt.getMt().getExceptions().get((typeN*-1)-1); //TODO: doci=?? add docs for exceptions, return type and implements } return typeReport(isExternal,p.evilPush(that), ti,path); } private static ClassB typeReport(Path isExternal,Program p,Type ti, List<Ast.C> src){ p=p.navigate(src); NormType normTi=(ti instanceof NormType)?(NormType)ti:null; NormType resolvedTi=null; TypeKind tk = getTypeKind(src,ti, resolvedTi); Mdf mdf=(normTi!=null)?normTi.getMdf():Mdf.Immutable; Mdf resMdf=(resolvedTi!=null)?resolvedTi.getMdf():Mdf.Immutable; Path pi=(normTi!=null)?normTi.getPath():((Ast.HistoricType)ti).getPath(); Path resPi=(resolvedTi!=null)?resolvedTi.getPath():pi; boolean ph=(normTi!=null)?!Functions.isComplete(normTi):false; boolean resPh=(resolvedTi!=null)?!Functions.isComplete(resolvedTi):ph; String suffix=(ti instanceof Ast.HistoricType)?selectorsToString(((Ast.HistoricType)ti).getSelectors()):""; String allAsString=ToFormattedText.of(ti); return typeReport(isExternal,src, tk, mdf, resMdf, pi, resPi, ph, resPh, suffix, ti.getDoc(), allAsString); //unfold? } //private static boolean isExternal(List<String>path,Path pi){return pi.isPrimitive()||pi.outerNumber()>path.size(); } private static TypeKind getTypeKind(List<Ast.C>path,Type ti, NormType resolvedTi) { if(ti instanceof NormType){return TypeKind.Normal; //NormType nt=(NormType)ti; //if(isExternal(path,nt.getPath())){return TypeKind.ExternalNormal;} //return TypeKind.InternalNormal; } if(resolvedTi==null){return TypeKind.AliasUnresolvable;} return TypeKind.Alias; //Ast.HistoricType ht=(Ast.HistoricType)ti; //boolean tiExt=isExternal(path,ht.getPath()); //if(resolvedTi==null && tiExt){return TypeKind.ExternalAliasUnresolvable;} //if(resolvedTi==null){return TypeKind.InternalAliasUnresolvable;} //if(tiExt){return TypeKind.ExternalAlias;} //if(isExternal(path,resolvedTi.getPath())){return TypeKind.InternalExternalAlias;} //return TypeKind.InternalExternalAlias; } private static String selectorsToString(List<MethodSelectorX> selectors) { String result=""; for(MethodSelectorX msx:selectors){ result+="."+msx.getMs().toString(); if(!msx.getX().isEmpty()){result+="."+msx.getX();} } return result; } private static ClassB typeReport(Path isExternal,List<Ast.C> path, TypeKind kind, Mdf mdf, Mdf resMdf, Path pi, Path resPi, boolean ph, boolean resPh, String suffix, Doc doc, String allAsString) throws Error { assert mdf!=null && resMdf!=null; Doc dPi=liftDoc(path,Doc.factory(pi),1); Doc dResPi=liftDoc(path,Doc.factory(resPi),1); if(isExternal!=null && dPi.getAnnotations().get(0) instanceof String){ dPi=Doc.factory(Functions.add1Outer(Functions.add1Outer(From.fromP(pi,isExternal)))); } if(isExternal!=null && dResPi.getAnnotations().get(0) instanceof String){ dResPi=Doc.factory(Functions.add1Outer(Functions.add1Outer(From.fromP(resPi,isExternal)))); } return Resources.Error.multiPartStringClassB("TypeReport", "TypeKind",""+kind,//:Normal, Alias, AliasUnresolvable "Mdf",""+((mdf==Mdf.Immutable)?resMdf:mdf).name(),//:String //"ResolvedMdf",""+resMdf,//:String "Path",dPi,//:Doc with one annotation, can be typeAny or not "ResolvedPath",dResPi,//:Doc with one annotation, can be typeAny or not "Ph",""+ph,//:Boolean "ResolvedPh",""+resPh,//:Boolean "Suffix",""+suffix,//:String (may be empty for not alias type) "Doc",liftDoc(path,doc,1),//Doc "AllAsString",""+allAsString//String ); } /* annotationN==-1 is HardWrap Hard wrap: just wrap the content of the comment in @stringU Soft wrap: if the content is already wrapped in @stringU, leave it as it is. What should we do for @int32 and similar? */ public static String extractDocAsString(ClassB that,List<Ast.C>path,int annotationN){ //System.out.println("extractDocAsString("+path+" annotationN:"+annotationN+")"); Errors42.checkExistsPathMethod(that, path,Optional.empty()); ClassB current = that.getClassB(path); Doc d=current.getDoc1(); d=liftDoc(path,d,0); //System.out.println("extractDocAsString("+d+")"); if(annotationN<=0){ String result=d.toString(); //System.out.println("extractDocAsString(result:"+result+")"); if(annotationN==-1 || !result.startsWith("@stringU\n")){ return result;// extra @stringU will be added since we return "String" } assert result.endsWith("\n"); if(result.startsWith("@stringU\n")){result=result.substring("@stringU\n".length(),result.length()-1);} return EncodingHelper.parseStringUnicode(result); } if(d.getAnnotations().size()<annotationN){throw Resources.notAct;} Object o=d.getAnnotations().get(annotationN-1); return o.toString(); } public static Path extractDocPath(ClassB that,List<Ast.C>path,int annNumber){ Errors42.checkExistsPathMethod(that, path,Optional.empty()); ClassB current = that.getClassB(path); Doc d=current.getDoc1(); d=liftDoc(path,d,0);//ok, it is as should be if wrote in the class (see under) if(d.getAnnotations().size()<annNumber){throw Resources.notAct;} Object o=d.getAnnotations().get(annNumber-1); //if(o instanceof String){throw Resources.notAct;} if(!(o instanceof Path)){ throw Resources.notAct; } Path pRes=(Path)o; assert pRes.isPrimitive() || pRes.outerNumber()>=1; if(pRes.isPrimitive()){return pRes;} pRes=pRes.setNewOuter(pRes.outerNumber()-1); return pRes; } /* 5)extractDocPath:Lib*,path, pathNumber ->typeAny //error for internal paths or number bigger than possible. */ private static Doc liftDoc(List<Ast.C> path, Doc doc,int newNested) { //for all external paths (pi.outern>path.size) new outern=oldOutern-size+newNested //for all internal paths(otherwise) becomes a .string, normalized in path, List<Object> ann=new ArrayList<>(); for(Object o:doc.getAnnotations()){ if(o instanceof String){ann.add(o);continue;} assert o instanceof Path:o.getClass().getCanonicalName(); Path pi=(Path)o; if(pi.isPrimitive()){ann.add(o);continue;} if(pi.outerNumber()>path.size()){ o=pi.setNewOuter((pi.outerNumber()-path.size())+newNested); ann.add(o);continue; } List<Ast.C>topPi=ClassOperations.toTop(path, pi); o="."+String.join(".",Map.of(ci->""+ci,topPi)); ann.add(o);//continue; } return doc.withAnnotations(ann); } }