package org.overture.codegen.trans;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
import org.overture.codegen.ir.IRConstants;
import org.overture.codegen.ir.IRInfo;
import org.overture.codegen.ir.PIR;
import org.overture.codegen.ir.SDeclIR;
import org.overture.codegen.ir.SExpIR;
import org.overture.codegen.ir.SImportIR;
import org.overture.codegen.ir.analysis.AnalysisException;
import org.overture.codegen.ir.analysis.DepthFirstAnalysisAdaptor;
import org.overture.codegen.ir.declarations.AAllImportIR;
import org.overture.codegen.ir.declarations.ADefaultClassDeclIR;
import org.overture.codegen.ir.declarations.AFieldDeclIR;
import org.overture.codegen.ir.declarations.AFromModuleImportsIR;
import org.overture.codegen.ir.declarations.AFuncDeclIR;
import org.overture.codegen.ir.declarations.AFunctionValueImportIR;
import org.overture.codegen.ir.declarations.AMethodDeclIR;
import org.overture.codegen.ir.declarations.AModuleDeclIR;
import org.overture.codegen.ir.declarations.AModuleImportsIR;
import org.overture.codegen.ir.declarations.ANamedTraceDeclIR;
import org.overture.codegen.ir.declarations.AOperationValueImportIR;
import org.overture.codegen.ir.declarations.ARecordDeclIR;
import org.overture.codegen.ir.declarations.AStateDeclIR;
import org.overture.codegen.ir.declarations.ATypeDeclIR;
import org.overture.codegen.ir.declarations.ATypeImportIR;
import org.overture.codegen.ir.declarations.AValueValueImportIR;
import org.overture.codegen.ir.expressions.AEqualsBinaryExpIR;
import org.overture.codegen.ir.expressions.ANewExpIR;
import org.overture.codegen.ir.expressions.AUndefinedExpIR;
import org.overture.codegen.ir.name.ATypeNameIR;
import org.overture.codegen.ir.types.ARecordTypeIR;
import org.overture.codegen.trans.assistants.TransAssistantIR;
public class ModuleToClassTransformation extends DepthFirstAnalysisAdaptor
implements ITotalTransformation
{
private ADefaultClassDeclIR clazz = null;
private IRInfo info;
private TransAssistantIR transAssistant;
private List<AModuleDeclIR> allModules;
private Logger log = Logger.getLogger(this.getClass().getName());
public ModuleToClassTransformation(IRInfo info,
TransAssistantIR transAssistant, List<AModuleDeclIR> allModules)
{
this.info = info;
this.transAssistant = transAssistant;
this.allModules = allModules;
}
@Override
public void caseAModuleDeclIR(AModuleDeclIR node) throws AnalysisException
{
clazz = new ADefaultClassDeclIR();
clazz.setSourceNode(node.getSourceNode());
clazz.setAccess(IRConstants.PUBLIC);
clazz.setName(node.getName());
// Prevent instantiation of the class
AMethodDeclIR privConstructor = info.getDeclAssistant().consDefaultContructor(node.getName());
privConstructor.setAccess(IRConstants.PRIVATE);
clazz.getMethods().add(privConstructor);
makeStateAccessExplicit(node);
handleImports(node.getImport(), clazz);
// Wrap declarations in a new list to avoid a concurrent modifications
// exception when moving the module declarations to the class
for (SDeclIR decl : new LinkedList<>(node.getDecls()))
{
if (decl instanceof AMethodDeclIR)
{
AMethodDeclIR method = (AMethodDeclIR) decl;
method.setAccess(IRConstants.PUBLIC);
method.setStatic(true);
clazz.getMethods().add(method);
} else if (decl instanceof AFuncDeclIR)
{
// Functions are static by definition
AFuncDeclIR func = (AFuncDeclIR) decl;
func.setAccess(IRConstants.PUBLIC);
clazz.getFunctions().add(func);
} else if (decl instanceof ATypeDeclIR)
{
ATypeDeclIR typeDecl = (ATypeDeclIR) decl;
typeDecl.setAccess(IRConstants.PUBLIC);
clazz.getTypeDecls().add(typeDecl);
} else if (decl instanceof AStateDeclIR)
{
// Handle this as the last thing since it may depend on value definitions
continue;
} else if (decl instanceof ANamedTraceDeclIR)
{
clazz.getTraces().add((ANamedTraceDeclIR) decl);
} else if (decl instanceof AFieldDeclIR)
{
AFieldDeclIR field = (AFieldDeclIR) decl;
field.setAccess(IRConstants.PUBLIC);
field.setStatic(true);
clazz.getFields().add(field);
} else
{
log.error("Got unexpected declaration: " + decl);
}
}
AStateDeclIR stateDecl = getStateDecl(node);
if (stateDecl != null)
{
ARecordDeclIR record = new ARecordDeclIR();
record.setSourceNode(stateDecl.getSourceNode());
record.setName(stateDecl.getName());
if (stateDecl.getInvDecl() != null)
{
// The state invariant constrains the type of the state
// see https://github.com/overturetool/overture/issues/459
record.setInvariant(stateDecl.getInvDecl().clone());
}
for (AFieldDeclIR field : stateDecl.getFields())
{
record.getFields().add(field.clone());
}
ATypeDeclIR typeDecl = new ATypeDeclIR();
typeDecl.setAccess(IRConstants.PUBLIC);
typeDecl.setDecl(record);
clazz.getTypeDecls().add(typeDecl);
ATypeNameIR typeName = new ATypeNameIR();
typeName.setName(stateDecl.getName());
typeName.setDefiningClass(clazz.getName());
ARecordTypeIR stateType = new ARecordTypeIR();
stateType.setName(typeName);
// The state field can't be final since you are allow to assign to it in
// VDM-SL, e.g. St := mk_St(...)
clazz.getFields().add(transAssistant.consField(IRConstants.PRIVATE, stateType, stateDecl.getName(), getInitExp(stateDecl)));
}
info.removeModule(node.getName());
info.addClass(clazz);
}
private void handleImports(final AModuleImportsIR moduleImports,
final ADefaultClassDeclIR clazz) throws AnalysisException
{
// name = moduleImports.getName();
if (moduleImports == null)
{
return;
}
for (AFromModuleImportsIR fromImports : moduleImports.getImports())
{
// String fromName = fromImports.getName();
for (List<SImportIR> sig : fromImports.getSignatures())
{
for (SImportIR imp : sig)
{
// TODO Implement the import analysis cases
imp.apply(new DepthFirstAnalysisAdaptor()
{
@Override
public void caseAAllImportIR(AAllImportIR node)
throws AnalysisException
{
}
@Override
public void caseATypeImportIR(ATypeImportIR node)
throws AnalysisException
{
}
@Override
public void caseAFunctionValueImportIR(
AFunctionValueImportIR node)
throws AnalysisException
{
}
@Override
public void caseAOperationValueImportIR(
AOperationValueImportIR node)
throws AnalysisException
{
}
@Override
public void caseAValueValueImportIR(
AValueValueImportIR node)
throws AnalysisException
{
/*
* String renamed = node.getRenamed(); if (renamed != null) { //STypeIR impType =
* node.getImportType(); String from = node.getFromModuleName(); String name =
* node.getName(); AFieldDeclIR impFieldCopy = getValue(name, from).clone();
* impFieldCopy.setAccess(IRConstants.PUBLIC); impFieldCopy.setName(renamed);
* clazz.getFields().add(impFieldCopy);
* //clazz.getFields().add(transAssistant.consConstField(access, type, fromName, initExp));
* }
*/
}
});
}
}
}
}
private void makeStateAccessExplicit(final AModuleDeclIR module)
throws AnalysisException
{
final AStateDeclIR stateDecl = getStateDecl(module);
if (stateDecl == null)
{
// Nothing to do
return;
}
module.apply(new SlStateAccessTrans(stateDecl, info, transAssistant));
}
public AStateDeclIR getStateDecl(AModuleDeclIR module)
{
for (SDeclIR decl : module.getDecls())
{
if (decl instanceof AStateDeclIR)
{
return (AStateDeclIR) decl;
}
}
return null;
}
private SExpIR getInitExp(AStateDeclIR stateDecl)
{
if (stateDecl.getInitExp() instanceof AEqualsBinaryExpIR)
{
AEqualsBinaryExpIR eqExp = (AEqualsBinaryExpIR) stateDecl.getInitExp();
return eqExp.getRight().clone();
} else
{
ANewExpIR defaultRecInit = new ANewExpIR();
defaultRecInit.setName(transAssistant.getTypeName(stateDecl));
defaultRecInit.setType(transAssistant.getRecType(stateDecl));
for (int i = 0; i < stateDecl.getFields().size(); i++)
{
defaultRecInit.getArgs().add(new AUndefinedExpIR());
}
return defaultRecInit;
}
}
@SuppressWarnings("unused")
private AFieldDeclIR getValue(String fieldName, String moduleName)
{
for (AModuleDeclIR module : allModules)
{
if (module.getName().equals(moduleName))
{
for (SDeclIR decl : module.getDecls())
{
if (decl instanceof AFieldDeclIR)
{
AFieldDeclIR fieldDecl = (AFieldDeclIR) decl;
if (fieldDecl.getName().equals(fieldName))
{
return fieldDecl;
}
}
}
}
}
log.error("Could not find field " + fieldName + " in module "
+ moduleName);
return null;
}
@Override
public PIR getResult()
{
return clazz;
}
}