package org.overture.codegen.trans.conc;
import org.apache.log4j.Logger;
import org.overture.codegen.ir.IRGeneratedTag;
import org.overture.codegen.ir.SStmIR;
import org.overture.codegen.ir.STypeIR;
import org.overture.codegen.ir.analysis.AnalysisException;
import org.overture.codegen.ir.analysis.DepthFirstAnalysisAdaptor;
import org.overture.codegen.ir.declarations.ADefaultClassDeclIR;
import org.overture.codegen.ir.declarations.AMethodDeclIR;
import org.overture.codegen.ir.expressions.AIdentifierVarExpIR;
import org.overture.codegen.ir.expressions.SVarExpIR;
import org.overture.codegen.ir.statements.AAssignToExpStmIR;
import org.overture.codegen.ir.statements.AAssignmentStmIR;
import org.overture.codegen.ir.statements.ABlockStmIR;
import org.overture.codegen.ir.statements.ACallObjectExpStmIR;
import org.overture.codegen.ir.statements.AMapSeqUpdateStmIR;
import org.overture.codegen.ir.types.AVoidTypeIR;
import org.overture.codegen.trans.assistants.TransAssistantIR;
/**
* This transformation generates a "state change" call to the Sentinel class to make it re-evaluate permission
* predicates. It assumes all state updates to come from the local assignment statement, the assignment statement or the
* "map put statement".
*
* @author pvj
*/
public class EvalPermPredTrans extends DepthFirstAnalysisAdaptor
{
private TransAssistantIR transAssistant;
private ConcPrefixes concPrefixes;
private Logger log = Logger.getLogger(this.getClass().getName());
public EvalPermPredTrans(TransAssistantIR transAssistant,
ConcPrefixes concPrefixes)
{
this.transAssistant = transAssistant;
this.concPrefixes = concPrefixes;
}
@Override
public void caseAAssignmentStmIR(AAssignmentStmIR node)
throws AnalysisException
{
if(transAssistant.getInfo().getDeclAssistant().isTest(node.getAncestor(ADefaultClassDeclIR.class)))
{
return;
}
handleStateUpdate(node);
}
@Override
public void caseAAssignToExpStmIR(AAssignToExpStmIR node)
throws AnalysisException
{
if(transAssistant.getInfo().getDeclAssistant().isTest(node.getAncestor(ADefaultClassDeclIR.class)))
{
return;
}
if (node.getTarget() instanceof SVarExpIR)
{
SVarExpIR var = (SVarExpIR) node.getTarget();
if (var.getIsLocal())
{
return;
}
}
handleStateUpdate(node);
}
@Override
public void caseAMapSeqUpdateStmIR(AMapSeqUpdateStmIR node)
throws AnalysisException
{
if(transAssistant.getInfo().getDeclAssistant().isTest(node.getAncestor(ADefaultClassDeclIR.class)))
{
return;
}
handleStateUpdate(node);
}
private void handleStateUpdate(SStmIR node)
{
if (!transAssistant.getInfo().getSettings().generateConc())
{
return;
}
AMethodDeclIR enclosingMethod = node.getAncestor(AMethodDeclIR.class);
if (enclosingMethod != null)
{
Boolean isStatic = enclosingMethod.getStatic();
if (isStatic != null && isStatic)
{
return;
}
if (enclosingMethod.getIsConstructor())
{
return;
}
if (isIRGenerated(enclosingMethod))
{
return;
}
} else
{
// Can in fact be okay since the IR construction of the thread definition skips the
// explicit operation definition implicitly associated with the thread definition.
//
// Example:
// thread
// (x := 2;)
//
}
STypeIR fieldType = getSentinelFieldType(node);
AIdentifierVarExpIR sentinelVar = new AIdentifierVarExpIR();
sentinelVar.setIsLocal(true);
sentinelVar.setIsLambda(false);
sentinelVar.setName(concPrefixes.sentinelInstanceName());
sentinelVar.setType(fieldType);
ACallObjectExpStmIR callSentinel = new ACallObjectExpStmIR();
callSentinel.setObj(sentinelVar);
callSentinel.setFieldName(concPrefixes.stateChangedMethodName());
callSentinel.setType(new AVoidTypeIR());
ABlockStmIR replacementBlock = new ABlockStmIR();
transAssistant.replaceNodeWith(node, replacementBlock);
replacementBlock.getStatements().add(node);
replacementBlock.getStatements().add(callSentinel);
}
private STypeIR getSentinelFieldType(SStmIR node)
{
ADefaultClassDeclIR enclosingClass = node.getAncestor(ADefaultClassDeclIR.class);
STypeIR fieldType = null;
if (enclosingClass != null)
{
fieldType = transAssistant.getInfo().getTypeAssistant().getFieldType(enclosingClass, concPrefixes.sentinelInstanceName(), transAssistant.getInfo().getClasses());
} else
{
log.error("Could not find enclosing class of assignment statement");
}
return fieldType;
}
private boolean isIRGenerated(AMethodDeclIR method)
{
return method.getTag() instanceof IRGeneratedTag;
}
}