/**
*
*/
package org.overture.codegen.trans.conc;
import java.util.LinkedList;
import java.util.List;
import org.overture.codegen.ir.IRConstants;
import org.overture.codegen.ir.IRGeneratedTag;
import org.overture.codegen.ir.IRInfo;
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.AFieldDeclIR;
import org.overture.codegen.ir.declarations.AFormalParamLocalParamIR;
import org.overture.codegen.ir.declarations.AInterfaceDeclIR;
import org.overture.codegen.ir.declarations.AMethodDeclIR;
import org.overture.codegen.ir.declarations.APersyncDeclIR;
import org.overture.codegen.ir.declarations.SClassDeclIR;
import org.overture.codegen.ir.expressions.ABoolLiteralExpIR;
import org.overture.codegen.ir.expressions.ACastUnaryExpIR;
import org.overture.codegen.ir.expressions.AEqualsBinaryExpIR;
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.ASelfExpIR;
import org.overture.codegen.ir.name.ATokenNameIR;
import org.overture.codegen.ir.name.ATypeNameIR;
import org.overture.codegen.ir.patterns.AIdentifierPatternIR;
import org.overture.codegen.ir.statements.AAssignToExpStmIR;
import org.overture.codegen.ir.statements.ABlockStmIR;
import org.overture.codegen.ir.statements.AElseIfStmIR;
import org.overture.codegen.ir.statements.AIfStmIR;
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.ABoolBasicTypeIR;
import org.overture.codegen.ir.types.AClassTypeIR;
import org.overture.codegen.ir.types.AExternalTypeIR;
import org.overture.codegen.ir.types.AIntNumericBasicTypeIR;
import org.overture.codegen.ir.types.AMethodTypeIR;
import org.overture.codegen.ir.types.AVoidTypeIR;
/**
* @author gkanos
*/
public class MainClassConcTrans extends DepthFirstAnalysisAdaptor
{
public static final String MULTIPLE_INHERITANCE_WARNING = "Generation of concurrency "
+ "constructs does not support multiple inheritance";
private IRInfo info;
private ConcPrefixes concPrefixes;
public MainClassConcTrans(IRInfo info, ConcPrefixes concPrefixes)
{
this.info = info;
this.concPrefixes = concPrefixes;
}
@Override
public void caseADefaultClassDeclIR(ADefaultClassDeclIR node)
throws AnalysisException
{
if (!info.getSettings().generateConc())
{
return;
}
if(info.getDeclAssistant().isTest(node))
{
return;
}
if (node.getSuperNames().size() > 1)
{
info.addTransformationWarning(node, MULTIPLE_INHERITANCE_WARNING);
return;
}
for (AFieldDeclIR fieldIR : node.getFields())
{
if (!fieldIR.getFinal())
{
fieldIR.setVolatile(true);
}
}
AInterfaceDeclIR interf = new AInterfaceDeclIR();
interf.setName(concPrefixes.evalPpTypeName());
node.getInterfaces().add(interf);
AExternalTypeIR sentType = new AExternalTypeIR();
sentType.setName(concPrefixes.sentinelClassName());
AFieldDeclIR sentinelfld = new AFieldDeclIR();
sentinelfld.setName(concPrefixes.sentinelInstanceName());
sentinelfld.setType(sentType);
sentinelfld.setAccess(IRConstants.PUBLIC);
sentinelfld.setVolatile(true);
sentinelfld.setStatic(false);
node.getFields().add(sentinelfld);
for (AMethodDeclIR methodIR : node.getMethods())
{
if (methodIR.getStatic() != null && !methodIR.getStatic()
&& !isIRGenerated(methodIR))
{
if (!methodIR.getIsConstructor() && !methodIR.getAbstract())
{
ABlockStmIR bodyStm = new ABlockStmIR();
APlainCallStmIR entering = new APlainCallStmIR();
APlainCallStmIR leaving = new APlainCallStmIR();
entering.setName(concPrefixes.enteringMethodName());
AClassTypeIR sentinel = new AClassTypeIR();
sentinel.setName(concPrefixes.sentinelInstanceName());
entering.setClassType(sentinel);
entering.setType(new AVoidTypeIR());
AFieldExpIR field = new AFieldExpIR();
field.setMemberName(methodIR.getName());
ACastUnaryExpIR cast = new ACastUnaryExpIR();
AIdentifierVarExpIR varSentinel = new AIdentifierVarExpIR();
varSentinel.setIsLocal(true);
varSentinel.setIsLambda(false);
varSentinel.setName(concPrefixes.sentinelInstanceName());
AExternalTypeIR etype = new AExternalTypeIR();
etype.setName(node.getName()
+ concPrefixes.sentinelClassPostFix());
cast.setExp(varSentinel);
cast.setType(etype);
field.setObject(cast);
entering.getArgs().add(field);
leaving.setName(concPrefixes.leavingMethodName());
leaving.setClassType(sentinel.clone());
leaving.setType(new AVoidTypeIR());
leaving.getArgs().add(field.clone());
bodyStm.getStatements().add(entering);
ATryStmIR trystm = new ATryStmIR();
trystm.setStm(methodIR.getBody());
trystm.setFinally(leaving);
bodyStm.getStatements().add(trystm);
methodIR.setBody(bodyStm);
}
}
if (methodIR.getIsConstructor())
{
ABlockStmIR bodyConst = new ABlockStmIR();
AAssignToExpStmIR stm = new AAssignToExpStmIR();
AIdentifierVarExpIR field = new AIdentifierVarExpIR();
field.setName(concPrefixes.sentinelInstanceName());
field.setIsLocal(false);
ANewExpIR newexp = new ANewExpIR();
ATypeNameIR classtype = new ATypeNameIR();
classtype.setName(node.getName()
+ concPrefixes.sentinelClassPostFix());
newexp.setName(classtype);
newexp.getArgs().add(new ASelfExpIR());
stm.setExp(newexp);
stm.setTarget(field);
bodyConst.getStatements().add(stm);
bodyConst.getStatements().add(methodIR.getBody());
methodIR.setBody(bodyConst);
}
}
// declaration of the method.
AIntNumericBasicTypeIR fnr = new AIntNumericBasicTypeIR();
AIdentifierPatternIR identifier = new AIdentifierPatternIR();
identifier.setName(concPrefixes.funcNumberParamName());
AFormalParamLocalParamIR fnrloc = new AFormalParamLocalParamIR();
fnrloc.setType(fnr);
fnrloc.setPattern(identifier);
AMethodTypeIR methType = new AMethodTypeIR();
methType.setResult(new ABoolBasicTypeIR());
AMethodDeclIR evaluatePPmethod = new AMethodDeclIR();
evaluatePPmethod.setAccess(IRConstants.PUBLIC);
evaluatePPmethod.setName(concPrefixes.evalPpMethodName());
evaluatePPmethod.setImplicit(false);
evaluatePPmethod.setMethodType(methType);
evaluatePPmethod.setIsConstructor(false);
evaluatePPmethod.getFormalParams().add(fnrloc);
// Body of the method.
if (node.getMethods().size() != 0)
{
// fixing the overloaded operation problem
List<AMethodDeclIR> classuniqueMethods = new LinkedList<>();
for (AMethodDeclIR m : node.getMethods())
{
classuniqueMethods.add(m.clone());
}
classuniqueMethods.clear();
List<AMethodDeclIR> allMethods;
if (!node.getSuperNames().isEmpty())
{
allMethods = info.getDeclAssistant().getAllMethods(node, info.getClasses());
} else
{
allMethods = node.getMethods();
}
for (AMethodDeclIR method : allMethods)
{
if (!classuniqueMethods.contains(method))
{
classuniqueMethods.add(method.clone());
}
}
AIfStmIR bodyif = new AIfStmIR();
for (int i = 0; i < classuniqueMethods.size(); i++)
{
AIdentifierVarExpIR testVar = new AIdentifierVarExpIR();
testVar.setType(new AIntNumericBasicTypeIR());
testVar.setName(concPrefixes.funcNumberParamName());
testVar.setIsLocal(true);
if (i == 0)
{
AEqualsBinaryExpIR firstBranch = new AEqualsBinaryExpIR();
AIntLiteralExpIR methNum = new AIntLiteralExpIR();
methNum.setValue((long) i);
firstBranch.setLeft(testVar);
firstBranch.setRight(methNum);
AReturnStmIR ret = new AReturnStmIR();
ABoolLiteralExpIR boolret = new ABoolLiteralExpIR();
boolret.setValue(true);
ret.setExp(boolret);
for (APersyncDeclIR per : node.getPerSyncs())
{
if (per.getOpname().equals(classuniqueMethods.get(i).getName()))
{
ret.setExp(per.getPred());
}
}
bodyif.setIfExp(firstBranch);
bodyif.setThenStm(ret);
}
else
{
AReturnStmIR ret = new AReturnStmIR();
ABoolLiteralExpIR boolret = new ABoolLiteralExpIR();
boolret.setValue(true);
ret.setExp(boolret);
for (APersyncDeclIR per : node.getPerSyncs())
{
if (per.getOpname().equals(classuniqueMethods.get(i).getName()))
{
ret.setExp(per.getPred());
}
}
AElseIfStmIR newBranch = new AElseIfStmIR();
AEqualsBinaryExpIR Branches = new AEqualsBinaryExpIR();
AIntLiteralExpIR methNum = new AIntLiteralExpIR();
methNum.setValue((long) i);
Branches.setLeft(testVar);
Branches.setRight(methNum);
newBranch.setElseIf(Branches);
newBranch.setThenStm(ret.clone());
bodyif.getElseIf().add(newBranch);
}
}
AReturnStmIR ret = new AReturnStmIR();
ABoolLiteralExpIR defaultPer = new ABoolLiteralExpIR();
defaultPer.setValue(true);
ret.setExp(defaultPer);
bodyif.setElseStm(ret.clone());
evaluatePPmethod.setBody(bodyif);
}
node.getMethods().add(evaluatePPmethod);
if (node.getThread() != null)
{
makeThread(node);
}
}
private boolean isIRGenerated(AMethodDeclIR method)
{
return method.getTag() instanceof IRGeneratedTag;
}
private void makeThread(ADefaultClassDeclIR node)
{
SClassDeclIR threadClass = getThreadClass(node.getSuperNames(), node);
threadClass.getSuperNames().clear();
ATokenNameIR superName = new ATokenNameIR();
superName.setName(concPrefixes.vdmThreadClassName());
threadClass.getSuperNames().add(superName);
}
private SClassDeclIR getThreadClass(List<ATokenNameIR> superNames,
SClassDeclIR classCg)
{
if (superNames.isEmpty()
|| superNames.get(0).getName().equals(concPrefixes.vdmThreadClassName()))
{
return classCg;
} else
{
SClassDeclIR superClass = null;
for (SClassDeclIR c : info.getClasses())
{
if (c.getName().equals(superNames.get(0).getName()))
{
superClass = c;
break;
}
}
return getThreadClass(superClass.getSuperNames(), superClass);
}
}
}