package is.L42.connected.withSafeOperators;
import is.L42.connected.withSafeOperators.ExtractInfo.ClassKind;
import is.L42.connected.withSafeOperators.ExtractInfo.IsUsed;
import tools.Assertions;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import platformSpecific.javaTranslation.Resources;
import platformSpecific.javaTranslation.Resources.Error;
import sugarVisitors.ToFormattedText;
import ast.Ast.C;
import ast.Ast.Doc;
import ast.Ast.Mdf;
import ast.Ast.MethodSelector;
import ast.Ast.Path;
import ast.Ast.Position;
import ast.Ast.Type;
import ast.Ast;
import ast.ErrorMessage;
import ast.ExpCore;
import ast.ExpCore.ClassB;
import ast.ExpCore.ClassB.Member;
import ast.ExpCore.ClassB.MethodWithType;
import ast.ExpCore.X;
import ast.Util.PathMx;
import ast.Util.PathPath;
import ast.Util.PathSPath;
import auxiliaryGrammar.Functions;
import programReduction.Program;
public class Errors42 {
//"SourceUnfit", caused by redirect
public static Error errorSourceUnfit(List<Ast.C> current,Path destExternalPath,ExtractInfo.ClassKind kindSrc,ExtractInfo.ClassKind kindDest,List<Member>unexpected,boolean headerOk,List<Path>unexpectedInterfaces){
return Resources.Error.multiPartStringError("SourceUnfit",
"SrcPath",formatPathIn(current), //the path of the class that can not be redirected
"DestExternalPath",formatPathOut(destExternalPath), //the path of the class that can not be redirected
// "PrivatePath",""+isPrivate,//the path can not be redirected since is private
"SrcKind",kindSrc.name(),//the kind of the class at path
"DestKind",kindDest.name(),
//"IncompatibleClassKind",""+!headerOk,//if the path can not be redirected because of their respective kinds. This information would make no sense if I can get the kind for dest!
"UnexpectedMembers",""+ExtractInfo.showMembers(unexpected),//methods that are not present in dest (or present but with different declared vs Interface implemented status)
"UnexpectedImplementedInterfaces",ExtractInfo.showPaths(unexpectedInterfaces)//sort of interfaces implemented in path but not in dest, more complex for ambiguities
);
}
//"ClassClash" caused by sum, renameClass, renameClassStrict, renameClass
static Error errorClassClash(List<Ast.C> current, List<Path> confl/*,ExtractInfo.ClassKind kindA,ExtractInfo.ClassKind kindB*/) {
return Resources.Error.multiPartStringError("ClassClash",
"Path",formatPathIn(current),//the path of the clash, in the rename is the path of the destination clash
//"LeftKind",kindA.name(),//kind of left and right classes
//"RightKind",kindB.name(),//this allows to infer if the class kinds was compatible
//Well, is just enough to see if conflict is empty then was incompatible kinds...
"ConflictingImplementedInterfaces",ExtractInfo.showPaths(confl)//the list of interface that define methods with same name
);
}
//"MethodClash" caused by sum, renameMethod, renameClassStrict, renameClass
static Error errorMethodClash(List<Ast.C> pathForError, Member mta, Member mtb, boolean excOk, List<Integer> pars, boolean retType, boolean thisMdf,boolean rightIsInterfaceAbstract) {
return Resources.Error.multiPartStringError("MethodClash",
"Path",formatPathIn(pathForError),//the path of the clash (that own the method), in the rename is the path of the destination clash
"Left",sugarVisitors.ToFormattedText.of(mta).replace("\n","").trim(),//implementation dependend print of the left and right methods
"Right",sugarVisitors.ToFormattedText.of(mtb).replace("\n","").trim(),
"LeftKind",ExtractInfo.memberKind(mta),//kind of the left/right methods
"RightKind",(rightIsInterfaceAbstract)?"InterfaceAbstractMethod":ExtractInfo.memberKind(mtb),
"DifferentParameters",""+ pars,//number of parameters with different types
"DifferentReturnType",""+ !retType,//if the return types are different
"DifferentThisMdf",""+ !thisMdf,//if the modifier for "this" is different
"IncompatibleException",""+!excOk);//if they have an incompatible exception list
}
//"ParameterMismatch" caused by sumMethod
static Error errorParameterMismatch(List<Ast.C> pathForError, Member mta, Member mtb, boolean par, boolean mdf,boolean parNameOk) {
return Resources.Error.multiPartStringError("ParameterMismatch",
"Path",formatPathIn(pathForError),//the path of the clash (that own the method), in the rename is the path of the destination clash
"Left",sugarVisitors.ToFormattedText.of(mta).replace("\n","").trim(),//implementation dependend print of the left and right methods
"Right",sugarVisitors.ToFormattedText.of(mtb).replace("\n","").trim(),
"LeftKind",ExtractInfo.memberKind(mta),//kind of the left/right methods
"RightKind",ExtractInfo.memberKind(mtb),
"FirstParameterTypeOk",""+ par,//first parameter=return type
"MdfOk",""+ mdf,// the modifier for "this" is compatible
"ParNameContainedInRight",""+ parNameOk// disjoint par names
);//if they have an incompatible exception list
}
//"InvalidOnTopLevel", caused by redirect and addDocumentationOnNestedClass
static Error errorInvalidOnTopLevel() {
return Resources.Error.multiPartStringError("InvalidOnTopLevel");
}
//"MemberUnavailable", caused by most operations referring to paths and methods
static enum MemberUnavailable{PrivatePath,PrivateMethod,NonExistentPath,NonExistentMethod}
static Member checkExistsPathMethod(ClassB cb, List<Ast.C> path,Optional<MethodSelector>ms){
try{
Boolean[] isPrivateRef=new Boolean[]{false};//used in closures
for(C c:path){if(c.isUnique()){isPrivateRef[0]=true;}}
ClassB cbi=cb.getClassB(path);
Boolean[] isPrivateMeth=new Boolean[]{false};
boolean absentMeth=false;
if(ms.isPresent()){
Optional<Member> meth=Functions.getIfInDom(cbi.getMs(),ms.get());
absentMeth=!meth.isPresent();
if(meth.isPresent()){
meth.get().match(
nc->{throw Assertions.codeNotReachable();},
mi->{return null;},
mt->{if(mt.getMs().isUnique()){isPrivateMeth[0]=true;}return null;}
);
if(!isPrivateMeth[0]){return meth.get();}
}
}
MemberUnavailable kind=null;
if(absentMeth){kind=MemberUnavailable.NonExistentMethod;}
if(isPrivateMeth[0]){kind=MemberUnavailable.PrivateMethod;}
if(isPrivateRef[0]){kind=MemberUnavailable.PrivatePath;}
if(kind==null){return null;}
throw Resources.Error.multiPartStringError("MemberUnavailable",
"Path",formatPathIn(path),
"Selector",""+((ms.isPresent())?ms.get():""),
"InvalidKind",""+kind.name(),
"IsPrivate",""+kind.name().contains("Private"));
}
catch(ast.ErrorMessage.PathMetaOrNonExistant e){
throw Resources.Error.multiPartStringError("MemberUnavailable",
"Path",formatPathIn(path),
"Selector",""+((ms.isPresent())?ms.get():""),
"InvalidKind",""+MemberUnavailable.NonExistentPath,
"IsPrivate","false");
}
}
//"PrivacyCoupuled", caused by removeImplementation
static Error errorPrivacyCoupuled(List<Path> coupuledPaths, List<PathMx> ordered) {
return Resources.Error.multiPartStringError("PrivacyCoupuled",
"CoupuledPath",""+coupuledPaths,//private paths that are still used
"CoupuledMethods",""+ordered);//private methods that are still used
}
//"PathClash", caused by renameClassStrict, if two paths are prefix of one other
public static Resources.Error errorPrefix(List<Ast.C> a, List<Ast.C> b) {
boolean aIsLonger=a.size()>b.size();
List<Ast.C> shorter=aIsLonger?b:a;
List<Ast.C> longer=aIsLonger?a:b;
return Resources.Error.multiPartStringError("PathClash",
"Prefix",""+shorter,
"Clashing",""+longer);}
//"InvalidOnMember", caused by pop if there is more then one nested class
static Error errorInvalidOnMember(Doc doc) {
return Resources.Error.multiPartStringError("InvalidOnMember",
"Doc",doc);
}
//"AmbiguousPop", caused by pop if there is more then one nested class
static Error errorAmbiguousPop(ClassB cb) {
return Resources.Error.multiPartStringError("AmbiguousPop",
"numberOfNestedClasses",""+cb.getMs().size());
}
//"NotBox", caused by pop if the top level is not of box kind
static Error errorNotBox(ClassB cb, List<MethodSelector> meth, Set<Path> used,ExtractInfo.ClassKind kind) {
return Resources.Error.multiPartStringError("NotBox",
"UsedBy",""+used,
"Supertypes",""+cb.getSupertypes(),
"ContainsMethods",""+meth,
"ActualKind",""+kind.name());
}
public static void checkMethodClash(List<Ast.C>pathForError,MethodWithType mta, MethodWithType mtb,boolean rightIsInterfaceAbstract){
boolean implClash=mta.get_inner().isPresent() && mtb.get_inner().isPresent();
boolean exc=ExtractInfo.isExceptionOk(mta,mtb);
List<Integer> pars=ExtractInfo.isParTypeOk(mta,mtb);
boolean retType=mta.getMt().getReturnType().equals(mtb.getMt().getReturnType());
boolean thisMdf=mta.getMt().getMdf().equals(mtb.getMt().getMdf());
if(!implClash && exc && pars.isEmpty() && retType && thisMdf && !rightIsInterfaceAbstract){return;}
if(mta.get_inner().isPresent()){mta=mta.with_inner(Optional.of(new ExpCore.X(Position.noInfo,"implementation")));}
if(mtb.get_inner().isPresent()){mtb=mtb.with_inner(Optional.of(new ExpCore.X(Position.noInfo,"implementation")));}
throw errorMethodClash(pathForError, mta, mtb, exc, pars, retType, thisMdf,false);
}
/* static void checkCoherentMapping(List<PathPath> setVisited) {
// setVisited is a set of individual redirected classes,
// created by walking the sub-tree under each cascade redirect.
// getPath1() is the path in the library before redirecting.
// getPath2() is the proposed path in the redirected library.
// We will allow many paths to be redirected into a single new path,
// but not vice-versa.
for(PathPath p1:setVisited){
for(PathPath p2:setVisited){
if(p1.equals(p2)){continue;}
if(p1.getPath1().equals(p2.getPath1())){
throw errorIncoherentRedirectMapping(setVisited, p1.getPath1(),p1.getPath2(),p2.getPath2());
}
}
}
return;
}*/
static Error errorIncoherentRedirectMapping(List<PathPath>verified,List<PathSPath>ambiguities,Path incoSrc,List<Path> _incoDest) {
Doc src=Doc.empty();
Doc dest=Doc.empty();
//Doc ambig=Doc.empty();
for(PathPath v:verified){
src=src.sum(formatPathIn(v.getPath1().getCBar()));
dest=dest.sum(formatPathOut(v.getPath2()));
}
for(PathSPath a:ambiguities){
//if(a.getPaths().size()!=1){
// ambig=ambig.sum(formatPathIn(a.getPath().getCBar()));
// ambig=ambig.sum(Doc.factory("@"+a.getPaths().size()));
// }
Doc srci=formatPathIn(a.getPath().getCBar());
for(Path pij:a.getPathsSet()){
src=src.sum(srci);
dest=dest.sum(formatPathOut(pij));
}
}
Doc incoDest=Doc.empty();
for(Path pi:_incoDest){incoDest=incoDest.sum(formatPathOut(pi));}
return Resources.Error.multiPartStringError("IncoherentRedirectMapping",
"Src",src.formatNewLinesAsList(),
"Dest",dest.formatNewLinesAsList(),
//"Ambiguities",ambig.formatNewLinesAsList(),
"IncoherentSrc",incoSrc==null?Doc.empty():formatPathIn(incoSrc.getCBar()),
"IncoherentDest",incoDest.formatNewLinesAsList()
);
}
static Doc formatPathIn(List<Ast.C> path){
//if(path.isEmpty()){return Doc.factory(Path.outer(0));}
String res="@";
for(Ast.C ci:path){res+="."+ci;}
if(path.isEmpty()){res="@.\n";}
else {res+="\n";}
return Doc.factory(true,res);
}
static Doc formatPathOut(Path path){
if(path.isPrimitive()){return Doc.factory(path);}
assert path.outerNumber()>0;
return Doc.factory(Path.outer(path.outerNumber()+1,path.getCBar())).withNewlineTerminator();
}
static Doc formatPath(Path path){
if(path.isPrimitive()){return Doc.factory(path).withNewlineTerminator();}
if(path.outerNumber()==0){return formatPathIn(path.getCBar());}
return formatPathOut(path);
}
public static void checkCompatibleMs(List<Ast.C> pathForError,MethodWithType mem, MethodSelector dest) {
int sizeA = mem.getMs().getNames().size();
int sizeB = dest.getNames().size();
if(sizeA==sizeB){return;}
List<Integer> parsWrong=new ArrayList<>();
int min=Math.min(sizeA,sizeB);
int max=Math.max(sizeA,sizeB);
for(int i=min;i<max;i++){parsWrong.add(i);}
List<Type> ts = new ArrayList<>(mem.getMt().getTs());
for(int i=sizeA;i<sizeB;i++){
ts.add(ast.Ast.NormType.immVoid);
}
if(sizeA>sizeB){
ts=ts.subList(0, sizeB);
}
MethodWithType memb = mem.withMs(dest).withMt(mem.getMt().withTs(ts));
throw errorMethodClash(pathForError, mem,memb, true, parsWrong,true, true, false);
}
}