/*
* #%~
* VDM Code Generator
* %%
* Copyright (C) 2008 - 2014 Overture
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #~%
*/
package org.overture.codegen.vdm2cpp;
import java.io.File;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.overture.ast.analysis.AnalysisException;
import org.overture.ast.definitions.PDefinition;
import org.overture.ast.definitions.SClassDefinition;
import org.overture.ast.definitions.SFunctionDefinition;
import org.overture.ast.definitions.SOperationDefinition;
import org.overture.ast.expressions.ANotYetSpecifiedExp;
import org.overture.ast.expressions.PExp;
import org.overture.ast.node.INode;
import org.overture.ast.statements.ANotYetSpecifiedStm;
import org.overture.codegen.analysis.violations.InvalidNamesResult;
import org.overture.codegen.analysis.violations.UnsupportedModelingException;
import org.overture.codegen.analysis.violations.VdmAstAnalysis;
import org.overture.codegen.analysis.violations.Violation;
import org.overture.codegen.assistant.DeclAssistantCG;
import org.overture.codegen.cgast.SExpCG;
import org.overture.codegen.cgast.analysis.DepthFirstAnalysisAdaptor;
import org.overture.codegen.cgast.declarations.AClassDeclCG;
import org.overture.codegen.ir.CodeGenBase;
import org.overture.codegen.ir.IRStatus;
import org.overture.codegen.ir.IrNodeInfo;
import org.overture.codegen.logging.Logger;
import org.overture.codegen.trans.assistants.TransAssistantCG;
import org.overture.codegen.trans.funcvalues.FunctionValueAssistant;
import org.overture.codegen.utils.Generated;
import org.overture.codegen.utils.GeneratedData;
import org.overture.codegen.utils.GeneratedModule;
import org.overture.codegen.vdm2cpp.timing.inserter.TimingInjectorVisitor;
import org.overture.codegen.vdm2cpp.timing.inserter.TimingMainCreator;
import org.overture.codegen.vdm2cpp.vdmtools.CGGenHelper;
public class CppCodeGen extends CodeGenBase
{
// public static final String[] RESERVED_TYPE_NAMES = {
// // Classes used from the Java standard library
// "Utils", "Record", "Long", "Double", "Character", "String", "List",
// "Set" };
String generator_type;
boolean generate_timing;
public CppCodeGen(String gen_type,boolean gen_timing)
{
super();
generator_type = gen_type;
generate_timing = gen_timing;
init();
}
private void init()
{
this.transAssistant = new TransAssistantCG(generator.getIRInfo(), varPrefixes);
}
public List<GeneratedModule> generateJavaFromVdmQuotes()
{
return null;
}
public GeneratedData generateCppFromVdm(
List<SClassDefinition> mergedParseLists) throws AnalysisException,
UnsupportedModelingException
{
for (SClassDefinition classDef : mergedParseLists)
{
if (generator.getIRInfo().getAssistantManager().getDeclAssistant().isLibrary(classDef))
{
simplifyLibraryClass(classDef);
}
}
InvalidNamesResult invalidNamesResult = validateVdmModelNames(mergedParseLists);
validateVdmModelingConstructs(mergedParseLists);
List<IRStatus<AClassDeclCG>> statuses = new ArrayList<IRStatus<AClassDeclCG>>();
for (SClassDefinition classDef : mergedParseLists)
{
statuses.add((IRStatus)generator.generateFrom(classDef));
}
List<AClassDeclCG> classes = getClassDecls(statuses);
//javaFormat.setClasses(classes);
LinkedList<IRStatus<AClassDeclCG>> canBeGenerated = new LinkedList<IRStatus<AClassDeclCG>>();
List<GeneratedModule> generated = new ArrayList<GeneratedModule>();
for (IRStatus<AClassDeclCG> status : statuses)
{
if (status.canBeGenerated())
{
canBeGenerated.add(status);
} else
{
generated.add(new GeneratedModule(status.getIrNodeName(), status.getUnsupportedInIr(), new HashSet<IrNodeInfo>()));
}
}
FunctionValueAssistant functionValueAssistant = new FunctionValueAssistant();
DepthFirstAnalysisAdaptor[] analyses = null;
if(generator_type.toLowerCase().equals("stdlib"))
{
analyses = new CppStdLibTransSeries(this).consAnalyses(classes, functionValueAssistant);
}
else
{
analyses = new CppVdmtoolsTransSeries(this).consAnalyses(classes, functionValueAssistant);
}
for (DepthFirstAnalysisAdaptor transformation : analyses)
{
for (IRStatus<AClassDeclCG> status : canBeGenerated)
{
try
{
AClassDeclCG classCg = status.getIrNode();
classCg.apply(transformation);
} catch (org.overture.codegen.cgast.analysis.AnalysisException e)
{
Logger.getLog().printErrorln("Error when generating code for class "
+ status.getIrNodeName() + ": " + e.getMessage());
Logger.getLog().printErrorln("Skipping class..");
e.printStackTrace();
}
}
}
List<String> skipping = new LinkedList<String>();
TypeHierarchyAnalyser tan = new TypeHierarchyAnalyser();
for (IRStatus<AClassDeclCG> status : canBeGenerated) {
AClassDeclCG cls = status.getIrNode();
try {
cls.apply(tan);
} catch (org.overture.codegen.cgast.analysis.AnalysisException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
XtendAnswerStringVisitor mergeVisitor = null;
CGGenHelper helper = null;
if(generator_type.toLowerCase().equals("stdlib"))
{
mergeVisitor = new CGcppstdlib(tan);
}
else
{
mergeVisitor = new CGvdmtools(tan);
helper = new CGGenHelper();
}
//CGNew mergeVisitor = new CGNew(tan);
TimingInjectorVisitor timing = new TimingInjectorVisitor();
//FunctionValueAssistant functionValue = funcValueTransformation.getFunctionValueAssistant();
//javaFormat.setFunctionValueAssistant(functionValue);
for (IRStatus<AClassDeclCG> status : canBeGenerated)
{
StringWriter writer = new StringWriter();
AClassDeclCG classCg = status.getIrNode();
String className = status.getIrNodeName();
try
{
SClassDefinition vdmClass = (SClassDefinition) status.getIrNode().getSourceNode().getVdmNode();
if (shouldBeGenerated(vdmClass, generator.getIRInfo().getAssistantManager().getDeclAssistant()))
{
// classCg.apply(mergeVisitor, writer);
//
// if (mergeVisitor.hasMergeErrors())
// {
// generated.add(new GeneratedModule(className, classCg, mergeVisitor.getMergeErrors()));
// }
//
// TODO: In the Java code generator the mergeVisitor keeps track of nodes that
// unsupported by the backend. These can be transferred to the generated module
//
//else if(mergeVisitor.hasUnsupportedTargLangNodes())
//{
// generated.add(new GeneratedModule(className, new HashSet<VdmNodeInfo>(), mergeVisitor.getUnsupportedInTargLang()));
//}
// else
// {
// String formattedJavaCode = writer.toString();
// generated.add(new GeneratedModule(className, classCg, formattedJavaCode));
// }
if(generate_timing)
{
classCg.apply(timing);
}
String code = classCg.apply(mergeVisitor);
if(helper != null)
{
helper.addClass(classCg);
}
generated.add(new GeneratedModule(className,classCg,code));
}
else
{
if (!skipping.contains(vdmClass.getName().getName()))
{
skipping.add(vdmClass.getName().getName());
}
}
} catch (org.overture.codegen.cgast.analysis.AnalysisException e)
{
Logger.getLog().printErrorln("Error generating code for class "
+ status.getIrNodeName() + ": " + e.getMessage());
Logger.getLog().printErrorln("Skipping class..");
e.printStackTrace();
}
}
if(helper != null)
{
generated.add(new GeneratedModule("CGBase",null,(String) helper.GenerateHelper()));
}
if(generate_timing)
{
System.out.println(TimingMainCreator.generateMainMethod( timing.getRegisteredMethods()));
}
// List<AInterfaceDeclCG> funcValueInterfaces = functionValue.getFunctionValueInterfaces();
//
// for (AInterfaceDeclCG funcValueInterface : funcValueInterfaces)
// {
// StringWriter writer = new StringWriter();
//
// try
// {
// funcValueInterface.apply(mergeVisitor, writer);
// //String formattedJavaCode = JavaCodeGenUtil.formatJavaCode(writer.toString());
// generated.add(new GeneratedModule(funcValueInterface.getName(), funcValueInterface, formattedJavaCode));
//
// } catch (org.overture.codegen.cgast.analysis.AnalysisException e)
// {
// Logger.getLog().printErrorln("Error generating code for function value interface "
// + funcValueInterface.getName() + ": " + e.getMessage());
// Logger.getLog().printErrorln("Skipping interface..");
// e.printStackTrace();
// }
// }
//javaFormat.clearFunctionValueAssistant();
//javaFormat.clearClasses();
return new GeneratedData(generated, generateJavaFromVdmQuotes(), invalidNamesResult, skipping);
}
private void simplifyLibraryClass(SClassDefinition classDef)
{
for (PDefinition def : classDef.getDefinitions())
{
if (def instanceof SOperationDefinition)
{
SOperationDefinition op = (SOperationDefinition) def;
op.setBody(new ANotYetSpecifiedStm());
op.setPrecondition(null);
op.setPostcondition(null);
}
else if (def instanceof SFunctionDefinition)
{
SFunctionDefinition func = (SFunctionDefinition) def;
func.setBody(new ANotYetSpecifiedExp());
func.setPrecondition(null);
func.setPostcondition(null);
}
}
}
private List<AClassDeclCG> getClassDecls(List<IRStatus<AClassDeclCG>> statuses)
{
List<AClassDeclCG> classDecls = new LinkedList<AClassDeclCG>();
for (IRStatus<AClassDeclCG> status : statuses)
{
AClassDeclCG classCg = status.getIrNode();
if (classCg != null)
{
classDecls.add(classCg);
}
}
return classDecls;
}
public Generated generateCppFromVdmExp(PExp exp) throws AnalysisException
{
// There is no name validation here.
IRStatus<SExpCG> expStatus = generator.generateFrom(exp);
try
{
SExpCG expCg = expStatus.getIrNode();
if (expStatus.canBeGenerated())
{
//javaFormat.init();
CGvdmtools mergeVisitor = new CGvdmtools();//vdm2cppGen(null,null,null);//javaFormat.getMergeVisitor();
return new Generated(expCg.apply(mergeVisitor));
//if (mergeVisitor.hasMergeErrors())
//{
// return new Generated(mergeVisitor.getMergeErrors());
//}
//
// TODO: In the Java code generator the mergeVisitor keeps track of nodes that
// unsupported by the backend. These can be transferred to the generated module
//
//else if(mergeVisitor.hasUnsupportedTargLangNodes())
//{
// generated.add(new GeneratedModule(className, new HashSet<VdmNodeInfo>(), mergeVisitor.getUnsupportedInTargLang()));
//}
//else
//{
// String code = writer.toString();
// return new Generated(code);
//}
} else
{
return new Generated(expStatus.getUnsupportedInIr(), new HashSet<IrNodeInfo>());
}
} catch (org.overture.codegen.cgast.analysis.AnalysisException e)
{
Logger.getLog().printErrorln("Could not generate expression: "
+ exp);
e.printStackTrace();
return null;
}
}
public void generateJavaSourceFile(File outputFolder,
GeneratedModule generatedModule)
{
if (generatedModule != null && generatedModule.canBeGenerated()
&& !generatedModule.hasMergeErrors())
{
//JavaCodeGenUtil.saveJavaClass(outputFolder, generatedModule.getName()
// + IJavaCodeGenConstants.JAVA_FILE_EXTENSION, generatedModule.getContent());
}
}
public void generateJavaSourceFiles(File outputFolder,
List<GeneratedModule> generatedClasses)
{
for (GeneratedModule classCg : generatedClasses)
{
generateJavaSourceFile(outputFolder, classCg);
}
}
private InvalidNamesResult validateVdmModelNames(
List<SClassDefinition> mergedParseLists) throws AnalysisException
{
//AssistantManager assistantManager = generator.getIRInfo().getAssistantManager();
//VdmAstAnalysis analysis = new VdmAstAnalysis(assistantManager);
//Set<Violation> reservedWordViolations = analysis.usesIllegalNames(mergedParseLists, new ReservedWordsComparison(IJavaCodeGenConstants.RESERVED_WORDS, irInfo, INVALID_NAME_PREFIX));
//Set<Violation> typenameViolations = analysis.usesIllegalNames(mergedParseLists, new TypenameComparison(RESERVED_TYPE_NAMES, generator.getIRInfo(), INVALID_NAME_PREFIX));
//String[] generatedTempVarNames = GeneralUtils.concat(IRConstants.GENERATED_TEMP_NAMES, varPrefixes.GENERATED_TEMP_NAMES);
//Set<Violation> tempVarViolations = analysis.usesIllegalNames(mergedParseLists, new GeneratedVarComparison(generatedTempVarNames, generator.getIRInfo(), INVALID_NAME_PREFIX));
// if (!reservedWordViolations.isEmpty() || !typenameViolations.isEmpty()
// || !tempVarViolations.isEmpty())
// {
// return new InvalidNamesResult(reservedWordViolations, typenameViolations, tempVarViolations, INVALID_NAME_PREFIX);
// } else
// {
return new InvalidNamesResult();
// }
}
private void validateVdmModelingConstructs(
List<? extends INode> mergedParseLists) throws AnalysisException,
UnsupportedModelingException
{
VdmAstAnalysis analysis = new VdmAstAnalysis(generator.getIRInfo().getAssistantManager());
Set<Violation> violations = analysis.usesUnsupportedModelingConstructs(mergedParseLists);
if (!violations.isEmpty())
{
throw new UnsupportedModelingException("The model uses modeling constructs that are not supported for Java code Generation", violations);
}
}
private boolean shouldBeGenerated(SClassDefinition classDef,
DeclAssistantCG declAssistant)
{
if (declAssistant.isLibrary(classDef))
{
return false;
}
// String name = classDef.getName().getName();
//
// if(getJavaSettings().getClassesToSkip().contains(name))
// {
// return false;
// }
// for (SClassDefinition superDef : classDef.getSuperDefs())
// {
// if (declAssistant.classIsLibrary(superDef))
// {
// return false;
// }
// }
return true;
}
}