Package com.asakusafw.compiler.operator.util

Source Code of com.asakusafw.compiler.operator.util.GeneratorUtil

/**
* Copyright 2011-2014 Asakusa Framework Team.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.asakusafw.compiler.operator.util;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;

import com.asakusafw.compiler.common.Precondition;
import com.asakusafw.compiler.operator.OperatorCompilingEnvironment;
import com.asakusafw.compiler.operator.OperatorPortDeclaration;
import com.asakusafw.utils.collections.Lists;
import com.asakusafw.utils.java.jsr269.bridge.Jsr269;
import com.asakusafw.utils.java.model.syntax.AnnotationElement;
import com.asakusafw.utils.java.model.syntax.Expression;
import com.asakusafw.utils.java.model.syntax.FormalParameterDeclaration;
import com.asakusafw.utils.java.model.syntax.Literal;
import com.asakusafw.utils.java.model.syntax.ModelFactory;
import com.asakusafw.utils.java.model.syntax.NamedType;
import com.asakusafw.utils.java.model.syntax.SimpleName;
import com.asakusafw.utils.java.model.syntax.Type;
import com.asakusafw.utils.java.model.syntax.TypeParameterDeclaration;
import com.asakusafw.utils.java.model.util.AttributeBuilder;
import com.asakusafw.utils.java.model.util.ImportBuilder;
import com.asakusafw.utils.java.model.util.Models;
import com.asakusafw.utils.java.model.util.TypeBuilder;
import com.asakusafw.vocabulary.flow.In;
import com.asakusafw.vocabulary.flow.Out;
import com.asakusafw.vocabulary.flow.Source;
import com.asakusafw.vocabulary.flow.graph.ShuffleKey;
import com.asakusafw.vocabulary.operator.KeyInfo;
import com.asakusafw.vocabulary.operator.OperatorInfo;

/**
* JavaのDOMを構築する際のユーティリティ。
* @since 0.1.0
* @version 0.5.0
*/
public class GeneratorUtil {

    private final OperatorCompilingEnvironment environment;

    private final ModelFactory factory;

    private final ImportBuilder importer;

    /**
     * インスタンスを生成する。
     * @param environment 環境オブジェクト
     * @param factory DOMを構築するためのファクトリ
     * @param importer インポート宣言を構築するビルダー
     * @throws IllegalArgumentException 引数に{@code null}が含まれる場合
     */
    public GeneratorUtil(
            OperatorCompilingEnvironment environment,
            ModelFactory factory,
            ImportBuilder importer) {
        Precondition.checkMustNotBeNull(environment, "environment"); //$NON-NLS-1$
        Precondition.checkMustNotBeNull(factory, "factory"); //$NON-NLS-1$
        Precondition.checkMustNotBeNull(importer, "importer"); //$NON-NLS-1$
        this.environment = environment;
        this.factory = factory;
        this.importer = importer;
    }

    /**
     * 指定の型に対する演算子ファクトリークラスの単純名を返す。
     * @param type 対象の型
     * @return 対応する単純名
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public final SimpleName getFactoryName(TypeElement type) {
        Precondition.checkMustNotBeNull(type, "type"); //$NON-NLS-1$
        return factory.newSimpleName(MessageFormat.format(
                "{0}{1}",
                type.getSimpleName(),
                "Factory"));
    }

    /**
     * 指定の型に対する演算子実装クラスの単純名を返す。
     * @param type 対象の型
     * @return 対応する単純名
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public final SimpleName getImplementorName(TypeElement type) {
        Precondition.checkMustNotBeNull(type, "type"); //$NON-NLS-1$
        return factory.newSimpleName(getImplmentorName(
                type.getSimpleName().toString()));
    }

    /**
     * 指定の型に対する演算子実装クラスの名前を返す。
     * @param typeName 対象の型名
     * @return 対応する単純名
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public static final String getImplmentorName(String typeName) {
        Precondition.checkMustNotBeNull(typeName, "typeName"); //$NON-NLS-1$
        return MessageFormat.format(
                "{0}{1}",
                typeName,
                "Impl");
    }

    /**
     * 指定の型に対応する型のモデルを返す。
     * @param type 対象の型
     * @return 型のモデル
     * @throws IllegalArgumentException 引数に{@code null}が含まれる場合
     */
    public final Type t(TypeMirror type) {
        Precondition.checkMustNotBeNull(type, "type"); //$NON-NLS-1$
        return importer.resolve(new Jsr269(factory).convert(type));
    }

    /**
     * 指定の型に対応する型のモデルを返す。
     * @param type 対象の型
     * @return 型のモデル
     * @throws IllegalArgumentException 引数に{@code null}が含まれる場合
     */
    public final Type t(TypeElement type) {
        Precondition.checkMustNotBeNull(type, "type"); //$NON-NLS-1$
        DeclaredType t = environment.getTypeUtils().getDeclaredType(type);
        return importer.resolve(new Jsr269(factory).convert(t));
    }

