/* * #%~ * 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.Iterator; import java.util.LinkedList; import java.util.List; import org.apache.log4j.Logger; import org.overture.ast.analysis.AnalysisException; import org.overture.ast.definitions.AClassInvariantDefinition; import org.overture.ast.definitions.AExplicitFunctionDefinition; import org.overture.ast.definitions.AExplicitOperationDefinition; import org.overture.ast.definitions.AImplicitFunctionDefinition; import org.overture.ast.definitions.AImplicitOperationDefinition; import org.overture.ast.definitions.AInstanceVariableDefinition; import org.overture.ast.definitions.AMutexSyncDefinition; import org.overture.ast.definitions.ANamedTraceDefinition; import org.overture.ast.definitions.APerSyncDefinition; import org.overture.ast.definitions.AStateDefinition; import org.overture.ast.definitions.AThreadDefinition; import org.overture.ast.definitions.ATypeDefinition; import org.overture.ast.definitions.AValueDefinition; import org.overture.ast.definitions.traces.ATraceDefinitionTerm; import org.overture.ast.expressions.PExp; import org.overture.ast.intf.lex.ILexNameToken; import org.overture.ast.patterns.PPattern; import org.overture.ast.statements.PStm; import org.overture.ast.types.AAccessSpecifierAccessSpecifier; import org.overture.ast.types.AFieldField; import org.overture.ast.types.ANamedInvariantType; import org.overture.ast.types.AOperationType; import org.overture.ast.types.ARecordInvariantType; import org.overture.ast.types.PType; import org.overture.ast.util.ClonableString; import org.overture.codegen.ir.IRConstants; import org.overture.codegen.ir.IRInfo; import org.overture.codegen.ir.SDeclIR; import org.overture.codegen.ir.SExpIR; import org.overture.codegen.ir.SPatternIR; import org.overture.codegen.ir.SStmIR; import org.overture.codegen.ir.STermIR; import org.overture.codegen.ir.STypeIR; import org.overture.codegen.ir.declarations.AFieldDeclIR; import org.overture.codegen.ir.declarations.AFormalParamLocalParamIR; import org.overture.codegen.ir.declarations.AFuncDeclIR; import org.overture.codegen.ir.declarations.AMethodDeclIR; import org.overture.codegen.ir.declarations.AMutexSyncDeclIR; import org.overture.codegen.ir.declarations.ANamedTraceDeclIR; import org.overture.codegen.ir.declarations.ANamedTypeDeclIR; import org.overture.codegen.ir.declarations.APersyncDeclIR; import org.overture.codegen.ir.declarations.ARecordDeclIR; import org.overture.codegen.ir.declarations.AStateDeclIR; import org.overture.codegen.ir.declarations.AThreadDeclIR; import org.overture.codegen.ir.declarations.ATypeDeclIR; import org.overture.codegen.ir.expressions.ALambdaExpIR; import org.overture.codegen.ir.expressions.ANotImplementedExpIR; import org.overture.codegen.ir.name.ATokenNameIR; import org.overture.codegen.ir.name.ATypeNameIR; import org.overture.codegen.ir.statements.ANotImplementedStmIR; import org.overture.codegen.ir.traces.ATraceDeclTermIR; import org.overture.codegen.ir.types.AMethodTypeIR; import org.overture.codegen.ir.types.ATemplateTypeIR; public class DeclVisitorIR extends AbstractVisitorIR<IRInfo, SDeclIR> { private Logger log = Logger.getLogger(this.getClass().getName()); @Override public SDeclIR caseAStateDefinition(AStateDefinition node, IRInfo question) throws AnalysisException { AAccessSpecifierAccessSpecifier access = node.getAccess(); ILexNameToken name = node.getName(); AExplicitFunctionDefinition initdef = node.getInitdef(); PExp initExp = node.getInitExpression(); PPattern initPattern = node.getInitPattern(); AExplicitFunctionDefinition invdef = node.getInvdef(); PExp invExp = node.getInvExpression(); PPattern invPattern = node.getInvPattern(); String accessCg = access.getAccess().toString(); String nameCg = name != null ? name.getName() : null; SDeclIR initDeclCg = initdef != null ? initdef.apply(question.getDeclVisitor(), question) : null; SExpIR initExpCg = initExp != null ? initExp.apply(question.getExpVisitor(), question) : null; SPatternIR initPatternCg = initPattern != null ? initPattern.apply(question.getPatternVisitor(), question) : null; SDeclIR invDeclCg = invdef != null ? invdef.apply(question.getDeclVisitor(), question) : null; SExpIR invExpCg = invExp != null ? invExp.apply(question.getExpVisitor(), question) : null; SPatternIR invPatternCg = invPattern != null ? invPattern.apply(question.getPatternVisitor(), question) : null; AStateDeclIR stateDeclCg = new AStateDeclIR(); stateDeclCg.setAccess(accessCg); stateDeclCg.setName(nameCg); if (initDeclCg instanceof AFuncDeclIR) { stateDeclCg.setInitDecl((AFuncDeclIR) initDeclCg); } stateDeclCg.setInitExp(initExpCg); stateDeclCg.setInitPattern(initPatternCg); if (invDeclCg instanceof AFuncDeclIR) { stateDeclCg.setInvDecl((AFuncDeclIR) invDeclCg); } stateDeclCg.setInvExp(invExpCg); stateDeclCg.setInvPattern(invPatternCg); stateDeclCg.setExecutable(node.getCanBeExecuted()); for (AFieldField field : node.getFields()) { SDeclIR fieldCg = field.apply(question.getDeclVisitor(), question); if (fieldCg instanceof AFieldDeclIR) { stateDeclCg.getFields().add((AFieldDeclIR) fieldCg); } else { return null; } } return stateDeclCg; } @Override public SDeclIR caseAClassInvariantDefinition(AClassInvariantDefinition node, IRInfo question) throws AnalysisException { // Do not report the node as unsupported and generate nothing return null; } @Override public SDeclIR caseATraceDefinitionTerm(ATraceDefinitionTerm node, IRInfo question) throws AnalysisException { // Do not report the node as unsupported and generate nothing return null; } @Override public SDeclIR caseANamedTraceDefinition(ANamedTraceDefinition node, IRInfo question) throws AnalysisException { if (!question.getSettings().generateTraces()) { return null; } ANamedTraceDeclIR namedTraceDecl = new ANamedTraceDeclIR(); for (ClonableString cloStr : node.getPathname()) { ATokenNameIR name = new ATokenNameIR(); name.setName(cloStr.value); namedTraceDecl.getPathname().add(name); } for (ATraceDefinitionTerm term : node.getTerms()) { STermIR termCg = term.apply(question.getTermVisitor(), question); if (termCg instanceof ATraceDeclTermIR) { namedTraceDecl.getTerms().add((ATraceDeclTermIR) termCg); } else { log.error("Expected term to be of type " + ATraceDeclTermIR.class.getName() + ". Got: " + termCg); return null; } } return namedTraceDecl; } @Override public SDeclIR caseANamedInvariantType(ANamedInvariantType node, IRInfo question) throws AnalysisException { PType type = node.getType(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); ATypeNameIR typeName = new ATypeNameIR(); typeName.setDefiningClass(node.getName().getModule()); typeName.setName(node.getName().getName()); ANamedTypeDeclIR namedTypeDecl = new ANamedTypeDeclIR(); namedTypeDecl.setName(typeName); namedTypeDecl.setType(typeCg); return namedTypeDecl; } @Override public SDeclIR caseARecordInvariantType(ARecordInvariantType node, IRInfo question) throws AnalysisException { ILexNameToken name = node.getName(); LinkedList<AFieldField> fields = node.getFields(); ARecordDeclIR record = new ARecordDeclIR(); record.setName(name.getName()); if (node.getInvDef() != null) { SDeclIR invCg = node.getInvDef().apply(question.getDeclVisitor(), question); record.setInvariant(invCg); } LinkedList<AFieldDeclIR> recordFields = record.getFields(); for (AFieldField aFieldField : fields) { SDeclIR res = aFieldField.apply(question.getDeclVisitor(), question); if (res instanceof AFieldDeclIR) { AFieldDeclIR fieldDecl = (AFieldDeclIR) res; recordFields.add(fieldDecl); } else { return null; } } return record; } @Override public SDeclIR caseAFieldField(AFieldField node, IRInfo question) throws AnalysisException { // Record fields are public String access = IRConstants.PUBLIC; String name = node.getTagname().getName(); boolean isStatic = false; boolean isFinal = false; STypeIR type = node.getType().apply(question.getTypeVisitor(), question); SExpIR exp = null; return question.getDeclAssistant().constructField(access, name, isStatic, isFinal, type, exp); } @Override public SDeclIR caseATypeDefinition(ATypeDefinition node, IRInfo question) throws AnalysisException { String access = node.getAccess().getAccess().toString(); PType type = node.getType(); SDeclIR declCg = type.apply(question.getDeclVisitor(), question); SDeclIR invCg = node.getInvdef() != null ? node.getInvdef().apply(question.getDeclVisitor(), question) : null; ATypeDeclIR typeDecl = new ATypeDeclIR(); typeDecl.setAccess(access); typeDecl.setDecl(declCg); typeDecl.setInv(invCg); return typeDecl; } @Override public SDeclIR caseAExplicitFunctionDefinition( AExplicitFunctionDefinition node, IRInfo question) throws AnalysisException { String accessCg = node.getAccess().getAccess().toString(); String funcNameCg = node.getName().getName(); STypeIR typeCg = node.getType().apply(question.getTypeVisitor(), question); if (!(typeCg instanceof AMethodTypeIR)) { question.addUnsupportedNode(node, "Expected method type for explicit function. Got: " + typeCg); return null; } AMethodTypeIR methodTypeCg = (AMethodTypeIR) typeCg; AFuncDeclIR method = new AFuncDeclIR(); method.setAccess(accessCg); method.setMethodType(methodTypeCg); method.setName(funcNameCg); Iterator<List<PPattern>> iterator = node.getParamPatternList().iterator(); List<PPattern> paramPatterns = iterator.next(); LinkedList<AFormalParamLocalParamIR> formalParameters = method.getFormalParams(); for (int i = 0; i < paramPatterns.size(); i++) { SPatternIR pattern = paramPatterns.get(i).apply(question.getPatternVisitor(), question); AFormalParamLocalParamIR param = new AFormalParamLocalParamIR(); param.setType(methodTypeCg.getParams().get(i).clone()); param.setPattern(pattern); formalParameters.add(param); } if (node.getIsUndefined()) { method.setBody(new ANotImplementedExpIR()); } else if (node.getIsCurried()) { AMethodTypeIR nextLevel = (AMethodTypeIR) methodTypeCg; ALambdaExpIR currentLambda = new ALambdaExpIR(); ALambdaExpIR topLambda = currentLambda; while (iterator.hasNext()) { nextLevel = (AMethodTypeIR) nextLevel.getResult(); paramPatterns = iterator.next(); for (int i = 0; i < paramPatterns.size(); i++) { PPattern param = paramPatterns.get(i); SPatternIR patternCg = param.apply(question.getPatternVisitor(), question); AFormalParamLocalParamIR paramCg = new AFormalParamLocalParamIR(); paramCg.setPattern(patternCg); paramCg.setType(nextLevel.getParams().get(i).clone()); currentLambda.getParams().add(paramCg); } currentLambda.setType(nextLevel.clone()); if (iterator.hasNext()) { ALambdaExpIR nextLambda = new ALambdaExpIR(); currentLambda.setExp(nextLambda); currentLambda = nextLambda; } } SExpIR bodyExp = node.getBody().apply(question.getExpVisitor(), question); currentLambda.setExp(bodyExp); method.setBody(topLambda); } else { SExpIR bodyCg = node.getBody().apply(question.getExpVisitor(), question); method.setBody(bodyCg); } boolean isAbstract = method.getBody() == null; method.setAbstract(isAbstract); // If the function uses any type parameters they will be // registered as part of the method declaration LinkedList<ILexNameToken> typeParams = node.getTypeParams(); for (int i = 0; i < typeParams.size(); i++) { ILexNameToken typeParam = typeParams.get(i); ATemplateTypeIR templateType = new ATemplateTypeIR(); templateType.setName(typeParam.getName()); method.getTemplateTypes().add(templateType); } AExplicitFunctionDefinition preCond = node.getPredef(); SDeclIR preCondCg = preCond != null ? preCond.apply(question.getDeclVisitor(), question) : null; method.setPreCond(preCondCg); AExplicitFunctionDefinition postCond = node.getPostdef(); SDeclIR postCondCg = postCond != null ? postCond.apply(question.getDeclVisitor(), question) : null; method.setPostCond(postCondCg); method.setImplicit(false); return method; } @Override public SDeclIR caseAImplicitFunctionDefinition( AImplicitFunctionDefinition node, IRInfo question) throws AnalysisException { String accessCg = node.getAccess().getAccess().toString(); String funcNameCg = node.getName().getName(); STypeIR typeCg = node.getType().apply(question.getTypeVisitor(), question); if (!(typeCg instanceof AMethodTypeIR)) { question.addUnsupportedNode(node, "Expected method type for implicit function. Got: " + typeCg); return null; } AFuncDeclIR func = new AFuncDeclIR(); AExplicitFunctionDefinition preCond = node.getPredef(); SDeclIR preCondCg = preCond != null ? preCond.apply(question.getDeclVisitor(), question) : null; func.setPreCond(preCondCg); AExplicitFunctionDefinition postCond = node.getPostdef(); SDeclIR postCondCg = postCond != null ? postCond.apply(question.getDeclVisitor(), question) : null; func.setPostCond(postCondCg); // If the function uses any type parameters they will be // registered as part of the method declaration List<ILexNameToken> typeParams = node.getTypeParams(); for (int i = 0; i < typeParams.size(); i++) { ILexNameToken typeParam = typeParams.get(i); ATemplateTypeIR templateType = new ATemplateTypeIR(); templateType.setName(typeParam.getName()); func.getTemplateTypes().add(templateType); } func.setAbstract(false); func.setAccess(accessCg); func.setImplicit(true); func.setBody(new ANotImplementedExpIR()); func.setFormalParams(question.getDeclAssistant().consFormalParams(node.getParamPatterns(), question)); func.setMethodType((AMethodTypeIR) typeCg); func.setName(funcNameCg); // The implicit function is currently constructed without the result information: // SPatternIR resPatternCg = node.getResult().getPattern().apply(question.getPatternVisitor(), question); // STypeIR resTypeCg = node.getResult().getType().apply(question.getTypeVisitor(), question); return func; } @Override public SDeclIR caseAExplicitOperationDefinition( AExplicitOperationDefinition node, IRInfo question) throws AnalysisException { AMethodDeclIR method = question.getDeclAssistant().initMethod(node, question); if (method == null) { question.addUnsupportedNode(node, "Expected method type for explicit operation. Got: " + node.getType()); return null; } if (!(node.getType() instanceof AOperationType)) { question.addUnsupportedNode(node, "Node type should be an operation type. Got: " + node.getType()); return null; } List<PType> ptypes = ((AOperationType) node.getType()).getParameters(); LinkedList<PPattern> paramPatterns = node.getParameterPatterns(); LinkedList<AFormalParamLocalParamIR> formalParameters = method.getFormalParams(); for (int i = 0; i < ptypes.size(); i++) { STypeIR paramType = ptypes.get(i).apply(question.getTypeVisitor(), question); SPatternIR patternCg = paramPatterns.get(i).apply(question.getPatternVisitor(), question); AFormalParamLocalParamIR param = new AFormalParamLocalParamIR(); param.setType(paramType); param.setPattern(patternCg); formalParameters.add(param); } return method; } @Override public SDeclIR caseAImplicitOperationDefinition( AImplicitOperationDefinition node, IRInfo question) throws AnalysisException { AMethodDeclIR method = question.getDeclAssistant().initMethod(node, question); if (method == null) { question.addUnsupportedNode(node, "Expected method type for explicit operation. Got: " + node.getType()); return null; } // The curent IR construction does not include: // // Name of result and its type: // APatternTypePair res = node.getResult(); // Ext clauses (read and write): // LinkedList<AExternalClause> externals = node.getExternals(); // Exceptions thrown: // LinkedList<AErrorCase> errors = node.getErrors(); method.setBody(new ANotImplementedStmIR()); method.setFormalParams(question.getDeclAssistant().consFormalParams(node.getParameterPatterns(), question)); return method; } @Override public SDeclIR caseAInstanceVariableDefinition( AInstanceVariableDefinition node, IRInfo question) throws AnalysisException { String access = node.getAccess().getAccess().toString(); String name = node.getName().getName(); boolean isStatic = node.getAccess().getStatic() != null; boolean isFinal = false; STypeIR type = node.getType().apply(question.getTypeVisitor(), question); SExpIR exp = node.getExpression().apply(question.getExpVisitor(), question); return question.getDeclAssistant().constructField(access, name, isStatic, isFinal, type, exp); } @Override public SDeclIR caseAValueDefinition(AValueDefinition node, IRInfo question) throws AnalysisException { String access = node.getAccess().getAccess().toString(); String name = node.getPattern().toString(); boolean isStatic = true; boolean isFinal = true; PType type = node.getType(); PExp exp = node.getExpression(); STypeIR typeCg = type.apply(question.getTypeVisitor(), question); SExpIR expCg = exp.apply(question.getExpVisitor(), question); return question.getDeclAssistant().constructField(access, name, isStatic, isFinal, typeCg, expCg); } @Override public SDeclIR caseAThreadDefinition(AThreadDefinition node, IRInfo question) throws AnalysisException { PStm stm = node.getOperationDef().getBody(); SStmIR stmIR = stm.apply(question.getStmVisitor(), question); AThreadDeclIR threaddcl = new AThreadDeclIR(); threaddcl.setStm(stmIR); return threaddcl; } @Override public SDeclIR caseAPerSyncDefinition(APerSyncDefinition node, IRInfo question) throws AnalysisException { PExp guard = node.getGuard(); ILexNameToken opname = node.getOpname(); APersyncDeclIR predicate = new APersyncDeclIR(); predicate.setPred(guard.apply(question.getExpVisitor(), question)); predicate.setOpname(opname.getName()); return predicate; } @Override public SDeclIR caseAMutexSyncDefinition(AMutexSyncDefinition node, IRInfo question) throws AnalysisException { LinkedList<ILexNameToken> operations = node.getOperations(); AMutexSyncDeclIR mutexdef = new AMutexSyncDeclIR(); for (ILexNameToken opname : operations) { ATokenNameIR token = new ATokenNameIR(); token.setName(opname.getName()); mutexdef.getOpnames().add(token); } return mutexdef; } }