/*
* ******************************************************************************
* 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 java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import de.monticore.grammar.grammar._ast.ASTMCGrammar;
import de.monticore.symboltable.CommonScopeSpanningSymbol;
import de.monticore.symboltable.MutableScope;
import de.monticore.symboltable.SymbolKind;
import de.se_rwth.commons.logging.Log;
/**
* @author Pedram Mir Seyed Nazari
*/
public class MCGrammarSymbol extends CommonScopeSpanningSymbol {
public static final EssentialMCGrammarKind KIND = new EssentialMCGrammarKind();
private final List<MCGrammarSymbolReference> superGrammars = new ArrayList<>();
/**
* Is the grammar abstract?
*/
private boolean isComponent = false;
// the start production of the grammar
private MCProdSymbol startProd;
public MCGrammarSymbol(String name) {
super(name, KIND);
}
@Override
protected MutableScope createSpannedScope() {
return new MCGrammarScope(Optional.empty());
}
public void setStartProd(MCProdSymbol startRule) {
this.startProd = startRule;
}
/**
* The start production typically is the first defined production in the
* grammar.
*
* @return the start production of the grammar, if not a component grammar
*/
public Optional<MCProdSymbol> getStartProd() {
return Optional.ofNullable(startProd);
}
/**
* @return true, if the grammar is abstract
*/
public boolean isComponent() {
return isComponent;
}
public void setComponent(boolean isComponent) {
this.isComponent = isComponent;
}
public List<MCGrammarSymbolReference> getSuperGrammars() {
return ImmutableList.copyOf(superGrammars);
}
public List<MCGrammarSymbol> getSuperGrammarSymbols() {
return ImmutableList.copyOf(superGrammars.stream().filter(g -> g.getReferencedSymbol() != null)
.map(g -> g.getReferencedSymbol())
.collect(Collectors.toList()));
}
public void addSuperGrammar(MCGrammarSymbolReference superGrammarRef) {
this.superGrammars.add(Log.errorIfNull(superGrammarRef));
}
public Collection<MCProdSymbol> getProds() {
return this.getSpannedScope().resolveLocally(MCProdSymbol.KIND);
}
public Collection<String> getProdNames() {
final Set<String> prodNames = new LinkedHashSet<>();
for (final MCProdSymbol prodSymbol : getProds()) {
prodNames.add(prodSymbol.getName());
}
return ImmutableSet.copyOf(prodNames);
}
public Optional<MCProdSymbol> getProd(String prodName) {
return this.getSpannedScope().resolveLocally(prodName, MCProdSymbol.KIND);
}
public Optional<MCProdSymbol> getProdWithInherited(String ruleName) {
Optional<MCProdSymbol> mcProd = getProd(ruleName);
Iterator<MCGrammarSymbolReference> itSuperGrammars = superGrammars.iterator();
while (!mcProd.isPresent() && itSuperGrammars.hasNext()) {
mcProd = itSuperGrammars.next().getReferencedSymbol().getProdWithInherited(ruleName);
}
return mcProd;
}
public Optional<MCProdSymbol> getInheritedProd(String ruleName) {
Optional<MCProdSymbol> mcProd = Optional.empty();
Iterator<MCGrammarSymbolReference> itSuperGrammars = superGrammars.iterator();
while (!mcProd.isPresent() && itSuperGrammars.hasNext()) {
mcProd = itSuperGrammars.next().getReferencedSymbol().getProdWithInherited(ruleName);
}
return mcProd;
}
public Map<String, MCProdSymbol> getProdsWithInherited() {
final Map<String, MCProdSymbol> ret = new LinkedHashMap<>();
for (int i = superGrammars.size() - 1; i >= 0; i--) {
final MCGrammarSymbolReference superGrammarRef = superGrammars.get(i);
if (superGrammarRef.existsReferencedSymbol()) {
ret.putAll(superGrammarRef.getReferencedSymbol().getProdsWithInherited());
}
}
for (final MCProdSymbol prodSymbol : getProds()) {
ret.put(prodSymbol.getName(), prodSymbol);
}
return ret;
}
public Optional<ASTMCGrammar> getAstGrammar() {
return getAstNode().filter(ASTMCGrammar.class::isInstance).map(ASTMCGrammar.class::cast);
}
public static class EssentialMCGrammarKind implements SymbolKind {
private static final String NAME = EssentialMCGrammarKind.class.getName();
protected EssentialMCGrammarKind() {
}
@Override
public String getName() {
return NAME;
}
@Override
public boolean isKindOf(SymbolKind kind) {
return NAME.equals(kind.getName()) || SymbolKind.super.isKindOf(kind);
}
}
}