de.monticore.codegen.mc2cd.TransformationHelper.java Source code

Java tutorial

Introduction

Here is the source code for de.monticore.codegen.mc2cd.TransformationHelper.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;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty;
import static de.monticore.codegen.GeneratorHelper.AST_DOT_PACKAGE_SUFFIX_DOT;

import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;

import de.monticore.ast.ASTNode;
import de.monticore.codegen.GeneratorHelper;
import de.monticore.generating.templateengine.reporting.Reporting;
import de.monticore.grammar.grammar._ast.*;
import de.monticore.io.paths.IterablePath;
import de.monticore.languages.grammar.MCGrammarSymbol;
import de.monticore.languages.grammar.MCRuleSymbol;
import de.monticore.languages.grammar.MCTypeSymbol;
import de.monticore.languages.grammar.MCTypeSymbol.KindType;
import de.monticore.prettyprint.IndentPrinter;
import de.monticore.types.types._ast.ASTPrimitiveType;
import de.monticore.types.types._ast.ASTSimpleReferenceType;
import de.monticore.types.types._ast.ASTType;
import de.monticore.types.types._ast.ASTTypeArgument;
import de.monticore.types.types._ast.ASTVoidType;
import de.monticore.types.types._ast.TypesNodeFactory;
import de.monticore.umlcd4a.cd4analysis._ast.ASTCD4AnalysisNode;
import de.monticore.umlcd4a.cd4analysis._ast.ASTCDAttribute;
import de.monticore.umlcd4a.cd4analysis._ast.ASTCDClass;
import de.monticore.umlcd4a.cd4analysis._ast.ASTCDCompilationUnit;
import de.monticore.umlcd4a.cd4analysis._ast.ASTCDInterface;
import de.monticore.umlcd4a.cd4analysis._ast.ASTCDParameter;
import de.monticore.umlcd4a.cd4analysis._ast.ASTModifier;
import de.monticore.umlcd4a.cd4analysis._ast.ASTStereoValue;
import de.monticore.umlcd4a.cd4analysis._ast.CD4AnalysisNodeFactory;
import de.monticore.umlcd4a.cd4analysis._parser.CD4AnalysisParser;
import de.monticore.umlcd4a.prettyprint.CDPrettyPrinterConcreteVisitor;
import de.monticore.utils.ASTNodes;
import de.se_rwth.commons.Names;
import de.se_rwth.commons.logging.Log;

public final class TransformationHelper {

    public static final String DEFAULT_FILE_EXTENSION = ".java";

    public final static String GENERATED_CLASS_SUFFIX = "TOP";

    public static final String AST_PREFIX = "AST";

    public static final String AST_PACKAGE_SUFFIX = "_ast";

    private TransformationHelper() {
        // noninstantiable
    }

    public static String getClassProdName(ASTClassProd classProd) {
        return classProd.getName();
    }

    public static String typeToString(ASTType type) {
        if (type instanceof ASTSimpleReferenceType) {
            return Names.getQualifiedName(((ASTSimpleReferenceType) type).getNames());
        } else if (type instanceof ASTPrimitiveType) {
            return type.toString();
        }
        return "";
    }

    public static String typeReferenceToString(ASTGenericType typeReference) {
        return typeReference.getTypeName();
    }

    /**
     * Pretty prints a CD AST to a String object.
     * 
     * @param cdCompilationUnit the top node of the CD AST to be pretty printed
     */
    // TODO: should be placed somewhere in the UML/P CD project
    public static String prettyPrint(ASTCD4AnalysisNode astNode) {
        // set up objects
        CDPrettyPrinterConcreteVisitor prettyPrinter = new CDPrettyPrinterConcreteVisitor(new IndentPrinter());

        // run, check result and return
        String prettyPrintedAst = prettyPrinter.prettyprint(astNode);
        checkArgument(!isNullOrEmpty(prettyPrintedAst));
        return prettyPrintedAst;
    }

    public static Optional<String> getUsageName(ASTNode root, ASTNode successor) {
        List<ASTNode> intermediates = ASTNodes.getIntermediates(root, successor);
        for (ASTNode ancestor : Lists.reverse(intermediates)) {
            if (ancestor instanceof ASTConstantGroup) {
                return Optional.ofNullable(((ASTConstantGroup) ancestor).getUsageName().orElse(null));
            }
            if (ancestor instanceof ASTNonTerminal) {
                return Optional.ofNullable(((ASTNonTerminal) ancestor).getUsageName().orElse(null));
            }
            if (ancestor instanceof ASTNonTerminalSeparator) {
                return Optional.ofNullable(((ASTNonTerminalSeparator) ancestor).getUsageName().orElse(null));
            }
            if (ancestor instanceof ASTTerminal) {
                return Optional.ofNullable(((ASTTerminal) ancestor).getUsageName().orElse(null));
            }
            if (ancestor instanceof ASTAttributeInAST) {
                return ((ASTAttributeInAST) ancestor).getName();
            }
        }
        return Optional.empty();
    }

