/* * #%~ * The VDM Type Checker * %% * Copyright (C) 2008 - 2016 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.typechecker.visitor; import org.overture.ast.analysis.AnalysisException; import org.overture.ast.analysis.intf.IQuestionAnswer; import org.overture.ast.definitions.AExplicitFunctionDefinition; import org.overture.ast.definitions.AImplicitFunctionDefinition; import org.overture.ast.definitions.AUntypedDefinition; import org.overture.ast.definitions.PDefinition; import org.overture.ast.intf.lex.ILexNameToken; import org.overture.ast.modules.AAllExport; import org.overture.ast.modules.AFunctionExport; import org.overture.ast.modules.AOperationExport; import org.overture.ast.modules.ATypeExport; import org.overture.ast.modules.AValueExport; import org.overture.ast.typechecker.NameScope; import org.overture.ast.types.ANamedInvariantType; import org.overture.ast.types.ARecordInvariantType; import org.overture.ast.types.PType; import org.overture.typechecker.FlatCheckedEnvironment; import org.overture.typechecker.ModuleEnvironment; import org.overture.typechecker.TypeCheckInfo; import org.overture.typechecker.TypeCheckerErrors; import org.overture.typechecker.assistant.ITypeCheckerAssistantFactory; public class TypeCheckerExportsVisitor extends AbstractTypeCheckVisitor { public TypeCheckerExportsVisitor(IQuestionAnswer<TypeCheckInfo, PType> typeCheckVisitor) { super(typeCheckVisitor); } public PType caseAAllExport(AAllExport node, TypeCheckInfo question) throws AnalysisException { return null; // Implicitly OK. } public PType caseAFunctionExport(AFunctionExport exp, TypeCheckInfo question) throws AnalysisException { ITypeCheckerAssistantFactory af = question.assistantFactory; ModuleEnvironment menv = (ModuleEnvironment)question.env; for (ILexNameToken name : exp.getNameList()) { PDefinition def = af.createPDefinitionListAssistant().findName(menv.getDefinitions(), name, NameScope.NAMES); if (def == null) { TypeCheckerErrors.report(3183, "Exported function " + name + " not defined in module", name.getLocation(), exp); } else { PType act = af.createPDefinitionAssistant().getType(def); if (exp.getTypeParams() != null && !exp.getTypeParams().isEmpty()) { if (def instanceof AExplicitFunctionDefinition) { AExplicitFunctionDefinition efd = (AExplicitFunctionDefinition)def; FlatCheckedEnvironment params = new FlatCheckedEnvironment(af, af.createAExplicitFunctionDefinitionAssistant().getTypeParamDefinitions(efd), question.env, NameScope.NAMES); TypeCheckInfo newQuestion = question.newInfo(params); PType type = question.assistantFactory.createPTypeAssistant().typeResolve(exp.getExportType(), null, THIS, newQuestion); if (efd.getTypeParams() == null) { TypeCheckerErrors.report(3352, "Exported " + name + " function has no type paramaters", name.getLocation(), exp); } else if (!efd.getTypeParams().equals(exp.getTypeParams())) { TypeCheckerErrors.report(3353, "Exported " + name + " function type parameters incorrect", name.getLocation(), exp); TypeCheckerErrors.detail2("Exported", exp.getTypeParams(), "Actual", efd.getTypeParams()); } if (act != null && !act.toString().equals(type.toString())) { TypeCheckerErrors.report(3184, "Exported " + name + " function type incorrect", name.getLocation(), exp); TypeCheckerErrors.detail2("Exported", type, "Actual", act); } } else if (def instanceof AImplicitFunctionDefinition) { AImplicitFunctionDefinition ifd = (AImplicitFunctionDefinition)def; FlatCheckedEnvironment params = new FlatCheckedEnvironment(af, af.createAImplicitFunctionDefinitionAssistant().getTypeParamDefinitions(ifd), question.env, NameScope.NAMES); TypeCheckInfo newQuestion = question.newInfo(params); PType type = question.assistantFactory.createPTypeAssistant().typeResolve(exp.getExportType(), null, THIS, newQuestion); if (ifd.getTypeParams() == null) { TypeCheckerErrors.report(3352, "Exported " + name + " function has no type paramaters", name.getLocation(), exp); } else if (!ifd.getTypeParams().equals(exp.getTypeParams())) { TypeCheckerErrors.report(3353, "Exported " + name + " function type parameters incorrect", name.getLocation(), exp); TypeCheckerErrors.detail2("Exported", exp.getTypeParams(), "Actual", ifd.getTypeParams()); } if (act != null && !act.toString().equals(type.toString())) { TypeCheckerErrors.report(3184, "Exported " + name + " function type incorrect", name.getLocation(), exp); TypeCheckerErrors.detail2("Exported", type, "Actual", act); } } } else { PType type = question.assistantFactory.createPTypeAssistant().typeResolve(exp.getExportType(), null, THIS, question); if (act != null && !af.createPTypeAssistant().equals(act, type)) { TypeCheckerErrors.report(3184, "Exported " + name + " function type incorrect", name.getLocation(), exp); TypeCheckerErrors.detail2("Exported", type, "Actual", act); } } } } return null; } public PType caseAOperationExport(AOperationExport exp, TypeCheckInfo question) throws AnalysisException { ITypeCheckerAssistantFactory af = question.assistantFactory; ModuleEnvironment menv = (ModuleEnvironment)question.env; for (ILexNameToken name : exp.getNameList()) { PDefinition def = af.createPDefinitionListAssistant().findName(menv.getDefinitions(), name, NameScope.NAMES); if (def == null) { TypeCheckerErrors.report(3185, "Exported operation " + name + " not defined in module", name.getLocation(), exp); } else { PType act = def.getType(); PType type = question.assistantFactory.createPTypeAssistant().typeResolve(exp.getExportType(), null, THIS, question); if (act != null && !af.createPTypeAssistant().equals(act, type)) { TypeCheckerErrors.report(3186, "Exported operation type does not match actual type", name.getLocation(), exp); TypeCheckerErrors.detail2("Exported", type, "Actual", act); } } } return null; } public PType caseATypeExport(ATypeExport exp, TypeCheckInfo question) throws AnalysisException { ILexNameToken name = exp.getName(); ITypeCheckerAssistantFactory af = question.assistantFactory; ModuleEnvironment menv = (ModuleEnvironment)question.env; PDefinition def = af.createPDefinitionListAssistant().findType(menv.getDefinitions(), name, name.getModule()); if (def == null) { TypeCheckerErrors.report(3187, "Exported type " + name + " not defined in module", name.getLocation(), exp); } else { if (exp.getStruct()) { PType type = af.createPDefinitionAssistant().getType(def); if (!(type instanceof ANamedInvariantType) && !(type instanceof ARecordInvariantType)) { TypeCheckerErrors.report(67, "Exported type " + name + " not structured", name.getLocation(), exp); } } } return null; } public PType caseAValueExport(AValueExport exp, TypeCheckInfo question) throws AnalysisException { ITypeCheckerAssistantFactory af = question.assistantFactory; ModuleEnvironment menv = (ModuleEnvironment)question.env; PType type = question.assistantFactory.createPTypeAssistant().typeResolve(exp.getExportType().clone(), null, THIS, question); for (ILexNameToken name : exp.getNameList()) { PDefinition def = af.createPDefinitionListAssistant().findName(menv.getDefinitions(), name, NameScope.NAMES); if (def == null) { TypeCheckerErrors.report(3188, "Exported value " + name + " not defined in module", name.getLocation(), exp); } else if (def instanceof AUntypedDefinition) { // OK } else { PType act = question.assistantFactory.createPTypeAssistant().typeResolve(def.getType(), null, THIS, question); if (act != null && !question.assistantFactory.getTypeComparator().compatible(act, type)) { TypeCheckerErrors.report(3189, "Exported type does not match actual type", act.getLocation(), act); TypeCheckerErrors.detail2("Exported", type, "Actual", act); } } } return null; } }