    /**
     * 指定の型に対応する型のモデルを返す。
     * @param type 対象の型
     * @return 型のモデル
     * @throws IllegalArgumentException 引数に{@code null}が含まれる場合
     */
    public final Type t(java.lang.reflect.Type type) {
        Precondition.checkMustNotBeNull(type, "type"); //$NON-NLS-1$
        return importer.toType(type);
    }

    /**
     * 指定の値に対応するリテラルのモデルを返す。
     * @param value 対象の値
     * @return 指定の値に対応するリテラルのモデル
     * @throws IllegalArgumentException 引数に{@code null}が含まれる場合
     */
    public Literal v(String value) {
        Precondition.checkMustNotBeNull(value, "value"); //$NON-NLS-1$
        return Models.toLiteral(factory, value);
    }

    /**
     * 指定の値に対応するリテラルのモデルを返す。
     * @param pattern {@link MessageFormat}のパターン
     * @param arguments {@link MessageFormat}の引数一覧
     * @return 指定の値に対応するリテラルのモデル
     * @throws IllegalArgumentException 引数に{@code null}が含まれる場合
     */
    public Literal v(String pattern, Object... arguments) {
        Precondition.checkMustNotBeNull(pattern, "pattern"); //$NON-NLS-1$
        Precondition.checkMustNotBeNull(arguments, "arguments"); //$NON-NLS-1$
        return Models.toLiteral(factory, MessageFormat.format(pattern, arguments));
    }

    /**
     * 指定のデータの種類に対する{@link Source 結果型}を返す。
     * @param type 対象データの種類
     * @return 対応する結果型
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public Type toSourceType(TypeMirror type) {
        Precondition.checkMustNotBeNull(type, "type"); //$NON-NLS-1$
        Type source = t(Source.class);
        Type modelType = t(type);
        return factory.newParameterizedType(source, Collections.singletonList(modelType));
    }

    /**
     * 指定のデータの種類に対する{@link In 入力型}を返す。
     * @param type 対象データの種類
     * @return 対応する入力型
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public Type toInType(TypeMirror type) {
        Precondition.checkMustNotBeNull(type, "type"); //$NON-NLS-1$
        Type source = t(In.class);
        Type modelType = t(type);
        return factory.newParameterizedType(source, Collections.singletonList(modelType));
    }

    /**
     * 指定のデータの種類に対する{@link Out 出力型}を返す。
     * @param type 対象データの種類
     * @return 対応する出力型
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public Type toOutType(TypeMirror type) {
        Precondition.checkMustNotBeNull(type, "type"); //$NON-NLS-1$
        Type source = t(Out.class);
        Type modelType = t(type);
        return factory.newParameterizedType(source, Collections.singletonList(modelType));
    }

    /**
     * Returns the representation for type parameter declarations of the executable element.
     * @param element target element
     * @return the corresponded representation
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public List<TypeParameterDeclaration> toTypeParameters(ExecutableElement element) {
        Precondition.checkMustNotBeNull(element, "element"); //$NON-NLS-1$
        return toTypeParameters(element.getTypeParameters());
    }

    /**
     * Returns the representation for type parameter declarations of the type element.
     * @param element target element
     * @return the corresponded representation
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public List<TypeParameterDeclaration> toTypeParameters(TypeElement element) {
        Precondition.checkMustNotBeNull(element, "element"); //$NON-NLS-1$
        return toTypeParameters(element.getTypeParameters());
    }

    private List<TypeParameterDeclaration> toTypeParameters(
            List<? extends TypeParameterElement> typeParameters) {
        assert typeParameters != null;
        List<TypeParameterDeclaration> results = Lists.create();
        for (TypeParameterElement typeParameter : typeParameters) {
            SimpleName name = factory.newSimpleName(typeParameter.getSimpleName().toString());
            List<Type> typeBounds = Lists.create();
            for (TypeMirror typeBound : typeParameter.getBounds()) {
                typeBounds.add(t(typeBound));
            }
            results.add(factory.newTypeParameterDeclaration(name, typeBounds));
        }
        return results;
    }

    /**
     * Returns the representation for type variables of the executable element.
     * @param element target element
     * @return the corresponded representation
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public List<Type> toTypeVariables(ExecutableElement element) {
        Precondition.checkMustNotBeNull(element, "element"); //$NON-NLS-1$
        return toTypeVariables(element.getTypeParameters());
    }

    /**
     * Returns the representation for type variables of the type element.
     * @param element target element
     * @return the corresponded representation
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public List<Type> toTypeVariables(TypeElement element) {
        Precondition.checkMustNotBeNull(element, "element"); //$NON-NLS-1$
        return toTypeVariables(element.getTypeParameters());
    }

    private List<Type> toTypeVariables(List<? extends TypeParameterElement> typeParameters) {
        List<Type> results = Lists.create();
        for (TypeParameterElement typeParameter : typeParameters) {
            SimpleName name = factory.newSimpleName(typeParameter.getSimpleName().toString());
            results.add(factory.newNamedType(name));
        }
        return results;
    }

    /**
     * Converts {@link OperatorPortDeclaration} into an operator factory method parameter.
     * @param var target port declaration
     * @param name the actual parameter name
     * @return related parameter declaration
     * @throws IllegalArgumentException if some parameters were {@code null}
     */
    public FormalParameterDeclaration toFactoryMethodInput(OperatorPortDeclaration var, SimpleName name) {
        Precondition.checkMustNotBeNull(var, "var"); //$NON-NLS-1$
        Precondition.checkMustNotBeNull(name, "name"); //$NON-NLS-1$
        AttributeBuilder attributes = new AttributeBuilder(factory);
        ShuffleKey key = var.getShuffleKey();
        if (key != null) {
            List<Expression> group = new ArrayList<Expression>();
            for (String entry : key.getGroupProperties()) {
                group.addAll(new AttributeBuilder(factory)
                        .annotation(t(KeyInfo.Group.class), "expression", Models.toLiteral(factory, entry))
                        .toAnnotations());
            }
            List<Expression> order = new ArrayList<Expression>();
            for (ShuffleKey.Order entry : key.getOrderings()) {
                order.addAll(new AttributeBuilder(factory)
                        .annotation(
                                t(KeyInfo.Order.class),
                                "direction", new TypeBuilder(factory, t(KeyInfo.Direction.class))
                                        .field(entry.getDirection().name())
                                        .toExpression(),
                                "expression", Models.toLiteral(factory, entry.getProperty()))
                        .toAnnotations());
            }

            attributes.annotation(
                    t(KeyInfo.class),
                    "group", factory.newArrayInitializer(group),
                    "order", factory.newArrayInitializer(order));
        }
        return factory.newFormalParameterDeclaration(
                attributes.toAttributes(),
                toSourceType(var.getType().getRepresentation()),
                false,
                name,
                0);
    }

