package driver;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
import files.BackedRequire;
import compiler.PostParser;
import compiler.java.CompiledClass;
import compiler.java.DynamicJavaCompiler;
import compiler.java.MemoryClassLoader;
import compiler.java.StringJavaFileObject;
import parser.Match;
import util.FileUtils;
/**
* Using an ordered list of source files as input, compiles everything and
* ensures that the framework's products are placed at the appropriate location.
*/
public class CompilationDriver
{
/*****************************************************************************
* @see {@link CompilationDriver}
*/
public static void drive(List<SourceFile> files)
{
new CompilationDriver().run(files);
}
/****************************************************************************/
private static final PostParser postParser = new PostParser();
/****************************************************************************/
private static final DynamicJavaCompiler compiler = DynamicJavaCompiler.get();
/****************************************************************************/
private void run(List<SourceFile> files)
{
for (SourceFile file : files)
{
Context.get().currentFile = file;
enableRequiredMacros(file);
String code = expandFile(file);
/* Macros defined in the file are compiled during the parse, via
* callbacks. This is needed because subsequent macros in the file might
* use macros defined earlier. The callback will also add the macro to
* $file. See {@link grammar.java.CallbacksMacroDefinition}. */
if (!file.isMacro() && file.isCompileTimeDependency())
{
List<CompiledClass> classes = compileFile(file, code);
dumpAndOrLoadClasses(classes);
}
if (!file.isMacro() || Config.get().dumpMacroSource) {
writeGeneratedSource(file, code);
}
disableMacros(file);
}
Context.get().currentFile = null;
}
/*****************************************************************************
* Returns the macro-expansion of $file.
*/
private String expandFile(SourceFile file)
{
Match match = file.parser().parse();
return postParser.run(match).originalString();
}
/*****************************************************************************
* Returns the compiled classes for the classes defined in $code, which should
* be the result of macro-expanding the code from $file. $file should not be a
* macro file.
*/
private List<CompiledClass> compileFile(SourceFile file, String code)
{
return
compiler.compile(new StringJavaFileObject(file.path(), code));
}
/****************************************************************************/
public static void dumpAndOrLoadClasses(List<CompiledClass> classes)
{
dumpAndOrLoadClasses(classes, MemoryClassLoader.get(),
Config.get().targetDir(), true, Config.get().cache());
}
/******************************************************************************
* Load $classes with $classLoader if $load, write them in $targetDir if $dump.
*/
public static void dumpAndOrLoadClasses(List<CompiledClass> classes,
MemoryClassLoader loader, Path targetDir, boolean load, boolean dump)
{
for (CompiledClass klass : classes) {
dumpAndOrLoadClass(klass, loader, targetDir, load, dump);
}
}
/****************************************************************************/
public static void dumpAndOrLoadClass(CompiledClass klass)
{
dumpAndOrLoadClass(klass, MemoryClassLoader.get(),
Config.get().targetDir(), true, Config.get().cache());
}
/****************************************************************************/
public static void dumpAndOrLoadClass(CompiledClass klass,
MemoryClassLoader loader, Path targetDir, boolean load, boolean dump)
{
if (load) { klass.load(loader); }
if (dump) { klass.dump(targetDir); }
}
/****************************************************************************/
private void writeGeneratedSource(SourceFile file, String code)
{
File dest = Config.get().generatedSrcDir()
.resolve(file.path().relativePath()).toFile();
FileUtils.write(dest, code);
}
/****************************************************************************/
private void enableRequiredMacros(SourceFile file)
{
for (BackedRequire bReq : file.requires().get()) {
bReq.enableRequiredMacros();
}
}
/****************************************************************************/
private void disableRequiredMacros(SourceFile file)
{
for (BackedRequire bReq : file.requires().get()) {
bReq.disableRequiredMacros();
}
}
/*****************************************************************************
* Disable the macros required by $file, and defined by it.
*/
private void disableMacros(SourceFile file)
{
file.disableMacros();
disableRequiredMacros(file);
}
}