/*
* ******************************************************************************
* MontiCore Language Workbench
* Copyright (c) 2016, 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.grammar.symboltable;
import static com.google.common.base.Preconditions.checkArgument;
import static de.monticore.codegen.GeneratorHelper.isQualified;
import static de.monticore.symboltable.modifiers.AccessModifier.ALL_INCLUSION;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.function.Predicate;
import de.monticore.symboltable.CommonScope;
import de.monticore.symboltable.MutableScope;
import de.monticore.symboltable.ScopeSpanningSymbol;
import de.monticore.symboltable.Symbol;
import de.monticore.symboltable.SymbolKind;
import de.monticore.symboltable.modifiers.AccessModifier;
import de.monticore.symboltable.resolving.ResolvingInfo;
import de.se_rwth.commons.Names;
import de.se_rwth.commons.logging.Log;
/**
* @author Pedram Mir Seyed Nazari
*/
public class MCGrammarScope extends CommonScope {
public MCGrammarScope(Optional<MutableScope> enclosingScope) {
super(enclosingScope, true);
}
@Override
public void setSpanningSymbol(ScopeSpanningSymbol symbol) {
checkArgument(symbol instanceof MCGrammarSymbol);
super.setSpanningSymbol(symbol);
}
@Override
@SuppressWarnings("unchecked")
public Optional<MCGrammarSymbol> getSpanningSymbol() {
return (Optional<MCGrammarSymbol>) super.getSpanningSymbol();
}
@Override
public <T extends Symbol> Optional<T> resolveImported(String name, SymbolKind kind, AccessModifier modifier) {
final Collection<T> resolvedSymbols = resolveManyLocally(new ResolvingInfo(getResolvingFilters()), name, kind, modifier, x -> true);
if (resolvedSymbols.isEmpty()) {
return resolveInSuperGrammars(name, kind, modifier);
}
return getResolvedOrThrowException(resolvedSymbols);
}
public <T extends Symbol> Collection<T> resolveMany(ResolvingInfo resolvingInfo, String name, SymbolKind kind, AccessModifier modifier,
Predicate<Symbol> predicate) {
final Collection<T> resolvedSymbols = new LinkedHashSet<T>();
Optional<T> resolvedSymbol = this.resolveImported(name, kind, modifier);
if (!resolvedSymbol.isPresent()) {
resolvedSymbol = resolveInSuperGrammars(name, kind, modifier);
}
if (!resolvedSymbol.isPresent()) {
// continue with enclosing scope
resolvedSymbols.addAll(super.resolveMany(resolvingInfo, name, kind, modifier, predicate));
}
else {
resolvedSymbols.add(resolvedSymbol.get());
}
return resolvedSymbols;
}
protected <T extends Symbol> Optional<T> resolveInSuperGrammars(String name, SymbolKind kind, AccessModifier modifier) {
Optional<T> resolvedSymbol = Optional.empty();
final MCGrammarSymbol spanningSymbol = getSpanningSymbol().get();
for (MCGrammarSymbolReference superGrammarRef : spanningSymbol.getSuperGrammars()) {
if (checkIfContinueWithSuperGrammar(name, superGrammarRef.getName())
&& (superGrammarRef.existsReferencedSymbol())) {
final MCGrammarSymbol superGrammar = superGrammarRef.getReferencedSymbol();
resolvedSymbol = resolveInSuperGrammar(name, kind, superGrammar);
// Stop as soon as symbol is found in a super grammar.
if (resolvedSymbol.isPresent()) {
break;
}
}
}
return resolvedSymbol;
}
private boolean checkIfContinueWithSuperGrammar(String name, String superGrammarName) {
// checks cases:
// 1) A and A
// 2) c.A and A
// 3) A and p.A
// 4) p.A and p.A
// 5) c.A and p.A // <-- only continue with this case, since we can be sure,
// that we are not searching for the super grammar itself.
if (Names.getSimpleName(superGrammarName).equals(Names.getSimpleName(name))) {
// checks cases 1) and 4)
if (superGrammarName.equals(name) ||
// checks cases 2) and 3)
(isQualified(superGrammarName) != isQualified(name))) {
return false;
} else {
// case 5)
return true;
}
}
// names have different simple names and the name isn't qualified (A and p.B)
return isQualified(superGrammarName) && !isQualified(name);
}
private <T extends Symbol> Optional<T> resolveInSuperGrammar(String name, SymbolKind kind,
MCGrammarSymbol superGrammar) {
Log.trace("Continue in scope of super grammar " + superGrammar.getName(),
MCGrammarScope.class.getSimpleName());
return superGrammar.getSpannedScope().resolveImported(name, kind, ALL_INCLUSION);
}
}