package org.overture.codegen.traces;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import org.overture.ast.definitions.SFunctionDefinition;
import org.overture.ast.definitions.SOperationDefinition;
import org.overture.ast.lex.Dialect;
import org.overture.ast.statements.ACallStm;
import org.overture.codegen.assistant.DeclAssistantIR;
import org.overture.codegen.assistant.ExpAssistantIR;
import org.overture.codegen.ir.INode;
import org.overture.codegen.ir.IRConstants;
import org.overture.codegen.ir.IRInfo;
import org.overture.codegen.ir.SExpIR;
import org.overture.codegen.ir.SStmIR;
import org.overture.codegen.ir.STraceDeclIR;
import org.overture.codegen.ir.STypeIR;
import org.overture.codegen.ir.SourceNode;
import org.overture.codegen.ir.analysis.AnalysisException;
import org.overture.codegen.ir.analysis.AnswerAdaptor;
import org.overture.codegen.ir.analysis.DepthFirstAnalysisAdaptor;
import org.overture.codegen.ir.declarations.AFieldDeclIR;
import org.overture.codegen.ir.declarations.AMethodDeclIR;
import org.overture.codegen.ir.declarations.AVarDeclIR;
import org.overture.codegen.ir.declarations.SClassDeclIR;
import org.overture.codegen.ir.expressions.AAnonymousClassExpIR;
import org.overture.codegen.ir.expressions.AApplyExpIR;
import org.overture.codegen.ir.expressions.ACastUnaryExpIR;
import org.overture.codegen.ir.expressions.AExplicitVarExpIR;
import org.overture.codegen.ir.expressions.AFieldExpIR;
import org.overture.codegen.ir.expressions.AIdentifierVarExpIR;
import org.overture.codegen.ir.expressions.AIntLiteralExpIR;
import org.overture.codegen.ir.expressions.ANewExpIR;
import org.overture.codegen.ir.expressions.ATypeArgExpIR;
import org.overture.codegen.ir.name.ATypeNameIR;
import org.overture.codegen.ir.patterns.AIdentifierPatternIR;
import org.overture.codegen.ir.patterns.ASetMultipleBindIR;
import org.overture.codegen.ir.statements.ABlockStmIR;
import org.overture.codegen.ir.statements.ACallObjectExpStmIR;
import org.overture.codegen.ir.statements.APlainCallStmIR;
import org.overture.codegen.ir.statements.AReturnStmIR;
import org.overture.codegen.ir.statements.ASkipStmIR;
import org.overture.codegen.ir.statements.SCallStmIR;
import org.overture.codegen.ir.traces.AApplyExpTraceCoreDeclIR;
import org.overture.codegen.ir.traces.ABracketedExpTraceCoreDeclIR;
import org.overture.codegen.ir.traces.AConcurrentExpTraceCoreDeclIR;
import org.overture.codegen.ir.traces.ALetBeStBindingTraceDeclIR;
import org.overture.codegen.ir.traces.ALetDefBindingTraceDeclIR;
import org.overture.codegen.ir.traces.ARepeatTraceDeclIR;
import org.overture.codegen.ir.traces.ATraceDeclTermIR;
import org.overture.codegen.ir.types.ABoolBasicTypeIR;
import org.overture.codegen.ir.types.AClassTypeIR;
import org.overture.codegen.ir.types.AExternalTypeIR;
import org.overture.codegen.ir.types.AMethodTypeIR;
import org.overture.codegen.ir.types.AObjectTypeIR;
import org.overture.codegen.ir.types.AVoidTypeIR;
import org.overture.codegen.ir.types.SSetTypeIR;
import org.overture.codegen.trans.assistants.TransAssistantIR;
import org.overture.config.Settings;
public class TraceStmBuilder extends AnswerAdaptor<TraceNodeData>
{
protected String traceEnclosingClass;
protected StoreAssistant storeAssistant;
protected TracesTrans traceTrans;
protected Logger log = Logger.getLogger(this.getClass().getName());
public TraceStmBuilder(TracesTrans traceTrans, String traceEnclosingClass,
StoreAssistant storeAssist)
{
this.traceTrans = traceTrans;
this.traceEnclosingClass = traceEnclosingClass;
this.storeAssistant = storeAssist;
}
public IRInfo getInfo()
{
return getTransAssist().getInfo();
}
@Override
public TraceNodeData caseATraceDeclTermIR(ATraceDeclTermIR node)
throws AnalysisException
{
String name = getInfo().getTempVarNameGen().nextVarName(traceTrans.getTracePrefixes().altTraceNodeNamePrefix());
AClassTypeIR classType = getTransAssist().consClassType(traceTrans.getTracePrefixes().altTraceNodeNodeClassName());
if (node.getTraceDecls().size() == 1)
{
return node.getTraceDecls().getFirst().apply(this);
}
{
AVarDeclIR altTests = getTransAssist().consDecl(name, classType, getTransAssist().consDefaultConsCall(classType));
ABlockStmIR stms = new ABlockStmIR();
stms.getLocalDefs().add(altTests);
List<SStmIR> addStms = new LinkedList<SStmIR>();
for (STraceDeclIR traceDecl : node.getTraceDecls())
{
TraceNodeData nodeData = traceDecl.apply(this);
stms.getStatements().add(nodeData.getStms());
addStms.add(getTransAssist().consInstanceCallStm(classType, name, traceTrans.getTracePrefixes().addMethodName(), nodeData.getNodeVar()));
}
stms.getStatements().addAll(addStms);
return new TraceNodeData(getInfo().getExpAssistant().consIdVar(name, classType.clone()), stms, stms);
}
}
@Override
public TraceNodeData caseAApplyExpTraceCoreDeclIR(
AApplyExpTraceCoreDeclIR node) throws AnalysisException
{
List<AVarDeclIR> argDecls = replaceArgsWithVars(node.getCallStm());
String classTypeName;
if (Settings.dialect != Dialect.VDM_SL)
{
classTypeName = traceTrans.getTracePrefixes().callStmClassTypeName();
} else
{
classTypeName = traceTrans.getTracePrefixes().callStmBaseClassTypeName();
}
AClassTypeIR callStmType = getTransAssist().consClassType(classTypeName);
String callStmName = getInfo().getTempVarNameGen().nextVarName(traceTrans.getTracePrefixes().callStmNamePrefix());
AAnonymousClassExpIR callStmCreation = new AAnonymousClassExpIR();
callStmCreation.setType(callStmType);
AMethodDeclIR typeCheckMethod = consTypeCheckMethod(node.getCallStm().clone());
if (typeCheckMethod != null)
{
callStmCreation.getMethods().add(typeCheckMethod);
}
AMethodDeclIR preCondMethod = condMeetsPreCondMethod(node.getCallStm().clone());
if (preCondMethod != null)
{
callStmCreation.getMethods().add(preCondMethod);
}
callStmCreation.getMethods().add(consExecuteMethod(node.getCallStm().clone()));
callStmCreation.getMethods().add(traceTrans.getToStringBuilder().consToString(getInfo(), node.getCallStm(), storeAssistant.getIdConstNameMap(), storeAssistant, getTransAssist()));
AVarDeclIR callStmDecl = getTransAssist().consDecl(callStmName, callStmType.clone(), callStmCreation);
AClassTypeIR stmTraceNodeType = getTransAssist().consClassType(traceTrans.getTracePrefixes().stmTraceNodeClassName());
ANewExpIR newStmTraceNodeExp = getTransAssist().consDefaultConsCall(stmTraceNodeType);
newStmTraceNodeExp.getArgs().add(getInfo().getExpAssistant().consIdVar(callStmName, callStmType.clone()));
String stmNodeName = getInfo().getTempVarNameGen().nextVarName(traceTrans.getTracePrefixes().stmTraceNodeNamePrefix());
AVarDeclIR stmNodeDecl = getTransAssist().consDecl(stmNodeName, stmTraceNodeType.clone(), newStmTraceNodeExp);
ABlockStmIR decls = new ABlockStmIR();
if (!argDecls.isEmpty())
{
decls.getLocalDefs().addAll(argDecls);
}
decls.getLocalDefs().add(callStmDecl);
decls.getLocalDefs().add(stmNodeDecl);
return new TraceNodeData(getInfo().getExpAssistant().consIdVar(stmNodeName, stmTraceNodeType.clone()), decls, decls);
}
@Override
public TraceNodeData caseABracketedExpTraceCoreDeclIR(
ABracketedExpTraceCoreDeclIR node) throws AnalysisException
{
return buildFromDeclTerms(node.getTerms());
}
@Override
public TraceNodeData caseAConcurrentExpTraceCoreDeclIR(
AConcurrentExpTraceCoreDeclIR node) throws AnalysisException
{
String name = getInfo().getTempVarNameGen().nextVarName(traceTrans.getTracePrefixes().concTraceNodeNamePrefix());
AClassTypeIR classType = getTransAssist().consClassType(traceTrans.getTracePrefixes().concTraceNodeNodeClassName());
AVarDeclIR concNodeDecl = getTransAssist().consDecl(name, classType, getTransAssist().consDefaultConsCall(classType));
ABlockStmIR stms = new ABlockStmIR();
stms.getLocalDefs().add(concNodeDecl);
List<SStmIR> addStms = new LinkedList<SStmIR>();
// The number of declarations is > 1
for (STraceDeclIR term : node.getDecls())
{
TraceNodeData nodeData = term.apply(this);
AIdentifierVarExpIR var = nodeData.getNodeVar();
nodeData.getNodeVarScope().getStatements().add(getTransAssist().consInstanceCallStm(classType, name, traceTrans.getTracePrefixes().addMethodName(), var));
stms.getStatements().add(nodeData.getStms());
}
stms.getStatements().addAll(addStms);
return new TraceNodeData(getInfo().getExpAssistant().consIdVar(name, classType.clone()), stms, stms);
}
@Override
public TraceNodeData caseALetBeStBindingTraceDeclIR(
ALetBeStBindingTraceDeclIR node) throws AnalysisException
{
ASetMultipleBindIR bind = node.getBind();
IdentifierPatternCollector idCollector = new IdentifierPatternCollector();
idCollector.setTopNode(bind);
if (Settings.dialect != Dialect.VDM_SL)
{
List<AIdentifierPatternIR> patterns = idCollector.findOccurences();
for (AIdentifierPatternIR p : patterns)
{
String idConstName = getInfo().getTempVarNameGen().nextVarName(traceTrans.getTracePrefixes().idConstNamePrefix());
storeAssistant.getIdConstNameMap().put(((AIdentifierPatternIR) p).getName(), idConstName);
}
}
String name = getInfo().getTempVarNameGen().nextVarName(traceTrans.getTracePrefixes().altTraceNodeNamePrefix());
AClassTypeIR classType = getTransAssist().consClassType(traceTrans.getTracePrefixes().altTraceNodeNodeClassName());
AIdentifierPatternIR id = getInfo().getPatternAssistant().consIdPattern(name);
AVarDeclIR altTests = getTransAssist().consDecl(name, classType, getTransAssist().consDefaultConsCall(classType));
STraceDeclIR body = node.getBody();
SExpIR exp = node.getStExp();
TraceNodeData bodyTraceData = body.apply(this);
SSetTypeIR setType = getTransAssist().getSetTypeCloned(bind.getSet());
TraceLetBeStStrategy strategy = new TraceLetBeStStrategy(getTransAssist(), exp, setType, traceTrans.getLangIterator(), getInfo().getTempVarNameGen(), traceTrans.getIteVarPrefixes(), storeAssistant, storeAssistant.getIdConstNameMap(), traceTrans.getTracePrefixes(), id, altTests, bodyTraceData, this);
if (getTransAssist().hasEmptySet(bind))
{
getTransAssist().cleanUpBinding(bind);
ABlockStmIR skip = getTransAssist().wrap(new ASkipStmIR());
return new TraceNodeData(null, skip, skip);
}
ABlockStmIR outerBlock = getTransAssist().consIterationBlock(node.getBind().getPatterns(), bind.getSet(), getInfo().getTempVarNameGen(), strategy, traceTrans.getIteVarPrefixes());
return new TraceNodeData(getInfo().getExpAssistant().consIdVar(name, classType.clone()), outerBlock, outerBlock);
}
@Override
public TraceNodeData caseALetDefBindingTraceDeclIR(
ALetDefBindingTraceDeclIR node) throws AnalysisException
{
ABlockStmIR outer = new ABlockStmIR();
outer.setScoped(true);
IdentifierPatternCollector idCollector = new IdentifierPatternCollector();
ABlockStmIR declBlock = new ABlockStmIR();
List<AIdentifierVarExpIR> traceVars = new LinkedList<>();
for (AVarDeclIR dec : node.getLocalDefs())
{
// Find types for all sub patterns
PatternTypeFinder typeFinder = new PatternTypeFinder(getInfo());
dec.getPattern().apply(typeFinder, dec.getType());
idCollector.setTopNode(dec);
List<AIdentifierPatternIR> idOccurences = idCollector.findOccurences();
AVarDeclIR decCopy = dec.clone();
decCopy.setFinal(true);
declBlock.getLocalDefs().add(decCopy);
for (AIdentifierPatternIR occ : idOccurences)
{
if (Settings.dialect != Dialect.VDM_SL)
{
String idConstName = getInfo().getTempVarNameGen().nextVarName(traceTrans.getTracePrefixes().idConstNamePrefix());
storeAssistant.getIdConstNameMap().put(occ.getName(), idConstName);
outer.getLocalDefs().add(storeAssistant.consIdConstDecl(idConstName));
storeAssistant.appendStoreRegStms(declBlock, occ.getName(), idConstName, false);
}
traceVars.add(getInfo().getExpAssistant().consIdVar(occ.getName(), PatternTypeFinder.getType(typeFinder, occ)));
}
}
TraceNodeData bodyNodeData = node.getBody().apply(this);
for (int i = traceVars.size() - 1; i >= 0; i--)
{
AIdentifierVarExpIR a = traceVars.get(i);
ACallObjectExpStmIR addVar = consAddTraceVarCall(bodyNodeData.getNodeVar(), a);
ensureStoreLookups(addVar);
bodyNodeData.getNodeVarScope().getStatements().add(addVar);
}
outer.getStatements().add(declBlock);
outer.getStatements().add(bodyNodeData.getStms());
return new TraceNodeData(bodyNodeData.getNodeVar(), outer, bodyNodeData.getNodeVarScope());
}
@Override
public TraceNodeData caseARepeatTraceDeclIR(ARepeatTraceDeclIR node)
throws AnalysisException
{
Long from = node.getFrom();
Long to = node.getTo();
if (from == 1 && to == 1)
{
return node.getCore().apply(this);
} else
{
String name = getInfo().getTempVarNameGen().nextVarName(traceTrans.getTracePrefixes().repeatTraceNodeNamePrefix());
TraceNodeData traceData = node.getCore().apply(this);
AIdentifierVarExpIR varArg = traceData.getNodeVar();
AIntLiteralExpIR fromArg = getInfo().getExpAssistant().consIntLiteral(from);
AIntLiteralExpIR toArg = getInfo().getExpAssistant().consIntLiteral(to);
AClassTypeIR repeat = getTransAssist().consClassType(traceTrans.getTracePrefixes().repeatTraceNodeNamePrefix());
ABlockStmIR block = new ABlockStmIR();
block.getStatements().add(traceData.getStms());
block.getStatements().add(consDecl(traceTrans.getTracePrefixes().repeatTraceNodeNodeClassName(), name, varArg, fromArg, toArg));
return new TraceNodeData(getInfo().getExpAssistant().consIdVar(name, repeat), block, block);
}
}
/**
* Assumes dialect is VDM-SL. This method does not work with store lookups for local variables and since code
* generated VDM-SL traces do not rely on this then it is safe to use this method for this dialect.
*
* @param callStm
* the call statement for which we want to replace the arguments with variables
* @return the variable declarations corresponding to the variables that replace the arguments
*/
protected List<AVarDeclIR> replaceArgsWithVars(SStmIR callStm)
{
List<AVarDeclIR> decls = new LinkedList<AVarDeclIR>();
if (Settings.dialect != Dialect.VDM_SL)
{
return decls;
}
List<SExpIR> args = null;
if (callStm instanceof SCallStmIR)
{
args = ((SCallStmIR) callStm).getArgs();
} else if (callStm instanceof ACallObjectExpStmIR)
{
args = ((ACallObjectExpStmIR) callStm).getArgs();
} else
{
log.error("Expected a call statement or call object statement. Got: "
+ callStm);
return decls;
}
for (SExpIR arg : args)
{
String argName = getInfo().getTempVarNameGen().nextVarName(traceTrans.getTracePrefixes().callStmArgNamePrefix());
STypeIR type = arg.getType();
AVarDeclIR argDecl = getTransAssist().consDecl(argName, type.clone(), arg.clone());
argDecl.setFinal(true);
decls.add(argDecl);
getTransAssist().replaceNodeWith(arg, getInfo().getExpAssistant().consIdVar(argName, type.clone()));
}
return decls;
}
protected AMethodDeclIR consExecuteMethod(SStmIR stm)
{
AMethodTypeIR methodType = new AMethodTypeIR();
methodType.setResult(new AObjectTypeIR());
AMethodDeclIR execMethod = new AMethodDeclIR();
execMethod.setImplicit(false);
execMethod.setAbstract(false);
execMethod.setAccess(IRConstants.PUBLIC);
execMethod.setAsync(false);
execMethod.setIsConstructor(false);
execMethod.setMethodType(methodType);
execMethod.setName(traceTrans.getTracePrefixes().callStmExecMethodNamePrefix());
execMethod.setStatic(false);
ABlockStmIR body = new ABlockStmIR();
body.getStatements().add(makeInstanceCall(stm));
ensureStoreLookups(body);
execMethod.setBody(body);
return execMethod;
}
protected void ensureStoreLookups(SStmIR body)
{
if (Settings.dialect == Dialect.VDM_SL)
{
return;
}
try
{
final Set<String> localVarNames = storeAssistant.getIdConstNameMap().keySet();
body.apply(new DepthFirstAnalysisAdaptor()
{
// No need to consider explicit variables because they cannot be local
@Override
public void caseAIdentifierVarExpIR(AIdentifierVarExpIR node)
throws AnalysisException
{
if (localVarNames.contains(node.getName()))
{
getTransAssist().replaceNodeWith(node, storeAssistant.consStoreLookup(node));
}
}
});
} catch (AnalysisException e)
{
log.error("Problem replacing variable expressions with storage lookups");
}
}
public TraceNodeData buildFromDeclTerms(List<ATraceDeclTermIR> terms)
throws AnalysisException
{
String name = getInfo().getTempVarNameGen().nextVarName(traceTrans.getTracePrefixes().seqTraceNodeNamePrefix());
AClassTypeIR classType = getTransAssist().consClassType(traceTrans.getTracePrefixes().seqClassTypeName());
AVarDeclIR seqNodeDecl = getTransAssist().consDecl(name, classType, getTransAssist().consDefaultConsCall(classType));
ABlockStmIR stms = new ABlockStmIR();
stms.getLocalDefs().add(seqNodeDecl);
for (ATraceDeclTermIR term : terms)
{
TraceNodeData nodeData = term.apply(this);
stms.getStatements().add(nodeData.getStms());
AIdentifierVarExpIR var = nodeData.getNodeVar();
nodeData.getNodeVarScope().getStatements().add(getTransAssist().consInstanceCallStm(classType, name, traceTrans.getTracePrefixes().addMethodName(), var));
}
return new TraceNodeData(getInfo().getExpAssistant().consIdVar(name, classType.clone()), stms, stms);
}
public AMethodDeclIR consTypeCheckMethod(SStmIR stm)
{
return null;
}
public AMethodDeclIR condMeetsPreCondMethod(SStmIR stm)
{
if (!canBeGenerated())
{
return null;
}
AMethodDeclIR meetsPredMethod = initPredDecl(traceTrans.getTracePrefixes().callStmMeetsPreCondNamePrefix());
boolean isOp = false;
String pre = "pre_";
List<SExpIR> args = null;
if (stm instanceof APlainCallStmIR)
{
APlainCallStmIR plainCall = (APlainCallStmIR) stm;
args = plainCall.getArgs();
SourceNode source = plainCall.getSourceNode();
if (source != null)
{
org.overture.ast.node.INode vdmNode = source.getVdmNode();
if (vdmNode instanceof ACallStm)
{
ACallStm callStm = (ACallStm) vdmNode;
if (callStm.getRootdef() instanceof SOperationDefinition)
{
SOperationDefinition op = (SOperationDefinition) callStm.getRootdef();
if (op.getPredef() == null)
{
// The pre condition is "true"
return null;
}
isOp = true;
} else if (callStm.getRootdef() instanceof SFunctionDefinition)
{
SFunctionDefinition func = (SFunctionDefinition) callStm.getRootdef();
if (func.getPredef() == null)
{
// The pre condition is true
return null;
}
}
} else
{
log.error("Expected VDM source node to be a call statement at this point. Got: "
+ vdmNode);
}
} else
{
log.error("Could not find VDM source node for the plain statement call: "
+ plainCall);
}
plainCall.setName(pre + plainCall.getName());
plainCall.setType(new ABoolBasicTypeIR());
meetsPredMethod.setBody(plainCall);
} else
{
log.error("Got unexpected statement: " + stm);
return null;
}
if (args != null)
{
if (isOp)
{
DeclAssistantIR dAssist = this.getInfo().getDeclAssistant();
String invokedModule = getInvokedModule(stm);
SClassDeclIR clazz = dAssist.findClass(getInfo().getClasses(), invokedModule);
for (AFieldDeclIR f : clazz.getFields())
{
if (!f.getFinal())
{
// It's the state component
if (traceEnclosingClass.equals(invokedModule))
{
ExpAssistantIR eAssist = getInfo().getExpAssistant();
AIdentifierVarExpIR stateArg = eAssist.consIdVar(f.getName(), f.getType().clone());
traceTrans.getCloneFreeNodes().add(stateArg);
args.add(stateArg);
} else
{
AExternalTypeIR traceNodeClassType = new AExternalTypeIR();
traceNodeClassType.setName(traceTrans.getTracePrefixes().traceUtilClassName());
AExplicitVarExpIR readStateMethod = new AExplicitVarExpIR();
readStateMethod.setClassType(traceNodeClassType);
readStateMethod.setIsLambda(false);
readStateMethod.setIsLocal(false);
readStateMethod.setName(traceTrans.getTracePrefixes().readStateMethodName());
AMethodTypeIR readStateMethodType = new AMethodTypeIR();
readStateMethodType.setResult(f.getType().clone());
readStateMethodType.getParams().add(getTransAssist().consClassType(invokedModule));
readStateMethodType.getParams().add(f.getType().clone());
readStateMethod.setType(readStateMethodType);
AApplyExpIR readStateCall = new AApplyExpIR();
readStateCall.setRoot(readStateMethod);
readStateCall.setType(f.getType().clone());
ATypeArgExpIR moduleArg = new ATypeArgExpIR();
moduleArg.setType(getTransAssist().consClassType(invokedModule));
ATypeArgExpIR stateArg = new ATypeArgExpIR();
stateArg.setType(f.getType().clone());
readStateCall.getArgs().add(moduleArg);
readStateCall.getArgs().add(stateArg);
args.add(readStateCall);
}
break;
}
}
}
} else
{
log.error("Could not find args for: " + stm);
}
ensureStoreLookups(meetsPredMethod.getBody());
return meetsPredMethod;
}
protected AMethodDeclIR initPredDecl(String name)
{
AMethodTypeIR methodType = new AMethodTypeIR();
methodType.setResult(new ABoolBasicTypeIR());
AMethodDeclIR meetsPredMethod = new AMethodDeclIR();
meetsPredMethod.setImplicit(false);
meetsPredMethod.setAbstract(false);
meetsPredMethod.setAccess(IRConstants.PUBLIC);
meetsPredMethod.setAsync(false);
meetsPredMethod.setIsConstructor(false);
meetsPredMethod.setMethodType(methodType);
meetsPredMethod.setStatic(false);
meetsPredMethod.setName(name);
return meetsPredMethod;
}
protected boolean canBeGenerated()
{
// This only works for VDM-SL
return Settings.dialect == Dialect.VDM_SL
&& getInfo().getSettings().generatePreConds();
}
protected String getInvokedModule(SStmIR stm)
{
if (stm instanceof APlainCallStmIR)
{
APlainCallStmIR call = (APlainCallStmIR) stm;
STypeIR type = call.getClassType();
if (type instanceof AClassTypeIR)
{
return ((AClassTypeIR) type).getName();
}
}
return traceEnclosingClass;
}
protected SStmIR makeInstanceCall(SStmIR stm)
{
if (stm instanceof ACallObjectExpStmIR)
{
// Assume the class enclosing the trace to be S
// self.op(42) becomes ((S)instance).op(42L)
// a.op(42) remains a.op(42L) if a is local
// a.op(42) becomes ((S)instance).a.op(42L) if a is an instance variable
ACallObjectExpStmIR call = (ACallObjectExpStmIR) stm;
try
{
call.getObj().apply(new CallObjTraceLocalizer(getTransAssist(), traceTrans.getTracePrefixes(), traceEnclosingClass));
} catch (AnalysisException e)
{
log.error("Got unexpected problem when trying to create instance call"
+ e.getMessage());
e.printStackTrace();
}
/**
* We don't narrow the types of the arguments, which we should and which we do for the 'APlainCallStmIR'
* case using <code>castArgs(call);</code>. Code generation of traces does not really work for PP..
*/
if (call.getType() instanceof AVoidTypeIR)
{
return handleVoidValueReturn(call);
}
return stm;
} else if (stm instanceof APlainCallStmIR)
{
// Assume the class enclosing the trace to be S
// Example: op(42) becomes ((S)instance).op(42L)
try
{
return handlePlainCallStm((APlainCallStmIR) stm);
} catch (AnalysisException e)
{
log.error("Got unexpected problem when handling plain call statement: "
+ e.getMessage());
e.printStackTrace();
}
}
// Super call statements are not supported and this case should not be reached!
log.error("Got unexpected statement: " + stm);
return stm;
}
protected SStmIR handleVoidValueReturn(SStmIR stm)
{
AExternalTypeIR traceNodeClassType = new AExternalTypeIR();
traceNodeClassType.setName(traceTrans.getTracePrefixes().voidValueEnclosingClassName());
AExplicitVarExpIR voidValue = new AExplicitVarExpIR();
voidValue.setType(new AObjectTypeIR());
voidValue.setClassType(traceNodeClassType);
voidValue.setIsLambda(false);
voidValue.setIsLocal(true);
voidValue.setName(traceTrans.getTracePrefixes().voidValueFieldName());
AReturnStmIR returnVoidVal = new AReturnStmIR();
returnVoidVal.setExp(voidValue);
ABlockStmIR block = new ABlockStmIR();
block.getStatements().add(stm);
block.getStatements().add(returnVoidVal);
return block;
}
protected SStmIR handlePlainCallStm(APlainCallStmIR callStmIR)
throws AnalysisException
{
STypeIR type = callStmIR.getType();
if (callStmIR.getIsStatic())
{
if (type instanceof AVoidTypeIR)
{
return handleVoidValueReturn(callStmIR);
} else
{
return callStmIR;
}
}
List<SExpIR> args = callStmIR.getArgs();
STypeIR classType = callStmIR.getClassType();
String name = callStmIR.getName();
SourceNode sourceNode = callStmIR.getSourceNode();
AClassTypeIR consClassType = getTransAssist().consClassType(traceEnclosingClass);
ACastUnaryExpIR cast = new ACastUnaryExpIR();
cast.setType(consClassType);
cast.setExp(getInfo().getExpAssistant().consIdVar(traceTrans.getTracePrefixes().callStmMethodParamName(), consClassType.clone()));
if (type instanceof AVoidTypeIR)
{
ACallObjectExpStmIR paramExp = new ACallObjectExpStmIR();
paramExp.setObj(cast);
paramExp.setFieldName(name);
paramExp.setType(type.clone());
for (SExpIR arg : args)
{
paramExp.getArgs().add(arg.clone());
}
paramExp.setSourceNode(sourceNode);
return handleVoidValueReturn(paramExp);
} else
{
AFieldExpIR field = new AFieldExpIR();
String fieldModule = classType instanceof AClassTypeIR
? ((AClassTypeIR) classType).getName()
: traceEnclosingClass;
field.setType(getInfo().getTypeAssistant().getMethodType(getInfo(), fieldModule, name, args));
field.setMemberName(name);
field.setObject(cast);
AApplyExpIR apply = new AApplyExpIR();
apply.setType(type.clone());
apply.setRoot(field);
apply.setSourceNode(callStmIR.getSourceNode());
for (SExpIR arg : args)
{
apply.getArgs().add(arg.clone());
}
String resultName = getInfo().getTempVarNameGen().nextVarName(traceTrans.getTracePrefixes().callStmResultNamePrefix());
AVarDeclIR resultDecl = getTransAssist().consDecl(resultName, type.clone(), apply);
AReturnStmIR returnStm = new AReturnStmIR();
returnStm.setExp(getInfo().getExpAssistant().consIdVar(resultName, type.clone()));
ABlockStmIR stms = new ABlockStmIR();
stms.getLocalDefs().add(resultDecl);
stms.getStatements().add(returnStm);
return stms;
}
}
protected ABlockStmIR consDecl(String classTypeName, String varName,
SExpIR... args)
{
ATypeNameIR typeName = getTransAssist().consTypeNameForClass(classTypeName);
AClassTypeIR classType = getTransAssist().consClassType(classTypeName);
ANewExpIR newExp = new ANewExpIR();
newExp.setName(typeName);
newExp.setType(classType);
for (SExpIR arg : args)
{
newExp.getArgs().add(arg);
}
return getTransAssist().wrap(getTransAssist().consDecl(varName, classType.clone(), newExp));
}
public ACallObjectExpStmIR consAddTraceVarCall(AIdentifierVarExpIR subject,
AIdentifierVarExpIR t)
{
ANewExpIR newVar = new ANewExpIR();
newVar.setName(getTransAssist().consTypeNameForClass(traceTrans.getTracePrefixes().traceVarClassName()));
newVar.setType(getTransAssist().consClassType(traceTrans.getTracePrefixes().traceVarClassName()));
newVar.getArgs().add(getInfo().getExpAssistant().consStringLiteral(t.getName(), false));
newVar.getArgs().add(getInfo().getExpAssistant().consStringLiteral(""
+ getTransAssist().getInfo().getTypeAssistant().getVdmType(t.getType()), false));
newVar.getArgs().add(traceTrans.getToStringBuilder().toStringOf(t.clone()));
return getTransAssist().consInstanceCallStm(subject.getType(), subject.getName(), traceTrans.getTracePrefixes().addVarFirstMethodName(), newVar);
}
private TransAssistantIR getTransAssist()
{
return traceTrans.getTransAssist();
}
@Override
public TraceNodeData createNewReturnValue(INode node)
throws AnalysisException
{
assert false : "This should never happen";
return null;
}
@Override
public TraceNodeData createNewReturnValue(Object node)
throws AnalysisException
{
assert false : "This should never happen";
return null;
}
}