/*
* #%~
* VDM Code Generator
* %%
* Copyright (C) 2008 - 2014 Overture
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #~%
*/
package org.overture.codegen.trans.assistants;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
import org.overture.ast.lex.Dialect;
import org.overture.ast.types.PType;
import org.overture.ast.types.SSeqType;
import org.overture.codegen.ir.IRInfo;
import org.overture.codegen.ir.ITempVarGen;
import org.overture.codegen.ir.SExpIR;
import org.overture.codegen.ir.SMultipleBindIR;
import org.overture.codegen.ir.SPatternIR;
import org.overture.codegen.ir.SStmIR;
import org.overture.codegen.ir.STypeIR;
import org.overture.codegen.ir.SourceNode;
import org.overture.codegen.ir.analysis.AnalysisException;
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.AMethodDeclIR;
import org.overture.codegen.ir.declarations.AModuleDeclIR;
import org.overture.codegen.ir.declarations.AStateDeclIR;
import org.overture.codegen.ir.declarations.AVarDeclIR;
import org.overture.codegen.ir.expressions.AAndBoolBinaryExpIR;
import org.overture.codegen.ir.expressions.AApplyExpIR;
import org.overture.codegen.ir.expressions.ACastUnaryExpIR;
import org.overture.codegen.ir.expressions.ACompSeqExpIR;
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.ALessNumericBinaryExpIR;
import org.overture.codegen.ir.expressions.ANewExpIR;
import org.overture.codegen.ir.expressions.ANotUnaryExpIR;
import org.overture.codegen.ir.name.ATypeNameIR;
import org.overture.codegen.ir.patterns.AIdentifierPatternIR;
import org.overture.codegen.ir.patterns.ASeqMultipleBindIR;
import org.overture.codegen.ir.patterns.ASetMultipleBindIR;
import org.overture.codegen.ir.statements.AAssignToExpStmIR;
import org.overture.codegen.ir.statements.ABlockStmIR;
import org.overture.codegen.ir.statements.ACallObjectExpStmIR;
import org.overture.codegen.ir.statements.AForLoopStmIR;
import org.overture.codegen.ir.statements.AIfStmIR;
import org.overture.codegen.ir.statements.AIncrementStmIR;
import org.overture.codegen.ir.statements.ALocalPatternAssignmentStmIR;
import org.overture.codegen.ir.types.ABoolBasicTypeIR;
import org.overture.codegen.ir.types.AClassTypeIR;
import org.overture.codegen.ir.types.AIntNumericBasicTypeIR;
import org.overture.codegen.ir.types.AMethodTypeIR;
import org.overture.codegen.ir.types.ARecordTypeIR;
import org.overture.codegen.ir.types.ASeqSeqTypeIR;
import org.overture.codegen.ir.types.ASetSetTypeIR;
import org.overture.codegen.ir.types.AUnknownTypeIR;
import org.overture.codegen.ir.types.AVoidTypeIR;
import org.overture.codegen.ir.types.SSeqTypeIR;
import org.overture.codegen.ir.types.SSetTypeIR;
import org.overture.codegen.trans.IIterationStrategy;
import org.overture.codegen.trans.IterationVarPrefixes;
import org.overture.config.Settings;
public class TransAssistantIR extends BaseTransformationAssistant
{
protected IRInfo info;
private Logger log = Logger.getLogger(this.getClass().getName());
public TransAssistantIR(IRInfo info)
{
this.info = info;
}
public IRInfo getInfo()
{
return info;
}
public SSetTypeIR getSetTypeCloned(SExpIR set) throws AnalysisException
{
STypeIR typeCg = set.getType();
return getSetTypeCloned(typeCg);
}
public SSetTypeIR getSetTypeCloned(STypeIR typeCg) throws AnalysisException
{
if (typeCg instanceof SSetTypeIR)
{
SSetTypeIR setTypeCg = (SSetTypeIR) typeCg;
return setTypeCg.clone();
}
return null;
}
public SSeqTypeIR getSeqTypeCloned(SExpIR seq) throws AnalysisException
{
STypeIR typeCg = seq.getType();
return getSeqTypeCloned(typeCg);
}
public SSeqTypeIR getSeqTypeCloned(STypeIR typeCg) throws AnalysisException
{
if (typeCg instanceof SSeqTypeIR)
{
SSeqTypeIR seqTypeCg = (SSeqTypeIR) typeCg;
return seqTypeCg.clone();
} else
{
SourceNode sourceNode = typeCg.getSourceNode();
if (sourceNode != null && sourceNode.getVdmNode() instanceof PType)
{
PType vdmType = (PType) sourceNode.getVdmNode();
SSeqType seqType = info.getTcFactory().createPTypeAssistant().getSeq(vdmType);
try
{
typeCg = seqType.apply(info.getTypeVisitor(), info);
return (SSeqTypeIR) typeCg;
} catch (org.overture.ast.analysis.AnalysisException e)
{
}
}
throw new AnalysisException("Exptected sequence type. Got: "
+ typeCg);
}
}
public STypeIR getElementType(STypeIR t)
{
STypeIR elementType;
if (t instanceof ASetSetTypeIR)
{
elementType = ((ASetSetTypeIR) t).getSetOf().clone();
} else if (t instanceof ASeqSeqTypeIR)
{
elementType = ((ASeqSeqTypeIR) t).getSeqOf().clone();
} else
{
log.error("Expected set or sequence type. Got: " + t);
elementType = new AUnknownTypeIR();
elementType.setSourceNode(t.getSourceNode());
}
return elementType;
}
public AIdentifierVarExpIR consSuccessVar(String successVarName)
{
AIdentifierVarExpIR successVar = new AIdentifierVarExpIR();
successVar.setIsLambda(false);
successVar.setIsLocal(true);
successVar.setName(successVarName);
successVar.setType(new ABoolBasicTypeIR());
return successVar;
}
public AVarDeclIR consBoolVarDecl(String boolVarName, boolean initValue)
{
return info.getDeclAssistant().consLocalVarDecl(new ABoolBasicTypeIR(), info.getPatternAssistant().consIdPattern(boolVarName), info.getExpAssistant().consBoolLiteral(initValue));
}
public SExpIR consAndExp(SExpIR left, SExpIR right)
{
AAndBoolBinaryExpIR andExp = new AAndBoolBinaryExpIR();
andExp.setType(new ABoolBasicTypeIR());
andExp.setLeft(left);
andExp.setRight(right);
return andExp;
}
public SExpIR consLessThanCheck(String varName, long value)
{
AIdentifierVarExpIR left = new AIdentifierVarExpIR();
left.setType(new AIntNumericBasicTypeIR());
left.setIsLocal(true);
left.setName(varName);
AIntLiteralExpIR right = info.getExpAssistant().consIntLiteral(value);
ALessNumericBinaryExpIR less = new ALessNumericBinaryExpIR();
less.setType(new ABoolBasicTypeIR());
less.setLeft(left);
less.setRight(right);
return less;
}
public SExpIR consBoolCheck(String boolVarName, boolean negate)
{
AIdentifierVarExpIR boolVarExp = new AIdentifierVarExpIR();
boolVarExp.setType(new ABoolBasicTypeIR());
boolVarExp.setIsLocal(true);
boolVarExp.setName(boolVarName);
if (negate)
{
ANotUnaryExpIR negated = new ANotUnaryExpIR();
negated.setType(new ABoolBasicTypeIR());
negated.setExp(boolVarExp);
return negated;
} else
{
return boolVarExp;
}
}
public AAssignToExpStmIR consBoolVarAssignment(SExpIR predicate,
String boolVarName)
{
AAssignToExpStmIR boolVarAssignment = new AAssignToExpStmIR();
boolVarAssignment.setTarget(consBoolCheck(boolVarName, false));
boolVarAssignment.setExp(predicate != null ? predicate.clone()
: info.getExpAssistant().consBoolLiteral(true));
return boolVarAssignment;
}
public AVarDeclIR consSetBindDecl(String setBindName, SExpIR col)
throws AnalysisException
{
return info.getDeclAssistant().consLocalVarDecl(col.getType().clone(), info.getPatternAssistant().consIdPattern(setBindName), col.clone());
}
public AVarDeclIR consDecl(String varName, STypeIR type, SExpIR exp)
{
return info.getDeclAssistant().consLocalVarDecl(type, info.getPatternAssistant().consIdPattern(varName), exp);
}
public AClassTypeIR consClassType(String classTypeName)
{
AClassTypeIR classType = new AClassTypeIR();
classType.setName(classTypeName);
return classType;
}
public SExpIR consInstanceCall(STypeIR instanceType, String instanceName,
STypeIR returnType, String memberName, SExpIR... args)
{
AIdentifierVarExpIR instance = new AIdentifierVarExpIR();
instance.setType(instanceType.clone());
instance.setName(instanceName);
instance.setIsLocal(true);
AFieldExpIR fieldExp = new AFieldExpIR();
fieldExp.setMemberName(memberName);
fieldExp.setObject(instance);
AMethodTypeIR methodType = new AMethodTypeIR();
methodType.setResult(returnType.clone());
AApplyExpIR instanceCall = new AApplyExpIR();
instanceCall.setType(returnType.clone());
if (args != null)
{
for (SExpIR arg : args)
{
methodType.getParams().add(arg.getType().clone());
instanceCall.getArgs().add(arg);
}
}
fieldExp.setType(methodType.clone());
instanceCall.setRoot(fieldExp);
return instanceCall;
}
// TODO: This actually forces the return type to be 'void'. Maybe generalise?
public ACallObjectExpStmIR consInstanceCallStm(STypeIR instanceType,
String instanceName, String memberName, SExpIR... args)
{
AIdentifierVarExpIR instance = new AIdentifierVarExpIR();
instance.setName(instanceName);
instance.setType(instanceType.clone());
ACallObjectExpStmIR call = new ACallObjectExpStmIR();
call.setType(new AVoidTypeIR());
call.setFieldName(memberName);
call.setObj(instance);
for (SExpIR arg : args)
{
call.getArgs().add(arg);
}
return call;
}
public AVarDeclIR consNextElementDeclared(STypeIR iteratorType,
STypeIR elementType, SPatternIR id, String iteratorName,
String nextElementMethod) throws AnalysisException
{
ACastUnaryExpIR cast = consNextElementCall(iteratorType, iteratorName, elementType, nextElementMethod);
return info.getDeclAssistant().consLocalVarDecl(elementType, id.clone(), cast);
}
public ALocalPatternAssignmentStmIR consNextElementAssignment(
STypeIR iteratorType, STypeIR elementType, SPatternIR id,
String iteratorName, String nextElementMethod,
AVarDeclIR nextElementDecl) throws AnalysisException
{
ACastUnaryExpIR cast = consNextElementCall(iteratorType, iteratorName, elementType, nextElementMethod);
ALocalPatternAssignmentStmIR assignment = new ALocalPatternAssignmentStmIR();
assignment.setTarget(id.clone());
assignment.setExp(cast);
// Associate the pattern assignment with its declaration and
// the corresponding success variable (both are graph fields)
assignment.setTag(nextElementDecl.getTag());
assignment.setNextElementDecl(nextElementDecl);
// assignment.setSuccessVarDecl(successVarDecl);
return assignment;
}
public ANewExpIR consDefaultConsCall(String className)
{
return consDefaultConsCall(consClassType(className));
}
public ANewExpIR consDefaultConsCall(AClassTypeIR classType)
{
ANewExpIR initAltNode = new ANewExpIR();
initAltNode.setType(classType.clone());
initAltNode.setName(consTypeNameForClass(classType.getName()));
return initAltNode;
}
public ATypeNameIR consTypeNameForClass(String classTypeName)
{
ATypeNameIR typeName = new ATypeNameIR();
typeName.setDefiningClass(null);
typeName.setName(classTypeName);
return typeName;
}
public ACastUnaryExpIR consNextElementCall(STypeIR iteratorType,
String iteratorName, STypeIR elementType, String nextElementMethod)
{
ACastUnaryExpIR cast = new ACastUnaryExpIR();
cast.setType(elementType.clone());
cast.setExp(consInstanceCall(iteratorType, iteratorName, elementType.clone(), nextElementMethod));
return cast;
}
public SStmIR consConditionalIncrement(String counterName, SExpIR predicate)
{
AIdentifierVarExpIR col = new AIdentifierVarExpIR();
col.setType(new AIntNumericBasicTypeIR());
col.setIsLambda(false);
col.setIsLocal(true);
col.setName(counterName);
AIncrementStmIR inc = new AIncrementStmIR();
inc.setVar(col);
AIfStmIR ifStm = new AIfStmIR();
ifStm.setIfExp(predicate);
ifStm.setThenStm(inc);
return ifStm;
}
public ABlockStmIR consIterationBlock(List<SPatternIR> ids, SExpIR set,
ITempVarGen tempGen, IIterationStrategy strategy,
IterationVarPrefixes iteVarPrefixes) throws AnalysisException
{
ABlockStmIR outerBlock = new ABlockStmIR();
consIterationBlock(outerBlock, ids, set, tempGen, strategy, iteVarPrefixes);
return outerBlock;
}
public AIdentifierVarExpIR consSetVar(String setName, SExpIR set)
{
if (set == null)
{
return null;
}
AIdentifierVarExpIR setVar = new AIdentifierVarExpIR();
STypeIR setType = set.getType().clone();
setVar.setType(setType);
setVar.setName(setName);
setVar.setIsLocal(true);
return setVar;
}
private ABlockStmIR consIterationBlock(ABlockStmIR outerBlock,
List<SPatternIR> patterns, SExpIR set, ITempVarGen tempGen,
IIterationStrategy strategy, IterationVarPrefixes iteVarPrefixes)
throws AnalysisException
{
// Variable names
String setName = tempGen.nextVarName(iteVarPrefixes.set());
AIdentifierVarExpIR setVar = consSetVar(setName, set);
ABlockStmIR forBody = null;
List<AVarDeclIR> extraDecls = strategy.getOuterBlockDecls(setVar, patterns);
if (extraDecls != null)
{
outerBlock.getLocalDefs().addAll(extraDecls);
}
if (setVar != null)
{
outerBlock.getLocalDefs().add(consSetBindDecl(setName, set));
ABlockStmIR nextBlock = outerBlock;
for (int i = 0;;)
{
SPatternIR pattern = patterns.get(i);
List<SStmIR> stms = strategy.getPreForLoopStms(setVar, patterns, pattern);
if (stms != null)
{
nextBlock.getStatements().addAll(stms);
}
// Construct next for loop
AForLoopStmIR forLoop = new AForLoopStmIR();
forLoop.setInit(strategy.getForLoopInit(setVar, patterns, pattern));
forLoop.setCond(strategy.getForLoopCond(setVar, patterns, pattern));
forLoop.setInc(strategy.getForLoopInc(setVar, patterns, pattern));
ABlockStmIR stmCollector = new ABlockStmIR();
AVarDeclIR nextElementDeclared = strategy.getNextElementDeclared(setVar, patterns, pattern);
if (nextElementDeclared != null)
{
stmCollector.getLocalDefs().add(nextElementDeclared);
}
ALocalPatternAssignmentStmIR assignment = strategy.getNextElementAssigned(setVar, patterns, pattern);
if (assignment != null)
{
stmCollector.getStatements().add(assignment);
}
forBody = stmCollector;
forLoop.setBody(forBody);
nextBlock.getStatements().add(forLoop);
if (++i < patterns.size())
{
nextBlock = forBody;
} else
{
List<SStmIR> extraForLoopStatements = strategy.getForLoopStms(setVar, patterns, pattern);
if (extraForLoopStatements != null)
{
forBody.getStatements().addAll(extraForLoopStatements);
}
break;
}
}
}
List<SStmIR> extraOuterBlockStms = strategy.getPostOuterBlockStms(setVar, patterns);
if (extraOuterBlockStms != null)
{
outerBlock.getStatements().addAll(extraOuterBlockStms);
}
return forBody;
}
// FIXME make this method work on generic PMUltipleBinds
public ABlockStmIR consComplexCompIterationBlock(
List<SMultipleBindIR> multipleSetBinds, ITempVarGen tempGen,
IIterationStrategy strategy, IterationVarPrefixes iteVarPrefixes)
throws AnalysisException
{
ABlockStmIR outerBlock = new ABlockStmIR();
ABlockStmIR nextMultiBindBlock = outerBlock;
for (SMultipleBindIR bind : multipleSetBinds)
{
if (hasEmptySet(bind))
{
multipleSetBinds.clear();
return outerBlock;
}
}
strategy.setFirstBind(true);
for (int i = 0; i < multipleSetBinds.size(); i++)
{
strategy.setLastBind(i == multipleSetBinds.size() - 1);
SMultipleBindIR mb = multipleSetBinds.get(i);
if (mb instanceof ASetMultipleBindIR)
{
nextMultiBindBlock = consIterationBlock(nextMultiBindBlock, mb.getPatterns(), ((ASetMultipleBindIR) mb).getSet(), tempGen, strategy, iteVarPrefixes);
} else if (mb instanceof ASeqMultipleBindIR)
{
nextMultiBindBlock = consIterationBlock(nextMultiBindBlock, mb.getPatterns(), ((ASeqMultipleBindIR) mb).getSeq(), tempGen, strategy, iteVarPrefixes);
} else
{
log.error("Expected set multiple bind or sequence multiple bind. Got: "
+ mb);
}
strategy.setFirstBind(false);
}
return outerBlock;
}
public ACastUnaryExpIR consNextElementCall(STypeIR instanceType,
String instance, String member, ACompSeqExpIR seqComp)
throws AnalysisException
{
STypeIR elementType = getSeqTypeCloned(seqComp).getSeqOf();
SExpIR nextCall = consInstanceCall(instanceType, instance, elementType.clone(), member);
ACastUnaryExpIR cast = new ACastUnaryExpIR();
cast.setType(elementType.clone());
cast.setExp(nextCall);
return cast;
}
public Boolean hasEmptySet(SMultipleBindIR binding) throws AnalysisException
{
if (binding instanceof ASetMultipleBindIR)
{
return isEmptySetSeq(((ASetMultipleBindIR) binding).getSet());
} else if (binding instanceof ASeqMultipleBindIR)
{
return isEmptySetSeq(((ASeqMultipleBindIR) binding).getSeq());
}
return false;
}
public Boolean isEmptySetSeq(SExpIR set) throws AnalysisException
{
if (set.getType() instanceof SSetTypeIR)
{
return ((SSetTypeIR) set.getType()).getEmpty();
} else if (set.getType() instanceof SSeqTypeIR)
{
return ((SSeqTypeIR) set.getType()).getEmpty();
}
return false;
}
public void cleanUpBinding(SMultipleBindIR binding)
{
if (binding instanceof ASetMultipleBindIR)
{
ASetMultipleBindIR sb = (ASetMultipleBindIR) binding;
sb.setSet(null);
sb.getPatterns().clear();
} else if (binding instanceof ASeqMultipleBindIR)
{
ASeqMultipleBindIR sb = (ASeqMultipleBindIR) binding;
sb.setSeq(null);
sb.getPatterns().clear();
} else
{
log.error("Expected multiple set bind or multiple sequence bind. Got: "
+ binding);
}
}
public AFieldDeclIR consField(String access, STypeIR type, String name,
SExpIR initExp)
{
AFieldDeclIR stateField = new AFieldDeclIR();
stateField.setAccess(access);
stateField.setType(type);
stateField.setStatic(true);
stateField.setFinal(false);
stateField.setVolatile(false);
stateField.setName(name);
stateField.setInitial(initExp);
return stateField;
}
public AApplyExpIR consConditionalCall(AMethodDeclIR node,
AMethodDeclIR predMethod)
{
AIdentifierVarExpIR condVar = new AIdentifierVarExpIR();
condVar.setType(predMethod.getMethodType().clone());
condVar.setName(predMethod.getName());
condVar.setIsLambda(false);
condVar.setIsLocal(true);
AApplyExpIR condCall = new AApplyExpIR();
condCall.setType(new ABoolBasicTypeIR());
condCall.setRoot(condVar);
LinkedList<AFormalParamLocalParamIR> params = node.getFormalParams();
for (AFormalParamLocalParamIR p : params)
{
SPatternIR paramPattern = p.getPattern();
if (!(paramPattern instanceof AIdentifierPatternIR))
{
log.error("Expected parameter pattern to be an identifier pattern at this point. Got: "
+ paramPattern);
return null;
}
AIdentifierPatternIR paramId = (AIdentifierPatternIR) paramPattern;
AIdentifierVarExpIR paramArg = new AIdentifierVarExpIR();
paramArg.setType(p.getType().clone());
paramArg.setIsLocal(true);
paramArg.setIsLambda(false);
paramArg.setName(paramId.getName());
condCall.getArgs().add(paramArg);
}
if (Settings.dialect == Dialect.VDM_SL)
{
ADefaultClassDeclIR encClass = node.getAncestor(ADefaultClassDeclIR.class);
if (encClass != null)
{
for (AFieldDeclIR f : encClass.getFields())
{
if (!f.getFinal())
{
// It's the state component
AIdentifierVarExpIR stateArg = info.getExpAssistant().consIdVar(f.getName(), f.getType().clone());
condCall.getArgs().add(stateArg);
break;
}
}
} else
{
log.error("Could not find enclosing class of " + node);
}
}
return condCall;
}
public AVarDeclIR consClassVarDeclDefaultCtor(String className,
String varName)
{
AClassTypeIR classType = consClassType(className);
ANewExpIR init = consDefaultConsCall(className);
AVarDeclIR classDecl = consDecl(varName, classType, init);
classDecl.setFinal(true);
return classDecl;
}
public ABlockStmIR wrap(AVarDeclIR decl)
{
ABlockStmIR block = new ABlockStmIR();
block.getLocalDefs().add(decl);
return block;
}
public ARecordTypeIR consRecType(String definingModule, String recName)
{
ATypeNameIR typeName = new ATypeNameIR();
typeName.setDefiningClass(definingModule);
typeName.setName(recName);
ARecordTypeIR recType = new ARecordTypeIR();
recType.setName(typeName);
return recType;
}
public ARecordTypeIR getRecType(final AStateDeclIR stateDecl)
{
ARecordTypeIR stateType = new ARecordTypeIR();
stateType.setName(getTypeName(stateDecl));
return stateType;
}
public ATypeNameIR getTypeName(final AStateDeclIR stateDecl)
{
ATypeNameIR stateName = new ATypeNameIR();
stateName.setDefiningClass(getEnclosingModuleName(stateDecl));
stateName.setName(stateDecl.getName());
return stateName;
}
public String getEnclosingModuleName(AStateDeclIR stateDecl)
{
AModuleDeclIR module = stateDecl.getAncestor(AModuleDeclIR.class);
if (module != null)
{
return module.getName();
} else
{
log.error("Could not find enclosing module name of state declaration "
+ stateDecl.getName());
return null;
}
}
public ABlockStmIR wrap(SStmIR stm)
{
ABlockStmIR block = new ABlockStmIR();
block.getStatements().add(stm);
return block;
}
}