/******************************************************************************* * * Copyright (c) 2008 Fujitsu Services Ltd. * * Author: Nick Battle * * This file is part of VDMJ. * * VDMJ 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. * * VDMJ 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 VDMJ. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ package org.overture.typechecker; import java.util.List; import java.util.Vector; import org.overture.ast.analysis.AnalysisException; import org.overture.ast.definitions.PDefinition; import org.overture.ast.modules.AModuleModules; import org.overture.ast.typechecker.NameScope; import org.overture.ast.typechecker.Pass; import org.overture.ast.util.modules.CombinedDefaultModule; import org.overture.config.Release; import org.overture.config.Settings; import org.overture.typechecker.assistant.ITypeCheckerAssistantFactory; import org.overture.typechecker.assistant.TypeCheckerAssistantFactory; import org.overture.typechecker.assistant.definition.PDefinitionAssistantTC; import org.overture.typechecker.visitor.TypeCheckVisitor; /** * A class to coordinate all module type checking processing. */ public class ModuleTypeChecker extends TypeChecker { /** The list of modules to check. */ private final List<AModuleModules> modules; /** * Create a type checker with the list of modules passed. The warnings flag indicates whether warnings should be * printed or just counted. */ public final ITypeCheckerAssistantFactory assistantFactory; /** * VDM-only constructor. <b>NOT</b> for use by extensions. * * @param modules */ public ModuleTypeChecker(List<AModuleModules> modules) { super(); assistantFactory = new TypeCheckerAssistantFactory(); this.modules = modules; } /** * Perform the type checking for the set of modules. This is a complicated process. * <p> * First the module names are checked for uniqueness. Then each module generates its implicit definitions (eg. for * pre_ and post_ functions). Then export definitions for each module are generated, and the import definitions * linked to them. Next all the definition in the set of modules are type resolved by creating a list of all * modules' definitions and calling their typeResolve methods. Then the type checking of the modules' definitions * can proceed, covering the types, values and remaining definitions in that order. Next, the declared types of the * imports for each module are compared with the (now determined) types of the exports. Finally the usage of the * imports and definitions for each module are checked. */ @Override public void typeCheck() { // Check for module name duplication boolean nothing = true; boolean hasFlat = false; for (AModuleModules m1 : modules) { for (AModuleModules m2 : modules) { if (m1 != m2 && m1.getName().equals(m2.getName())) { TypeChecker.report(3429, "Module " + m1.getName() + " duplicates " + m2.getName(), m1.getName().getLocation()); } } if (m1.getIsFlat()) { hasFlat = true; } else { if (hasFlat && Settings.release == Release.CLASSIC) { TypeChecker.report(3308, "Cannot mix modules and flat specifications", m1.getName().getLocation()); } } if (!m1.getTypeChecked()) { nothing = false; } } if (nothing) { return; } // Mark top level definitions of flat specifications as used new PDefinitionAssistantTC(new TypeCheckerAssistantFactory()); for (AModuleModules module : modules) { if (module instanceof CombinedDefaultModule) { for (PDefinition definition : module.getDefs()) { assistantFactory.createPDefinitionAssistant().markUsed(definition); } } } // Generate implicit definitions for pre_, post_, inv_ functions etc. for (AModuleModules m : modules) { if (!m.getTypeChecked()) { Environment env = new ModuleEnvironment(assistantFactory, m); assistantFactory.createPDefinitionListAssistant().implicitDefinitions(m.getDefs(), env); } } // Exports have to be identified before imports can be processed. for (AModuleModules m : modules) { if (!m.getTypeChecked()) { assistantFactory.createAModuleModulesAssistant().processExports(m); // Populate exportDefs } } // Process the imports early because renamed imports create definitions // which can affect type resolution. for (AModuleModules m : modules) { if (!m.getTypeChecked()) { assistantFactory.createAModuleModulesAssistant().processImports(m, modules); // Populate importDefs } } // Create a list of all definitions from all modules, including // imports of renamed definitions. List<PDefinition> alldefs = new Vector<PDefinition>(); List<PDefinition> checkDefs = new Vector<PDefinition>(); for (AModuleModules m : modules) { for (PDefinition d : m.getImportdefs()) { alldefs.add(d); if (!m.getTypeChecked()) { checkDefs.add(d); } } } for (AModuleModules m : modules) { for (PDefinition d : m.getDefs()) { alldefs.add(d); if (!m.getTypeChecked()) { checkDefs.add(d); } } } // Attempt type resolution of unchecked definitions from all modules. Environment env = new FlatCheckedEnvironment(assistantFactory, alldefs, NameScope.NAMESANDSTATE); TypeCheckVisitor tc = new TypeCheckVisitor(); for (PDefinition d : checkDefs) { try { assistantFactory.createPDefinitionAssistant().typeResolve(d, tc, new TypeCheckInfo(assistantFactory, env)); } catch (TypeCheckException te) { report(3430, te.getMessage(), te.location); if (te.extras != null) { for (TypeCheckException e: te.extras) { report(3430, e.getMessage(), e.location); } } } catch (AnalysisException te) { report(3431, te.getMessage(), null);// FIXME: internal error } } // Proceed to type check all definitions, considering types, values // and remaining definitions, in that order. for (Pass pass : Pass.values()) { for (AModuleModules m : modules) { if (!m.getTypeChecked()) { Environment e = new ModuleEnvironment(assistantFactory, m); for (PDefinition d : m.getDefs()) { // System.out.println("Number of Defs: " + m.getDefs().size()); // System.out.println("Def to typecheck: " + d.getName()); if (d.getPass() == pass) { try { d.apply(tc, new TypeCheckInfo(assistantFactory, e, NameScope.NAMES)); // System.out.println(); } catch (TypeCheckException te) { report(3431, te.getMessage(), te.location); if (te.extras != null) { for (TypeCheckException ex: te.extras) { report(3431, ex.getMessage(), ex.location); } } } catch (AnalysisException te) { report(3431, te.getMessage(), null);// FIXME: internal error } } // System.out.println("Number of Defs: " + m.getDefs().size()); } } } } // Report any discrepancies between the final checked types of // definitions and their explicit imported types. for (AModuleModules m : modules) { if (!m.getTypeChecked()) { assistantFactory.createAModuleModulesAssistant().processImports(m, modules); // Re-populate importDefs try { assistantFactory.createAModuleModulesAssistant().typeCheckExports(m); assistantFactory.createAModuleModulesAssistant().typeCheckImports(m); } catch (TypeCheckException te) { report(3432, te.getMessage(), te.location); if (te.extras != null) { for (TypeCheckException e: te.extras) { report(3432, e.getMessage(), e.location); } } } catch (AnalysisException te) { report(3431, te.getMessage(), null);// FIXME: internal error } } } // Any names that have not been referenced or exported produce "unused" // warnings. for (AModuleModules m : modules) { if (!m.getTypeChecked()) { assistantFactory.createPDefinitionListAssistant().unusedCheck(m.getImportdefs()); assistantFactory.createPDefinitionListAssistant().unusedCheck(m.getDefs()); } } } }