/* * #%~ * The VDM Type Checker * %% * 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.typechecker.visitor; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Vector; import org.overture.ast.analysis.AnalysisException; import org.overture.ast.analysis.QuestionAnswerAdaptor; import org.overture.ast.analysis.intf.IQuestionAnswer; import org.overture.ast.definitions.AExplicitFunctionDefinition; import org.overture.ast.definitions.AMultiBindListDefinition; import org.overture.ast.definitions.PDefinition; import org.overture.ast.definitions.SClassDefinition; import org.overture.ast.expressions.PExp; import org.overture.ast.factory.AstFactory; import org.overture.ast.intf.lex.ILexLocation; import org.overture.ast.node.INode; import org.overture.ast.patterns.PMultipleBind; import org.overture.ast.typechecker.NameScope; import org.overture.ast.types.ABooleanBasicType; import org.overture.ast.types.PType; import org.overture.ast.util.PTypeSet; import org.overture.typechecker.Environment; import org.overture.typechecker.FlatCheckedEnvironment; import org.overture.typechecker.TypeCheckInfo; import org.overture.typechecker.TypeCheckerErrors; import org.overture.typechecker.utilities.type.QualifiedDefinition; public class AbstractTypeCheckVisitor extends QuestionAnswerAdaptor<TypeCheckInfo, PType> { public AbstractTypeCheckVisitor( IQuestionAnswer<TypeCheckInfo, PType> visitor) { super(visitor); } public AbstractTypeCheckVisitor() { super(); } @Override public PType createNewReturnValue(INode node, TypeCheckInfo question) { return null; } @Override public PType createNewReturnValue(Object node, TypeCheckInfo question) { return null; } @Override public PType defaultINode(INode node, TypeCheckInfo question) throws AnalysisException { return THIS.defaultINode(node, question); } protected PType typeCheckIf(ILexLocation ifLocation, PExp testExp, INode thenNode, List<? extends INode> elseIfNodeList, INode elseNode, TypeCheckInfo question) throws AnalysisException { boolean isExpression = testExp.parent() instanceof PExp; question.qualifiers = null; PType test = testExp.apply(THIS, question.newConstraint(null)); if (!question.assistantFactory.createPTypeAssistant().isType(test, ABooleanBasicType.class)) { TypeCheckerErrors.report((isExpression ? 3108 : 3224), "If expression is not boolean", testExp.getLocation(), testExp); } List<QualifiedDefinition> qualified = testExp.apply(question.assistantFactory.getQualificationVisitor(), question); for (QualifiedDefinition qdef : qualified) { qdef.qualifyType(); } PTypeSet rtypes = new PTypeSet(question.assistantFactory); question.qualifiers = null; rtypes.add(thenNode.apply(THIS, question)); for (QualifiedDefinition qdef : qualified) { qdef.resetType(); } if (elseIfNodeList != null) { for (INode stmt : elseIfNodeList) { question.qualifiers = null; rtypes.add(stmt.apply(THIS, question)); } } if (elseNode != null) { question.qualifiers = null; rtypes.add(elseNode.apply(THIS, question)); } else { // If the else case is empty then it is a statement and its type is void rtypes.add(AstFactory.newAVoidType(ifLocation)); } return rtypes.getType(ifLocation); } /** * Type checks a AElseIf node * * @param elseIfNode * @param elseIfLocation * @param test * @param thenNode * @param question * @return * @throws AnalysisException */ PType typeCheckAElseIf(INode elseIfNode, ILexLocation elseIfLocation, INode test, INode thenNode, TypeCheckInfo question) throws AnalysisException { if (!question.assistantFactory.createPTypeAssistant().isType(test.apply(THIS, question.newConstraint(null)), ABooleanBasicType.class)) { boolean isExpression = elseIfNode.parent() instanceof PExp; TypeCheckerErrors.report((isExpression ? 3086 : 3218), "Expression is not boolean", elseIfLocation, elseIfNode); } List<QualifiedDefinition> qualified = test.apply(question.assistantFactory.getQualificationVisitor(), question); for (QualifiedDefinition qdef : qualified) { qdef.qualifyType(); } PType type = thenNode.apply(THIS, question); for (QualifiedDefinition qdef : qualified) { qdef.resetType(); } return type; } PType typeCheckANotYetSpecifiedExp(INode node, ILexLocation location) { return AstFactory.newAUnknownType(location);// Because we terminate anyway } /** * Type checks a let node * * @param node * @param localDefs * @param body * @param question * @return * @throws AnalysisException */ protected PType typeCheckLet(INode node, LinkedList<PDefinition> localDefs, INode body, TypeCheckInfo question) throws AnalysisException { // Each local definition is in scope for later local definitions... Environment local = question.env; for (PDefinition d : localDefs) { if (d instanceof AExplicitFunctionDefinition) { // Functions' names are in scope in their bodies, whereas // simple variable declarations aren't local = new FlatCheckedEnvironment(question.assistantFactory, d, local, question.scope); // cumulative question.assistantFactory.createPDefinitionAssistant().implicitDefinitions(d, local); question.assistantFactory.createPDefinitionAssistant().typeResolve(d, THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope, question.qualifiers)); if (question.env.isVDMPP()) { SClassDefinition cdef = question.env.findClassDefinition(); // question.assistantFactory.createPDefinitionAssistant().setClassDefinition(d, cdef); d.setClassDefinition(cdef); d.setAccess(question.assistantFactory.createPAccessSpecifierAssistant().getStatic(d, true)); } d.apply(THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope, question.qualifiers)); } else { question.assistantFactory.createPDefinitionAssistant().implicitDefinitions(d, local); question.assistantFactory.createPDefinitionAssistant().typeResolve(d, THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope, question.qualifiers)); d.apply(THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope)); local = new FlatCheckedEnvironment(question.assistantFactory, d, local, question.scope); // cumulative } } PType r = body.apply(THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope, null, question.constraint, null)); local.unusedCheck(question.env); return r; } /** * Type check method for let be such that * @param node * @param nodeLocation * @param bind * @param suchThat * @param body * @param question * @return a pair of the type and definition * @throws AnalysisException */ protected Map.Entry<PType, AMultiBindListDefinition> typecheckLetBeSt( INode node, ILexLocation nodeLocation, PMultipleBind bind, PExp suchThat, INode body, TypeCheckInfo question) throws AnalysisException { final PDefinition def = AstFactory.newAMultiBindListDefinition(nodeLocation, question.assistantFactory.createPMultipleBindAssistant().getMultipleBindList((PMultipleBind) bind)); def.apply(THIS, question.newConstraint(null)); List<PDefinition> qualified = new Vector<PDefinition>(); for (PDefinition d: question.assistantFactory.createPDefinitionAssistant().getDefinitions(def)) { PDefinition copy = d.clone(); copy.setNameScope(NameScope.LOCAL); qualified.add(copy); } Environment local = new FlatCheckedEnvironment(question.assistantFactory, qualified, question.env, question.scope); TypeCheckInfo newInfo = new TypeCheckInfo(question.assistantFactory, local, question.scope, question.qualifiers, question.constraint, null); if (suchThat != null && !question.assistantFactory.createPTypeAssistant().isType(suchThat.apply(THIS, newInfo.newConstraint(null)), ABooleanBasicType.class)) { boolean isExpression = node instanceof PExp; TypeCheckerErrors.report((isExpression ? 3117 : 3225), "Such that clause is not boolean", nodeLocation, node); } newInfo.qualifiers = null; final PType r = body.apply(THIS, newInfo); local.unusedCheck(); return new Map.Entry<PType, AMultiBindListDefinition>() { @Override public AMultiBindListDefinition setValue( AMultiBindListDefinition value) { return null; } @Override public AMultiBindListDefinition getValue() { return (AMultiBindListDefinition) def; } @Override public PType getKey() { return r; } }; } }