    /**
     * Converts {@link OperatorPortDeclaration} into a member of {@link OperatorInfo}.
     * @param var target port declaration
     * @param position the factory parameter position
     * @return related meta-data
     * @throws IllegalArgumentException if some parameters were {@code null}
     */
    public Expression toMetaData(OperatorPortDeclaration var, int position) {
        Precondition.checkMustNotBeNull(var, "var"); //$NON-NLS-1$
        NamedType type;
        TypeMirror representation = var.getType().getRepresentation();
        List<AnnotationElement> members = Lists.create();
        members.add(factory.newAnnotationElement(
                factory.newSimpleName("name"),
                Models.toLiteral(factory, var.getName())));
        members.add(factory.newAnnotationElement(
                factory.newSimpleName("type"),
                factory.newClassLiteral(t(environment.getErasure(representation)))));
        if (var.getKind() == OperatorPortDeclaration.Kind.INPUT) {
            type = (NamedType) t(OperatorInfo.Input.class);
            members.add(factory.newAnnotationElement(
                    factory.newSimpleName("position"),
                    Models.toLiteral(factory, position)));
            String typeVariable = getTypeVariableName(representation);
            if (typeVariable != null) {
                members.add(factory.newAnnotationElement(
                        factory.newSimpleName("typeVariable"),
                        Models.toLiteral(factory, typeVariable)));
            }
        } else if (var.getKind() == OperatorPortDeclaration.Kind.OUTPUT) {
            type = (NamedType) t(OperatorInfo.Output.class);
            String typeVariable = getTypeVariableName(representation);
            if (typeVariable != null) {
                members.add(factory.newAnnotationElement(
                        factory.newSimpleName("typeVariable"),
                        Models.toLiteral(factory, typeVariable)));
            }
        } else if (var.getKind() == OperatorPortDeclaration.Kind.CONSTANT) {
            type = (NamedType) t(OperatorInfo.Parameter.class);
            members.add(factory.newAnnotationElement(
                    factory.newSimpleName("position"),
                    Models.toLiteral(factory, position)));
            String typeVariable = getTypeVariableNameInClass(representation);
            if (typeVariable != null) {
                members.add(factory.newAnnotationElement(
                        factory.newSimpleName("typeVariable"),
                        Models.toLiteral(factory, typeVariable)));
            }
        } else {
            throw new AssertionError(var);
        }
        return factory.newNormalAnnotation(
                type,
                members);
    }

    private String getTypeVariableName(TypeMirror representation) {
        if (representation.getKind() == TypeKind.TYPEVAR) {
            return ((TypeVariable) representation).asElement().getSimpleName().toString();
        }
        return null;
    }

    private String getTypeVariableNameInClass(TypeMirror representation) {
        if (representation.getKind() != TypeKind.DECLARED) {
            return null;
        }
        List<? extends TypeMirror> typeArgs = ((DeclaredType) representation).getTypeArguments();
        if (typeArgs.size() != 1) {
            return null;
        }
        DeclaredType raw = (DeclaredType) environment.getErasure(representation);
        if (environment.getTypeUtils().isSameType(raw, environment.getDeclaredType(Class.class)) == false) {
            return null;
        }
        return getTypeVariableName(typeArgs.get(0));
    }
}
TOP

Related Classes of com.asakusafw.compiler.operator.util.GeneratorUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.