package facade;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
import org.antlr.v4.runtime.misc.ParseCancellationException;
import coreVisitors.CloneVisitor;
import coreVisitors.InjectionOnSugar;
import profiling.Timer;
import programReduction.ProgramReduction;
import sugarVisitors.CollapsePositions;
import sugarVisitors.CollectDeclaredClassNamesAndMethodNames;
import sugarVisitors.Desugar;
import sugarVisitors.InjectionOnCore;
import sugarVisitors.ToFormattedText;
import tools.Assertions;
import tools.StringBuilders;
import ast.Ast;
import ast.Ast.Position;
import ast.ErrorMessage;
import ast.ExpCore;
import ast.ErrorMessage.FinalResult;
import ast.ExpCore.ClassB;
import ast.ExpCore.ClassB.Member;
import ast.ExpCore.ClassB.MethodWithType;
import ast.Expression;
public class L42 {
public static enum ExecutionStage{None,Reading,Parsing,CheckingWellFormedness,Desugaring,MetaExecution,Closing;}
private static ExecutionStage _stage=ExecutionStage.None;
public static boolean profilerPrintOn=true;
private static void setExecutionStage(ExecutionStage newStage){
System.out.println(newStage);
if(_stage!=ExecutionStage.None){
Timer.deactivate(_stage.toString());
}
if(newStage!=ExecutionStage.None){
Timer.activate(newStage.toString());
}
_stage=newStage;
}
private static long privateNum=0L;
public synchronized static long freshPrivate(){privateNum+=1L;return privateNum;}
public synchronized static void setFreshPrivateCap(long cap){
privateNum=Math.max(privateNum, cap);
}
public synchronized static void resetFreshPrivate(){//for testing
privateNum=0L;
}
public static ExecutionStage getStage(){return _stage;}
public static int compilationRounds=0;
public static boolean trustPluginsAndFinalProgram=true;
public static StringBuilder record=new StringBuilder();
public static String messageOfLastTopLevelError="";
public static String reconstructedStackTrace="";
public static String[] programArgs=null;
public static List<URL> pluginPaths=null;
public static final Set<String> usedNames=new HashSet<String>();
public static void printDebug(String s){
record.append(s);
record.append("\n");
System.err.println(s);
}
private static void setClassPath(Path p) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
assert Files.isDirectory(p);
List<URL> fileNames = new ArrayList<>();
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(p)){
for (Path path : directoryStream) {
fileNames.add(path.toUri().toURL());
}
}
catch (IOException ex) {
Assertions.codeNotReachable(""+ex);
}
//System.out.println(fileNames);
L42.pluginPaths=fileNames;
URLClassLoader loader= (URLClassLoader) ClassLoader.getSystemClassLoader();
Method method= URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class });
method.setAccessible(true);
for(URL url:fileNames){
method.invoke(loader, new Object[] { url });
}
}
public static void main(String [] arg) throws IOException, InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
//assert false;
setClassPath(Paths.get("Plugins"));
L42.programArgs=arg;
try{
Configuration.loadAll();
Path path = Paths.get(arg[arg.length-1]);
String code=null;
if(Files.isDirectory(path)){
L42.setRootPath(path);
code=L42.pathToString(path.resolve("This.L42"));
}
else {
L42.setRootPath(path.getParent());
code=L42.pathToString(path);
}
FinalResult res = L42.runSlow(path.toString(),code);
System.out.println("------------------------------");
System.out.println("END (zero for success): "+res.getErrCode());
}
catch(ParseCancellationException parser){
System.out.println(parser.getMessage());
//parser.printStackTrace(System.out);
}
catch(ErrorMessage msg){
ErrorFormatter.topFormatErrorMessage(msg);
}
finally{
if (L42.profilerPrintOn){
System.out.print(Timer.report());
}
}
}
public static String pathToString(Path p) {
StringBuffer b=new StringBuffer();
try (Stream<String> lines = Files.lines(p)) {
lines.forEach((l)->{b.append("\n");b.append(l);});
b.append("\n");
return b.toString();
}
catch (IOException e) {throw new Error(e);}
}
public static int runSlow(Path p) throws IOException{
try{
L42.setExecutionStage(ExecutionStage.Reading);
String code=pathToString(p);
throw runSlow(p.toString(),code);}
catch(ErrorMessage.FinalResult e){return e.getErrCode();}
catch(ErrorMessage e){
int result= -1*e.getClass().getCanonicalName().hashCode();
assert result<0;
return result;
}
}
public static void finalErr(ClassB result,String s){
throw new ErrorMessage.MalformedFinalResult(result, s);
}
public static ErrorMessage.FinalResult checkFinalError(ClassB result){
L42.setExecutionStage(ExecutionStage.Closing);
ClassB.NestedClass last=(ClassB.NestedClass)result.getMs().get(result.getMs().size()-1);
if(!(last.getInner() instanceof ClassB)){finalErr(result,"The last class can not be completed");}
ClassB lastC=(ClassB)last.getInner();
//TODO: booh what is the right kind? if(!(lastC.getH() instanceof Ast.TraitHeader)){finalErr(result,"The last class is not a Trait");}
if(!lastC.getMs().isEmpty()){finalErr(result,"The last class contains members");}
String errCode=lastC.getDoc1().toString();
if(!errCode.startsWith("@exitStatus\n")){
finalErr(result,"The last class is not an exitStatus class:"+errCode);
}
errCode=errCode.substring("@exitStatus\n".length());
int errCodeInt=0;
try{errCodeInt=Integer.parseInt(errCode.substring(0,errCode.length()-1));}
catch(NumberFormatException e){finalErr(result,"The exitStatus is not a valid number: "+errCode);}
if(errCodeInt>0 && errCodeInt<100){finalErr(result,"The exitStatus is reserved: "+errCodeInt);}
return new ErrorMessage.FinalResult(errCodeInt,result);
}
public static ErrorMessage.FinalResult runSlow(String fileName,String code){
try{
L42.setExecutionStage(ExecutionStage.Parsing);
Expression code1=Parser.parse(fileName,code);
assert code1 instanceof Expression.ClassB || code1 instanceof Expression.ClassReuse;
L42.setExecutionStage(ExecutionStage.CheckingWellFormedness);
auxiliaryGrammar.WellFormedness.checkAll(code1);
L42.setExecutionStage(ExecutionStage.Desugaring);
Expression code2=Desugar.of(code1);
assert auxiliaryGrammar.WellFormedness.checkAll(code2);
ExpCore.ClassB code3=(ExpCore.ClassB)code2.accept(new InjectionOnCore());
assert coreVisitors.CheckNoVarDeclaredTwice.of(code3);
// L42.usedNames.addAll(CollectDeclaredVarsAndCheckNoDeclaredTwice.of(code2));
//L42.usedNames.addAll(CollectDeclaredClassNamesAndMethodNames.of(code2));
L42.setExecutionStage(ExecutionStage.MetaExecution);
//ClassB result= (ClassB)Executor.stepStar(exe,code3);
//Refresh of position identities, it is used to generate correct Java code.
code3=(ClassB)code3.accept(new CloneVisitor(){
@Override public ExpCore visit(ClassB cb){
Position p=cb.getP();
cb=cb.withP(new Position(p.getFile(),p.getLine1(),p.getPos1(),p.getLine2(),p.getPos2(),p.get_next()));
return super.visit(cb);
}
});
//ClassB result= Configuration.reduction.of(code3);
ClassB result= ProgramReduction.allSteps(code3);
//System.out.println("--------------------------");
//System.out.println(ToFormattedText.of(result));
//System.out.println("--------------------------");
return checkFinalError(result);
}finally{L42.setExecutionStage(ExecutionStage.None);}
}
public static Path path;
public static void setRootPath(Path path) {
L42.path=path;
}
}