org.jsweet.input.typescriptdef.ast.DeclarationHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.jsweet.input.typescriptdef.ast.DeclarationHelper.java

Source

/* 
 * TypeScript definitions to Java translator - http://www.jsweet.org
 * Copyright (C) 2015 CINCHEO SAS <renaud.pawlak@cincheo.fr>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *  
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package org.jsweet.input.typescriptdef.ast;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.jsweet.JSweetDefTranslatorConfig;

/**
 * A helper class to factorize common functions on declarations.
 * 
 * @author Renaud Pawlak
 */
public abstract class DeclarationHelper {

    public static final Map<String, int[]> JAVA_OBJECT_METHODS = new HashMap<String, int[]>();
    // public static final Set<String> JAVA_FINAL_OBJECT_METHODS = new
    // HashSet<String>();
    // public static final Set<String> JAVA_OBJECT_METHOD_NAMES = new
    // HashSet<String>();
    public static final Set<String> JS_OBJECT_METHOD_NAMES = new HashSet<String>();
    public static final Set<String> JS_PRIMITIVE_TYPE_NAMES = new HashSet<String>();

    static {
        JS_OBJECT_METHOD_NAMES.add("toString");

        JS_PRIMITIVE_TYPE_NAMES.add("boolean");
        JS_PRIMITIVE_TYPE_NAMES.add("number");

        if (!JSweetDefTranslatorConfig.isJDKReplacementMode()) {
            // toString is common to Java and Javascript
            // JAVA_OBJECT_METHOD_NAMES.add("finalize");
            // JAVA_OBJECT_METHOD_NAMES.add("clone");
            // JAVA_OBJECT_METHOD_NAMES.add("equals");
            // JAVA_OBJECT_METHOD_NAMES.add("hashCode");
            // JAVA_OBJECT_METHOD_NAMES.add("notify");
            // JAVA_OBJECT_METHOD_NAMES.add("notifyAll");
            // JAVA_OBJECT_METHOD_NAMES.add("getClass");

            JAVA_OBJECT_METHODS.put("finalize", new int[] { 0 });
            JAVA_OBJECT_METHODS.put("clone", new int[] { 0 });
            JAVA_OBJECT_METHODS.put("equals", new int[] { 1 });
            JAVA_OBJECT_METHODS.put("hashCode", new int[] { 0 });
            JAVA_OBJECT_METHODS.put("notify", new int[] { 0 });
            JAVA_OBJECT_METHODS.put("notifyAll", new int[] { 0 });
            JAVA_OBJECT_METHODS.put("getClass", new int[] { 0 });
            JAVA_OBJECT_METHODS.put("wait", new int[] { 0, 1, 2 });

            // JAVA_FINAL_OBJECT_METHODS.add("notify():void");
            // JAVA_FINAL_OBJECT_METHODS.add("notifyAll():void");
            // JAVA_FINAL_OBJECT_METHODS.add("wait():void");
            // JAVA_FINAL_OBJECT_METHODS.add("wait(long):void");
            // JAVA_FINAL_OBJECT_METHODS.add("wait(long,int):void");
            // JAVA_FINAL_OBJECT_METHODS.add("getClass():java.lang.Class");
        }
    }

    public static boolean isPrimitiveType(String name) {
        return JS_PRIMITIVE_TYPE_NAMES.contains(name);
    }

    public static String getActualFunctionName(FunctionDeclaration function) {
        if (JAVA_OBJECT_METHODS.keySet().contains(function.getName())) {
            if (ArrayUtils.contains(JAVA_OBJECT_METHODS.get(function.getName()), function.getParameters().length)) {
                return StringUtils.capitalize(function.getName());
            }
        }
        return function.getName();
    }

    public static String toJavaIdentifier(String identifier) {
        if (JSweetDefTranslatorConfig.JAVA_KEYWORDS.contains(identifier)) {
            return StringUtils.capitalize(identifier);
        }
        if (JSweetDefTranslatorConfig.JAVA_TS_KEYWORDS.contains(identifier)) {
            return StringUtils.capitalize(identifier);
        }

        // TODO: this is not what happens... it must have been transformed
        // before
        if (Character.isDigit(identifier.charAt(0))) {
            return "$$" + identifier.charAt(0) + "$$" + identifier.substring(1);
        }
        return identifier;
    }

    public static Declaration[] addMember(DeclarationContainer container, Declaration declaration) {
        return ArrayUtils.add(container.getMembers(), declaration);
    }

    public static Declaration[] replaceMember(DeclarationContainer container, Declaration existingDeclaration,
            Declaration withNewDeclaration) {
        int index = ArrayUtils.indexOf(container.getMembers(), existingDeclaration);
        if (index >= 0) {
            container.getMembers()[index] = withNewDeclaration;
        }
        return container.getMembers();
    }

    public static Declaration[] removeMember(DeclarationContainer container, Declaration declaration) {
        int index = ArrayUtils.indexOf(container.getMembers(), declaration);
        if (index < 0) {
            return container.getMembers();
        }
        return ArrayUtils.remove(container.getMembers(), index);
    }

