Package com.codereligion.hammock.compiler

Source Code of com.codereligion.hammock.compiler.MethodParser

package com.codereligion.hammock.compiler;

import com.codereligion.hammock.Functor;
import com.codereligion.hammock.Input;
import com.codereligion.hammock.compiler.model.Argument;
import com.codereligion.hammock.compiler.model.Closure;
import com.codereligion.hammock.compiler.model.ClosureBuilder;
import com.codereligion.hammock.compiler.model.ClosureName;
import com.codereligion.hammock.compiler.model.Name;
import com.codereligion.hammock.compiler.model.Type;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;

import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import java.util.List;
import java.util.Locale;
import java.util.Set;

public class MethodParser implements Parser {

    private final ProcessingEnvironment env;

    public MethodParser(ProcessingEnvironment env) {
        this.env = env;
    }

    @Override
    public void check(Element element) throws UnsupportedUsageException {
        final ExecutableElement method = (ExecutableElement) element;
        final Set<Modifier> modifiers = method.getModifiers();
        final List<? extends VariableElement> parameters = method.getParameters();

        final boolean returnsVoid = MethodFilter.VOID.apply(method);

        if (returnsVoid) {
            throw new UnsupportedUsageException(method, "void methods are not supported");
        }

        final boolean isStatic = modifiers.contains(Modifier.STATIC);

        if (isStatic) {
            if (parameters.isEmpty()) {
                throw new UnsupportedUsageException(method, "too few arguments");
            }
           
            if (parameters.size() > 1) {
                if (isNotAnyAnnotatedWithInput(parameters)) {
                    throw new UnsupportedUsageException(method, "multiple parameters require one @Input");
                }
               
                if (isMoreThanOneAnnotatedWithInput(parameters)) {
                    throw new UnsupportedUsageException(method, "illegal usage of @Input");
                }
            }
        }

        final boolean isObjectMethod = MethodFilter.OBJECT.apply(method);

        if (isObjectMethod) {
            throw new UnsupportedUsageException(method, "can't use java.lang.Object methods");
        }
    }

    private boolean isNotAnyAnnotatedWithInput(List<? extends VariableElement> parameters) {
        for (VariableElement parameter : parameters) {
            if (parameter.getAnnotation(Input.class) != null) {
                return false;
            }
        }

        return true;
    }

    private boolean isMoreThanOneAnnotatedWithInput(List<? extends VariableElement> parameters) {
        boolean found = false;

        for (VariableElement parameter : parameters) {
            if (parameter.getAnnotation(Input.class) != null) {
                if (found) {
                    return true;
                } else {
                    found = true;
                }
            }
        }

        return false;
    }

    @Override
    public void parse(Element element, Function<TypeElement, Type> storage) {
        final TypeElement typeElement = (TypeElement) element.getEnclosingElement();
        final ExecutableElement method = (ExecutableElement) element;
        final Functor annotation = method.getAnnotation(Functor.class);

        final String defaultName = method.getSimpleName().toString();
        final ClosureName delegate = new ClosureName(defaultName);
        final ClosureName name = new ClosureName(annotation.name().isEmpty() ? defaultName : annotation.name());

        final List<? extends VariableElement> parameters = method.getParameters();
        final boolean isStatic = method.getModifiers().contains(Modifier.STATIC);

        final Argument input;

        if (isStatic) {
            input = findInput(parameters);
        } else {
            input = new Argument(box(typeElement.asType()), "input");
        }

        final ClosureBuilder builder;

        TypeMirror returnType = method.getReturnType();
       
        if (returnType.getKind() == TypeKind.BOOLEAN) {
            builder = new ClosureBuilder(input, delegate);
        } else {
            builder = new ClosureBuilder(input, delegate, new Name(box(returnType).toString()));
        }

        builder.withName(name);
        builder.withStatic(isStatic);
        builder.withGraceful(annotation.graceful());
        builder.withNullTo(annotation.nullTo());

        if (isStatic) {
            builder.withDelegate(typeElement.getSimpleName().toString());
           
            for (VariableElement parameter : parameters) {
                final boolean isInput = parameter.getAnnotation(Input.class) != null;
                final boolean isOnlyParameter = parameters.size() == 1;
                builder.withArgument(new Argument(box(parameter.asType()), parameter, isInput || isOnlyParameter));
            }
        } else {
            for (VariableElement parameter : parameters) {
                builder.withArgument(new Argument(box(parameter.asType()), parameter));
            }
        }

        final Closure closure = builder.build();

        final Type type = storage.apply(typeElement);
        Preconditions.checkNotNull(type, "No type found for %s", typeElement);
        type.getClosures().add(closure);
    }

    private TypeElement box(TypeMirror returnType) {
        final Types types = env.getTypeUtils();

        final String name = returnType.toString();
        switch (name) {
            case "byte":
            case "short":
            case "int":
            case "long":
            case "float":
            case "double":
            case "char":
            case "boolean":
                final TypeKind kind = TypeKind.valueOf(name.toUpperCase(Locale.ENGLISH));
                return types.boxedClass(types.getPrimitiveType(kind));
            default:
                return (TypeElement) types.asElement(returnType);
        }
    }

    private Argument findInput(List<? extends VariableElement> parameters) {
        if (parameters.size() == 1) {
            final VariableElement firstParameter = parameters.get(0);
            return new Argument(box(firstParameter.asType()), firstParameter, true);
        } else {
            for (VariableElement parameter : parameters) {
                if (parameter.getAnnotation(Input.class) != null) {
                    return new Argument(box(parameter.asType()), parameter);
                }
            }
        }
           
        throw new AssertionError();
    }

}
TOP

Related Classes of com.codereligion.hammock.compiler.MethodParser

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.