/*
* ******************************************************************************
* 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.generating.templateengine.reporting.reporter;
import java.io.File;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Optional;
import java.util.stream.Collectors;
import de.monticore.ast.ASTNode;
import de.monticore.generating.templateengine.reporting.commons.AReporter;
import de.monticore.generating.templateengine.reporting.commons.ReportingConstants;
import de.monticore.generating.templateengine.reporting.commons.ReportingRepository;
import de.monticore.prettyprint.IndentPrinter;
import de.monticore.symboltable.ArtifactScope;
import de.monticore.symboltable.GlobalScope;
import de.monticore.symboltable.ImportStatement;
import de.monticore.symboltable.Scope;
import de.monticore.symboltable.ScopeSpanningSymbol;
import de.monticore.symboltable.Scopes;
import de.monticore.symboltable.Symbol;
import de.monticore.symboltable.types.CommonJFieldSymbol;
import de.monticore.symboltable.types.CommonJMethodSymbol;
import de.monticore.symboltable.types.CommonJTypeSymbol;
import de.monticore.symboltable.types.JFieldSymbol;
import de.monticore.symboltable.types.JMethodSymbol;
import de.monticore.symboltable.types.JTypeSymbol;
import de.monticore.symboltable.types.references.JTypeReference;
import de.se_rwth.commons.Names;
public class SymbolTableReporter extends AReporter {
static final String SIMPLE_FILE_NAME = "13_SymbolTable";
protected final String outputDir;
protected final String modelName;
protected final ReportingRepository repository;
protected boolean printEmptyOptional = false;
protected boolean printAllFieldsCommented = false;
protected boolean printEmptyList = false;
public SymbolTableReporter(
String outputDir,
String modelName,
ReportingRepository repository) {
super(outputDir + File.separator + ReportingConstants.REPORTING_DIR + File.separator
+ modelName,
Names.getSimpleName(modelName) + "_ST", ReportingConstants.OD_FILE_EXTENSION);
this.outputDir = outputDir;
this.modelName = modelName;
this.repository = repository;
}
@Override
protected void writeHeader() {
writeLine("//========================================================== Symbol Table");
}
private void writeFooter() {
writeLine("//========================================================== Explanation");
writeLine("//Shows symbol table after finishing the generation process.");
}
@Override
public void flush(ASTNode ast) {
if (ast != null) {
Optional<? extends Scope> scope = ast.getSpannedScope();
while (scope.isPresent() && !(scope.get() instanceof GlobalScope)) {
scope = scope.get().getEnclosingScope();
}
if (scope.isPresent()) {
reportSymbolTableScope(scope.get());
}
}
writeFooter();
super.flush(ast);
}
protected void reportScope(Scope scope, IndentPrinter printer) {
final Collection<Symbol> symbols = Scopes.getLocalSymbolsAsCollection(scope);
String type;
String scopeName;
scopeName = repository.getScopeNameFormatted(scope);
type = Names.getSimpleName(scope.getClass().getName());
printer.println(scopeName + ": " + type + "{");
printer.indent();
reportAllFields(scope.getClass(), printer);
if (scope.getName().isPresent()) {
printer.println("name = \"" + scope.getName().get() + "\";");
} else if (printEmptyOptional) {
printer.println("name = Optional.Empty;");
}
if (scope instanceof ArtifactScope) {
ArtifactScope artifactScope = (ArtifactScope) scope;
if (!artifactScope.getImports().isEmpty()) {
printer.print("imports = [\"");
String sep = "";
for (ImportStatement imp: artifactScope.getImports()) {
printer.print(sep);
sep = ", ";
printer.print(imp.getStatement());
printer.print("\"");
}
printer.println("];");
} else if (printEmptyList) {
printer.println("imports = [];");
}
printer.println("packageName = \"" + artifactScope.getPackageName() + "\";");
}
printer.println("isShadowingScope = " + scope.isShadowingScope() + ";");
printer.println("exportsSymbols = " + scope.exportsSymbols() + ";");
if (scope.getAstNode().isPresent()) {
printer.print("astNode = ");
printer.print(repository.getASTNodeNameFormatted(scope.getAstNode().get()));
printer.println(";");
} else if (printEmptyOptional) {
printer.println("astNode = Optional.Empty;");
}
if (scope.getSpanningSymbol().isPresent()) {
printer.print("spanningSymbol = ");
reportSymbol(scope.getSpanningSymbol().get(), printer);
printer.println(";");
}
else if (printEmptyOptional) {
printer.println("spanningSymbol = Optional.Empty;");
}
if (scope.getEnclosingScope().isPresent()) {
printer.print("enclosingScope = ");
printer.print(repository.getScopeNameFormatted(scope.getEnclosingScope().get()));
printer.println(";");
}
else if (printEmptyOptional) {
printer.println("enclosingScope = Optional.Empty;");
}
Collection<Symbol> reportedSymbols = symbols.stream()
.filter(sym -> !(sym instanceof ScopeSpanningSymbol)).collect(Collectors.toList());
if (!reportedSymbols.isEmpty()) {
printer.print("symbols = ");
printer.println("// *size: " + reportedSymbols.size());
printer.indent();
}
else if (printEmptyList) {
printer.println("symbols = [];");
}
String sep = "";
for (Symbol symbol : reportedSymbols) {
if (!(symbol instanceof ScopeSpanningSymbol)) {
printer.print(sep);
sep = ",\n";
reportSymbol(symbol, printer);
}
}
if (!reportedSymbols.isEmpty()) {
printer.println(";");
printer.unindent();
}
if (!scope.getSubScopes().isEmpty()) {
printer.print("subScopes = ");
printer.println("// *size: " + scope.getSubScopes().size());
printer.indent();
}
else if (printEmptyList) {
printer.println("subScopes = [];");
}
sep = "";
for (Scope subScope : scope.getSubScopes()) {
printer.print(sep);
sep = ",\n";
reportScope(subScope, printer);
}
if (!scope.getSubScopes().isEmpty()) {
printer.println(";");
printer.unindent();
}
printer.unindent();
printer.print("}");
}
@Override
public void reportSymbolTableScope(Scope scope) {
IndentPrinter printer = new IndentPrinter();
printer.println("objectdiagram " + Names.getSimpleName(modelName) + "_ST {");
printer.indent();
reportScope(scope, printer);
printer.println();
printer.unindent();
printer.println("}");
writeLine(printer.getContent());
}
protected void reportSymbol(Symbol sym, IndentPrinter printer) {
String type = Names.getSimpleName(sym.getClass().getSimpleName());
String symName = repository.getSymbolNameFormatted(sym);
printer.println(symName + ": " + type + " {");
printer.indent();
reportAttributes(sym, printer);
printer.unindent();
printer.print("}");
}
protected void reportAttributes(Symbol sym, IndentPrinter printer) {
reportAllFields(sym.getClass(), printer);
printer.println("name = \"" + sym.getName() + "\";");
printer.println("KIND = \"" + sym.getKind() + "\";");
if (sym.getAstNode().isPresent()) {
printer.print("astNode = ");
printer.print(repository.getASTNodeNameFormatted(sym.getAstNode().get()));
printer.println(";");
}
else if (printEmptyOptional) {
printer.print("astNode = Optional.Empty;");
}
if (sym instanceof ScopeSpanningSymbol) {
ScopeSpanningSymbol spanningSym = (ScopeSpanningSymbol) sym;
printer.println("spannedScope = "
+ repository.getScopeNameFormatted(spanningSym.getSpannedScope()) + ";");
}
printer.print("enclosingScope = ");
printer.print(repository.getScopeNameFormatted(sym.getEnclosingScope()));
printer.println(";");
printer.println("accesModifier = \"" + sym.getAccessModifier().toString() + "\";");
}
protected void reportCommonJFieldAttributes(
CommonJFieldSymbol<? extends JTypeReference<? extends JTypeSymbol>> sym,
IndentPrinter printer) {
printer.println("isFinal = " + sym.isFinal() + ";");
printer.println("isParameter = " + sym.isParameter() + ";");
printer.println("isStatic = " + sym.isStatic() + ";");
}
protected void reportCommonJMethodAttributes(
CommonJMethodSymbol<? extends JTypeSymbol, ? extends JTypeReference<? extends JTypeSymbol>, ? extends JFieldSymbol> sym,
IndentPrinter printer) {
printer.println("isFinal = " + sym.isFinal() + ";");
printer.println("isStatic = " + sym.isStatic() + ";");
printer.println("isAbstract = " + sym.isAbstract() + ";");
printer.println("isConstructor = " + sym.isConstructor() + ";");
printer.println("isEllipsisParameterMethod = " + sym.isEllipsisParameterMethod() + ";");
if (!sym.isConstructor()) {
printer.println("returnType = "
+ repository.getSymbolNameFormatted(sym.getReturnType()) + ";");
}
reportListOfReferences("exceptions", sym.getExceptions(), printer);
}
protected void reportCommonJTypeAttributes(
CommonJTypeSymbol<? extends JTypeSymbol, ? extends JFieldSymbol, ? extends JMethodSymbol, ? extends JTypeReference<? extends JTypeSymbol>> sym,
IndentPrinter printer) {
printer.println("isFinal = " + sym.isFinal() + ";");
printer.println("isAbstract = " + sym.isAbstract() + ";");
printer.println("isEnum = " + sym.isEnum() + ";");
printer.println("isFormalTypeParameter = " + sym.isFormalTypeParameter() + ";");
printer.println("isInnerType = " + sym.isInnerType() + ";");
printer.println("isInterface = " + sym.isInterface() + ";");
if (sym.getSuperClass().isPresent()) {
printer.println("superClass = "
+ repository.getSymbolNameFormatted(sym.getSuperClass().get())
+ ";");
}
else if (printEmptyOptional) {
printer.print("superClass = Optional.Empty;");
}
reportListOfReferences("interfaces", sym.getInterfaces(), printer);
}
protected void reportListOfReferences(String listName,
Collection<? extends JTypeReference<? extends JTypeSymbol>> refs, IndentPrinter printer) {
if (!refs.isEmpty()) {
printer.print(listName + " = ");
String delim = "";
for (JTypeReference<? extends JTypeSymbol> anno : refs) {
printer.print(delim);
printer.print(repository.getSymbolNameFormatted(anno));
delim = ", ";
}
printer.println(";");
}
else if (printEmptyList) {
printer.println(listName + " = [];");
}
}
/**
* @return the printEmptyOptional
*/
public boolean isPrintEmptyOptional() {
return this.printEmptyOptional;
}
/**
* @param printEmptyOptional the printEmptyOptional to set
*/
public void setPrintEmptyOptional(boolean printEmptyOptional) {
this.printEmptyOptional = printEmptyOptional;
}
/**
* @return the printEmptyList
*/
public boolean isPrintEmptyList() {
return this.printEmptyList;
}
/**
* @return the printAllFieldsCommented
*/
public boolean isPrintAllFieldsCommented() {
return this.printAllFieldsCommented;
}
/**
* @param printAllFieldsCommented the printAllFieldsCommented to set
*/
public void setPrintAllFieldsCommented(boolean printAllFieldsCommented) {
this.printAllFieldsCommented = printAllFieldsCommented;
}
/**
* @param printEmptyList the printEmptyList to set
*/
public void setPrintEmptyList(boolean printEmptyList) {
this.printEmptyList = printEmptyList;
}
protected void reportAllFields(Class<?> clazz, IndentPrinter printer) {
if (!isPrintAllFieldsCommented()) {
return;
}
printer.print("/* fields = ");
for (Field field : clazz.getDeclaredFields()) {
printer.print(field.getName() + " ");
}
while (clazz.getSuperclass() != null) {
clazz = clazz.getSuperclass();
for (Field field : clazz.getDeclaredFields()) {
printer.print(field.getName() + " ");
}
}
printer.println("*/");
}
}