/* * ****************************************************************************** * 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.symboltable.references; import de.monticore.ast.ASTNode; import de.monticore.symboltable.Scope; import de.monticore.symboltable.Symbol; import de.monticore.symboltable.SymbolKind; import de.monticore.symboltable.modifiers.AccessModifier; import de.se_rwth.commons.logging.Log; import java.util.Optional; import java.util.function.Predicate; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Strings.emptyToNull; import static com.google.common.base.Strings.isNullOrEmpty; /** * Default implementation of {@link SymbolReference}. * * @author Pedram Mir Seyed Nazari * */ public class CommonSymbolReference<T extends Symbol> implements SymbolReference<T> { private final String referencedName; private final SymbolKind referencedKind; private AccessModifier accessModifier = AccessModifier.ALL_INCLUSION; private Predicate<Symbol> predicate = x -> true; private ASTNode astNode; /** * The enclosing scope of the reference, not of the referenced symbol (i.e., symbol definition). */ private final Scope enclosingScope; private T referencedSymbol; public CommonSymbolReference(String referencedSymbolName, SymbolKind referencedSymbolKind, Scope enclosingScopeOfReference) { this.referencedName = Log.errorIfNull(emptyToNull(referencedSymbolName)); this.referencedKind = Log.errorIfNull(referencedSymbolKind); this.enclosingScope = Log.errorIfNull(enclosingScopeOfReference); } @Override public String getName() { return referencedName; } @Override public T getReferencedSymbol() { if (!isReferencedSymbolLoaded()) { referencedSymbol = loadReferencedSymbol().orElse(null); if (!isReferencedSymbolLoaded()) { throw new FailedLoadingSymbol(referencedName); } } else { Log.debug("Full information of '" + referencedName + "' already loaded. Use cached " + "version.", CommonSymbolReference.class.getSimpleName()); } return referencedSymbol; } @Override public Scope getEnclosingScope() { return enclosingScope; } @Override public boolean existsReferencedSymbol() { return isReferencedSymbolLoaded() || loadReferencedSymbol().isPresent(); } public boolean isReferencedSymbolLoaded() { return referencedSymbol != null; } protected Optional<T> loadReferencedSymbol() { checkArgument(!isNullOrEmpty(referencedName), " 0xA4070 Symbol name may not be null or empty."); Log.errorIfNull(referencedKind); Log.debug("Load full information of '" + referencedName + "' (Kind " + referencedKind.getName() + ").", SymbolReference.class.getSimpleName()); Optional<T> resolvedSymbol = enclosingScope.resolve(referencedName, referencedKind, accessModifier, predicate); if (resolvedSymbol.isPresent()) { Log.debug("Loaded full information of '" + referencedName + "' successfully.", SymbolReference.class.getSimpleName()); } else { Log.warn("0xA1038 " + SymbolReference.class.getSimpleName() + " Could not load full information of '" + referencedName + "' (Kind " + referencedKind.getName() + ")."); } return resolvedSymbol; } public Optional<ASTNode> getAstNode() { return Optional.ofNullable(astNode); } @Override public void setAstNode(ASTNode astNode) { this.astNode = astNode; } public void setAccessModifier(AccessModifier accessModifier) { this.accessModifier = accessModifier; } public void setPredicate(Predicate<Symbol> predicate) { this.predicate = predicate; } }