package platformSpecific.fakeInternet;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.IntStream;
import ast.Ast;
import ast.ErrorMessage;
import ast.ExpCore;
import ast.Ast.Doc;
import ast.Ast.Mdf;
import ast.Ast.NormType;
import ast.Ast.Path;
import ast.ExpCore.Using;
import auxiliaryGrammar.EncodingHelper;
import auxiliaryGrammar.Functions;
import facade.PData;
import platformSpecific.javaTranslation.Resources;
import programReduction.Program;
import tools.Assertions;
import tools.Map;
import tools.StringBuilders;
public class PluginWithPart implements PluginType{
public final String url;
public final String part;
public final Class<?>pointed;
public PluginWithPart(String url, String part) {
super();
this.url = url;
this.part = part;
try {
this.pointed=Class.forName(part);
}
catch (ExceptionInInitializerError e) {
e.printStackTrace();
throw e;
}
catch (ClassNotFoundException e) {
throw new ErrorMessage.InvalidURL(url+"\n"+part,null);
}
}
public List<NormType> typeOf(Program p, Using u){
List<NormType> res=new ArrayList<>();
UsingInfo ui=new UsingInfo(p,u);
if(ui.methOrKs==null){ res.add(jTo42(Void.TYPE));}
else{
if(ui.methOrKs instanceof Constructor){
res.add(jTo42(ui.plgInfo.plgClass));
}
if(ui.methOrKs instanceof Method){
res.add(jTo42(((Method)ui.methOrKs).getReturnType()));
}
}
if (!ui.staticMethod) {res.add(jTo42(ui.plgInfo.plgClass));}
for(String t :ui.names)
res.add(jTo42(t));
return res;
}
private static ast.Ast.NormType jTo42(Class<?> jt){
if (jt.equals(Void.TYPE)){return NormType.immVoid;}
if (jt.equals(ast.Ast.Path.class)){return NormType.classAny;}
return NormType.immLibrary;
}
private static ast.Ast.NormType jTo42(String jt){
jt=jt.substring(1);
jt=jt.substring(jt.indexOf("_"));
if (jt.equals("_ast%Ast$Path")){
return NormType.classAny;
}
return NormType.immLibrary;
}
public Object execute(Program p, Using u){
assert false: "is this not called with compilation?";
//rest of implementation is wrong
Method method = ProtectedPluginType.getMethod(pointed, p, u.getS().nameToS(), u.getS().getNames().size(),u);
List<ExpCore> es = u.getEs();
ExpCore rec=null;
if ((method.getModifiers() & Modifier.STATIC) == 0) {
rec=es.get(0);
es=es.subList(1,es.size());
}
return ProtectedPluginType.executeMethod(method, p, rec, es.toArray());
}
public static class PlgInfo{
public String plgString;
public String plgName;
public Class<?> plgClass;
public PlgInfo(Doc doc){
plgString=doc._getParameterForPlugin();
plgString=plgString.trim();
plgName=doc._getParameterForPluginPart();
plgName=plgName.trim();
try{plgClass=Class.forName(plgName);}
catch(ClassNotFoundException|SecurityException e){
throw Assertions.codeNotReachable();
}
}
}
public static class UsingInfo{
public boolean staticMethod=false;
public List<String> names;// avoiding _this, just the parameter names, encoding java types
public String jMethName=null;//can also be new for constructors and instanceof
public boolean needPData=false;//is using.ms.m starts with #
public List<String> ts=new ArrayList<>();//types as javaCanonicalNames
public List<Class<?>>jts=new ArrayList<>();
//assert names.size()==ts.size(), but jts.size()==ts.size() or ts.size()+1 if needPData
public Object methOrKs=null;//will stay null for instanceof
public boolean isVoid=false;
public PlgInfo plgInfo;
public Ast.MethodSelector usingMs;
public UsingInfo(PlgInfo pi,Method m){
plgInfo=pi;
methOrKs=m;
isVoid=m.getReturnType().equals(Void.TYPE);
staticMethod=Modifier.isStatic(m.getModifiers());
jMethName=m.getName();
jts.addAll(Arrays.asList(m.getParameterTypes()));
commonInit();
}
private void commonInit() {
names=new ArrayList<>();
List<Class<?>> jtsNoPData = jts;
needPData=false;
if(!jts.isEmpty() && jts.get(0).equals(PData.class)){jtsNoPData.remove(0);needPData=true;}
if(!staticMethod){names.add("_this");}
{int i=0;for(Class<?> jt:jtsNoPData){i++;//Ok, we star at 1 for first parameter
String t=jt.getCanonicalName();
ts.add(t);
String name=EncodingHelper.javaClassToX(i,jt.getName());
names.add(name);
}}
assert names!=null;
usingMs=Ast.MethodSelector.of(needPData?"#"+jMethName:jMethName, names);
}
public UsingInfo(PlgInfo pi,Constructor<?> m){
plgInfo=pi;
methOrKs=m;
isVoid=false;
staticMethod=true;
jMethName="new";
jts.addAll(Arrays.asList(m.getParameterTypes()));
commonInit();
}
public UsingInfo(Program p,Using s){
usingMs=s.getS();
plgInfo=new PlgInfo(p.extractClassB(s.getPath()).getDoc1());
if(usingMs.nameToS().equals("instanceof")){
assert usingMs.getNames().size()==1 && usingMs.getNames().get(0).equals("_this");
//TODO: better error message?
names=Collections.emptyList();
jMethName="instanceof";
isVoid=true;//expression executed if instanceOf is True
return;
}
names = s.getS().getNames();
staticMethod=true;
if(!names.isEmpty() && names.get(0).equals("_this")){
staticMethod=false;
names=names.subList(1,names.size());
}
jMethName=s.getS().nameToS();
needPData=jMethName.startsWith("#");
if(needPData){jMethName=jMethName.substring(1);}
for(String n:names){
String t=EncodingHelper.xToJavaClass(n);
Class<?>tClass;
tClass = tToClass(t);
ts.add(tClass.getCanonicalName());//t has $ for nestedclasses, canonicalname have . instead
jts.add(tClass);
}
if(needPData){
jts.add(0,PData.class);
}
if(jMethName.equals("new")){
assert this.staticMethod;
try{methOrKs=plgInfo.plgClass.getDeclaredConstructor(jts.toArray(new Class<?>[0]));}
catch(NoSuchMethodException e){
throw new Error(e);
}
}
else{
Method m;
try{m=Class.forName(plgInfo.plgName).getMethod(jMethName, jts.toArray(new Class<?>[0]));}
catch(ClassNotFoundException|NoSuchMethodException|SecurityException e){throw Assertions.codeNotReachable();}
isVoid=m.getReturnType().equals(Void.TYPE);
methOrKs=m;
}
}
private Class<?> tToClass(String t) {
switch(t){
case "byte":return byte.class;
case "short":return short.class;
case "int":return int.class;
case "long":return long.class;
case "float":return float.class;
case "double":return double.class;
case "char":return char.class;
case "boolean":return boolean.class;
}
try {return Class.forName(t);}
catch (ClassNotFoundException e) { throw new Error(e); }
}
}
@Override
public String executableJ(Program p,Using s,String te,List<String>tes,Set<String> labels){
UsingInfo ui=new UsingInfo(p,s);
if (ui.methOrKs==null){return executableInstanceof(ui,s,te,tes,labels);}
//if static meth tes=e1..en, parRec=null, rec=plgName
//else tes=e0..en, parRec=e0, rec=plF //that is, e1..en do not contains the first of tes
//if Meth par1 of type PData opt=`Resources.pData(),`
//else opt=``
String parRec="null";
if(!ui.staticMethod){
parRec=tes.get(0);
tes=tes.subList(1,tes.size());
}
String opt="";
if(ui.needPData){
opt="platformSpecific.javaTranslation.Resources.pData(),";
}
StringBuilder res=new StringBuilder();
//plgExecutor("`PathName`",p,(plgName)`parRec`,
res.append("platformSpecific.javaTranslation.Resources.plgExecutor(");
res.append("\""+s.getS().nameToS()+"\",");
res.append("platformSpecific.javaTranslation.Resources.getP(), ");
res.append("("+ui.plgInfo.plgClass.getCanonicalName()+")"+parRec+", ");
//(plF,xsF)->{ `T1` _1;..`Tn` _n;
String plF="L"+Functions.freshName("pl",labels);
String trF="L"+Functions.freshName("tr",labels);
String xsF="L"+Functions.freshName("xs",labels);
res.append("("+plF+","+xsF+")->{\n");
{int i=0;for(String t:ui.ts){i++;
res.append(t+" _"+i+";\n");
}}
// try{_1=(`T1`)xsF[0];.._n=(`Tn`)xsF[n-1];}
res.append("try{\n");
{int i=0;for(String t:ui.ts){i++;
if(t.equals("ast.Ast.Path")){
res.append("_"+i+"=auxiliaryGrammar.EncodingHelper.ensureExtractPathFromJava("+xsF+"["+(i-1)+"]);\n");
}
else {
res.append("_"+i+"=("+t+")"+xsF+"["+(i-1)+"];\n");
}
}}
res.append("}\n");
// catch(ClassCastException cce){assert false; throw DoNotAct;}
res.append("catch(ClassCastException cce){assert false:\"\"+cce+java.util.Arrays.asList("+ xsF+");throw platformSpecific.javaTranslation.Resources.notAct;}");
// return plgName.name(`opt` _1,..,_n);
res.append("\n try{\n");
if(!ui.isVoid){res.append("return ");}
if(ui.methOrKs instanceof Method){
if(ui.staticMethod){
res.append(ui.plgInfo.plgClass.getCanonicalName()+"."+ui.jMethName+"("+opt);
}
else{
res.append(plF+"."+ui.jMethName+"("+opt);
}
}
else{
res.append("new "+ui.plgInfo.plgClass.getCanonicalName()+"("+opt);
}
StringBuilders.formatSequence(res,
IntStream.range(1, ui.ts.size()+1).iterator(),
", ",i->res.append("_"+i));
res.append(");\n");
if(ui.isVoid){res.append("return platformSpecific.javaTranslation.Resources.Void.instance;\n");}
res.append("}catch(Throwable "+trF+
"){throw new platformSpecific.javaTranslation.Resources.Error("+trF+");}"
+ "},()->");
// },
//()->`te`,`te1`,..,`ten`);
res.append(te);
for(String t:tes){res.append(", "+t);}
res.append(")");
return res.toString();
}
private String executableInstanceof(UsingInfo ui, Using s, String te, List<String> tes, Set<String> labels) {
String path=ui.plgInfo.plgClass.getCanonicalName();
String plF="L"+Functions.freshName("pl",labels);
String xsF="L"+Functions.freshName("xs",labels);
//plgExecutor("instanceofPath",p,obj,
// (plF,empty)->{ if (plF instanceof Path){throw Resources.notAct;}
// return Resources.Void.instance;}
// ,()->e);
return "platformSpecific.javaTranslation.Resources.plgExecutor("
+ "\"instanceof "+path+"\",platformSpecific.javaTranslation.Resources.getP(),"
+ "(Object)"+tes.get(0)+" ,"
+ "("+plF+","+xsF+")->{ if ("+plF+" instanceof "+path+"){throw platformSpecific.javaTranslation.Resources.notAct;}"
+ "return platformSpecific.javaTranslation.Resources.Void.instance;}"
+ ",()->"+te+")"
;
}
}