/*
* #%~
* 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.assistant;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.overture.ast.analysis.AnalysisException;
import org.overture.ast.definitions.AAssignmentDefinition;
import org.overture.ast.definitions.AClassInvariantDefinition;
import org.overture.ast.definitions.AInstanceVariableDefinition;
import org.overture.ast.definitions.ANamedTraceDefinition;
import org.overture.ast.definitions.AStateDefinition;
import org.overture.ast.definitions.ATypeDefinition;
import org.overture.ast.definitions.AValueDefinition;
import org.overture.ast.definitions.SFunctionDefinition;
import org.overture.ast.definitions.SOperationDefinition;
import org.overture.ast.expressions.ACaseAlternative;
import org.overture.ast.expressions.ALambdaExp;
import org.overture.ast.expressions.ARealLiteralExp;
import org.overture.ast.expressions.PExp;
import org.overture.ast.expressions.SBinaryExp;
import org.overture.ast.expressions.SUnaryExp;
import org.overture.ast.patterns.PMultipleBind;
import org.overture.ast.statements.AAssignmentStm;
import org.overture.ast.types.AIntNumericBasicType;
import org.overture.ast.types.ANatNumericBasicType;
import org.overture.ast.types.ANatOneNumericBasicType;
import org.overture.ast.types.AUnionType;
import org.overture.ast.types.PType;
import org.overture.ast.types.SMapTypeBase;
import org.overture.codegen.ir.INode;
import org.overture.codegen.ir.IRInfo;
import org.overture.codegen.ir.SExpIR;
import org.overture.codegen.ir.SMultipleBindIR;
import org.overture.codegen.ir.STypeIR;
import org.overture.codegen.ir.expressions.AApplyExpIR;
import org.overture.codegen.ir.expressions.ABoolIsExpIR;
import org.overture.codegen.ir.expressions.ABoolLiteralExpIR;
import org.overture.codegen.ir.expressions.ACaseAltExpExpIR;
import org.overture.codegen.ir.expressions.ACastUnaryExpIR;
import org.overture.codegen.ir.expressions.ACharIsExpIR;
import org.overture.codegen.ir.expressions.ACharLiteralExpIR;
import org.overture.codegen.ir.expressions.AEnumSeqExpIR;
import org.overture.codegen.ir.expressions.AEqualsBinaryExpIR;
import org.overture.codegen.ir.expressions.AExplicitVarExpIR;
import org.overture.codegen.ir.expressions.AFieldExpIR;
import org.overture.codegen.ir.expressions.AGeneralIsExpIR;
import org.overture.codegen.ir.expressions.AIdentifierVarExpIR;
import org.overture.codegen.ir.expressions.AIntIsExpIR;
import org.overture.codegen.ir.expressions.AIntLiteralExpIR;
import org.overture.codegen.ir.expressions.AIsolationUnaryExpIR;
import org.overture.codegen.ir.expressions.AMapSeqGetExpIR;
import org.overture.codegen.ir.expressions.ANat1IsExpIR;
import org.overture.codegen.ir.expressions.ANatIsExpIR;
import org.overture.codegen.ir.expressions.ANotUnaryExpIR;
import org.overture.codegen.ir.expressions.ANullExpIR;
import org.overture.codegen.ir.expressions.AQuoteLiteralExpIR;
import org.overture.codegen.ir.expressions.ARatIsExpIR;
import org.overture.codegen.ir.expressions.ARealIsExpIR;
import org.overture.codegen.ir.expressions.ARealLiteralExpIR;
import org.overture.codegen.ir.expressions.AStringLiteralExpIR;
import org.overture.codegen.ir.expressions.ATokenIsExpIR;
import org.overture.codegen.ir.expressions.ATupleIsExpIR;
import org.overture.codegen.ir.expressions.AUndefinedExpIR;
import org.overture.codegen.ir.expressions.SBinaryExpIR;
import org.overture.codegen.ir.expressions.SIsExpIR;
import org.overture.codegen.ir.expressions.SQuantifierExpIR;
import org.overture.codegen.ir.expressions.SUnaryExpIR;
import org.overture.codegen.ir.expressions.SVarExpIR;
import org.overture.codegen.ir.statements.AForLoopStmIR;
import org.overture.codegen.ir.statements.AIdentifierStateDesignatorIR;
import org.overture.codegen.ir.statements.AWhileStmIR;
import org.overture.codegen.ir.types.ABoolBasicTypeIR;
import org.overture.codegen.ir.types.ACharBasicTypeIR;
import org.overture.codegen.ir.types.AClassTypeIR;
import org.overture.codegen.ir.types.AIntNumericBasicTypeIR;
import org.overture.codegen.ir.types.AMapMapTypeIR;
import org.overture.codegen.ir.types.ANat1NumericBasicTypeIR;
import org.overture.codegen.ir.types.ANatNumericBasicTypeIR;
import org.overture.codegen.ir.types.AQuoteTypeIR;
import org.overture.codegen.ir.types.ARatNumericBasicTypeIR;
import org.overture.codegen.ir.types.ARealNumericBasicTypeIR;
import org.overture.codegen.ir.types.ARecordTypeIR;
import org.overture.codegen.ir.types.ASeqSeqTypeIR;
import org.overture.codegen.ir.types.AStringTypeIR;
import org.overture.codegen.ir.types.ATokenBasicTypeIR;
import org.overture.codegen.ir.types.ATupleTypeIR;
import org.overture.codegen.ir.types.AUnionTypeIR;
import org.overture.codegen.ir.types.AUnknownTypeIR;
import org.overture.codegen.ir.types.SBasicTypeIR;
import org.overture.codegen.ir.utils.AHeaderLetBeStIR;
public class ExpAssistantIR extends AssistantBase
{
public ExpAssistantIR(AssistantManager assistantManager)
{
super(assistantManager);
}
public AIdentifierVarExpIR consIdVar(String name, STypeIR type)
{
AIdentifierVarExpIR var = new AIdentifierVarExpIR();
var.setIsLambda(false);
var.setIsLocal(true);
var.setType(type);
var.setName(name);
return var;
}
public SExpIR isolateExpression(SExpIR exp)
{
AIsolationUnaryExpIR isolationExp = new AIsolationUnaryExpIR();
isolationExp.setExp(exp);
isolationExp.setType(exp.getType().clone());
return isolationExp;
}
public ANotUnaryExpIR negate(SExpIR exp)
{
ANotUnaryExpIR negated = new ANotUnaryExpIR();
negated.setType(exp.getType().clone());
negated.setExp(exp);
return negated;
}
public SExpIR handleUnaryExp(SUnaryExp vdmExp, SUnaryExpIR codeGenExp,
IRInfo question) throws AnalysisException
{
SExpIR expCg = vdmExp.getExp().apply(question.getExpVisitor(), question);
STypeIR typeCg = vdmExp.getType().apply(question.getTypeVisitor(), question);
codeGenExp.setType(typeCg);
codeGenExp.setExp(expCg);
return codeGenExp;
}
public SExpIR handleBinaryExp(SBinaryExp vdmExp, SBinaryExpIR codeGenExp,
IRInfo question) throws AnalysisException
{
PType type = vdmExp.getType();
STypeIR typeCg = type != null
? type.apply(question.getTypeVisitor(), question) : null;
codeGenExp.setType(typeCg);
PExp vdmExpLeft = vdmExp.getLeft();
PExp vdmExpRight = vdmExp.getRight();
SExpIR leftExpCg = vdmExpLeft.apply(question.getExpVisitor(), question);
SExpIR rightExpCg = vdmExpRight.apply(question.getExpVisitor(), question);
codeGenExp.setLeft(leftExpCg);
codeGenExp.setRight(rightExpCg);
return codeGenExp;
}
public boolean isIntegerType(PExp exp)
{
PType type = exp.getType();
// Expressions like 1.0 are considered real literal expressions
// of type NatOneNumericBasicType
return (type instanceof ANatOneNumericBasicType
|| type instanceof ANatNumericBasicType
|| type instanceof AIntNumericBasicType)
&& !(exp instanceof ARealLiteralExp);
}
public boolean isIntegerType(SExpIR exp)
{
STypeIR type = exp.getType();
// Expressions like 1.0 are considered real literal expressions
// of type NatOneNumericBasicType
return (type instanceof ANat1NumericBasicTypeIR
|| type instanceof ANatNumericBasicTypeIR
|| type instanceof AIntNumericBasicTypeIR)
&& !(exp instanceof ARealLiteralExpIR);
}
public ABoolLiteralExpIR consBoolLiteral(boolean val)
{
ABoolLiteralExpIR boolLiteral = new ABoolLiteralExpIR();
boolLiteral.setType(new ABoolBasicTypeIR());
boolLiteral.setValue(val);
return boolLiteral;
}
public AIntLiteralExpIR consIntLiteral(long value)
{
AIntLiteralExpIR intLiteral = new AIntLiteralExpIR();
intLiteral.setType(new AIntNumericBasicTypeIR());
intLiteral.setValue(value);
return intLiteral;
}
public ARealLiteralExpIR consRealLiteral(double value)
{
ARealLiteralExpIR realLiteral = new ARealLiteralExpIR();
realLiteral.setType(new ARealNumericBasicTypeIR());
realLiteral.setValue(value);
return realLiteral;
}
public ACharLiteralExpIR consCharLiteral(char value)
{
ACharLiteralExpIR charLiteral = new ACharLiteralExpIR();
charLiteral.setType(new ACharBasicTypeIR());
charLiteral.setValue(value);
return charLiteral;
}
public AStringLiteralExpIR consStringLiteral(String value, boolean isNull)
{
AStringLiteralExpIR stringLiteral = new AStringLiteralExpIR();
stringLiteral.setType(new AStringTypeIR());
stringLiteral.setIsNull(isNull);
stringLiteral.setValue(value);
return stringLiteral;
}
public SExpIR consCharSequence(STypeIR seqType, String value)
{
AEnumSeqExpIR enumSeq = new AEnumSeqExpIR();
enumSeq.setType(seqType);
for (int i = 0; i < value.length(); i++)
{
char currentChar = value.charAt(i);
ACharLiteralExpIR charLit = new ACharLiteralExpIR();
charLit.setType(new ACharBasicTypeIR());
charLit.setValue(currentChar);
enumSeq.getMembers().add(charLit);
}
return enumSeq;
}
public AQuoteLiteralExpIR consQuoteLiteral(String value)
{
AQuoteLiteralExpIR quoteLiteral = new AQuoteLiteralExpIR();
AQuoteTypeIR type = new AQuoteTypeIR();
type.setValue(value);
quoteLiteral.setType(type);
quoteLiteral.setValue(value);
return quoteLiteral;
}
public AIntLiteralExpIR getDefaultIntValue()
{
return consIntLiteral(0L);
}
public AIntLiteralExpIR getDefaultNat1Value()
{
return consIntLiteral(1L);
}
public AIntLiteralExpIR getDefaultNatValue()
{
return consIntLiteral(0L);
}
public ARealLiteralExpIR getDefaultRealValue()
{
return consRealLiteral(0.0);
}
public ABoolLiteralExpIR getDefaultBoolValue()
{
return consBoolLiteral(false);
}
public ACharLiteralExpIR getDefaultCharlValue()
{
return consCharLiteral('0');
}
public AStringLiteralExpIR getDefaultStringlValue()
{
return consStringLiteral("", true);
}
public boolean isAssigned(PExp exp)
{
org.overture.ast.node.INode parent = exp.parent();
if (parent == null)
{
return false;
}
Set<org.overture.ast.node.INode> visitedNodes = new HashSet<>();
visitedNodes.add(parent);
do
{
if (parent instanceof AInstanceVariableDefinition
| parent instanceof AValueDefinition
| parent instanceof AAssignmentDefinition
| parent instanceof AAssignmentStm)
{
return true;
}
if (parent instanceof ALambdaExp)
{
return false;
}
parent = parent.parent();
if (parent != null)
{
if (visitedNodes.contains(parent))
{
parent = null;
} else
{
visitedNodes.add(parent);
}
}
} while (parent != null);
return false;
}
public AHeaderLetBeStIR consHeader(SMultipleBindIR binding, SExpIR suchThat)
{
AHeaderLetBeStIR header = new AHeaderLetBeStIR();
header.setBinding(binding);
header.setSuchThat(suchThat);
return header;
}
public boolean appearsInModuleStateInv(org.overture.ast.node.INode node)
{
AStateDefinition stateDef = node.getAncestor(AStateDefinition.class);
if (stateDef != null)
{
LinkedList<org.overture.ast.node.INode> ancestors = new LinkedList<>();
org.overture.ast.node.INode next = node;
do
{
ancestors.add(next);
next = node.parent();
} while (!(next instanceof AStateDefinition)
&& !ancestors.contains(next));
if (ancestors.getLast() == stateDef.getInvExpression())
{
return true;
}
}
return false;
}
public boolean outsideImperativeContext(org.overture.ast.node.INode node)
{
// The transformation of the 'and' and 'or' logical expressions also assumes that the
// expressions exist within a statement. However, in case it does not, the transformation
// is not performed. In this way, the 'and' and 'or' expressions can
// still be used (say) in instance variable assignment.
return node.getAncestor(SOperationDefinition.class) == null
&& node.getAncestor(SFunctionDefinition.class) == null
&& node.getAncestor(ANamedTraceDefinition.class) == null
&& node.getAncestor(ATypeDefinition.class) == null
&& node.getAncestor(AClassInvariantDefinition.class) == null;
}
public SExpIR handleQuantifier(PExp node, List<PMultipleBind> bindings,
PExp predicate, SQuantifierExpIR quantifier, IRInfo question,
String nodeStr) throws AnalysisException
{
LinkedList<SMultipleBindIR> bindingsCg = new LinkedList<SMultipleBindIR>();
for (PMultipleBind multipleBind : bindings)
{
SMultipleBindIR multipleBindCg = multipleBind.apply(question.getMultipleBindVisitor(), question);
if (multipleBindCg != null)
{
bindingsCg.add(multipleBindCg);
}
}
PType type = node.getType();
STypeIR typeCg = type.apply(question.getTypeVisitor(), question);
SExpIR predicateCg = predicate.apply(question.getExpVisitor(), question);
quantifier.setType(typeCg);
quantifier.setBindList(bindingsCg);
quantifier.setPredicate(predicateCg);
return quantifier;
}
public void handleAlternativesCasesExp(IRInfo question, PExp exp,
List<ACaseAlternative> cases, List<ACaseAltExpExpIR> casesCg)
throws AnalysisException
{
for (ACaseAlternative alt : cases)
{
SExpIR altCg = alt.apply(question.getExpVisitor(), question);
casesCg.add((ACaseAltExpExpIR) altCg);
}
PType expType = question.getTypeAssistant().resolve(exp.getType());
if (expType instanceof AUnionType)
{
AUnionType unionType = ((AUnionType) expType).clone();
question.getTcFactory().createAUnionTypeAssistant().expand(unionType);
for (int i = 0; i < cases.size(); i++)
{
ACaseAlternative vdmCase = cases.get(i);
ACaseAltExpExpIR cgCase = casesCg.get(i);
PType patternType = question.getAssistantManager().getTypeAssistant().getType(question, unionType, vdmCase.getPattern());
STypeIR patternTypeCg = patternType.apply(question.getTypeVisitor(), question);
cgCase.setPatternType(patternTypeCg);
}
} else
{
STypeIR expTypeCg = expType.apply(question.getTypeVisitor(), question);
for (ACaseAltExpExpIR altCg : casesCg)
{
altCg.setPatternType(expTypeCg.clone());
}
}
}
public boolean isLoopCondition(SExpIR exp)
{
INode node = exp.parent();
while (node instanceof SExpIR)
{
node = node.parent();
}
return node instanceof AWhileStmIR || node instanceof AForLoopStmIR;
// The ForLoopStmIR is only used in the transformation process. It corresponds
// to the standard for loop in Java, e.g. for(int i = 0; i < 10; i++){...}
}
public SExpIR consIsExp(SExpIR exp, STypeIR checkedType)
{
exp = exp.clone();
checkedType = checkedType.clone();
if (checkedType instanceof AUnionTypeIR)
{
return consGeneralIsExp(exp, checkedType);
} else if (checkedType instanceof SBasicTypeIR)
{
return consIsExpBasicType(exp, checkedType);
} else if (checkedType instanceof AQuoteTypeIR)
{
return consIsExpQuoteType(exp, (AQuoteTypeIR) checkedType);
} else if (checkedType instanceof ATupleTypeIR)
{
return consTupleIsExp(exp, checkedType);
} else if (checkedType instanceof ARecordTypeIR
|| checkedType instanceof AClassTypeIR
|| checkedType instanceof AStringTypeIR)
{
return consGeneralIsExp(exp, checkedType);
} else
{
if (checkedType instanceof ASeqSeqTypeIR)
{
ASeqSeqTypeIR seqType = (ASeqSeqTypeIR) checkedType;
if (seqType.getSeqOf() instanceof AUnknownTypeIR)
{
return consGeneralIsExp(exp, checkedType);
}
} else if (checkedType instanceof AMapMapTypeIR)
{
AMapMapTypeIR mapType = (AMapMapTypeIR) checkedType;
if (mapType.getFrom() instanceof AUnknownTypeIR
&& mapType.getTo() instanceof AUnknownTypeIR)
{
return consGeneralIsExp(exp, checkedType);
}
}
return null;
}
}
public SExpIR consIsExpQuoteType(SExpIR exp, AQuoteTypeIR quoteType)
{
AQuoteLiteralExpIR lit = new AQuoteLiteralExpIR();
lit.setType(quoteType);
lit.setValue(quoteType.getValue());
AEqualsBinaryExpIR equals = new AEqualsBinaryExpIR();
equals.setType(new ABoolBasicTypeIR());
equals.setLeft(exp);
equals.setRight(lit);
return equals;
}
public SExpIR consGeneralIsExp(SExpIR expCg, STypeIR checkedTypeCg)
{
AGeneralIsExpIR generalIsExp = new AGeneralIsExpIR();
generalIsExp = new AGeneralIsExpIR();
generalIsExp.setType(new ABoolBasicTypeIR());
generalIsExp.setExp(expCg);
generalIsExp.setCheckedType(checkedTypeCg);
return generalIsExp;
}
public ATupleIsExpIR consTupleIsExp(SExpIR exp, STypeIR checkedType)
{
ATupleIsExpIR tupleIsExp = new ATupleIsExpIR();
tupleIsExp.setType(new ABoolBasicTypeIR());
tupleIsExp.setExp(exp);
tupleIsExp.setCheckedType(checkedType);
return tupleIsExp;
}
public SExpIR consIsExpBasicType(SExpIR expCg, STypeIR checkedType)
{
SIsExpIR basicIsExp = null;
if (checkedType instanceof ABoolBasicTypeIR)
{
basicIsExp = new ABoolIsExpIR();
} else if (checkedType instanceof ANatNumericBasicTypeIR)
{
basicIsExp = new ANatIsExpIR();
} else if (checkedType instanceof ANat1NumericBasicTypeIR)
{
basicIsExp = new ANat1IsExpIR();
} else if (checkedType instanceof AIntNumericBasicTypeIR)
{
basicIsExp = new AIntIsExpIR();
} else if (checkedType instanceof ARatNumericBasicTypeIR)
{
basicIsExp = new ARatIsExpIR();
} else if (checkedType instanceof ARealNumericBasicTypeIR)
{
basicIsExp = new ARealIsExpIR();
} else if (checkedType instanceof ACharBasicTypeIR)
{
basicIsExp = new ACharIsExpIR();
} else if (checkedType instanceof ATokenBasicTypeIR)
{
basicIsExp = new ATokenIsExpIR();
} else
{
return null;
}
basicIsExp.setType(new ABoolBasicTypeIR());
basicIsExp.setExp(expCg);
return basicIsExp;
}
public SVarExpIR idStateDesignatorToExp(AIdentifierStateDesignatorIR node)
{
if (node.getExplicit())
{
AClassTypeIR classType = new AClassTypeIR();
classType.setName(node.getClassName());
AExplicitVarExpIR explicitVar = new AExplicitVarExpIR();
explicitVar.setClassType(classType);
explicitVar.setIsLambda(false);
explicitVar.setIsLocal(node.getIsLocal());
explicitVar.setName(node.getName());
explicitVar.setSourceNode(node.getSourceNode());
explicitVar.setTag(node.getTag());
explicitVar.setType(node.getType().clone());
return explicitVar;
} else
{
AIdentifierVarExpIR idVar = consIdVar(node.getName(), node.getType().clone());
idVar.setTag(node.getTag());
idVar.setSourceNode(node.getSourceNode());
idVar.setIsLocal(node.getIsLocal());
return idVar;
}
}
public boolean isOld(String name)
{
return name != null && name.startsWith("_");
}
public String oldNameToCurrentName(String oldName)
{
if (oldName != null && oldName.startsWith("_"))
{
return oldName.substring(1);
} else
{
return oldName;
}
}
public boolean isResult(String name)
{
return name != null && name.equals("RESULT");
}
public SExpIR findSubject(SExpIR next)
{
while (next instanceof AFieldExpIR || next instanceof AMapSeqGetExpIR
|| next instanceof AApplyExpIR)
{
if (next instanceof AFieldExpIR)
{
next = ((AFieldExpIR) next).getObject();
} else if (next instanceof AMapSeqGetExpIR)
{
next = ((AMapSeqGetExpIR) next).getCol();
} else if (next instanceof AApplyExpIR)
{
next = ((AApplyExpIR) next).getRoot();
}
}
return next;
}
public AUndefinedExpIR consUndefinedExp()
{
AUndefinedExpIR undefExp = new AUndefinedExpIR();
undefExp.setType(new AUnknownTypeIR());
return undefExp;
}
public ANullExpIR consNullExp()
{
ANullExpIR nullExp = new ANullExpIR();
nullExp.setType(new AUnknownTypeIR());
return nullExp;
}
public STypeIR handleMapType(SMapTypeBase node, IRInfo question,
boolean isInjective) throws AnalysisException
{
PType from = node.getFrom();
PType to = node.getTo();
boolean empty = node.getEmpty();
STypeIR fromCg = from.apply(question.getTypeVisitor(), question);
STypeIR toCg = to.apply(question.getTypeVisitor(), question);
AMapMapTypeIR mapType = new AMapMapTypeIR();
mapType.setFrom(fromCg);
mapType.setTo(toCg);
mapType.setEmpty(empty);
mapType.setInjective(isInjective);
return mapType;
}
public boolean isUndefined(SExpIR exp)
{
if (exp instanceof ACastUnaryExpIR)
{
return isUndefined(((ACastUnaryExpIR) exp).getExp());
} else if (exp instanceof AUndefinedExpIR)
{
return true;
} else
{
return false;
}
}
}