All Downloads are FREE. Search and download functionalities are using the official Maven repository.

prompto.compiler.PromptoClassLoader Maven / Gradle / Ivy

The newest version!
package prompto.compiler;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Paths;

import prompto.config.TempDirectories;
import prompto.error.SyntaxError;
import prompto.runtime.Context;
import prompto.runtime.Mode;
import prompto.utils.Logger;

/* a class loader which is able to create and store classes for prompto objects */
public class PromptoClassLoader extends URLClassLoader {
	
	static final Logger logger = new Logger();

	private static ClassLoader getParentClassLoader() {
		return PromptoClassLoader.class.getClassLoader();
	}

	private static URL[] makeClassesDirURLs() {
		File classesDir = TempDirectories.getJavaClassesDir();
		try {
			URL[] urls = { classesDir.toURI().toURL() };
			return urls;
		} catch (MalformedURLException e) {
			throw new RuntimeException(e);
		}
	}
	
	private static PromptoClassLoader instance = null;
	
	/* during testing, multiple threads may refer to different paths */
	private static Boolean testMode;
	private static ThreadLocal testInstance;
	public static PromptoClassLoader getInstance() {
		return instance!=null ? instance : testInstance == null ? null : testInstance.get();
	}
	
	public static PromptoClassLoader initialize(Context context) {
		return initialize(context, Mode.get()==Mode.UNITTEST);
	}
	
	public static PromptoClassLoader initialize(Context context, boolean testMode) {
		synchronized(PromptoClassLoader.class) {
			if(PromptoClassLoader.testMode==null)
				PromptoClassLoader.testMode = testMode;
			boolean currentMode = PromptoClassLoader.testMode;
			if(currentMode!=testMode)
				throw new UnsupportedOperationException("Cannot run test mode and regular mode in parallel!");
			if(testMode) {
				if(testInstance==null)
					testInstance = new ThreadLocal<>();
				testInstance.set(new PromptoClassLoader(context));
				return testInstance.get();
			} else {
				if(instance!=null)
					throw new UnsupportedOperationException("Can only have one PromptoClassLoader!");
				instance = new PromptoClassLoader(context);
				return instance;
			}
		}
	}

	public static void uninitialize() {
		synchronized(PromptoClassLoader.class) {
			if(PromptoClassLoader.testMode==null)
				return;
			if(PromptoClassLoader.testMode)
				testInstance = null;
			else
				instance = null;
		}		
	}
	
	Context context;
	
	private PromptoClassLoader(Context context) {
		super(makeClassesDirURLs(), getParentClassLoader());
		this.context = context;
	}
	
	public Context getContext() {
		return context;
	}
	
	public void setContext(Context context) {
		this.context = context;
	}
	
	File getClassDir() throws Exception {
		return Paths.get(getURLs()[0].toURI()).toFile();
	}

	@Override
	public Class findClass(String fullName) throws ClassNotFoundException {
		try {
			return super.findClass(fullName);
		} catch (ClassNotFoundException e) {
			// is this a Prompto class ?
			if(fullName.charAt(0)=='π') { 
				try {
					createPromptoClass(fullName);
					return super.findClass(fullName);
				} catch (Throwable t) {
					t = extractSyntaxError(t);
					logger.error(()->"Compilation of " + fullName + " failed. Check: " +  TempDirectories.getJavaClassesDir().getAbsolutePath(), t);
					throw new ClassNotFoundException(fullName, t);
				}
			} else
				throw e;
		}
	}

	private void createPromptoClass(String fullName) throws Exception {
		File classDir = getClassDir();
		// logger.debug(()->"Compiling " + fullName + " @ " + classDir.toString());
		// System.err.println("Compiling " + fullName + " @ " + classDir.toString());
		Compiler compiler = new Compiler(classDir); // where to store .class
		compiler.compileClass(context.getGlobalsContext(), fullName);
	}

	private Throwable extractSyntaxError(Throwable t) {
		Throwable s = t;
		while(s!=null) {
			if(s instanceof SyntaxError)
				return s;
			if(s==s.getCause())
				break;
			s = s.getCause();
		} 
		return t;
	}
	

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy