/*
* ******************************************************************************
* 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.codegen.mc2cd.transl;
import static de.monticore.codegen.mc2cd.TransformationHelper.createSimpleReference;
import static de.monticore.codegen.mc2cd.TransformationHelper.getPackageName;
import java.util.Optional;
import java.util.function.UnaryOperator;
import de.monticore.codegen.mc2cd.MCGrammarSymbolTableHelper;
import de.monticore.codegen.mc2cd.TransformationHelper;
import de.monticore.grammar.HelperGrammar;
import de.monticore.grammar.grammar._ast.ASTAttributeInAST;
import de.monticore.grammar.grammar._ast.ASTGenericType;
import de.monticore.grammar.grammar._ast.ASTLexProd;
import de.monticore.grammar.grammar._ast.ASTMCGrammar;
import de.monticore.grammar.grammar._ast.ASTNonTerminal;
import de.monticore.grammar.grammar._ast.ASTTerminal;
import de.monticore.grammar.symboltable.MCProdSymbol;
import de.monticore.types.types._ast.ASTConstantsTypes;
import de.monticore.types.types._ast.ASTType;
import de.monticore.types.types._ast.TypesNodeFactory;
import de.monticore.umlcd4a.cd4analysis._ast.ASTCDAttribute;
import de.monticore.umlcd4a.cd4analysis._ast.ASTCDCompilationUnit;
import de.monticore.utils.Link;
/**
* Infers the type that ASTCDAttributes should have according to what kind of rule the original
* nonterminals were referring to.
*
* @author Sebastian Oberhoff
*/
public class ReferenceTypeTranslation implements
UnaryOperator<Link<ASTMCGrammar, ASTCDCompilationUnit>> {
@Override
public Link<ASTMCGrammar, ASTCDCompilationUnit> apply(
Link<ASTMCGrammar, ASTCDCompilationUnit> rootLink) {
for (Link<ASTNonTerminal, ASTCDAttribute> link : rootLink.getLinks(ASTNonTerminal.class,
ASTCDAttribute.class)) {
link.target().setType(determineTypeToSet(link.source().getName(), rootLink.source()));
}
for (Link<ASTTerminal, ASTCDAttribute> link : rootLink.getLinks(ASTTerminal.class,
ASTCDAttribute.class)) {
link.target().setType(createSimpleReference("String"));
}
for (Link<ASTAttributeInAST, ASTCDAttribute> link : rootLink.getLinks(ASTAttributeInAST.class,
ASTCDAttribute.class)) {
ASTType type = determineTypeToSetForAttributeInAST(
link.source().getGenericType(), rootLink.source());
link.target().setType(type);
}
return rootLink;
}
private ASTType ruleSymbolToType(MCProdSymbol ruleSymbol, String typeName) {
if (ruleSymbol.isLexerProd()) {
if (!ruleSymbol.getAstNode().isPresent() || !(ruleSymbol.getAstNode().get() instanceof ASTLexProd)) {
return createSimpleReference("String");
}
return determineConstantsType(HelperGrammar.createConvertType((ASTLexProd)ruleSymbol.getAstNode().get()))
.map(lexType -> (ASTType) TypesNodeFactory.createASTPrimitiveType(lexType))
.orElse(createSimpleReference("String"));
}
else if (ruleSymbol.isExternal()) {
return createSimpleReference("AST" + typeName + "Ext");
}
else {
String qualifiedASTNodeName = getPackageName(ruleSymbol)
+ "AST" + ruleSymbol.getName();
return createSimpleReference(qualifiedASTNodeName);
}
}
private ASTType determineTypeToSetForAttributeInAST(ASTGenericType astGenericType,
ASTMCGrammar astMCGrammar) {
Optional<MCProdSymbol> ruleSymbol = TransformationHelper
.resolveAstRuleType(astGenericType);
if (!ruleSymbol.isPresent()) {
return determineTypeToSet(astGenericType.getTypeName(), astMCGrammar);
}
else if (ruleSymbol.get().isExternal()) {
return createSimpleReference(astGenericType + "Ext");
}
else {
String qualifiedASTNodeName = TransformationHelper
.getPackageName(ruleSymbol.get()) + "AST" + ruleSymbol.get().getName();
return createSimpleReference(qualifiedASTNodeName);
}
}
private ASTType determineTypeToSet(String typeName, ASTMCGrammar astMCGrammar) {
Optional<ASTType> byReference = MCGrammarSymbolTableHelper
.resolveRule(astMCGrammar, typeName)
.map(ruleSymbol -> ruleSymbolToType(ruleSymbol, typeName));
Optional<ASTType> byPrimitive = determineConstantsType(typeName)
.map(TypesNodeFactory::createASTPrimitiveType);
return byReference.orElse(byPrimitive.orElse(createSimpleReference(typeName)));
}
private Optional<Integer> determineConstantsType(String typeName) {
switch (typeName) {
case "int":
return Optional.of(ASTConstantsTypes.INT);
case "boolean":
return Optional.of(ASTConstantsTypes.BOOLEAN);
case "double":
return Optional.of(ASTConstantsTypes.DOUBLE);
case "float":
return Optional.of(ASTConstantsTypes.FLOAT);
case "char":
return Optional.of(ASTConstantsTypes.CHAR);
case "byte":
return Optional.of(ASTConstantsTypes.BYTE);
case "short":
return Optional.of(ASTConstantsTypes.SHORT);
case "long":
return Optional.of(ASTConstantsTypes.LONG);
default:
return Optional.empty();
}
}
}