/* * ****************************************************************************** * MontiCore Language Workbench * Copyright (c) 2015, MontiCore, All rights reserved. * * This project is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this project. If not, see <http://www.gnu.org/licenses/>. * ****************************************************************************** */ package de.monticore.modelloader; import de.monticore.AmbiguityException; import de.monticore.ModelingLanguage; import de.monticore.ast.ASTNode; import de.monticore.generating.templateengine.reporting.Reporting; import de.monticore.io.paths.ModelCoordinate; import de.monticore.io.paths.ModelCoordinates; import de.monticore.io.paths.ModelPath; import de.monticore.symboltable.MutableScope; import de.monticore.symboltable.ResolvingConfiguration; import de.se_rwth.commons.Names; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; import java.util.Optional; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Strings.isNullOrEmpty; /** * This class is responsible for loading models from the model path * ({@link de.monticore.io.paths.ModelPath}). * * @author Pedram Mir Seyed Nazari */ // TODO PN extract CommonModelLoader // TODO PN rename to ModelLoader public abstract class ModelingLanguageModelLoader<T extends ASTNode> { private final ModelingLanguage modelingLanguage; private AstProvider<T> astProvider; public ModelingLanguageModelLoader(ModelingLanguage modelingLanguage) { this.modelingLanguage = modelingLanguage; this.astProvider = new FileBasedAstProvider<>(modelingLanguage); } public void setAstProvider(AstProvider<T> astProvider) { this.astProvider = astProvider; } /** * Loads the model with the <code>qualifiedModelName</code>. If more than one * corresponding model is found, an {@link de.monticore.AmbiguityException} is * thrown. * * @param qualifiedModelName the qualified name of the model to be loaded * @param modelPath the modelPath * @return An ast of the loaded model. * @throws de.monticore.AmbiguityException is thrown, if more than one model * with the name <code>qualifiedModelName</code> * @see #loadModels(String, de.monticore.io.paths.ModelPath) */ public Optional<T> loadModel(final String qualifiedModelName, final ModelPath modelPath) { final Collection<T> models = loadModels(qualifiedModelName, modelPath); if (models.size() > 1) { throw new AmbiguityException("0xA4092 Multiple models were found with name '" + qualifiedModelName + "'"); } return models.stream().findFirst(); } /** * @deprecated use {@link #loadModelsIntoScope(String, ModelPath, MutableScope, ResolvingConfiguration)} * instead. */ @Deprecated public Collection<T> loadAmbiguousModelAndCreateSymbolTable(final String qualifiedModelName, final ModelPath modelPath, final MutableScope enclosingScope, final ResolvingConfiguration resolvingConfiguration) { return loadModelsIntoScope(qualifiedModelName, modelPath, enclosingScope, resolvingConfiguration); } /** * Loads all models with the specified <code>qualifiedModelName</code>, creates * the corresponding scope graphs and puts each in the <code>enclosingScope</code>. * * @param qualifiedModelName the qualified name of the model(s) to be loaded * @param modelPath the model path * @param enclosingScope the enclosing scope for each scope graph of the loaded models * @param resolvingConfiguration the configuration of the resolving filters * @return the asts of the loaded models (mapped to the corresponding symbol table elements) */ public Collection<T> loadModelsIntoScope(final String qualifiedModelName, final ModelPath modelPath, final MutableScope enclosingScope, final ResolvingConfiguration resolvingConfiguration) { final Collection<T> asts = loadModels(qualifiedModelName, modelPath); for (T ast : asts) { createSymbolTableFromAST(ast, qualifiedModelName, enclosingScope, resolvingConfiguration); } return asts; } /** * Creates the symbol table for the model in <code>modelName</code> using its * <code>ast</code> and adds its top scope (usually * {@link de.monticore.symboltable.ArtifactScope}) to the sub scopes. * * @param ast the ast of the model in <code>modelName</code> * @param modelName name of the model */ protected abstract void createSymbolTableFromAST(T ast, String modelName, MutableScope enclosingScope, ResolvingConfiguration resolvingConfiguration); /** * @deprecated use {@link #loadModels(String, ModelPath)} instead. */ public Collection<T> loadAmbiguousModels(final String qualifiedModelName, ModelPath modelPath) { checkArgument(!isNullOrEmpty(qualifiedModelName)); return loadModels(qualifiedModelName, modelPath); } /** * Loads one or more models with the <code>qualifiedModelName</code>. If only * one model is expected, use * {@link #loadModel(String, de.monticore.io.paths.ModelPath)} instead. * * @param qualifiedModelName the qualified name of the model(s) to be loaded * @param modelPath the model path * @return the asts of the loaded models * @see #loadModel(String, de.monticore.io.paths.ModelPath) */ public Collection<T> loadModels(final String qualifiedModelName, ModelPath modelPath) { checkArgument(!isNullOrEmpty(qualifiedModelName)); final Collection<T> foundModels = new ArrayList<>(); final ModelCoordinate resolvedCoordinate = resolve(qualifiedModelName, modelPath); if (resolvedCoordinate.hasLocation()) { final T ast = astProvider.getRootNode(resolvedCoordinate); Reporting.reportOpenInputFile(resolvedCoordinate.getParentDirectoryPath(), resolvedCoordinate.getQualifiedPath()); foundModels.add(ast); } return foundModels; } /** * @param qualifiedModelName example: "de.mc.statechartOne" * @return the resolved coordinate (the location of the model is set if * successful) */ private ModelCoordinate resolve(final String qualifiedModelName, final ModelPath modelPath) { String simpleName = Names.getSimpleName(qualifiedModelName); Path qualifiedPath = Paths.get( Names.getPathFromQualifiedName(qualifiedModelName)).resolve( simpleName + "." + modelingLanguage.getFileExtension()); ModelCoordinate qualifiedModel = ModelCoordinates.createQualifiedCoordinate(qualifiedPath); return modelPath.resolveModel(qualifiedModel); } public ModelingLanguage getModelingLanguage() { return modelingLanguage; } }