package org.overture.codegen.trans;
import org.apache.log4j.Logger;
import org.overture.ast.definitions.AExplicitFunctionDefinition;
import org.overture.ast.node.INode;
import org.overture.codegen.ir.SDeclIR;
import org.overture.codegen.ir.SExpIR;
import org.overture.codegen.ir.SourceNode;
import org.overture.codegen.ir.analysis.AnalysisException;
import org.overture.codegen.ir.analysis.DepthFirstAnalysisAdaptor;
import org.overture.codegen.ir.declarations.AMethodDeclIR;
import org.overture.codegen.ir.declarations.AVarDeclIR;
import org.overture.codegen.ir.expressions.AApplyExpIR;
import org.overture.codegen.ir.expressions.AIdentifierVarExpIR;
import org.overture.codegen.ir.expressions.AStringLiteralExpIR;
import org.overture.codegen.ir.statements.ABlockStmIR;
import org.overture.codegen.ir.statements.AReturnStmIR;
import org.overture.codegen.trans.assistants.TransAssistantIR;
public class PostCheckTrans extends DepthFirstAnalysisAdaptor
{
private IPostCheckCreator postCheckCreator;
private TransAssistantIR transAssistant;
private String funcResultNamePrefix;
private Object conditionalCallTag;
private Logger log = Logger.getLogger(this.getClass().getName());
public PostCheckTrans(IPostCheckCreator postCheckCreator,
TransAssistantIR transAssistant, String funcResultNamePrefix,
Object conditionalCallTag)
{
this.postCheckCreator = postCheckCreator;
this.transAssistant = transAssistant;
this.funcResultNamePrefix = funcResultNamePrefix;
this.conditionalCallTag = conditionalCallTag;
}
@Override
public void caseAMethodDeclIR(AMethodDeclIR node) throws AnalysisException
{
if (!transAssistant.getInfo().getSettings().generatePostCondChecks())
{
return;
}
SDeclIR postCond = node.getPostCond();
if (postCond == null)
{
return;
}
if (!(postCond instanceof AMethodDeclIR))
{
log.error("Expected post condition to be a method declaration at this point. Got: "
+ postCond);
return;
}
SourceNode sourceNode = postCond.getSourceNode();
if (sourceNode == null)
{
log.error("Could not find source node for method declaration");
return;
}
INode vdmNode = sourceNode.getVdmNode();
if (vdmNode == null)
{
log.error("Could not find VDM source node for method declaration");
return;
}
if (!(vdmNode instanceof AExplicitFunctionDefinition))
{
// Generation of post conditions is not supported for operations
return;
}
node.getBody().apply(this);
}
@Override
public void caseAReturnStmIR(AReturnStmIR node) throws AnalysisException
{
SExpIR result = node.getExp();
if (result == null)
{
log.error("Expected a value to be returned");
return;
}
AMethodDeclIR method = node.getAncestor(AMethodDeclIR.class);
if (method == null)
{
log.error("Could not find enclosing method for a return statement");
return;
}
if (method.getStatic() == null || !method.getStatic())
{
// Generation of a post condition is only supported for static operations
// where no 'self' and '~self' are being passed
return;
}
SDeclIR postCond = method.getPostCond();
if (!(postCond instanceof AMethodDeclIR))
{
log.error("Expected post condition to be a method declaration at this point. Got: "
+ postCond);
return;
}
AApplyExpIR postCondCall = transAssistant.consConditionalCall(method, (AMethodDeclIR) method.getPostCond());
postCondCall.setTag(conditionalCallTag);
String funcResultVarName = transAssistant.getInfo().getTempVarNameGen().nextVarName(funcResultNamePrefix);
AVarDeclIR resultDecl = transAssistant.consDecl(funcResultVarName, method.getMethodType().getResult().clone(), node.getExp().clone());
AIdentifierVarExpIR resultVar = transAssistant.getInfo().getExpAssistant().consIdVar(funcResultVarName, resultDecl.getType().clone());
postCondCall.getArgs().add(resultVar.clone());
AStringLiteralExpIR methodName = transAssistant.getInfo().getExpAssistant().consStringLiteral(method.getName(), false);
AApplyExpIR postCheckCall = postCheckCreator.consPostCheckCall(method, postCondCall, resultVar, methodName);
ABlockStmIR replacementBlock = new ABlockStmIR();
replacementBlock.getLocalDefs().add(resultDecl);
transAssistant.replaceNodeWith(node.getExp(), postCheckCall);
transAssistant.replaceNodeWith(node, replacementBlock);
replacementBlock.getStatements().add(node);
}
}