/*
* ******************************************************************************
* 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.typeToString;
import static de.monticore.grammar.Multiplicity.determineMultiplicity;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BinaryOperator;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import com.google.common.collect.Maps;
import de.monticore.ast.ASTNode;
import de.monticore.codegen.mc2cd.TransformationHelper;
import de.monticore.grammar.Multiplicity;
import de.monticore.grammar.grammar._ast.ASTMCGrammar;
import de.monticore.types.types._ast.ASTConstantsTypes;
import de.monticore.types.types._ast.ASTPrimitiveType;
import de.monticore.types.types._ast.ASTSimpleReferenceType;
import de.monticore.types.types._ast.ASTType;
import de.monticore.umlcd4a.cd4analysis._ast.ASTCDAttribute;
import de.monticore.umlcd4a.cd4analysis._ast.ASTCDCompilationUnit;
import de.monticore.utils.Link;
import de.se_rwth.commons.Names;
/**
* Checks for the multiplicity implied by the Monticore AST and modifies the type of the resulting
* attribute accordingly. Keep in mind that since nonterminals can be enclosed by blocks
* (parentheses) multiple multiplicities can apply. The rules for this operation, sorted from
* highest to lowest priority:
* <li>Star or Plus indicates a List
* <li>Question mark implies an Optional
* <li>the default is just a normal reference
*
* @author Sebastian Oberhoff
*/
public class MultiplicityTranslation implements
UnaryOperator<Link<ASTMCGrammar, ASTCDCompilationUnit>> {
@Override
public Link<ASTMCGrammar, ASTCDCompilationUnit> apply(
Link<ASTMCGrammar, ASTCDCompilationUnit> rootLink) {
Map<ASTCDAttribute, Multiplicity> cdAttributesToMaxMultiplicities =
mapCDAttributesToMaxMultiplicities(rootLink.getLinks(ASTNode.class, ASTCDAttribute.class));
cdAttributesToMaxMultiplicities.entrySet().stream()
.forEach(entry -> {
ASTCDAttribute cdAttribute = entry.getKey();
Multiplicity multiplicity = entry.getValue();
cdAttribute.setType(createNewType(cdAttribute.getType(), multiplicity));
});
return rootLink;
}
/**
* Groups all the links with identical targets and maps them to their maximum Multiplicities
*/
private Map<ASTCDAttribute, Multiplicity> mapCDAttributesToMaxMultiplicities(
Set<Link<ASTNode, ASTCDAttribute>> cdAttributeLinks) {
Map<ASTCDAttribute, List<Link<ASTNode, ASTCDAttribute>>> cdAttributesToLinks =
cdAttributeLinks.stream().collect(Collectors.groupingBy(Link::target));
return Maps.transformValues(cdAttributesToLinks,
linkList -> linkList.stream()
.map(link -> determineMultiplicity(link.rootLink().source(), link.source()))
.reduce(BinaryOperator.maxBy(Multiplicity::compareTo))
.get());
}
private static ASTType createNewType(ASTType oldType, Multiplicity multiplicity) {
if (oldType instanceof ASTPrimitiveType) {
if (multiplicity == Multiplicity.LIST) {
return createNewListType(changePrimitiveType(((ASTPrimitiveType) oldType).getPrimitive()));
}
} else {
if (multiplicity == Multiplicity.LIST) {
return createNewListType(typeToString(oldType));
}
else if (multiplicity == Multiplicity.OPTIONAL) {
return createSimpleReference("Optional", typeToString(oldType));
}
}
return oldType;
}
private static ASTSimpleReferenceType createNewListType(String oldTypeName) {
return createSimpleReference("java.util.List", oldTypeName);
// TODO GV, MB
/*
if (Names.getSimpleName(oldTypeName).startsWith(TransformationHelper.AST_PREFIX)) {
return createSimpleReference(oldTypeName + "List");
}
else {
return createSimpleReference("java.util.List", oldTypeName);
}*/
}
private static String changePrimitiveType(int primType) {
switch (primType) {
case ASTConstantsTypes.INT:
return "Integer";
case ASTConstantsTypes.BOOLEAN:
return "Boolean";
case ASTConstantsTypes.DOUBLE:
return "Double";
case ASTConstantsTypes.FLOAT:
return "Float";
case ASTConstantsTypes.CHAR:
return "Char";
case ASTConstantsTypes.BYTE:
return "Byte";
case ASTConstantsTypes.SHORT:
return "Short";
case ASTConstantsTypes.LONG:
return "Long";
default:
return "Object";
}
}
}