    public static Optional<String> getName(ASTNode node) {
        try {
            Method getNameMethod = node.getClass().getMethod("getName");
            String name = (String) getNameMethod.invoke(node);
            return Optional.ofNullable(name);
        } catch (ClassCastException | InvocationTargetException | IllegalAccessException | IllegalArgumentException
                | NoSuchMethodException | SecurityException e) {
            return Optional.empty();
        }
    }

    public static ASTModifier createFinalModifier() {
        ASTModifier modifier = CD4AnalysisNodeFactory.createASTModifier();
        modifier.setFinal(true);
        return modifier;
    }

    public static ASTCDParameter createParameter(String typeName, String parameterName) {
        ASTCDParameter parameter = CD4AnalysisNodeFactory.createASTCDParameter();
        parameter.setType(TransformationHelper.createSimpleReference(typeName));
        parameter.setName(parameterName);
        return parameter;
    }

    public static ASTModifier createPrivateModifier() {
        ASTModifier modifier = CD4AnalysisNodeFactory.createASTModifier();
        modifier.setPrivate(true);
        return modifier;
    }

    public static ASTModifier createStaticModifier() {
        ASTModifier modifier = CD4AnalysisNodeFactory.createASTModifier();
        modifier.setStatic(true);
        return modifier;
    }

    public static ASTModifier createProtectedModifier() {
        ASTModifier modifier = CD4AnalysisNodeFactory.createASTModifier();
        modifier.setProtected(true);
        return modifier;
    }

    public static ASTModifier createPublicModifier() {
        ASTModifier modifier = CD4AnalysisNodeFactory.createASTModifier();
        modifier.setPublic(true);
        return modifier;
    }

    public static ASTSimpleReferenceType createSimpleReference(String typeName, String... generics) {
        ASTSimpleReferenceType reference = TypesNodeFactory.createASTSimpleReferenceType();

        // set the name of the type
        ArrayList<String> name = new ArrayList<String>();
        name.add(typeName);
        reference.setNames(name);

        // set generics
        if (generics.length > 0) {
            List<ASTTypeArgument> typeArguments = new ArrayList<>();
            for (String generic : generics) {
                typeArguments.add(createSimpleReference(generic));
            }
            reference.setTypeArguments(TypesNodeFactory.createASTTypeArguments(typeArguments));
        }

        return reference;
    }

    public static ASTVoidType createVoidType() {
        return TypesNodeFactory.createASTVoidType();
    }

    public static String getAstPackageName(MCGrammarSymbol grammar) {
        // return grammar.getName().toLowerCase() + AST_DOT_PACKAGE_SUFFIX_DOT;
        return getPackageName(grammar);
    }

    public static String getPackageName(MCGrammarSymbol grammar) {
        return grammar.getFullName() + ".";
    }

    public static String getAstPackageName(ASTCDCompilationUnit cdCompilationUnit) {
        String packageName = Names.getQualifiedName(cdCompilationUnit.getPackage());
        if (!packageName.isEmpty()) {
            packageName = packageName + ".";
        }
        return packageName + cdCompilationUnit.getCDDefinition().getName().toLowerCase()
                + AST_DOT_PACKAGE_SUFFIX_DOT;
    }

    public static String getPackageName(ASTCDCompilationUnit cdCompilationUnit) {
        String packageName = Names.getQualifiedName(cdCompilationUnit.getPackage());
        if (!packageName.isEmpty()) {
            packageName = packageName + ".";
        }
        return packageName + cdCompilationUnit.getCDDefinition().getName() + ".";
    }

    public static String getBaseNodeName(ASTCDCompilationUnit cdCompilationUnit) {
        return getAstPackageName(cdCompilationUnit)
                + GeneratorHelper.getASTNodeBaseType(cdCompilationUnit.getCDDefinition().getName());
    }

    // TODO SO <- GV: change
    public static List<String> getAllGrammarConstants(ASTMCGrammar grammar) {
        List<String> constants = new ArrayList<>();
        MCGrammarSymbol grammarSymbol = MCGrammarSymbolTableHelper.getMCGrammarSymbol(grammar).get();
        Preconditions.checkState(grammarSymbol != null);
        for (MCTypeSymbol type : grammarSymbol.getTypes()) {
            if (type.getKindOfType().equals(KindType.ENUM) || type.getKindOfType().equals(KindType.CONST)) {
                for (String enumValue : type.getEnumValues()) {
                    if (!constants.contains(enumValue)) {
                        constants.add(enumValue);
                    }
                }
            }
        }
        return constants;
    }

    public static java.util.Optional<ASTCDAttribute> createAttributeUsingCdParser(String toParse)
            throws IOException {
        checkArgument(!Strings.isNullOrEmpty(toParse));
        java.util.Optional<ASTCDAttribute> astCDAttribute = (new CD4AnalysisParser())
                .parseCDAttribute(new StringReader(toParse));
        return astCDAttribute;
    }

