package facade;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import sugarVisitors.CollapsePositions;
import sugarVisitors.ToFormattedText;
import tools.Assertions;
import tools.StringBuilders;
import ast.Ast;
import ast.Ast.Doc;
import ast.Ast.Mdf;
import ast.Ast.Path;
import ast.Ast.Stage;
import ast.ErrorMessage;
import ast.ErrorMessage.UserLevelError.Kind;
import ast.ExpCore;
import ast.ExpCore.ClassB;
import ast.ExpCore.ClassB.Member;
import ast.ExpCore.ClassB.NestedClass;
import ast.ExpCore.ClassB.Phase;
import ast.Expression;
import ast.Ast.Position;
import ast.ExpCore.ClassB.MethodWithType;
import coreVisitors.InjectionOnSugar;
import coreVisitors.IsCompiled;
import facade.L42.ExecutionStage;
import platformSpecific.javaTranslation.Resources;
import programReduction.Program;
import programReduction.Program.EmptyProgram;
public class ErrorFormatter {
//TODO: in future, not display for coherent classes
public static String displayAbstractMethods(ClassB cb){
StringBuilder result=new StringBuilder();
//result.append("Abstract methods:\n");
//displayAbstractMethods(cb,result,"");
return result.toString();
}
@SuppressWarnings("unused")//TODO: what was this for
private static void displayAbstractMethods(ClassB cb,StringBuilder result,String nesting){
result.append("{\n");
for(Member m:cb.getMs()){
m.match(nc->{
if(!(nc.getInner() instanceof ClassB)){return null;}
if(((ClassB)nc.getInner()).isInterface()){return null;}
StringBuilder inner=new StringBuilder();
displayAbstractMethods((ClassB)nc.getInner(),inner,nesting+" ");
String innerStr=inner.toString();
if(!innerStr.contains("method")){return null;}
result.append(nesting);
result.append(nc.getName());
result.append(":");
result.append(innerStr);
return null;
},
mi->{
return null;
},
mt->{
if(mt.get_inner().isPresent()){return null;}
if(mt.getMt().getMdf()==Mdf.Class){return null;}
result.append(nesting);
result.append(ToFormattedText.of(mt).replace("\n", "\n"+nesting));
result.append("\n");
return null;
});
}
result.append("}\n");
}
public interface Reporter{ String toReport(ArrayList<Ast.Position>ps);}
public static ErrorMessage.UserLevelError formatError(Program p,ErrorMessage msg) {
Class<?> c=msg.getClass();
try {return formatError(p,msg, c);}
catch (IllegalAccessException | NoSuchFieldException | SecurityException e) {throw new Error(e);}
}
public static ErrorMessage.UserLevelError formatError(Program p,ErrorMessage msg, Class<?> c) throws IllegalAccessException, NoSuchFieldException, SecurityException {
String errorStart="\n\n\n------------------------------------\n";
ArrayList<Ast.Position> ps=new ArrayList<Ast.Position>();
String errorTxt="";
errorTxt+= infoFields(msg, c,ps);
try{
errorTxt+="Surrounding context:\n";
errorTxt+= envs(msg, c,ps);
ArrayList<Position> ps2 = ps;
if(!ps.isEmpty()){ps2=new ArrayList<>();}
try{errorTxt+= ctxP(msg, c,ps2);}catch(NoSuchFieldException ignored){}
}
catch(NoSuchFieldException ignored){}
pos(msg,c,ps);
Position pos=positionsFilter(ps);
if(c==ErrorMessage.DotDotDotCanNotBeResolved.class){
// ErrorMessage.DotDotDotCanNotBeResolved ddd=(ErrorMessage.DotDotDotCanNotBeResolved)msg;
}
errorTxt="Error kind: "+c.getSimpleName()+"\nPosition:"+
((pos==null)?"unknown":pos.toString())+"\n"+errorTxt;
//ps+"\n"+errorTxt;
ErrorMessage.UserLevelError.Kind kind=findKind(msg);
switch (kind){
case TypeError:
errorTxt=errorStart+"runStatus: "+kind.name()+"\n"+errorTxt;
break;
case MetaError:
errorTxt=errorStart+"runStatus: "+kind.name()+"\n"+
"Error in generating the following class: \n"
+reportPlaceOfMetaError(p,msg)/*.replace(".\n","\n")*/+"\n----------\n"+errorTxt;
default:
break;
}
Throwable cause=null;
if(msg.getCause()!=null){
if(msg.getCause() instanceof ErrorMessage){
ErrorMessage.UserLevelError uleCause=formatError(p,(ErrorMessage)msg.getCause());
cause=uleCause;
errorTxt+="\n-------- caused by -----\n"+uleCause.getErrorTxt();
}
else {cause=msg.getCause();}
}
ErrorMessage.UserLevelError result= new ErrorMessage.UserLevelError(kind,pos,msg,errorTxt);
result.initCause(cause);
return result;
}
private static String reportPlaceOfMetaError(Program p,ErrorMessage msg) {
ErrorMessage.MalformedFinalResult _msg=(ErrorMessage.MalformedFinalResult)msg;
ClassB cb=_msg.getFinalRes();
//String path=_msg.getReason();
String path=reportPlaceOfMetaError(p,cb);
return path+"\n-----\n"+_msg.getReason();
}
public static String reportPlaceOfMetaError(Program p,ClassB cb) {
for(Member m:cb.getMs()){
if(IsCompiled.of(m)){continue;}
return m.match(
nc->nc.getName()+"\nError is:\n"+L42.messageOfLastTopLevelError+"\n"+
"reconstructed stackTrace:"+L42.reconstructedStackTrace+"\n"+isItErrorPlace(p,nc.getInner()),
mi->formatSelectorCompact(mi.getS())+"."+isItErrorPlace(p,mi.getInner()),
mt->formatSelectorCompact(mt.getMs())+"."+isItErrorPlace(p,mt.getInner())
);
}
for(Member m:cb.getMs()){
String err=m.match(nc->{
ClassB ncb=(ClassB)nc.getInner();
if(ncb.getPhase()!=Phase.Coherent){
return nc.getName()+"."+isItErrorPlace(p,nc.getInner());
}
return null;
}, mi->null, mt->null);
if(err!=null){
return "NotStarOf "+err;
}
}
return "it should be a nested somewhere";//TODO: improve//
//throw Assertions.codeNotReachable();
}
private static String isItErrorPlace(Program p,ExpCore inner) {//TODO: rename method in giveErrorText?
if(inner instanceof ClassB){return reportPlaceOfMetaError(p,(ClassB)inner);}
return "\n "+reportMetaError(p,inner);
}
private static class ReportThrow extends coreVisitors.CloneWithPath{
List<Ast.C> collectedPath=null;
ExpCore.Signal collectedErr=null;
public ClassB.NestedClass visit(ClassB.NestedClass nc){
if(nc.getInner() instanceof ExpCore.Signal){
collectedPath=this.getLocator().getClassNamesPath();
collectedErr=(ExpCore.Signal )nc.getInner();
}
return super.visit(nc);}
}
public static String reportMetaError(Program p,ExpCore inner) {
ReportThrow rt=new ReportThrow();
inner.accept(rt);
String str1="";
if(rt.collectedErr!=null){
str1=ToFormattedText.of(rt.collectedErr)+"\nContained inside:"+Path.outer(0, rt.collectedPath)+"\n";
}
str1+=ToFormattedText.of(inner).replace("\n"," ");
return str1;
}
private static Kind findKind(ErrorMessage msg) {
if (L42.getStage()==ExecutionStage.CheckingWellFormedness){
return Kind.WellFormedness;}
if(msg instanceof ErrorMessage.TypeError){return Kind.TypeError;}
if(msg instanceof ErrorMessage.MalformedFinalResult){return Kind.MetaError;}
return Kind.Unclassified;
}
private static Position positionsFilter(ArrayList<Position> ps) {
if(ps.isEmpty()){return null;}
Position p=ps.get(0);
for(Position pi:ps){
p=CollapsePositions.accumulatePos(p, pi);
}
return p;
}
public static String envs(ErrorMessage msg, Class<?> c,ArrayList<Ast.Position> ps)
throws NoSuchFieldException, IllegalAccessException {
String errorTxt="";
Field f=c.getField("envs");
f.setAccessible(true);
Collection<?> envs=(Collection<?>)f.get(msg);
for(Object o:envs){
errorTxt+=errorFormat(o,ps)+"\n";
}
return errorTxt;
}
public static void pos(ErrorMessage msg, Class<?> c,ArrayList<Ast.Position> ps)
throws IllegalAccessException {
try{
Field f=c.getDeclaredField("pos");
f.setAccessible(true);
if( f.get(msg) instanceof Ast.Position){
Ast.Position pos=(Ast.Position)f.get(msg);
ps.add(pos);
}
}
catch(NoSuchFieldException ignored){}
}
public static String ctxP(ErrorMessage msg, Class<?> c,ArrayList<Ast.Position>ps)
throws NoSuchFieldException, IllegalAccessException {
String errorTxt="";
Field f=c.getDeclaredField("p");
f.setAccessible(true);
Collection<?> envs=(Collection<?>)f.get(msg);
if(envs!=null){
for(Object o:envs){
errorTxt+=errorFormat(o,ps)+"\n";
}}
return errorTxt;
}
public static String infoFields(ErrorMessage msg, Class<?> c,ArrayList<Ast.Position>ps)
throws IllegalAccessException {
String errorTxt="";
for(Field f:c.getDeclaredFields()){
f.setAccessible(true);
if(f.getName().equals("p")){continue;}
if(f.getName().equals("cb")){continue;}
Object obj=f.get(msg);
if(obj==null){continue;}
errorTxt+=f.getName();
errorTxt+=": ";
errorTxt+=errorFormat(obj,ps);
errorTxt+="\n";
}
return errorTxt;
}
public static String errorFormat(Object obj,ArrayList<Ast.Position>ps) {
if(obj instanceof ast.Ast.HasPos){ps.add(((ast.Ast.HasPos)obj).getP()); }
if(obj instanceof String){return (String)obj;}
if(obj instanceof Integer){return obj.toString();}
if(obj instanceof Expression){
Ast.Position p=CollapsePositions.of((Expression)obj);
ps.add(p);
return ToFormattedText.ofCompact((Expression)obj);
}
if(obj instanceof ExpCore){//thanks to Path, this have to be after Expression
Ast.Position p=CollapsePositions.of((ExpCore)obj);
ps.add(p);
ExpCore exp=(ExpCore)obj;
Expression expression=exp.accept(new InjectionOnSugar());
return errorFormat(expression,ps);
}
if(obj instanceof Ast.MethodSelector){
return formatSelectorCompact((Ast.MethodSelector)obj);
}
if(obj instanceof ExpCore.ClassB.MethodWithType){
return ToFormattedText.of((MethodWithType)obj).trim().replace("\n", " ");
}
// if(obj instanceof Ast.MethodType){
// }
if(obj instanceof Reporter){
return ((Reporter)obj).toReport(ps);
}
if(obj instanceof Collection<?>){
Collection<?> c=(Collection<?>)obj;
if(c.size()==0){return "[]";}
if(c.size()==1){return "["+errorFormat(c.iterator().next(),ps)+"]";}
String res="[\n";
for(Object o:c){
res+=" "+errorFormat(o,ps)+"\n";
}
return res+" ]\n";
}
if(obj instanceof Ast.Type){return ToFormattedText.of((Ast.Type)obj);}
if(obj instanceof ClassB.Member){return ToFormattedText.of((ClassB.Member)obj);}
//if(obj instanceof Expression){return ToFormattedText.of((Expression)obj);}
if(obj instanceof Expression.ClassB.Member){return ToFormattedText.of((Expression.ClassB.Member)obj);}
if(obj instanceof java.nio.file.Path){return obj.toString();}
if(obj instanceof Ast.Position){ return obj.toString();}
if(obj instanceof HashMap){ return obj.toString();}
if(obj instanceof Collection){ return obj.toString();}
if(obj instanceof ast.Util.PathMwt){ return obj.toString();}
if(obj instanceof ast.Ast.C){ return obj.toString();}
if(obj instanceof Boolean){ return obj.toString();}
return "unknown kind "+obj.getClass().getName();
}
public static String formatSelectorCompact(Ast.MethodSelector ms) {
StringBuilder sb=new StringBuilder();
sb.append(ms.nameToS()+"(");
StringBuilders.formatSequence(sb,ms.getNames().iterator(),", ",n->sb.append(n));
return sb.toString()+")";
}
public static void printType(Program p) {
//for(int i=0;i<50;i++){System.out.print("\n");}
//System.out.print("\n*************************\n");
//printType(0,p);
}
@SuppressWarnings("unused")//TODO: what was used for?
private static void printType(int i, Program p) {
printType(i,"",p.top());
try{printType(i+1,p.pop());}
catch(EmptyProgram ep){}
}
private static void printType(int i,String prefix, ClassB top) {
System.out.print("This"+i+prefix+" :{\n");
printMembers(top);
System.out.print(" }\n");
for(Member m:top.getMs()){
if(!(m instanceof NestedClass)){continue;}
NestedClass nc=(NestedClass)m;
if(nc.getInner() instanceof ClassB){
printType(i,"."+nc.getName(),(ClassB)nc.getInner());
}
}
}
private static void printMembers(ClassB top) {
for(Member m:top.getMs()){
if(!(m instanceof MethodWithType)){continue;}
MethodWithType mwt=(MethodWithType)m;
mwt=mwt.withDoc(Doc.empty());
mwt=mwt.with_inner(Optional.empty());
String txt=sugarVisitors.ToFormattedText.of(mwt);
txt=txt.replace("{","");
txt=txt.replace("}","");
txt=txt.replace("\n"," ");
System.out.print(" "+txt+"\n");
/* System.out.print(" "+mwt.getMt().getReturnType());
System.out.print(" "+mwt.getMs().getName());
System.out.print("(");
{int i=-1;for(String n:mwt.getMs().getNames()){i+=1;
System.out.print(mwt.getMt().getTs()
}}
System.out.print(")\n");
*/
}
}
private static String whyIsNotExecutable(ClassB cb) {
/*if(cb.getH() instanceof Ast.TraitHeader){
return "\n The requested path is a trait";
}*/
for(Member m: cb.getMs()){
if(!(m instanceof MethodWithType)){continue;}
/*MethodWithType mt=(MethodWithType)m;
if (!mt.getInner().isPresent() && !mt.isFieldGenerated()){
return "\n The method "+mt.getMs()+" of the requested path is abstract";
}*/
}
for(Member m: cb.getMs()){
if(!(m instanceof NestedClass)){continue;}
NestedClass nc=(NestedClass)m;
if (!(nc.getInner() instanceof ClassB)){
return "\n The nested class "+nc.getName()+" of the requested path is not compiled yet";
}
String nestedRes=whyIsNotExecutable((ClassB)nc.getInner());
if(nestedRes!=null){
return "."+nc.getName()+nestedRes;
}
}
return null;
}
public static String whyIsNotExecutable(Path path, Program p1) {
ClassB cb=p1.extractClassB(path);
String whyNot=whyIsNotExecutable(cb);
if (whyNot!=null){
return "The requested path is incomplete.\n "
+ToFormattedText.of(path)+whyNot;
}
return "The requested path is incomplete since it refers to other incomplete classes in the program";
}
@SuppressWarnings("unchecked")
public static void topFormatErrorMessage(ErrorMessage msg) {
//System.out.println(ErrorFormatter.formatError(msg).getErrorTxt());
L42.printDebug(
formatError(Program.emptyLibraryProgram(),msg).getErrorTxt()
);
for(Field f:msg.getClass().getDeclaredFields()){
f.setAccessible(true);
if(!f.getName().equals("p")){continue;}
List<ClassB> program;
try { program = (List<ClassB>)f.get(msg);}
catch (IllegalArgumentException | IllegalAccessException e) { throw new Error(e);}
if(program!=null){
for(ClassB cb:program){
L42.printDebug(displayAbstractMethods(cb));
}
}
}
}
}