    public static List<FunctionDeclaration> findConstructors(TypeDeclaration typeDeclaration) {
        if (typeDeclaration.getMembers() == null) {
            return null;
        }
        List<FunctionDeclaration> constructors = new ArrayList<FunctionDeclaration>();
        for (Declaration m : typeDeclaration.getMembers()) {
            if (m instanceof FunctionDeclaration) {
                if (((FunctionDeclaration) m).isConstructor()) {
                    constructors.add((FunctionDeclaration) m);
                }
            }
        }
        return constructors;
    }

    public static FunctionDeclaration findFirstConstructor(TypeDeclaration typeDeclaration) {
        if (typeDeclaration.getMembers() == null) {
            return null;
        }
        for (Declaration m : typeDeclaration.getMembers()) {
            if (m instanceof FunctionDeclaration) {
                if (((FunctionDeclaration) m).isConstructor()) {
                    return (FunctionDeclaration) m;
                }
            }
        }
        return null;
    }

    public static boolean isStatic(TypeDeclaration typeDeclaration) {
        if (typeDeclaration.getMembers() == null) {
            return true;
        }
        if (!typeDeclaration.isInterface()) {
            return false;
        }
        for (Declaration m : typeDeclaration.getMembers()) {
            if (!m.hasModifier("static")) {
                return false;
            }
        }
        return true;
    }

    public static TypeReference[] toTypeArguments(TypeParameterDeclaration[] typeParameterDeclarations) {
        if (typeParameterDeclarations == null) {
            return null;
        }
        TypeReference[] args = new TypeReference[typeParameterDeclarations.length];
        for (int i = 0; i < typeParameterDeclarations.length; i++) {
            args[i] = new TypeReference(null, typeParameterDeclarations[i].getName(), null);
        }
        return args;
    }

    public static List<FunctionDeclaration> findFunctions(DeclarationContainer container, String name) {
        if (container.getMembers() == null) {
            return null;
        }
        List<FunctionDeclaration> functions = new ArrayList<FunctionDeclaration>();
        for (Declaration m : container.getMembers()) {
            if (m instanceof FunctionDeclaration) {
                if (((FunctionDeclaration) m).getName().equals(name)) {
                    functions.add((FunctionDeclaration) m);
                }
            }
        }
        return functions;
    }

    public static FunctionDeclaration findFirstFunction(DeclarationContainer container, String name) {
        if (container.getMembers() == null) {
            return null;
        }
        for (Declaration m : container.getMembers()) {
            if (m instanceof FunctionDeclaration) {
                if (((FunctionDeclaration) m).getName().equals(name)) {
                    return (FunctionDeclaration) m;
                }
            }
        }
        return null;
    }

    public static VariableDeclaration findVariable(DeclarationContainer container, String name) {
        if (container.getMembers() == null) {
            return null;
        }
        for (Declaration m : container.getMembers()) {
            if (m instanceof VariableDeclaration) {
                if (((VariableDeclaration) m).getName().equals(name)) {
                    return (VariableDeclaration) m;
                }
            }
        }
        return null;
    }

    public static VariableDeclaration findVariableIgnoreCase(DeclarationContainer container, String name) {
        if (container.getMembers() == null) {
            return null;
        }
        for (Declaration m : container.getMembers()) {
            if (m instanceof VariableDeclaration) {
                if (((VariableDeclaration) m).getName().equalsIgnoreCase(name)) {
                    return (VariableDeclaration) m;
                }
            }
        }
        return null;
    }

    public static TypeDeclaration findType(DeclarationContainer container, String name) {
        if (container.getMembers() == null) {
            return null;
        }
        for (Declaration m : container.getMembers()) {
            if (m instanceof TypeDeclaration) {
                if (((TypeDeclaration) m).getName().equals(name)) {
                    return (TypeDeclaration) m;
                }
            }
        }
        return null;
    }

    public static TypeDeclaration findTypeIgnoreCase(DeclarationContainer container, String name) {
        if (container.getMembers() == null) {
            return null;
        }
        for (Declaration m : container.getMembers()) {
            if (m instanceof TypeDeclaration) {
                if (((TypeDeclaration) m).getName().equalsIgnoreCase(name)) {
                    return (TypeDeclaration) m;
                }
            }
        }
        return null;
    }

    public static ModuleDeclaration findModule(DeclarationContainer container, String name) {
        if (container.getMembers() == null) {
            return null;
        }
        for (Declaration m : container.getMembers()) {
            if (m instanceof ModuleDeclaration) {
                if (((ModuleDeclaration) m).getName().equals(name)) {
                    return (ModuleDeclaration) m;
                }
            }
        }
        return null;
    }

    public static ModuleDeclaration getOrCreateModule(DeclarationContainer container, String name) {
        ModuleDeclaration m = findModule(container, name);
        if (m == null) {
            m = new ModuleDeclaration(null, name, new Declaration[0]);
            container.addMember(m);
        }
        return m;
    }

