Package com.codereligion.hammock.compiler

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

package com.codereligion.hammock.compiler;

import com.codereligion.hammock.compiler.model.Name;
import com.codereligion.hammock.compiler.model.Type;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
import com.google.common.base.Function;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.io.Writer;
import java.util.Map;
import java.util.Set;

@SupportedAnnotationTypes("com.codereligion.hammock.Functor")
public class FunctorCompiler extends AbstractProcessor {

    private final Map<ElementKind, Parser> parsers = ImmutableMap.<ElementKind, Parser>of(
            ElementKind.METHOD, new MethodParser(),
            ElementKind.CLASS, new TypeParser(),
            ElementKind.INTERFACE, new TypeParser()
    );

    private final CacheLoader<TypeElement, Type> loader = new CacheLoader<TypeElement, Type>() {

        @Override
        public Type load(TypeElement element) throws Exception {
            return new Type(new Name(element.getQualifiedName() + "_"));
        }

    };

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        boolean claimed = false;

        final LoadingCache<TypeElement, Type> cache = CacheBuilder.newBuilder().build(loader);

        for (TypeElement annotation : annotations) {
            for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {
                try {
                    parse(element, cache);
                    claimed = true;
                } catch (UnsupportedUsageException e) {
                    error(e.getElement(), e.getMessage());
                }
            }
        }

        write(cache);

        return claimed;
    }

    private void parse(Element element, Function<TypeElement, Type> storage) throws UnsupportedUsageException {
        final ElementKind kind = element.getKind();

        final Parser parser = parsers.get(kind);

        if (parser == null) {
            throw new UnsupportedUsageException(element, "unsupported usage");
        }

        parser.check(element);
        parser.parse(element, storage);
    }

    private void write(LoadingCache<TypeElement, Type> cache) {
        for (Type type : cache.asMap().values()) {
            write(type);
        }
    }

    private void write(Type type) {
        final Thread thread = Thread.currentThread();
        final ClassLoader original = thread.getContextClassLoader();

        try {
            final ClassLoader loader = FunctorCompiler.class.getClassLoader();
            thread.setContextClassLoader(loader);

            final MustacheFactory factory = new DefaultMustacheFactory();
            final Mustache mustache = factory.compile("templates/template.mustache");

            try {
                final Filer filer = processingEnv.getFiler();
                final JavaFileObject file = filer.createSourceFile(type.getName().getQualified());

                try (Writer writer = file.openWriter()) {
                    mustache.execute(writer, type).flush();
                }
            } catch (IOException e) {
                throw new IllegalArgumentException(e);
            }
        } finally {
            thread.setContextClassLoader(original);
        }
    }

    private void error(Element element, String message) {
        processingEnv.getMessager().printMessage(Kind.ERROR, message, element);
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

}
TOP

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

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.