package platformSpecific.javaTranslation;
import facade.Configuration;
import facade.ErrorFormatter;
import facade.L42;
import facade.PData;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Supplier;
import coreVisitors.CloneVisitorWithProgram;
import coreVisitors.CollectClassBs0;
import coreVisitors.CollectPaths0;
import coreVisitors.FromInClass;
import coreVisitors.IsCompiled;
import platformSpecific.javaTranslation.Resources.Error;
import sugarVisitors.ToFormattedText;
import tools.Assertions;
import ast.Ast;
import ast.ErrorMessage;
import ast.ErrorMessage.TypeError;
import ast.ErrorMessage.UserLevelError;
import ast.ExpCore;
import ast.Ast.C;
import ast.Ast.Doc;
import ast.Ast.NormType;
import ast.Ast.Path;
import ast.Ast.Position;
import ast.Ast.SignalKind;
import ast.Ast.Stage;
import ast.ExpCore.ClassB;
import ast.ExpCore.ClassB.Phase;
import ast.PathAux;
import auxiliaryGrammar.EncodingHelper;
import auxiliaryGrammar.Functions;
import programReduction.Program;
public class Resources {
public static final ErrorMessage.PluginActionUndefined notAct=new ErrorMessage.PluginActionUndefined(-2);
public static final ErrorMessage.PluginActionUndefined actInEnd=new ErrorMessage.PluginActionUndefined(-1);
private static final HashMap<String,Object> usedRes=new HashMap<>();
/*public static class TypeMap{
HashMap<String,Object> types=new HashMap<>();
public void put(String k,Object val){types.put(k,val);}
public<T> T get(Class<T> clazz,String k){
Object val=types.get(k);
if(val!=null){return (T)val;}
return (T)new Revertable(){
public ast.ExpCore revert() {
return ast.Ast.Path.parse(k);
}
};
}
}
public static final TypeMap types=new TypeMap();
*/
public static String submitRes(Object cb){
HashSet<String> hs=new HashSet<>(usedRes.keySet());
String newK=Functions.freshName("key", hs);
assert !usedRes.containsKey(newK);
usedRes.put(newK,cb);
return newK;
}
private static PData p;
public static Program getP(){
assert p!=null;
assert p.p!=null;
return p.p;
}
public static PData pData(){assert p!=null; return p;}
public static <T> T withPDo(PData _p,Supplier<T> action){
if(p!=null){throw new IllegalAccessError();}
try{
p=_p;
return action.get();
}
finally{p=null;}
}
public static String pKeysString(){
String result="";
int[] data = pKeys();
for(int d:data){result+=","+d;}
return result;
}
public static int[] pKeys(){
List<Integer>res=new ArrayList<>();
Program p=getP();
while(true){
res.add(p.top().getUniqueId());
try{p=p.pop();}
catch(RuntimeException rte){break;}
}
return res.stream().mapToInt(Integer::intValue).toArray();
}
public static Object getRes(String key,int... ks){
Object o=usedRes.get(key);
if(o==null){throw new Error("Invalid resource "+key+" Valid resources are: "+usedRes.keySet());}
if(!(o instanceof ClassB)){return o;}
int[] newK = pKeys();
int common=0;
while(common<newK.length && common<ks.length){
if(newK[common]==ks[common]){common++;}
else{break;}
}
int shift=newK.length-common;
int padding=ks.length-common;
if(shift==0 && padding==0){return o;}
List<Ast.C>csPadding=new ArrayList<>();
for(int i=0;i<padding;i++){csPadding.add(C.of("Padding"+i));}
ClassB cb= (ClassB)FromInClass.of((ClassB)o,Path.outer(shift,csPadding));
//Configuration.typeSystem.computeStage(p, cb);
return cb;
}
public static void clearRes() {
usedRes.clear();
}
@SuppressWarnings("serial")
private static class L42Throwable extends RuntimeException{
public final Object unbox; public L42Throwable(Object u){unbox=u;}
}
@SuppressWarnings("serial")
public static class Error extends L42Throwable{
public String toString() {return "Error["+ unbox +"]";}
public Error(Object u){super(u);}
public static Error multiPartStringError(String kind,Object ... map){
ExpCore.ClassB cb = multiPartStringClassB(kind, map);
return new Error(cb);
}
public static ExpCore.ClassB multiPartStringClassB(String kind, Object... map) throws java.lang.Error {
List<ExpCore.ClassB.Member> ms=new ArrayList<>();
assert map.length%2==0;
ms.add(new ExpCore.ClassB.NestedClass(Doc.empty(),C.of("Kind"), EncodingHelper.wrapStringU(kind),null));
for(int i=0;i<map.length;i+=2){
String cName=(String)map[i];
ClassB inner;
if(map[i+1] instanceof String){inner=EncodingHelper.wrapStringU((String)map[i+1]);}
else if (map[i+1]instanceof Doc){//for now, just doc.
Doc docip1=(Doc)map[i+1];
inner=ClassB.docClass(docip1);
}
else{
throw new Error(map[i+1].toString());
}
if(!PathAux.isValidClassName(cName)){throw Assertions.codeNotReachable("Invalid name in multiPartStringError:"+cName);}
ms.add(new ExpCore.ClassB.NestedClass(Doc.empty(), C.of(cName), inner,null));
}
ExpCore.ClassB cb=ClassB.membersClass(ms,Position.noInfo,Phase.Coherent);
return cb;
}
}
@SuppressWarnings("serial")
public static class Exception extends L42Throwable{
public String toString() {return "Exception["+ unbox +"]";}
public Exception(Object u){super(u);}
}
@SuppressWarnings("serial")
public static class Return extends L42Throwable{
public String toString() {return "Return["+ unbox +"]";}
public Return(Object u){super(u);}
}
public static class Void implements Revertable{
public static final Void instance=new Void();
public static final Void type=new Void();
@Override
public ExpCore revert() {
return ExpCore.EPath.wrap(Path.Void());
}
}
public static class Any implements Revertable{
public static final Any type=new Any();
@Override
public ExpCore revert() {return ExpCore.EPath.wrap(Path.Any()); }}
public static class Library implements Revertable{
public static final Library type=new Library();
@Override
public ExpCore revert() {return ExpCore.EPath.wrap(Path.Library()); }}
public static interface PhI<T>{
public void commit(T t);
public void addAction(java.util.function.Consumer<T> r);
}
public static interface Revertable{
public static ast.ExpCore doRevert(Object o){
if (o instanceof Revertable){return ((Revertable)o).revert();}
return EncodingHelper.wrapResource(o);
}
public ast.ExpCore revert();
}
public static boolean isValid(Program p,Object res, Object[] xs) {
if(L42.trustPluginsAndFinalProgram){
return true;
}
ExpCore ec0=Revertable.doRevert(res);
List<ExpCore> es=new ArrayList<>();
for(Object o:xs){
es.add(Revertable.doRevert(o));
}
boolean strict=true;
for(ExpCore ec:es){
List<ClassB> cbs = CollectClassBs0.of(ec);
List<Path> ps = CollectPaths0.of(ec);
for(ClassB cb:cbs){
if(!cb.getPhase().subtypeEq(Phase.Typed)){strict=false;}
}
for(Path path:ps){
if(path.isPrimitive()){continue;}
ClassB extracted=p.extractClassB(path);
if(!extracted.getPhase().subtypeEq(Phase.Typed)){strict=false;}
}
}
List<ClassB> cbs = CollectClassBs0.of(ec0);
for(ClassB cb:cbs){
try{
newTypeSystem.TypeSystem.instance().topTypeLib(Phase.Typed,p.evilPush(cb));}
catch(ErrorMessage msg){
System.err.println("__________PLUGIN error identified_________");
throw msg;//to breakpoint here
}
}
return true;
}
public static ExecutorService pluginThreads=Executors.newCachedThreadPool();
public static <T> T block(java.util.function.Supplier<T> p){return p.get();}
public static platformSpecific.javaTranslation.Resources.Void unused=null;
public static interface PlgClosure<Pt,T>{
T apply(Pt plg,Object[] xs);
}
/**
* @param plg plugin instance
* @param cls plugin executor
* @param xs parameters
* @return a safe result, or a safe error, or an non-action exception
*/
public static <Pt,T> T plgExecuteSafe(Program p,Pt plg,PlgClosure<Pt,T> cls,Object ... xs){
T res=null;
try{
res=cls.apply(plg, xs);
if(Resources.isValid(p,res,xs)){return res;}
else{throw Resources.notAct;}
}
catch(Resources.Error errF){
Object errRes = errF.unbox;
if(Resources.isValid(p,errRes,xs)){throw errF;}
else{throw Resources.notAct;}
}
catch(ErrorMessage.PluginActionUndefined undF){throw undF;}
//catch(java.lang.Error |RuntimeException msg){//eclipse debugger can not hande it
catch(AssertionError msg){ throw msg;}
//catch(PathNonExistant msg){throw msg;}//comment this line after testing
//catch(TypeError msg){throw msg;}//comment this line after testing
catch(ErrorMessage msg){
System.out.println("###################RES#############");
System.out.println(res);
System.out.println("################################");
UserLevelError err = ErrorFormatter.formatError(p,msg);
throw Assertions.codeNotReachable("try to make this happen, is it possible? it should mean bug in plugin code\n"+err+"\n---------------\n",msg);
}
catch(NullPointerException msg){throw msg;}
catch(ClassCastException msg){throw msg;}
catch(RuntimeException msg){
//throw Resources.notAct;//will be
throw Assertions.codeNotReachable("try to make this happen, is it possible? it should mean bug in plugin code\n",msg);
}
catch(java.lang.Error msg){
//throw Resources.notAct;//will be
throw Assertions.codeNotReachable("try to make this happen, is it possible? it should mean bug in plugin code\n",msg);
}
catch(Throwable tF){
//throw Resources.notAct;//will be
throw new Error(tF);//To debug
}
}
/*public Object bar(Plugin plg,Object e1, Object e2,Callable<Object> conclE){
return plgExecutor("dbgInfo",null,new Plugin(),
(plF,xsF)->plF.MsumInt32£xn1£xn2(xsF[0],xsF[1]),
conclE,e1,e2);
}*/
public static <Pt,T> T plgExecutor(String plgCall,Program p,Pt plg,PlgClosure<Pt,T> cls,Callable<T> concl, Object ... es){
//System.err.println("Executing now."+plgCall);
Future<T> exe=null;
try{//for finally
while(true){//cycle on another plugin supervision
try{return plgExecuteSafe(p,plg,cls,es);}//call plg
catch(ErrorMessage.PluginActionUndefined und){
int wait=und.getWait();
if(wait<-1){//not call me again: wait until the end and return the result
return justGetResult(concl, exe);
}
//else, we are supervisionating an expression and plg will be called again
if(exe==null){exe=pluginThreads.submit(concl);}
justWait(exe, wait);
}
}
}finally{if(exe!=null){exe.cancel(true);}}
}
public static <T> void justWait(Future<T> exe, int wait){
try{
if(wait!=-1){//timeout
try{exe.get(wait, TimeUnit.MILLISECONDS);}
catch(TimeoutException e){}//loop again
}
else {exe.get();}
}
catch (InterruptedException ie){
Thread.currentThread().interrupt();
throw new Error(ie);
}
catch (ExecutionException ee){
if(ee.getCause() instanceof RuntimeException){
return;
//DO Nothing, just wait//throw (RuntimeException)ee.getCause();
}
throw new Error(ee);
}
}
public static <T> T justGetResult(Callable<T> concl, Future<T> exe){
try{
if(exe!=null){return exe.get();}
return concl.call();
}
catch (InterruptedException ie){
Thread.currentThread().interrupt();
throw new Error(ie);
}
catch (ExecutionException ee){
if(ee.getCause() instanceof RuntimeException){
throw (RuntimeException)ee.getCause();
}
throw new Error(ee);
}
catch (java.lang.Exception exc){
if(exc instanceof RuntimeException){
throw (RuntimeException)exc;
}
throw new Error(exc);
}
}
public static String nameOf(Ast.Type t) {
assert t instanceof NormType:
"";
Path p=((NormType)t).getPath();
return nameOf(p);
}
public static String nameOf(Ast.MethodSelector ms) {
return nameOf(ms.nameToS(),ms.getNames());
}
public static String nameOf(String name, List<String> names) {
String result="M"+name;
for(String x:names){result+="£x"+x;}
return nameOf(result);
}
public static String nameOf(Path path) {
if (path.equals(Path.Any())){return "Object";}
if (path.equals(Path.Library())){return "Object";}
if (path.equals(Path.Void())){return "platformSpecific.javaTranslation.Resources.Void";}
Program p=Resources.getP();
try{ClassB cb=p.extractClassB(path);
if( cb.getPhase().subtypeEq(Phase.Typed) && IsCompiled.of(cb)){ return nameOf(path.outerNumber(),path.getCBar()); }
}catch (ErrorMessage em){}
//return nameOf(path.outerNumber(),path.getCBar());
return "Object";//TODO: boh? new reduction would fix?
}
public static Revertable fromHash(int hash,String path){
return new platformSpecific.javaTranslation.Resources.Revertable(){
public ast.ExpCore revert() {
Program p=getP();
int dept=0;
while(System.identityHashCode(p.top().getP())!=hash){dept++;p=p.pop();}
return ExpCore.EPath.wrap(ast.Ast.Path.parse("This"+dept+path));
}};
}
public static String nameOf(int level, List<Ast.C> cs) {
Program p=Resources.getP();
Position pos=p.get(level).getP();
assert pos!=null;
assert pos!=Position.noInfo;
int hc = System.identityHashCode(pos);//ok, all relevant positions existed together at the same moment.
assert !pos.equals(Position.noInfo);
String res="This"+hc;
//??String res="This"+p.getCb(level).getUniqueId();
//String res="This"+level;
for(Ast.C s:cs){res+="."+s;}
return nameOf(res);
}
public static String nameOf(String s){
s=s.replace(".","£_");
s=s.replace("%","£p");
s=s.replace("#","£h");
return s;
}
public static String name42Of(String javaName){
String s=javaName;
s=s.replace("£_",".");
s=s.replace("£p","%");
s=s.replace("£h","#");
return s;
}
public static void cacheMessage(L42Throwable err) {
String s=extractMessage(err);
L42.messageOfLastTopLevelError=s;
L42.reconstructedStackTrace=extractTrace(err);
}
private static String extractTrace(L42Throwable err){
StackTraceElement[] st = err.getStackTrace();
String result="\n";
for(StackTraceElement si:st){
if(!si.getMethodName().startsWith("M")){continue;}
result+=extractClassName(si.getClassName());
result+=extractMethName(si.getMethodName());
result+="\n";
}
return result;
}
private static String extractMethName(String methodName) {
assert methodName.startsWith("M");
String end=")";
if (!methodName.contains("£x")){end="()";}
methodName=methodName.replaceFirst("£x", "(");
methodName=methodName.replaceAll("£x", ", ");
methodName=name42Of(methodName);
return "."+methodName.substring(1)+end;
}
private static String extractClassName(String className) {
if(className.startsWith("generated.Program42$This0£_")){
className=className.substring(27);
className=className.replace("£_", ".");
className=name42Of(className);
return className;
}
return className;//may be is plugin code?
}
private static String extractMessage(L42Throwable err) {
try{
Object obj=err.unbox;
Method toS = obj.getClass().getMethod("MtoS");
Object s42=toS.invoke(obj);
Method binaryRepr = s42.getClass().getMethod("MbinaryRepr");
Object lib=binaryRepr.invoke(s42);
if( lib instanceof String){return (String)lib;}
ExpCore.ClassB cb=(ExpCore.ClassB)Revertable.doRevert(lib);
return EncodingHelper.ensureExtractStringU(cb);//safer that extracting on lib, if the method return numbers or other stuff
} catch (NoSuchMethodException | SecurityException
| IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
return "";
}
}
}