/*******************************************************************************
* MontiCore Language Workbench
* Copyright (c) 2015, 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.se_rwth.monticoreeditor;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import com.google.common.collect.ImmutableList;
import de.monticore.ModelingLanguageFamily;
import de.monticore.ast.ASTNode;
import de.monticore.grammar.grammar._ast.ASTMCGrammar;
import de.monticore.io.paths.ModelPath;
import de.monticore.languages.grammar.MCGrammarSymbol;
import de.monticore.languages.grammar.MontiCoreGrammarLanguage;
import de.monticore.languages.grammar.MontiCoreGrammarModelLoader;
import de.monticore.symboltable.GlobalScope;
import de.monticore.symboltable.ResolvingConfiguration;
import de.monticore.symboltable.Scope;
import de.monticore.symboltable.Scopes;
import de.monticore.symboltable.references.FailedLoadingSymbol;
import de.se_rwth.commons.logging.Log;
import de.se_rwth.langeditor.modelstates.ModelState;
final class SymbolTableMaintainer {
private final MontiCoreGrammarLanguage grammarLanguage = new MontiCoreGrammarLanguage();
private final GlobalScope globalScope;
SymbolTableMaintainer(ModelStatesInProject astMapper, ImmutableList<Path> modelPath) {
MontiCoreGrammarModelLoader modelLoader =
(MontiCoreGrammarModelLoader) grammarLanguage.getModelLoader();
modelLoader.setAstProvider(astMapper);
ModelingLanguageFamily languageFamily = new ModelingLanguageFamily();
languageFamily.addModelingLanguage(grammarLanguage);
this.globalScope = new GlobalScope(new ModelPath(modelPath), languageFamily);
}
void acceptModelState(ModelState modelState) {
ASTNode rootNode = modelState.getRootNode();
if (rootNode instanceof ASTMCGrammar) {
try {
ASTMCGrammar mcGrammar = (ASTMCGrammar) rootNode;
if (!mcGrammar.getSymbol().isPresent()) {
grammarLanguage.getSymbolTableCreator(new ResolvingConfiguration(), globalScope)
.ifPresent(symbolTableCreator -> {
removeOldScope(mcGrammar);
Scope newScope = symbolTableCreator.createFromAST(mcGrammar);
setNewSuperGrammarScope(newScope);
});
}
}
catch (FailedLoadingSymbol e) {
e.printStackTrace();
}
}
}
private void removeOldScope(ASTMCGrammar mcGrammar) {
globalScope.getSubScopes().stream()
.filter(scope -> Scopes.getLocalSymbolsAsCollection(scope).stream()
.filter(MCGrammarSymbol.class::isInstance)
.map(MCGrammarSymbol.class::cast)
.map(MCGrammarSymbol::getName)
.anyMatch(name -> name.endsWith(mcGrammar.getName())))
.forEach(globalScope::removeSubScope);
}
private void setNewSuperGrammarScope(Scope newScope) {
List<MCGrammarSymbol> existingGrammarSymbols = globalScope.getSubScopes().stream()
.map(scope -> Scopes.getLocalSymbolsAsCollection(scope))
.flatMap(Collection::stream)
.filter(MCGrammarSymbol.class::isInstance)
.map(MCGrammarSymbol.class::cast)
.collect(Collectors.toList());
List<MCGrammarSymbol> newGrammarSymbols = Scopes.getLocalSymbolsAsCollection(newScope).stream()
.filter(MCGrammarSymbol.class::isInstance)
.map(MCGrammarSymbol.class::cast)
.collect(Collectors.toList());
for (MCGrammarSymbol existingGrammarSymbol : existingGrammarSymbols) {
for (MCGrammarSymbol newGrammarSymbol : newGrammarSymbols) {
try {
replaceSuperGrammar(existingGrammarSymbol, newGrammarSymbol);
}
catch (Exception e) {
Log.error(
"0xA1100 Error while updating supergrammar references for " + existingGrammarSymbol.getName(),
e);
}
}
}
}
private void replaceSuperGrammar(MCGrammarSymbol existingGrammarSymbol,
MCGrammarSymbol newGrammarSymbol) {
List<MCGrammarSymbol> superGrammars = new ArrayList<>(existingGrammarSymbol.getSuperGrammars());
boolean wasSuperGrammar = superGrammars.removeIf(superGrammar ->
superGrammar.getFullName().equals(newGrammarSymbol.getFullName()));
if (wasSuperGrammar) {
superGrammars.add(newGrammarSymbol);
}
existingGrammarSymbol.setSuperGrammars(superGrammars);
}
}