package org.overture.codegen.mojocg;
import java.io.File;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.overture.ast.analysis.AnalysisException;
import org.overture.ast.definitions.SClassDefinition;
import org.overture.ast.lex.Dialect;
import org.overture.ast.modules.AModuleModules;
import org.overture.codegen.ir.CodeGenBase;
import org.overture.codegen.ir.IRSettings;
import org.overture.codegen.mojocg.util.DelegateTrans;
import org.overture.codegen.printer.DefaultConsolePrinter;
import org.overture.codegen.utils.GeneralCodeGenUtils;
import org.overture.codegen.utils.GeneralUtils;
import org.overture.codegen.utils.GeneratedData;
import org.overture.codegen.vdm2java.JavaCodeGen;
import org.overture.codegen.vdm2java.JavaCodeGenMain;
import org.overture.codegen.vdm2java.JavaCodeGenUtil;
import org.overture.codegen.vdm2java.JavaSettings;
import org.overture.config.Release;
import org.overture.config.Settings;
import org.overture.typechecker.util.TypeCheckerUtil;
import org.overture.typechecker.util.TypeCheckerUtil.TypeCheckResult;
/**
* VDM-to-Java code generator mojo
*
* @goal generate
* @phase generate-sources
* @requiresDependencyResolution compile
*/
public class Vdm2JavaMojo extends Vdm2JavaBaseMojo
{
public static final String VDM_PP = "pp";
public static final String VDM_SL = "sl";
public static final String VDM_RT = "rt";
public static final String VDM_10 = "vdm10";
public static final String VDM_CLASSIC = "classic";
@Override
public void execute() throws MojoExecutionException, MojoFailureException
{
if (!verbose)
{
DefaultConsolePrinter.getDefaultLogger().setSilent(true);
}
if (outputDirectory != null && outputDirectory.exists())
{
getLog().info(String.format("Skipping Java code generation. Output folder '%s' already exists.", outputDirectory.getAbsolutePath()));
return;
}
getLog().info("Starting the VDM-to-Java code generator...");
// Let's make sure that maven knows to look in the output directory
project.addCompileSourceRoot(outputDirectory.getPath());
IRSettings irSettings = new IRSettings();
irSettings.setCharSeqAsString(true);
irSettings.setGeneratePreConds(false);
irSettings.setGeneratePreCondChecks(false);
irSettings.setGeneratePostConds(false);
irSettings.setGeneratePostCondChecks(false);
irSettings.setGenerateConc(genConcurrency);
JavaSettings javaSettings = new JavaSettings();
javaSettings.setDisableCloning(false);
javaSettings.setFormatCode(formatCode);
javaSettings.setGenJUnit4tests(genJUnit4Tests);
javaSettings.setPrintVdmLocations(printVdmLocations);
if(modulesToSkip != null && !modulesToSkip.isEmpty())
{
javaSettings.setModulesToSkip(modulesToSkip);
}
if (JavaCodeGenUtil.isValidJavaPackage(packageName))
{
javaSettings.setJavaRootPackage(packageName);
} else
{
if (packageName != null)
{
getLog().warn(String.format("%s is not a valid Java package.", packageName));
}
}
List<File> files = new LinkedList<File>();
if (specificationDir != null && specificationDir.isDirectory())
{
findVdmSources(files, specificationDir);
}
if (files == null || files.isEmpty())
{
getLog().info("Nothing to generate, no specification files.");
return;
}
outputDirectory.mkdirs();
List<File> tmp = new Vector<File>();
tmp.addAll(files);
if (release.equals(VDM_10))
{
Settings.release = Release.VDM_10;
} else if (release.equals(VDM_CLASSIC))
{
Settings.release = Release.CLASSIC;
} else
{
throw new MojoFailureException(String.format("Expected VDM version to be '%s' or '%s'", VDM_10, VDM_CLASSIC));
}
JavaCodeGen javaCodeGen = new JavaCodeGen();
javaCodeGen.setSettings(irSettings);
javaCodeGen.setJavaSettings(javaSettings);
addDelegateTrans(javaCodeGen);
GeneratedData genData = null;
if (dialect.equals(VDM_PP))
{
Settings.dialect = Dialect.VDM_PP;
TypeCheckResult<List<SClassDefinition>> tcResult = TypeCheckerUtil.typeCheckPp(files);
validateTcResult(tcResult);
try
{
genData = javaCodeGen.generate(CodeGenBase.getNodes(tcResult.result));
} catch (AnalysisException e)
{
e.printStackTrace();
throw new MojoExecutionException("Got unexpected error when trying to code generate VDM++ model: "
+ e.getMessage());
}
} else if (dialect.equals(VDM_SL))
{
Settings.dialect = Dialect.VDM_SL;
TypeCheckResult<List<AModuleModules>> tcResult = TypeCheckerUtil.typeCheckSl(files);
validateTcResult(tcResult);
try
{
genData = javaCodeGen.generate(CodeGenBase.getNodes(tcResult.result));
} catch (AnalysisException e)
{
e.printStackTrace();
throw new MojoExecutionException("Got unexpected error when trying to code generate VDM-SL model: "
+ e.getMessage());
}
} else if (dialect.equals(VDM_RT))
{
try
{
Settings.dialect = Dialect.VDM_RT;
TypeCheckResult<List<SClassDefinition>> tcResult = TypeCheckerUtil.typeCheckRt(files);
validateTcResult(tcResult);
javaSettings.setMakeClassesSerializable(true);
genData = javaCodeGen.generate(CodeGenBase.getNodes(tcResult.result));
} catch (AnalysisException e)
{
e.printStackTrace();
throw new MojoExecutionException("Got unexpected error when trying to code generate VDM-RT model: "
+ e.getMessage());
}
} else
{
throw new MojoExecutionException(String.format("Expected dialect to be '%s' or '%s'", VDM_SL, VDM_PP));
}
if (genData != null)
{
JavaCodeGenMain.processData(false, outputDirectory, javaCodeGen, genData, separateTestCode);
if (genData.hasErrors())
{
throw new MojoExecutionException("Could not code generate model.");
}
}
getLog().info("Code generation completed.");
}
private Map<String, String> buidDelegateMap()
{
if (delegates == null)
{
return new HashMap<>();
}
Map<String, String> map = new HashMap<String, String>();
for (String key : delegates.stringPropertyNames())
{
map.put(key, delegates.getProperty(key));
}
return map;
}
private void addDelegateTrans(JavaCodeGen javaCodeGen)
{
if (delegates != null && !delegates.isEmpty())
{
Map<String, String> delegateMap = buidDelegateMap();
getLog().debug("Found following bridge/delegate pairs:");
for (String entry : delegateMap.keySet())
{
getLog().debug(" Bridge class: " + entry + ". Delegate class: "
+ delegateMap.get(entry));
}
javaCodeGen.getTransSeries().getSeries().add(new DelegateTrans(delegateMap, javaCodeGen.getTransAssistant(), getLog()));
}
}
private void findVdmSources(List<File> files, File specificationRoot)
{
for (File f : GeneralUtils.getFilesRecursively(specificationRoot))
{
if (GeneralCodeGenUtils.isVdmSourceFile(f))
{
files.add(f);
}
}
}
private void validateTcResult(TypeCheckResult<?> tcResult)
throws MojoExecutionException
{
if (!tcResult.parserResult.errors.isEmpty()
|| !tcResult.errors.isEmpty())
{
String PARSE_TYPE_CHECK_ERR_MSG = "Could not parse or type check VDM model";
getLog().error(PARSE_TYPE_CHECK_ERR_MSG + ":\n"
+ GeneralCodeGenUtils.errorStr(tcResult));
throw new MojoExecutionException(PARSE_TYPE_CHECK_ERR_MSG);
}
// No type errors
}
}