/* * #%~ * 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.visitor; import java.util.LinkedList; import java.util.List; import org.overture.ast.analysis.AnalysisException; import org.overture.ast.definitions.AAssignmentDefinition; import org.overture.ast.definitions.AClassClassDefinition; import org.overture.ast.definitions.AInheritedDefinition; import org.overture.ast.definitions.AInstanceVariableDefinition; import org.overture.ast.definitions.AStateDefinition; import org.overture.ast.definitions.PDefinition; import org.overture.ast.definitions.SClassDefinition; import org.overture.ast.definitions.SFunctionDefinition; import org.overture.ast.definitions.SOperationDefinition; import org.overture.ast.expressions.*; import org.overture.ast.intf.lex.ILexToken; import org.overture.ast.lex.Dialect; import org.overture.ast.modules.AModuleModules; import org.overture.ast.patterns.AIdentifierPattern; import org.overture.ast.patterns.ASeqBind; import org.overture.ast.patterns.ASetBind; import org.overture.ast.patterns.ATypeBind; import org.overture.ast.patterns.PBind; import org.overture.ast.patterns.PMultipleBind; import org.overture.ast.patterns.PPattern; import org.overture.ast.typechecker.NameScope; import org.overture.ast.types.AClassType; import org.overture.ast.types.ARecordInvariantType; import org.overture.ast.types.ATokenBasicType; import org.overture.ast.types.PType; import org.overture.ast.types.SMapType; import org.overture.ast.types.SSeqType; import org.overture.ast.types.SSetType; import org.overture.codegen.ir.IRInfo; import org.overture.codegen.ir.SBindIR; import org.overture.codegen.ir.SExpIR; import org.overture.codegen.ir.SModifierIR; import org.overture.codegen.ir.SMultipleBindIR; import org.overture.codegen.ir.SPatternIR; import org.overture.codegen.ir.STypeIR; import org.overture.codegen.ir.SourceNode; import org.overture.codegen.ir.declarations.AFormalParamLocalParamIR; import org.overture.codegen.ir.expressions.AAbsUnaryExpIR; import org.overture.codegen.ir.expressions.AAndBoolBinaryExpIR; import org.overture.codegen.ir.expressions.AApplyExpIR; import org.overture.codegen.ir.expressions.ABoolLiteralExpIR; import org.overture.codegen.ir.expressions.ACardUnaryExpIR; import org.overture.codegen.ir.expressions.ACaseAltExpExpIR; import org.overture.codegen.ir.expressions.ACasesExpIR; import org.overture.codegen.ir.expressions.ACastUnaryExpIR; import org.overture.codegen.ir.expressions.ACharLiteralExpIR; import org.overture.codegen.ir.expressions.ACompMapExpIR; import org.overture.codegen.ir.expressions.ACompSeqExpIR; import org.overture.codegen.ir.expressions.ACompSetExpIR; import org.overture.codegen.ir.expressions.ADistConcatUnaryExpIR; import org.overture.codegen.ir.expressions.ADistIntersectUnaryExpIR; import org.overture.codegen.ir.expressions.ADistMergeUnaryExpIR; import org.overture.codegen.ir.expressions.ADistUnionUnaryExpIR; import org.overture.codegen.ir.expressions.ADivideNumericBinaryExpIR; import org.overture.codegen.ir.expressions.ADomainResByBinaryExpIR; import org.overture.codegen.ir.expressions.ADomainResToBinaryExpIR; import org.overture.codegen.ir.expressions.AElemsUnaryExpIR; import org.overture.codegen.ir.expressions.AEnumMapExpIR; import org.overture.codegen.ir.expressions.AEnumSeqExpIR; import org.overture.codegen.ir.expressions.AEnumSetExpIR; import org.overture.codegen.ir.expressions.AEqualsBinaryExpIR; import org.overture.codegen.ir.expressions.AExists1QuantifierExpIR; import org.overture.codegen.ir.expressions.AExistsQuantifierExpIR; import org.overture.codegen.ir.expressions.AExplicitVarExpIR; import org.overture.codegen.ir.expressions.AFieldExpIR; import org.overture.codegen.ir.expressions.AFieldNumberExpIR; import org.overture.codegen.ir.expressions.AFloorUnaryExpIR; import org.overture.codegen.ir.expressions.AForAllQuantifierExpIR; import org.overture.codegen.ir.expressions.AGreaterEqualNumericBinaryExpIR; import org.overture.codegen.ir.expressions.AGreaterNumericBinaryExpIR; import org.overture.codegen.ir.expressions.AHeadUnaryExpIR; import org.overture.codegen.ir.expressions.AHistoryExpIR; import org.overture.codegen.ir.expressions.AIdentifierVarExpIR; import org.overture.codegen.ir.expressions.AInSetBinaryExpIR; import org.overture.codegen.ir.expressions.AIndicesUnaryExpIR; import org.overture.codegen.ir.expressions.AInstanceofExpIR; import org.overture.codegen.ir.expressions.AIntDivNumericBinaryExpIR; import org.overture.codegen.ir.expressions.AIntLiteralExpIR; import org.overture.codegen.ir.expressions.ALambdaExpIR; import org.overture.codegen.ir.expressions.ALenUnaryExpIR; import org.overture.codegen.ir.expressions.ALessEqualNumericBinaryExpIR; import org.overture.codegen.ir.expressions.ALessNumericBinaryExpIR; import org.overture.codegen.ir.expressions.ALetBeStExpIR; import org.overture.codegen.ir.expressions.ALetDefExpIR; import org.overture.codegen.ir.expressions.AMapDomainUnaryExpIR; import org.overture.codegen.ir.expressions.AMapInverseUnaryExpIR; import org.overture.codegen.ir.expressions.AMapOverrideBinaryExpIR; import org.overture.codegen.ir.expressions.AMapRangeUnaryExpIR; import org.overture.codegen.ir.expressions.AMapUnionBinaryExpIR; import org.overture.codegen.ir.expressions.AMapletExpIR; import org.overture.codegen.ir.expressions.AMethodInstantiationExpIR; import org.overture.codegen.ir.expressions.AMinusUnaryExpIR; import org.overture.codegen.ir.expressions.AMkBasicExpIR; import org.overture.codegen.ir.expressions.AModNumericBinaryExpIR; import org.overture.codegen.ir.expressions.ANewExpIR; import org.overture.codegen.ir.expressions.ANotEqualsBinaryExpIR; import org.overture.codegen.ir.expressions.ANotImplementedExpIR; import org.overture.codegen.ir.expressions.ANotUnaryExpIR; import org.overture.codegen.ir.expressions.ANullExpIR; import org.overture.codegen.ir.expressions.AOrBoolBinaryExpIR; import org.overture.codegen.ir.expressions.APlusNumericBinaryExpIR; import org.overture.codegen.ir.expressions.APlusUnaryExpIR; import org.overture.codegen.ir.expressions.APowerNumericBinaryExpIR; import org.overture.codegen.ir.expressions.APowerSetUnaryExpIR; import org.overture.codegen.ir.expressions.AQuoteLiteralExpIR; import org.overture.codegen.ir.expressions.ARangeResByBinaryExpIR; import org.overture.codegen.ir.expressions.ARangeResToBinaryExpIR; import org.overture.codegen.ir.expressions.ARangeSetExpIR; import org.overture.codegen.ir.expressions.ARealLiteralExpIR; import org.overture.codegen.ir.expressions.ARecordModExpIR; import org.overture.codegen.ir.expressions.ARecordModifierIR; import org.overture.codegen.ir.expressions.ARemNumericBinaryExpIR; import org.overture.codegen.ir.expressions.AReverseUnaryExpIR; import org.overture.codegen.ir.expressions.ASelfExpIR; import org.overture.codegen.ir.expressions.ASeqConcatBinaryExpIR; import org.overture.codegen.ir.expressions.ASeqModificationBinaryExpIR; import org.overture.codegen.ir.expressions.ASetDifferenceBinaryExpIR; import org.overture.codegen.ir.expressions.ASetIntersectBinaryExpIR; import org.overture.codegen.ir.expressions.ASetProperSubsetBinaryExpIR; import org.overture.codegen.ir.expressions.ASetSubsetBinaryExpIR; import org.overture.codegen.ir.expressions.ASetUnionBinaryExpIR; import org.overture.codegen.ir.expressions.AStringLiteralExpIR; import org.overture.codegen.ir.expressions.ASubSeqExpIR; import org.overture.codegen.ir.expressions.ASubtractNumericBinaryExpIR; import org.overture.codegen.ir.expressions.ASuperVarExpIR; import org.overture.codegen.ir.expressions.ATailUnaryExpIR; import org.overture.codegen.ir.expressions.ATernaryIfExpIR; import org.overture.codegen.ir.expressions.AThreadIdExpIR; import org.overture.codegen.ir.expressions.ATimeExpIR; import org.overture.codegen.ir.expressions.ATimesNumericBinaryExpIR; import org.overture.codegen.ir.expressions.ATupleExpIR; import org.overture.codegen.ir.expressions.AUndefinedExpIR; import org.overture.codegen.ir.expressions.AXorBoolBinaryExpIR; import org.overture.codegen.ir.expressions.SVarExpIR; import org.overture.codegen.ir.name.ATypeNameIR; import org.overture.codegen.ir.patterns.ASeqBindIR; import org.overture.codegen.ir.patterns.ASetBindIR; 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.ARecordTypeIR; import org.overture.codegen.ir.types.ASeqSeqTypeIR; import org.overture.codegen.ir.types.AStringTypeIR; import org.overture.codegen.ir.types.AUnknownTypeIR; import org.overture.codegen.ir.utils.AHeaderLetBeStIR; import org.overture.config.Settings; public class ExpVisitorIR extends AbstractVisitorIR<IRInfo, SExpIR> { @Override public SExpIR caseANarrowExp(ANarrowExp node, IRInfo question) throws AnalysisException { PExp exp = node.getTest(); PType type = null; if (node.getBasicType() != null) { type = node.getBasicType(); } else if (node.getTypedef() != null) { type = question.getTcFactory().createPDefinitionAssistant().getType(node.getTypedef()); } SExpIR expCg = exp.apply(question.getExpVisitor(), question); STypeIR typeCg; if (type != null) { typeCg = type.apply(question.getTypeVisitor(), question); } else { log.error("Could not find type of narrow expression"); typeCg = new AUnknownTypeIR(); typeCg.setSourceNode(new SourceNode(node)); } ACastUnaryExpIR cast = new ACastUnaryExpIR(); cast.setExp(expCg); cast.setType(typeCg); return cast; } @Override public SExpIR caseAStateInitExp(AStateInitExp node, IRInfo question) throws AnalysisException { return node.getState().getInitExpression().apply(question.getExpVisitor(), question); } @Override public SExpIR caseAUndefinedExp(AUndefinedExp node, IRInfo question) throws AnalysisException { return new AUndefinedExpIR(); } @Override public SExpIR caseAPreOpExp(APreOpExp node, IRInfo question) throws AnalysisException { PExp exp = node.getExpression(); return exp.apply(question.getExpVisitor(), question); } @Override public SExpIR caseAPostOpExp(APostOpExp node, IRInfo question) throws AnalysisException { PExp exp = node.getPostexpression(); return exp.apply(question.getExpVisitor(), question); } @Override public SExpIR caseANotYetSpecifiedExp(ANotYetSpecifiedExp node, IRInfo question) throws AnalysisException { return new ANotImplementedExpIR(); } @Override public SExpIR caseATimeExp(ATimeExp node, IRInfo question) throws AnalysisException { STypeIR typeCg = node.getType().apply(question.getTypeVisitor(), question); ATimeExpIR timeExp = new ATimeExpIR(); timeExp.setType(typeCg); return timeExp; } @Override public SExpIR caseAThreadIdExp(AThreadIdExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); STypeIR typeIR = type.apply(question.getTypeVisitor(), question); AThreadIdExpIR threadId = new AThreadIdExpIR(); threadId.setType(typeIR); return threadId; } @Override public SExpIR caseANilExp(ANilExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); ANullExpIR nullExpCg = new ANullExpIR(); nullExpCg.setType(typeCg); return nullExpCg; } @Override public SExpIR caseAMkBasicExp(AMkBasicExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); if (!(type instanceof ATokenBasicType)) { question.addUnsupportedNode(node, "Expected token type for mk basic expression. Got: " + type); return null; } PExp arg = node.getArg(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); SExpIR argCg = arg.apply(question.getExpVisitor(), question); AMkBasicExpIR mkBasicExp = new AMkBasicExpIR(); mkBasicExp.setType(typeCg); mkBasicExp.setArg(argCg); return mkBasicExp; } @Override public SExpIR caseAIsExp(AIsExp node, IRInfo question) throws AnalysisException { // TODO: Optional types and collection types are not yet supported. // Also tuple types are poorly supported // Also check the IsExpTransformation PType checkedType = node.getBasicType(); if (checkedType == null) { checkedType = question.getTcFactory().createPDefinitionAssistant().getType(node.getTypedef()); } PExp exp = node.getTest(); SExpIR expCg = exp.apply(question.getExpVisitor(), question); if (expCg == null) { return null; } STypeIR checkedTypeCg = checkedType.apply(question.getTypeVisitor(), question); if (checkedTypeCg == null) { return null; } SExpIR isExp = question.getExpAssistant().consIsExp(expCg, checkedTypeCg); if (isExp == null) { question.addUnsupportedNode(node, "The 'is' expression is not supported for type: " + checkedType.getClass().getName()); return null; } return isExp; } @Override public SExpIR caseAIsOfClassExp(AIsOfClassExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); AClassType classType = node.getClassType(); PExp objRef = node.getExp(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); STypeIR classTypeCg = classType.apply(question.getTypeVisitor(), question); if (!(classTypeCg instanceof AClassTypeIR)) { log.error("Unexpected class type encountered for " + AIsOfClassExp.class.getName() + ". Expected class type: " + AClassTypeIR.class.getName() + ". Got: " + typeCg.getClass().getName() + " at " + node.getLocation()); } SExpIR objRefCg = objRef.apply(question.getExpVisitor(), question); AInstanceofExpIR instanceOfExp = new AInstanceofExpIR(); instanceOfExp.setType(typeCg); instanceOfExp.setCheckedType(classTypeCg); instanceOfExp.setExp(objRefCg); return instanceOfExp; } @Override public SExpIR caseACardinalityUnaryExp(ACardinalityUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new ACardUnaryExpIR(), question); } @Override public SExpIR caseAInSetBinaryExp(AInSetBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new AInSetBinaryExpIR(), question); } @Override public SExpIR caseANotInSetBinaryExp(ANotInSetBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().negate(question.getExpAssistant().handleBinaryExp(node, new AInSetBinaryExpIR(), question)); } @Override public SExpIR caseASetUnionBinaryExp(ASetUnionBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new ASetUnionBinaryExpIR(), question); } @Override public SExpIR caseASetIntersectBinaryExp(ASetIntersectBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new ASetIntersectBinaryExpIR(), question); } @Override public SExpIR caseASetDifferenceBinaryExp(ASetDifferenceBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new ASetDifferenceBinaryExpIR(), question); } @Override public SExpIR caseASubsetBinaryExp(ASubsetBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new ASetSubsetBinaryExpIR(), question); } @Override public SExpIR caseAProperSubsetBinaryExp(AProperSubsetBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new ASetProperSubsetBinaryExpIR(), question); } @Override public SExpIR caseADistUnionUnaryExp(ADistUnionUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new ADistUnionUnaryExpIR(), question); } @Override public SExpIR caseADistIntersectUnaryExp(ADistIntersectUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new ADistIntersectUnaryExpIR(), question); } @Override public SExpIR caseAPowerSetUnaryExp(APowerSetUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new APowerSetUnaryExpIR(), question); } @Override public SExpIR caseASetEnumSetExp(ASetEnumSetExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); if (!(type instanceof SSetType)) { log.error("Unexpected set type for set enumeration expression: " + type.getClass().getName() + " at " + node.getLocation()); } LinkedList<PExp> members = node.getMembers(); AEnumSetExpIR enumSet = new AEnumSetExpIR(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); enumSet.setType(typeCg); LinkedList<SExpIR> membersCg = enumSet.getMembers(); for (PExp member : members) { SExpIR memberCg = member.apply(question.getExpVisitor(), question); if (memberCg != null) { membersCg.add(memberCg); } else { return null; } } return enumSet; } @Override public SExpIR caseAForAllExp(AForAllExp node, IRInfo question) throws AnalysisException { // The inheritance hierarchy of the VDM AST tree is structured such that the bindings and the predicate // must also be passed to the method that handles the forall and the exists quantifiers return question.getExpAssistant().handleQuantifier(node, node.getBindList(), node.getPredicate(), new AForAllQuantifierExpIR(), question, "forall expression"); } @Override public SExpIR caseAExistsExp(AExistsExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleQuantifier(node, node.getBindList(), node.getPredicate(), new AExistsQuantifierExpIR(), question, "exists expression"); } @Override public SExpIR caseAExists1Exp(AExists1Exp node, IRInfo question) throws AnalysisException { PBind bind = node.getBind(); SBindIR bindCg = bind.apply(question.getBindVisitor(), question); PType type = node.getType(); PExp predicate = node.getPredicate(); SMultipleBindIR multipleBind = question.getBindAssistant().convertToMultipleBind(bindCg); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); SExpIR predicateCg = predicate.apply(question.getExpVisitor(), question); AExists1QuantifierExpIR exists1Exp = new AExists1QuantifierExpIR(); exists1Exp.getBindList().add(multipleBind); exists1Exp.setType(typeCg); exists1Exp.setPredicate(predicateCg); return exists1Exp; } @Override public SExpIR caseASetCompSetExp(ASetCompSetExp node, IRInfo question) throws AnalysisException { LinkedList<PMultipleBind> bindings = node.getBindings(); List<SMultipleBindIR> bindingsCg = new LinkedList<SMultipleBindIR>(); for (PMultipleBind multipleBind : bindings) { SMultipleBindIR multipleBindCg = multipleBind.apply(question.getMultipleBindVisitor(), question); if (multipleBindCg != null) { bindingsCg.add(multipleBindCg); } else { return null; } } PType type = node.getType(); PExp first = node.getFirst(); PExp predicate = node.getPredicate(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); SExpIR firstCg = first.apply(question.getExpVisitor(), question); SExpIR predicateCg = predicate != null ? predicate.apply(question.getExpVisitor(), question) : null; ACompSetExpIR setComp = new ACompSetExpIR(); setComp.setBindings(bindingsCg); setComp.setType(typeCg); setComp.setFirst(firstCg); setComp.setPredicate(predicateCg); return setComp; } @Override public SExpIR caseASetRangeSetExp(ASetRangeSetExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); PExp firstExp = node.getFirst(); PExp lastExp = node.getLast(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); SExpIR firstExpCg = firstExp.apply(question.getExpVisitor(), question); SExpIR lastExpCg = lastExp.apply(question.getExpVisitor(), question); ARangeSetExpIR setRange = new ARangeSetExpIR(); setRange.setType(typeCg); setRange.setFirst(firstExpCg); setRange.setLast(lastExpCg); return setRange; } @Override public SExpIR caseACasesExp(ACasesExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); PExp exp = node.getExpression(); PExp others = node.getOthers(); LinkedList<ACaseAlternative> cases = node.getCases(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); SExpIR expCg = exp.apply(question.getExpVisitor(), question); SExpIR othersCg = others != null ? others.apply(question.getExpVisitor(), question) : null; ACasesExpIR casesExpCg = new ACasesExpIR(); casesExpCg.setType(typeCg); casesExpCg.setExp(expCg); casesExpCg.setOthers(othersCg); question.getExpAssistant().handleAlternativesCasesExp(question, exp, cases, casesExpCg.getCases()); return casesExpCg; } @Override public SExpIR caseACaseAlternative(ACaseAlternative node, IRInfo question) throws AnalysisException { PPattern pattern = node.getPattern(); PExp result = node.getResult(); SPatternIR patternCg = pattern.apply(question.getPatternVisitor(), question); SExpIR resultCg = result.apply(question.getExpVisitor(), question); ACaseAltExpExpIR altCg = new ACaseAltExpExpIR(); altCg.setPattern(patternCg); altCg.setResult(resultCg); return altCg; } @Override public SExpIR caseAIfExp(AIfExp node, IRInfo question) throws AnalysisException { SExpIR testExp = node.getTest().apply(question.getExpVisitor(), question); SExpIR thenExp = node.getThen().apply(question.getExpVisitor(), question); STypeIR expectedType = node.getType().apply(question.getTypeVisitor(), question); ATernaryIfExpIR ternaryIf = new ATernaryIfExpIR(); ternaryIf.setCondition(testExp); ternaryIf.setTrueValue(thenExp); ternaryIf.setType(expectedType); LinkedList<AElseIfExp> elseExpList = node.getElseList(); ATernaryIfExpIR nextTernaryIf = ternaryIf; for (AElseIfExp currentElseExp : elseExpList) { ATernaryIfExpIR tmp = new ATernaryIfExpIR(); testExp = currentElseExp.getElseIf().apply(question.getExpVisitor(), question); thenExp = currentElseExp.getThen().apply(question.getExpVisitor(), question); expectedType = currentElseExp.getType().apply(question.getTypeVisitor(), question); tmp.setCondition(testExp); tmp.setTrueValue(thenExp); tmp.setType(expectedType); nextTernaryIf.setFalseValue(tmp); nextTernaryIf = tmp; } SExpIR elseExp = node.getElse().apply(question.getExpVisitor(), question); nextTernaryIf.setFalseValue(elseExp); if (node.parent() instanceof SBinaryExp) { return question.getExpAssistant().isolateExpression(ternaryIf); } return ternaryIf; } @Override public SExpIR caseATupleExp(ATupleExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); LinkedList<PExp> args = node.getArgs(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); ATupleExpIR tupleExp = new ATupleExpIR(); tupleExp.setType(typeCg); for (PExp exp : args) { SExpIR expCg = exp.apply(question.getExpVisitor(), question); if (expCg != null) { tupleExp.getArgs().add(expCg); } else { return null; } } return tupleExp; } @Override public SExpIR caseAFieldNumberExp(AFieldNumberExp node, IRInfo question) throws AnalysisException { long fieldCg = node.getField().getValue(); PType type = node.getType(); PExp tuple = node.getTuple(); AFieldNumberExpIR fieldNoExp = new AFieldNumberExpIR(); SExpIR tupleCg = tuple.apply(question.getExpVisitor(), question); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); fieldNoExp.setField(fieldCg); fieldNoExp.setType(typeCg); fieldNoExp.setTuple(tupleCg); return fieldNoExp; } @Override public SExpIR caseAFuncInstatiationExp(AFuncInstatiationExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); PExp func = node.getFunction(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); SExpIR funcCg = func.apply(question.getExpVisitor(), question); AMethodInstantiationExpIR methodInst = new AMethodInstantiationExpIR(); LinkedList<PType> actualTypes = node.getActualTypes(); for (PType actualType : actualTypes) { STypeIR actualTypeCg = actualType.apply(question.getTypeVisitor(), question); if (actualTypeCg != null) { methodInst.getActualTypes().add(actualTypeCg); } else { return null; } } methodInst.setFunc(funcCg); methodInst.setType(typeCg); return methodInst; } @Override public SExpIR caseALetBeStExp(ALetBeStExp node, IRInfo question) throws AnalysisException { PMultipleBind multipleBind = node.getBind(); SMultipleBindIR multipleBindCg = multipleBind.apply(question.getMultipleBindVisitor(), question); PType type = node.getType(); PExp suchThat = node.getSuchThat(); PExp value = node.getValue(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); SExpIR suchThatCg = suchThat != null ? suchThat.apply(question.getExpVisitor(), question) : null; SExpIR valueCg = value.apply(question.getExpVisitor(), question); ALetBeStExpIR letBeStExp = new ALetBeStExpIR(); AHeaderLetBeStIR header = question.getExpAssistant().consHeader(multipleBindCg, suchThatCg); letBeStExp.setType(typeCg); letBeStExp.setHeader(header); letBeStExp.setValue(valueCg); return letBeStExp; } @Override public SExpIR caseALetDefExp(ALetDefExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); PExp exp = node.getExpression(); ALetDefExpIR letDefExp = new ALetDefExpIR(); question.getDeclAssistant().setFinalLocalDefs(node.getLocalDefs(), letDefExp.getLocalDefs(), question); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); letDefExp.setType(typeCg); SExpIR expCg = exp.apply(question.getExpVisitor(), question); letDefExp.setExp(expCg); return letDefExp; } @Override public SExpIR caseAMuExp(AMuExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); ARecordInvariantType recType = node.getRecordType(); PExp rec = node.getRecord(); List<ARecordModifier> modifiers = node.getModifiers(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); STypeIR recTypeCg = recType.apply(question.getTypeVisitor(), question); if (!(recTypeCg instanceof ARecordTypeIR)) { question.addUnsupportedNode(node, "Expected a record type. Got: " + recTypeCg); return null; } SExpIR recCg = rec.apply(question.getExpVisitor(), question); List<ARecordModifierIR> modifiersCg = new LinkedList<ARecordModifierIR>(); for (ARecordModifier m : modifiers) { SModifierIR modifier = m.apply(question.getModifierVisitor(), question); if (modifier instanceof ARecordModifierIR) { modifiersCg.add((ARecordModifierIR) modifier); } else { question.addUnsupportedNode(node, "Expected modifier to be a record modifier for the 'mu' expression. Got: " + modifier); return null; } } ARecordModExpIR recModExp = new ARecordModExpIR(); recModExp.setType(typeCg); recModExp.setRecType((ARecordTypeIR) recTypeCg); recModExp.setRec(recCg); recModExp.setModifiers(modifiersCg); return recModExp; } @Override public SExpIR caseAMkTypeExp(AMkTypeExp node, IRInfo question) throws AnalysisException { ARecordInvariantType recType = node.getRecordType(); if (recType == null) { question.addUnsupportedNode(node, "Expected record type for mk_<type> expression. Got null."); return null; } STypeIR typeCg = recType.apply(question.getTypeVisitor(), question); if (!(typeCg instanceof ARecordTypeIR)) { question.addUnsupportedNode(node, "Expected record type but got: " + typeCg.getClass().getName() + " in 'mk_' expression"); return null; } ARecordTypeIR recordTypeCg = (ARecordTypeIR) typeCg; LinkedList<PExp> nodeArgs = node.getArgs(); ANewExpIR newExp = new ANewExpIR(); newExp.setType(recordTypeCg); newExp.setName(recordTypeCg.getName().clone()); LinkedList<SExpIR> newExpArgs = newExp.getArgs(); for (PExp arg : nodeArgs) { SExpIR argCg = arg.apply(question.getExpVisitor(), question); if (argCg != null) { newExpArgs.add(argCg); } else { return null; } } return newExp; } @Override public SExpIR caseASelfExp(ASelfExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); ASelfExpIR selfExpCg = new ASelfExpIR(); selfExpCg.setType(typeCg); return selfExpCg; } @Override public SExpIR caseASubseqExp(ASubseqExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); PExp from = node.getFrom(); PExp to = node.getTo(); PExp seq = node.getSeq(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); SExpIR fromCg = from.apply(question.getExpVisitor(), question); SExpIR toCg = to.apply(question.getExpVisitor(), question); SExpIR seqCg = seq.apply(question.getExpVisitor(), question); ASubSeqExpIR subSeq = new ASubSeqExpIR(); subSeq.setType(typeCg); subSeq.setFrom(fromCg); subSeq.setTo(toCg); subSeq.setSeq(seqCg); return subSeq; } @Override public SExpIR caseAReverseUnaryExp(AReverseUnaryExp node, IRInfo question) throws AnalysisException { PExp exp = node.getExp(); PType type = node.getType(); if (!(type instanceof SSeqType)) { question.addUnsupportedNode(node, "Unexpected sequence type for reverse unary expression: " + type.getClass().getName()); return null; } SSeqType seqType = (SSeqType) type; STypeIR seqTypeCg = seqType.apply(question.getTypeVisitor(), question); SExpIR expCg = exp.apply(question.getExpVisitor(), question); AReverseUnaryExpIR reverse = new AReverseUnaryExpIR(); reverse.setExp(expCg); reverse.setType(seqTypeCg); return reverse; } @Override public SExpIR caseADistConcatUnaryExp(ADistConcatUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new ADistConcatUnaryExpIR(), question); } @Override public SExpIR caseASeqCompSeqExp(ASeqCompSeqExp node, IRInfo question) throws AnalysisException { ACompSeqExpIR seqComp = new ACompSeqExpIR(); if (node.getSetBind() != null) { ASetBind setBind = node.getSetBind(); SBindIR bindTempCg = setBind.apply(question.getBindVisitor(), question); if (!(bindTempCg instanceof ASetBindIR)) { question.addUnsupportedNode(node, "Expected set bind for sequence comprehension. Got: " + bindTempCg); return null; } ASetBindIR setBindCg = (ASetBindIR) bindTempCg; seqComp.setSetBind(setBindCg); PExp set = node.getSetBind().getSet(); SExpIR setCg = set.apply(question.getExpVisitor(), question); seqComp.setSetSeq(setCg); } else { ASeqBind seqBind = node.getSeqBind(); SBindIR bindTempCg = seqBind.apply(question.getBindVisitor(), question); if (!(bindTempCg instanceof ASeqBindIR)) { question.addUnsupportedNode(node, "Expected seq bind for sequence comprehension. Got: " + bindTempCg); return null; } ASeqBindIR seqBindCg = (ASeqBindIR) bindTempCg; seqComp.setSeqBind(seqBindCg); PExp seq = node.getSeqBind().getSeq(); SExpIR seqCg = seq.apply(question.getExpVisitor(), question); seqComp.setSetSeq(seqCg); } PType type = node.getType(); PExp first = node.getFirst(); PExp predicate = node.getPredicate(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); SExpIR firstCg = first.apply(question.getExpVisitor(), question); SExpIR predicateCg = predicate != null ? predicate.apply(question.getExpVisitor(), question) : null; seqComp.setType(typeCg); seqComp.setFirst(firstCg); seqComp.setPredicate(predicateCg); return seqComp; } @Override public SExpIR caseASeqConcatBinaryExp(ASeqConcatBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new ASeqConcatBinaryExpIR(), question); } @Override public SExpIR caseAPlusPlusBinaryExp(APlusPlusBinaryExp node, IRInfo question) throws AnalysisException { if (node.getType() instanceof SSeqType) { return question.getExpAssistant().handleBinaryExp(node, new ASeqModificationBinaryExpIR(), question); } else if (node.getType() instanceof SMapType) { return question.getExpAssistant().handleBinaryExp(node, new AMapOverrideBinaryExpIR(), question); } question.addUnsupportedNode(node, "Expected sequence or map type for '++' binary expression but got: " + node.getType()); return null; } @Override public SExpIR caseAMapEnumMapExp(AMapEnumMapExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); AEnumMapExpIR enumMap = new AEnumMapExpIR(); enumMap.setType(typeCg); LinkedList<AMapletExp> members = node.getMembers(); for (PExp member : members) { SExpIR memberCg = member.apply(question.getExpVisitor(), question); if (!(memberCg instanceof AMapletExpIR)) { question.addUnsupportedNode(node, "Got expected map enumeration member: " + memberCg); return null; } else { enumMap.getMembers().add((AMapletExpIR) memberCg); } } return enumMap; } @Override public SExpIR caseAMapletExp(AMapletExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); PExp left = node.getLeft(); PExp right = node.getRight(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); SExpIR leftCg = left.apply(question.getExpVisitor(), question); SExpIR rightCg = right.apply(question.getExpVisitor(), question); AMapletExpIR maplet = new AMapletExpIR(); maplet.setType(typeCg); maplet.setLeft(leftCg); maplet.setRight(rightCg); return maplet; } @Override public SExpIR caseAMapCompMapExp(AMapCompMapExp node, IRInfo question) throws AnalysisException { LinkedList<PMultipleBind> bindings = node.getBindings(); PType type = node.getType(); AMapletExp first = node.getFirst(); PExp predicate = node.getPredicate(); List<SMultipleBindIR> bindingsCg = new LinkedList<SMultipleBindIR>(); for (PMultipleBind multipleBind : bindings) { SMultipleBindIR multipleBindCg = multipleBind.apply(question.getMultipleBindVisitor(), question); if (multipleBindCg != null) { bindingsCg.add(multipleBindCg); } else { return null; } } STypeIR typeCg = type.apply(question.getTypeVisitor(), question); SExpIR firstCg = first.apply(question.getExpVisitor(), question); SExpIR predicateCg = predicate != null ? predicate.apply(question.getExpVisitor(), question) : null; if (!(firstCg instanceof AMapletExpIR)) { question.addUnsupportedNode(node, "Generation of map comprehension expected a maplet expression. Got: " + firstCg); return null; } AMapletExpIR mapletExpCg = (AMapletExpIR) firstCg; ACompMapExpIR mapComp = new ACompMapExpIR(); mapComp.setBindings(bindingsCg); mapComp.setType(typeCg); mapComp.setFirst(mapletExpCg); mapComp.setPredicate(predicateCg); return mapComp; } @Override public SExpIR caseAMapDomainUnaryExp(AMapDomainUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new AMapDomainUnaryExpIR(), question); } @Override public SExpIR caseAMapRangeUnaryExp(AMapRangeUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new AMapRangeUnaryExpIR(), question); } @Override public SExpIR caseAMapUnionBinaryExp(AMapUnionBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new AMapUnionBinaryExpIR(), question); } @Override public SExpIR caseADistMergeUnaryExp(ADistMergeUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new ADistMergeUnaryExpIR(), question); } @Override public SExpIR caseADomainResToBinaryExp(ADomainResToBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new ADomainResToBinaryExpIR(), question); } @Override public SExpIR caseADomainResByBinaryExp(ADomainResByBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new ADomainResByBinaryExpIR(), question); } @Override public SExpIR caseARangeResToBinaryExp(ARangeResToBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new ARangeResToBinaryExpIR(), question); } @Override public SExpIR caseARangeResByBinaryExp(ARangeResByBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new ARangeResByBinaryExpIR(), question); } @Override public SExpIR caseAMapInverseUnaryExp(AMapInverseUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new AMapInverseUnaryExpIR(), question); } @Override public SExpIR caseAEqualsBinaryExp(AEqualsBinaryExp node, IRInfo question) throws AnalysisException { SExpIR eqBinExpCg = question.getExpAssistant().handleBinaryExp(node, new AEqualsBinaryExpIR(), question); // TODO: Update the type checker? // PVJ: For some reason the type checker does not decorate the SL // init expression (e.g. s = mk_StateName(1,2).) in state // definitions with a type (the type is null) // So this is really just to prevent null types // in the IR if (eqBinExpCg.getType() == null) { eqBinExpCg.setType(new ABoolBasicTypeIR()); } return eqBinExpCg; } @Override public SExpIR caseANotEqualBinaryExp(ANotEqualBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new ANotEqualsBinaryExpIR(), question); } @Override public SExpIR caseAIndicesUnaryExp(AIndicesUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new AIndicesUnaryExpIR(), question); } @Override public SExpIR caseASeqEnumSeqExp(ASeqEnumSeqExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); AEnumSeqExpIR enumSeq = new AEnumSeqExpIR(); if (type instanceof SSeqType) { STypeIR typeCg = type.apply(question.getTypeVisitor(), question); enumSeq.setType(typeCg); } else { question.addUnsupportedNode(node, "Unexpected sequence type for sequence enumeration expression: " + type.getClass().getName()); return null; } LinkedList<PExp> members = node.getMembers(); for (PExp member : members) { SExpIR memberCg = member.apply(question.getExpVisitor(), question); if (memberCg != null) { enumSeq.getMembers().add(memberCg); } else { return null; } } return enumSeq; } @Override public SExpIR caseASubclassResponsibilityExp( ASubclassResponsibilityExp node, IRInfo question) throws AnalysisException { return null;// Indicates an abstract body } @Override public SExpIR caseAFieldExp(AFieldExp node, IRInfo question) throws AnalysisException { SExpIR object = node.getObject().apply(question.getExpVisitor(), question); STypeIR type = node.getType().apply(question.getTypeVisitor(), question); String memberName = ""; if (node.getMemberName() != null) { memberName = node.getMemberName().getFullName(); } else { memberName = node.getField().getName(); } AFieldExpIR fieldExp = new AFieldExpIR(); fieldExp.setObject(object); fieldExp.setMemberName(memberName); fieldExp.setType(type); return fieldExp; } @Override public SExpIR caseAApplyExp(AApplyExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); PExp root = node.getRoot(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); SExpIR rootCg = root.apply(question.getExpVisitor(), question); AApplyExpIR applyExp = new AApplyExpIR(); applyExp.setType(typeCg); applyExp.setRoot(rootCg); for (PExp arg : node.getArgs()) { SExpIR argCg = arg.apply(question.getExpVisitor(), question); if (argCg != null) { applyExp.getArgs().add(argCg); } else { return null; } } return applyExp; } @Override public SExpIR caseAVariableExp(AVariableExp node, IRInfo question) throws AnalysisException { PDefinition varDef = node.getVardef(); PType type = node.getType(); String name = node.getName().getName(); PDefinition unfolded = varDef; while (unfolded instanceof AInheritedDefinition) { unfolded = ((AInheritedDefinition) unfolded).getSuperdef(); } boolean isLambda = question.getTcFactory().createPTypeAssistant().isFunction(type) && !(unfolded instanceof SFunctionDefinition); boolean explicit = node.getName().getExplicit(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); boolean isLocalDef = varDef instanceof AAssignmentDefinition || !(varDef.getNameScope() == NameScope.STATE || varDef.getNameScope() == NameScope.GLOBAL || varDef.getNameScope() == NameScope.VARSTATE || varDef.getNameScope() == NameScope.VARSANDSTATE); if (Settings.dialect == Dialect.VDM_PP || Settings.dialect == Dialect.VDM_RT) { SClassDefinition owningClass = varDef.getAncestor(SClassDefinition.class); SClassDefinition nodeParentClass = node.getAncestor(SClassDefinition.class); boolean isInstanceVarDef = varDef instanceof AInstanceVariableDefinition; boolean isExplOp = varDef instanceof SOperationDefinition; boolean isExplFunc = varDef instanceof SFunctionDefinition; boolean isDefInOwningClass = owningClass == nodeParentClass && (isLocalDef || isInstanceVarDef || isExplOp || isExplFunc); if (isExplOp && !isDefInOwningClass && !question.getTcFactory().createPDefinitionAssistant().isStatic(varDef)) { ASuperVarExpIR superVarExp = new ASuperVarExpIR(); superVarExp.setType(typeCg); superVarExp.setIsLocal(isLocalDef); superVarExp.setName(name); superVarExp.setIsLambda(isLambda); return superVarExp; } else if (explicit && !isLocalDef && question.getTcFactory().createPDefinitionAssistant().isStatic(varDef)) { return consExplicitVar(node.getName().getModule(), name, isLambda, typeCg, isLocalDef); } else { return consIdVar(name, isLambda, typeCg, isLocalDef); } } else if (Settings.dialect == Dialect.VDM_SL) { String defModuleName = varDef.getLocation().getModule(); String nodeModuleName = "DEFAULT"; AModuleModules nodeModule = node.getAncestor(AModuleModules.class); if (nodeModule != null) { nodeModuleName = nodeModule.getName().getName(); } boolean inOwningModule = defModuleName.equals(nodeModuleName); SVarExpIR res; if (inOwningModule) { res = consIdVar(name, isLambda, typeCg, isLocalDef); } else { res = consExplicitVar(defModuleName, name, isLambda, typeCg, isLocalDef); } if (question.getDeclAssistant().inFunc(node) || varDef.getAncestor(AStateDefinition.class) == null) { question.registerSlStateRead(res); } return res; } else { log.error("Got unexpected dialect " + Settings.dialect); return null; } } private SVarExpIR consExplicitVar(String className, String name, boolean isLambda, STypeIR typeCg, boolean isLocalDef) { AExplicitVarExpIR varExp = new AExplicitVarExpIR(); AClassTypeIR classType = new AClassTypeIR(); classType.setName(className); varExp.setType(typeCg); varExp.setIsLocal(isLocalDef); varExp.setClassType(classType); varExp.setName(name); varExp.setIsLambda(isLambda); return varExp; } private SVarExpIR consIdVar(String name, boolean isLambda, STypeIR typeCg, boolean isLocalDef) { AIdentifierVarExpIR varExp = new AIdentifierVarExpIR(); varExp.setType(typeCg); varExp.setIsLocal(isLocalDef); varExp.setName(name); varExp.setIsLambda(isLambda); return varExp; } @Override public SExpIR caseANewExp(ANewExp node, IRInfo question) throws AnalysisException { String className = node.getClassdef().getName().getName(); ATypeNameIR typeName = new ATypeNameIR(); typeName.setDefiningClass(null); typeName.setName(className); PType type = node.getType(); LinkedList<PExp> nodeArgs = node.getArgs(); ANewExpIR newExp = new ANewExpIR(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); newExp.setType(typeCg); newExp.setName(typeName); LinkedList<SExpIR> newExpArgs = newExp.getArgs(); for (PExp arg : nodeArgs) { SExpIR argCg = arg.apply(question.getExpVisitor(), question); if (argCg != null) { newExpArgs.add(argCg); } else { return null; } } return newExp; } @Override public SExpIR caseATimesNumericBinaryExp(ATimesNumericBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new ATimesNumericBinaryExpIR(), question); } @Override public SExpIR caseAPlusNumericBinaryExp(APlusNumericBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new APlusNumericBinaryExpIR(), question); } @Override public SExpIR caseASubtractNumericBinaryExp(ASubtractNumericBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new ASubtractNumericBinaryExpIR(), question); } @Override public SExpIR caseAGreaterEqualNumericBinaryExp( AGreaterEqualNumericBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new AGreaterEqualNumericBinaryExpIR(), question); } @Override public SExpIR caseAStarStarBinaryExp(AStarStarBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new APowerNumericBinaryExpIR(), question); } @Override public SExpIR caseAGreaterNumericBinaryExp(AGreaterNumericBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new AGreaterNumericBinaryExpIR(), question); } @Override public SExpIR caseALessEqualNumericBinaryExp( ALessEqualNumericBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new ALessEqualNumericBinaryExpIR(), question); } @Override public SExpIR caseALessNumericBinaryExp(ALessNumericBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new ALessNumericBinaryExpIR(), question); } @Override public SExpIR caseADivideNumericBinaryExp(ADivideNumericBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new ADivideNumericBinaryExpIR(), question); } @Override public SExpIR caseADivNumericBinaryExp(ADivNumericBinaryExp node, IRInfo question) throws AnalysisException { return (AIntDivNumericBinaryExpIR) question.getExpAssistant().handleBinaryExp(node, new AIntDivNumericBinaryExpIR(), question); } @Override public SExpIR caseAModNumericBinaryExp(AModNumericBinaryExp node, IRInfo question) throws AnalysisException { return (AModNumericBinaryExpIR) question.getExpAssistant().handleBinaryExp(node, new AModNumericBinaryExpIR(), question); } @Override public SExpIR caseARemNumericBinaryExp(ARemNumericBinaryExp node, IRInfo question) throws AnalysisException { return (ARemNumericBinaryExpIR) question.getExpAssistant().handleBinaryExp(node, new ARemNumericBinaryExpIR(), question); } @Override public SExpIR caseAImpliesBooleanBinaryExp(AImpliesBooleanBinaryExp node, IRInfo question) throws AnalysisException { // A => B is constructed as !A || B STypeIR typeCg = node.getType().apply(question.getTypeVisitor(), question); SExpIR leftExpCg = node.getLeft().apply(question.getExpVisitor(), question); SExpIR rightExpCg = node.getRight().apply(question.getExpVisitor(), question); ANotUnaryExpIR notExp = new ANotUnaryExpIR(); notExp.setType(typeCg); notExp.setExp(leftExpCg); AOrBoolBinaryExpIR orExp = new AOrBoolBinaryExpIR(); orExp.setType(typeCg); orExp.setLeft(notExp); orExp.setRight(rightExpCg); return orExp; } @Override public SExpIR caseAEquivalentBooleanBinaryExp( AEquivalentBooleanBinaryExp node, IRInfo question) throws AnalysisException { // A <=> B is constructed as !(A ^ B) STypeIR typeCg = node.getType().apply(question.getTypeVisitor(), question); SExpIR leftExpCg = node.getLeft().apply(question.getExpVisitor(), question); SExpIR rightExpCg = node.getRight().apply(question.getExpVisitor(), question); AXorBoolBinaryExpIR xorExp = new AXorBoolBinaryExpIR(); xorExp.setType(typeCg); xorExp.setLeft(leftExpCg); xorExp.setRight(rightExpCg); ANotUnaryExpIR notExp = new ANotUnaryExpIR(); notExp.setType(typeCg.clone()); notExp.setExp(question.getExpAssistant().isolateExpression(xorExp)); return notExp; } // Unary @Override public SExpIR caseAUnaryPlusUnaryExp(AUnaryPlusUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new APlusUnaryExpIR(), question); } @Override public SExpIR caseAUnaryMinusUnaryExp(AUnaryMinusUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new AMinusUnaryExpIR(), question); } @Override public SExpIR caseAFloorUnaryExp(AFloorUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new AFloorUnaryExpIR(), question); } @Override public SExpIR caseAAbsoluteUnaryExp(AAbsoluteUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new AAbsUnaryExpIR(), question); } @Override public SExpIR caseANotUnaryExp(ANotUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new ANotUnaryExpIR(), question); } @Override public SExpIR caseAOrBooleanBinaryExp(AOrBooleanBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new AOrBoolBinaryExpIR(), question); } @Override public SExpIR caseAAndBooleanBinaryExp(AAndBooleanBinaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleBinaryExp(node, new AAndBoolBinaryExpIR(), question); } @Override public SExpIR caseALenUnaryExp(ALenUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new ALenUnaryExpIR(), question); } @Override public SExpIR caseAElementsUnaryExp(AElementsUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new AElemsUnaryExpIR(), question); } @Override public SExpIR caseAHeadUnaryExp(AHeadUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new AHeadUnaryExpIR(), question); } @Override public SExpIR caseATailUnaryExp(ATailUnaryExp node, IRInfo question) throws AnalysisException { return question.getExpAssistant().handleUnaryExp(node, new ATailUnaryExpIR(), question); } // Literals // NOTE: The methods for handling of literals/constants look very similar and ideally should be // generalized in a method. However the nodes in the VDM AST don't share a parent with method // setValue at the current time of writing. @Override public SExpIR caseABooleanConstExp(ABooleanConstExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); boolean value = node.getValue().getValue(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); ABoolLiteralExpIR boolLitCg = new ABoolLiteralExpIR(); boolLitCg.setType(typeCg); boolLitCg.setValue(value); return boolLitCg; } @Override public SExpIR caseARealLiteralExp(ARealLiteralExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); double value = node.getValue().getValue(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); ARealLiteralExpIR realLitCg = new ARealLiteralExpIR(); realLitCg.setType(typeCg); realLitCg.setValue(value); return realLitCg; } @Override public SExpIR caseAIntLiteralExp(AIntLiteralExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); long value = node.getValue().getValue(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); AIntLiteralExpIR intLitCg = new AIntLiteralExpIR(); intLitCg.setType(typeCg); intLitCg.setValue(value); return intLitCg; } @Override public SExpIR caseACharLiteralExp(ACharLiteralExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); char value = node.getValue().getValue(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); ACharLiteralExpIR charLitCg = new ACharLiteralExpIR(); charLitCg.setType(typeCg); charLitCg.setValue(value); return charLitCg; } @Override public SExpIR caseAStringLiteralExp(AStringLiteralExp node, IRInfo question) throws AnalysisException { String value = node.getValue().getValue(); if (question.getSettings().getCharSeqAsString()) { PType type = node.getType(); STypeIR typeCg; /** * The operation argument passed to the 'setPriority' of the CPU class (VDM-RT) gets transformed into a * string literal where the type is missing: CPU1.setPriority(B`op, 4). The check below is really to * cirumvent this issue. */ if (type != null) { typeCg = type.apply(question.getTypeVisitor(), question); } else { typeCg = new AStringTypeIR(); } AStringLiteralExpIR stringLiteral = new AStringLiteralExpIR(); stringLiteral.setType(typeCg); stringLiteral.setIsNull(false); stringLiteral.setValue(value); return stringLiteral; } else { PType type = node.getType(); STypeIR strType; // Same issue with the 'setPriority' operation (see above) if (type != null) { strType = type.apply(question.getTypeVisitor(), question); } else { ASeqSeqTypeIR seqTypeCg = new ASeqSeqTypeIR(); seqTypeCg.setEmpty(false); seqTypeCg.setSeqOf(new ACharBasicTypeIR()); strType = seqTypeCg; } return question.getExpAssistant().consCharSequence(strType, value); } } @Override public SExpIR caseAQuoteLiteralExp(AQuoteLiteralExp node, IRInfo question) throws AnalysisException { String value = node.getValue().getValue(); STypeIR type = node.getType().apply(question.getTypeVisitor(), question); AQuoteLiteralExpIR quoteLit = new AQuoteLiteralExpIR(); quoteLit.setValue(value); quoteLit.setType(type); question.registerQuoteValue(value); return quoteLit; } @Override public SExpIR caseALambdaExp(ALambdaExp node, IRInfo question) throws AnalysisException { LinkedList<ATypeBind> bindList = node.getBindList(); PExp exp = node.getExpression(); PType type = node.getType(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); SExpIR expCg = exp.apply(question.getExpVisitor(), question); ALambdaExpIR lambdaExp = new ALambdaExpIR(); lambdaExp.setType(typeCg); lambdaExp.setExp(expCg); LinkedList<AFormalParamLocalParamIR> params = lambdaExp.getParams(); for (ATypeBind typeBind : bindList) { PType bindType = typeBind.getType(); PPattern pattern = typeBind.getPattern(); if (!(pattern instanceof AIdentifierPattern)) { question.addUnsupportedNode(node, "Expected identifier pattern for lambda expression. Got: " + pattern); return null; } STypeIR bindTypeCg = bindType.apply(question.getTypeVisitor(), question); SPatternIR patternCg = pattern.apply(question.getPatternVisitor(), question); AFormalParamLocalParamIR param = new AFormalParamLocalParamIR(); param.setPattern(patternCg); param.setType(bindTypeCg); params.add(param); } return lambdaExp; } @Override public SExpIR caseAHistoryExp(AHistoryExp node, IRInfo question) throws AnalysisException { PType type = node.getType(); ILexToken hop = node.getHop(); AClassClassDefinition enclosingClass = node.getAncestor(AClassClassDefinition.class); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); AHistoryExpIR history = new AHistoryExpIR(); history.setHistype(hop.toString().substring(1)); history.setType(typeCg); AClassTypeIR innerclassType = null; if (enclosingClass != null) { innerclassType = new AClassTypeIR(); innerclassType.setName(enclosingClass.getName() + "_sentinel"); history.setSentinelType(innerclassType); } else { String msg = "Enclosing class could not be found for history expression."; log.error(msg); question.addUnsupportedNode(node, msg); return null; } history.setOpsname(node.getOpnames().getFirst().getName()); if (node.getOpnames().size() == 1) { return history; } else { APlusNumericBinaryExpIR historyCounterSum = new APlusNumericBinaryExpIR(); historyCounterSum.setType(typeCg.clone()); historyCounterSum.setLeft(history); APlusNumericBinaryExpIR last = historyCounterSum; for (int i = 1; i < node.getOpnames().size() - 1; i++) { String nextOpName = node.getOpnames().get(i).toString(); AHistoryExpIR left = new AHistoryExpIR(); left.setType(typeCg.clone()); left.setSentinelType(innerclassType.clone()); left.setHistype(hop.toString().substring(1)); left.setOpsname(nextOpName); APlusNumericBinaryExpIR tmp = new APlusNumericBinaryExpIR(); tmp.setType(typeCg.clone()); tmp.setLeft(left); last.setRight(tmp); last = tmp; } String lastOpName = node.getOpnames().getLast().toString(); AHistoryExpIR lastHistoryExp = new AHistoryExpIR(); lastHistoryExp.setType(typeCg.clone()); lastHistoryExp.setSentinelType(innerclassType.clone()); lastHistoryExp.setHistype(hop.toString().substring(1)); lastHistoryExp.setOpsname(lastOpName); last.setRight(lastHistoryExp); return historyCounterSum; } } }