package org.overture.codegen.vdm2jml.trans;
import java.util.LinkedList;
import java.util.List;
import org.overture.ast.definitions.PDefinition;
import org.overture.ast.statements.ACallStm;
import org.overture.ast.types.AFunctionType;
import org.overture.ast.types.AOperationType;
import org.overture.ast.types.PType;
import org.overture.codegen.ir.SExpIR;
import org.overture.codegen.ir.SStmIR;
import org.overture.codegen.ir.STypeIR;
import org.overture.codegen.ir.SourceNode;
import org.overture.codegen.ir.declarations.ACatchClauseDeclIR;
import org.overture.codegen.ir.declarations.AMethodDeclIR;
import org.overture.codegen.ir.expressions.SVarExpIR;
import org.overture.codegen.ir.statements.ABlockStmIR;
import org.overture.codegen.ir.statements.AMetaStmIR;
import org.overture.codegen.ir.statements.APlainCallStmIR;
import org.overture.codegen.ir.statements.AReturnStmIR;
import org.overture.codegen.ir.statements.ATryStmIR;
import org.overture.codegen.ir.types.AExternalTypeIR;
import org.overture.codegen.traces.StoreAssistant;
import org.overture.codegen.traces.TraceStmBuilder;
import org.overture.codegen.traces.TracesTrans;
public class JmlTraceStmBuilder extends TraceStmBuilder
{
private static final String ASSERTION_ERROR_TYPE = "AssertionError";
private static final String ASSERTION_ERROR_PARAM = "e";
private List<TcExpInfo> tcExpInfo;
public JmlTraceStmBuilder(TracesTrans traceTrans,
String traceEnclosingClass, StoreAssistant storeAssist,
List<TcExpInfo> tcExpInfo)
{
super(traceTrans, traceEnclosingClass, storeAssist);
this.tcExpInfo = tcExpInfo;
}
private AMetaStmIR consTypeCheckExp(SVarExpIR arg, STypeIR formalParamType,
String traceEnclosingClass, StoreAssistant storeAssistant)
{
/**
* Don't do anything with 'tc' yet. Later it will be replaced with a proper dynamic type check
*/
AMetaStmIR tc = new AMetaStmIR();
tcExpInfo.add(new TcExpInfo(arg.getName(), formalParamType, tc, traceEnclosingClass));
return tc;
}
@Override
public AMethodDeclIR consTypeCheckMethod(SStmIR stm)
{
/**
* We don't need to consider the 'ACallObjectExpStmIR' since it only appears in the IR if we code generate a PP
* or RT model
*/
if (!(stm instanceof APlainCallStmIR))
{
return null;
}
APlainCallStmIR call = (APlainCallStmIR) stm;
if (call.getArgs().isEmpty())
{
// Nothing to type check
return null;
}
List<STypeIR> argTypes = null;
SourceNode source = call.getSourceNode();
if (source != null)
{
org.overture.ast.node.INode vdmNode = source.getVdmNode();
if (vdmNode instanceof ACallStm)
{
ACallStm callStm = (ACallStm) vdmNode;
PDefinition def = callStm.getRootdef();
PType type = def.getType();
List<PType> vdmArgTypes = null;
if (type instanceof AOperationType)
{
vdmArgTypes = ((AOperationType) type).getParameters();
;
} else if (type instanceof AFunctionType)
{
vdmArgTypes = ((AFunctionType) type).getParameters();
}
if (vdmArgTypes != null)
{
argTypes = new LinkedList<>();
for (PType t : vdmArgTypes)
{
try
{
argTypes.add(t.apply(traceTrans.getTransAssist().getInfo().getTypeVisitor(), traceTrans.getTransAssist().getInfo()));
} catch (org.overture.ast.analysis.AnalysisException e)
{
argTypes = null;
e.printStackTrace();
}
}
}
}
}
if (argTypes == null)
{
log.error("Could not find argument types for call statement: "
+ call);
return null;
}
if (argTypes.size() != call.getArgs().size())
{
log.error("Argument types and arguments do not match");
return null;
}
ABlockStmIR methodBody = new ABlockStmIR();
ATryStmIR tryStm = new ATryStmIR();
methodBody.getStatements().add(tryStm);
ABlockStmIR tryBody = new ABlockStmIR();
tryStm.setStm(tryBody);
tryStm.getCatchClauses().add(consTcFailHandling());
// Construct a body on the form
// try {
// //@ azzert tc(arg1));
// ...
// //@ azzert tc(argN));
// } catch(AssertionError e) { return false; }
// return true;
for (int i = 0; i < call.getArgs().size(); i++)
{
SExpIR a = call.getArgs().get(i);
if (a instanceof SVarExpIR)
{
AMetaStmIR tc = consTypeCheckExp((SVarExpIR) a, argTypes.get(i), traceEnclosingClass, storeAssistant);
tryBody.getStatements().add(tc);
} else
{
log.error("Expected argument to be a variable expression by now. Got: "
+ a);
}
}
// If we make it to end of the method it means that the arguments type checked successfully
AReturnStmIR retTrue = new AReturnStmIR();
retTrue.setExp(traceTrans.getTransAssist().getInfo().getExpAssistant().consBoolLiteral(true));
methodBody.getStatements().add(retTrue);
AMethodDeclIR typeCheckMethod = initPredDecl(traceTrans.getTracePrefixes().callStmIsTypeCorrectNamePrefix());
typeCheckMethod.setBody(methodBody);
return typeCheckMethod;
}
private ACatchClauseDeclIR consTcFailHandling()
{
AExternalTypeIR externalType = new AExternalTypeIR();
externalType.setName(ASSERTION_ERROR_TYPE);
ACatchClauseDeclIR catchClause = new ACatchClauseDeclIR();
catchClause.setType(externalType);
catchClause.setName(ASSERTION_ERROR_PARAM);
AReturnStmIR retFalse = new AReturnStmIR();
retFalse.setExp(traceTrans.getTransAssist().getInfo().getExpAssistant().consBoolLiteral(false));
catchClause.setStm(retFalse);
return catchClause;
}
}