    public static Declaration findDeclaration(DeclarationContainer container, String name) {
        if (container.getMembers() == null) {
            return null;
        }
        for (Declaration d : container.getMembers()) {
            if (d.getName().equals(name)) {
                return d;
            }
        }
        return null;
    }

    public static Declaration findDeclaration(DeclarationContainer container, Declaration declaration) {
        if (container.getMembers() == null) {
            return null;
        }
        int i = ArrayUtils.indexOf(container.getMembers(), declaration);
        if (i < 0) {
            return null;
        } else {
            return container.getMembers()[i];
        }
    }

    public static Declaration[] findAllVisibleDeclarations(DeclarationContainer container,
            Declaration declaration) {
        Declaration[] result = {};
        if (container.getMembers() == null) {
            return result;
        }
        for (Declaration d : container.getMembers()) {
            if (!d.isHidden() && d.equals(declaration)) {
                result = ArrayUtils.add(result, d);
            }
        }
        return result;
    }

    public static void addMembers(DeclarationContainer targetContainer, Declaration[] declarations) {
        for (Declaration d : declarations) {
            if (findDeclaration(targetContainer, d) == null) {
                targetContainer.addMember(d);
            }
        }
    }

    public static boolean areDeclarationsEqual(Declaration[] declarations1, Declaration[] declarations2) {
        for (Declaration d : declarations1) {
            if (!ArrayUtils.contains(declarations2, d)) {
                return false;
            }
        }
        for (Declaration d : declarations2) {
            if (!ArrayUtils.contains(declarations1, d)) {
                return false;
            }
        }
        return true;
    }

    @SuppressWarnings("unchecked")
    public static <T extends Declaration> T[] copy(T[] declarations) {
        if (declarations == null) {
            return null;
        }
        T[] to = Arrays.copyOf(declarations, declarations.length);
        for (int i = 0; i < declarations.length; i++) {
            to[i] = (T) declarations[i].copy();
        }
        return (T[]) to;
    }

    public static <T extends TypeReference> T[] copyReferences(T[] references) {
        return copyReferences(references, false);
    }

    @SuppressWarnings("unchecked")
    public static <T extends TypeReference> T[] copyReferences(T[] references, boolean copyDeclarations) {
        if (references == null) {
            return null;
        }
        T[] to = Arrays.copyOf(references, references.length);
        for (int i = 0; i < references.length; i++) {
            to[i] = (T) references[i].copy(copyDeclarations);
        }
        return (T[]) to;
    }

    public static <T extends Type> TypeReference[] toReferences(T[] types) {
        if (types == null) {
            return null;
        }
        TypeReference[] to = new TypeReference[types.length];
        for (int i = 0; i < types.length; i++) {
            to[i] = new TypeReference(null, types[i], null);
        }
        return to;
    }

    public static TypeDeclaration createFunctionalType(String name, int parameterCount, boolean hasResult,
            boolean disambiguation) {
        TypeDeclaration functionalType = null;
        TypeParameterDeclaration[] typeParameters = new TypeParameterDeclaration[parameterCount];
        for (int i = 0; i < parameterCount; i++) {
            typeParameters[i] = new TypeParameterDeclaration(null, "T" + (i + 1));
        }
        TypeParameterDeclaration resultType = new TypeParameterDeclaration(null, "R");
        ParameterDeclaration[] parameters = new ParameterDeclaration[typeParameters.length];
        for (int i = 0; i < typeParameters.length; i++) {
            parameters[i] = new ParameterDeclaration(null, "p" + (i + 1),
                    new TypeReference(null, typeParameters[i], null), false, false);
        }
        FunctionDeclaration newFunction = new FunctionDeclaration(null,
                JSweetDefTranslatorConfig.ANONYMOUS_FUNCTION_NAME,
                hasResult ? new TypeReference(null, resultType, null) : new TypeReference(null, "void", null),
                parameters, null);

        if (hasResult) {
            typeParameters = ArrayUtils.add(typeParameters, resultType);
        }
        functionalType = new TypeDeclaration(null, "interface", name, typeParameters, null,
                new FunctionDeclaration[] { newFunction });
        functionalType.addAnnotation(new FunctionalInterface() {
            @Override
            public Class<? extends Annotation> annotationType() {
                return FunctionalInterface.class;
            }
        });
        if (disambiguation) {
            functionalType.setDocumentation(
                    "/** This functional interface should be used for disambiguating lambdas in function parameters (by casting to this interface)."
                            + "<p>It was automatically generated for functions (taking lambdas) that lead to the same erased signature. */");
        } else {
            functionalType.setDocumentation(
                    "/** This functional interface was automatically generated for allowing lambdas taking "
                            + parameterCount + " parameters " + (hasResult ? " and returning a result." : ".")
                            + " */");
        }
        return functionalType;
    }

    public static Type getTypeOrComponentType(TypeReference typeReference) {
        if (typeReference.isArray()) {
            return getTypeOrComponentType(typeReference.getComponentType());
        } else {
            return typeReference.getDeclaration();
        }
    }

}