    /**
     * Checks if a handwritten class with the given qualifiedName (dot-separated)
     * exists on the target path
     * 
     * @param qualifiedName name of the class to search for
     * @return true if a handwritten class with the qualifiedName exists
     */
    public static boolean existsHandwrittenClass(IterablePath targetPath, String qualifiedName) {
        Path handwrittenFile = Paths.get(Names.getPathFromPackage(qualifiedName) + DEFAULT_FILE_EXTENSION);
        Log.debug("Checking existence of handwritten class " + qualifiedName + " by searching for "
                + handwrittenFile.toString(), TransformationHelper.class.getName());
        boolean result = targetPath.exists(handwrittenFile);
        if (result) {
            Reporting.reportUseHandwrittenCodeFile(targetPath.getResolvedPath(handwrittenFile).get(),
                    handwrittenFile);
        } else {
            Reporting.reportUseHandwrittenCodeFile(null, handwrittenFile);
        }
        return result;
    }

    public static String getQualifiedTypeNameAndMarkIfExternal(ASTGenericType ruleReference, ASTMCGrammar grammar,
            ASTCDClass cdClass) {

        Optional<MCRuleSymbol> typeSymbol = resolveAstRuleType(ruleReference);

        String qualifiedRuleName = getQualifiedAstName(typeSymbol, ruleReference, grammar);

        if (!typeSymbol.isPresent()) {
            addStereoType(cdClass, MC2CDStereotypes.EXTERNAL_TYPE.toString(), qualifiedRuleName);
        }

        return qualifiedRuleName;
    }

    // TODO GV: remove this if CDInterface and CDClass have a common type CDType
    public static String getQualifiedTypeNameAndMarkIfExternal(ASTGenericType ruleReference, ASTMCGrammar grammar,
            ASTCDInterface interf) {

        Optional<MCRuleSymbol> typeSymbol = resolveAstRuleType(ruleReference);

        String qualifiedRuleName = getQualifiedAstName(typeSymbol, ruleReference, grammar);

        if (!typeSymbol.isPresent()) {
            addStereoType(interf, MC2CDStereotypes.EXTERNAL_TYPE.toString(), qualifiedRuleName);
        }

        return qualifiedRuleName;
    }

    public static Optional<MCRuleSymbol> resolveAstRuleType(ASTGenericType type) {
        if (!type.getNames().isEmpty()) {
            String simpleName = type.getNames().get(type.getNames().size() - 1);
            if (!simpleName.startsWith(AST_PREFIX)) {
                return Optional.empty();
            }
            Optional<MCRuleSymbol> ruleSymbol = MCGrammarSymbolTableHelper.resolveRule(type,
                    simpleName.substring(AST_PREFIX.length()));
            if (ruleSymbol.isPresent() && ruleSymbol.get().getGrammarSymbol() != null) {
                return ruleSymbol;
            }
        }
        return Optional.empty();
    }

    public static boolean checkIfExternal(ASTGenericType type) {
        return !resolveAstRuleType(type).isPresent();
    }

    public static String getQualifiedAstName(Optional<MCRuleSymbol> typeSymbol, ASTGenericType type,
            ASTMCGrammar grammar) {
        if (!typeSymbol.isPresent()) {
            return type.getTypeName();
        }
        if (type.getNames().size() > 1) {
            return type.getTypeName();
        }
        MCGrammarSymbol refGrammar = typeSymbol.get().getGrammarSymbol();
        if (grammar.getSymbol().isPresent() && grammar.getSymbol().get().equals(refGrammar)) {
            return type.getTypeName();
        }
        return getAstPackageName(typeSymbol.get().getGrammarSymbol()) + type.getTypeName();
    }

    public static void addStereoType(ASTCDClass type, String stereotypeName, String stereotypeValue) {
        if (!type.getModifier().isPresent()) {
            type.setModifier(CD4AnalysisNodeFactory.createASTModifier());
        }
        addStereotypeValue(type.getModifier().get(), stereotypeName, stereotypeValue);
    }

    public static void addStereoType(ASTCDInterface type, String stereotypeName, String stereotypeValue) {
        if (!type.getModifier().isPresent()) {
            type.setModifier(CD4AnalysisNodeFactory.createASTModifier());
        }
        addStereotypeValue(type.getModifier().get(), stereotypeName, stereotypeValue);
    }

    public static void addStereoType(ASTCDAttribute attribute, String stereotypeName, String stereotypeValue) {
        if (!attribute.getModifier().isPresent()) {
            attribute.setModifier(CD4AnalysisNodeFactory.createASTModifier());
        }
        addStereotypeValue(attribute.getModifier().get(), stereotypeName, stereotypeValue);
    }

    public static void addStereotypeValue(ASTModifier astModifier, String stereotypeName, String stereotypeValue) {
        if (!astModifier.getStereotype().isPresent()) {
            astModifier.setStereotype(CD4AnalysisNodeFactory.createASTStereotype());
        }
        List<ASTStereoValue> stereoValueList = astModifier.getStereotype().get().getValues();
        ASTStereoValue stereoValue = CD4AnalysisNodeFactory.createASTStereoValue();
        stereoValue.setName(stereotypeName);
        stereoValue.setValue(stereotypeValue);
        stereoValueList.add(stereoValue);
    }

}