de.monticore.codegen.mc2cd.transl.MultiplicityTranslation.java Source code

Java tutorial

Introduction

Here is the source code for de.monticore.codegen.mc2cd.transl.MultiplicityTranslation.java

Source

/*
 * ******************************************************************************
 * 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";
        }
    }

}