/* * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.oracle.truffle.dsl.processor; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic.Kind; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.NodeChildren; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.TypeSystem; import com.oracle.truffle.api.dsl.TypeSystemReference; import com.oracle.truffle.dsl.processor.ProcessorContext.ProcessCallback; import com.oracle.truffle.dsl.processor.generator.NodeCodeGenerator; import com.oracle.truffle.dsl.processor.generator.TypeSystemCodeGenerator; import com.oracle.truffle.dsl.processor.java.ElementUtils; import com.oracle.truffle.dsl.processor.parser.AbstractParser; import com.oracle.truffle.dsl.processor.parser.NodeParser; import com.oracle.truffle.dsl.processor.parser.TypeSystemParser; /** * THIS IS NOT PUBLIC API. */ public class TruffleProcessor extends AbstractProcessor implements ProcessCallback { private List<AnnotationProcessor<?>> generators; @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latest(); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if (!roundEnv.processingOver()) { processImpl(roundEnv); } return false; } private void processImpl(RoundEnvironment env) { // TODO run verifications that other annotations are not processed out of scope of the // operation or type lattice. try { ProcessorContext.setThreadLocalInstance(new ProcessorContext(processingEnv, this)); for (AnnotationProcessor<?> generator : getGenerators()) { AbstractParser<?> parser = generator.getParser(); if (parser.getAnnotationType() != null) { for (Element e : env.getElementsAnnotatedWith(parser.getAnnotationType())) { processElement(generator, e, false); } } for (Class<? extends Annotation> annotationType : parser.getTypeDelegatedAnnotationTypes()) { for (Element e : env.getElementsAnnotatedWith(annotationType)) { TypeElement processedType; if (parser.isDelegateToRootDeclaredType()) { processedType = ElementUtils.findRootEnclosingType(e); } else { processedType = ElementUtils.findNearestEnclosingType(e); } processElement(generator, processedType, false); } } } } finally { ProcessorContext.setThreadLocalInstance(null); } } private static void processElement(AnnotationProcessor<?> generator, Element e, boolean callback) { try { generator.process(e, callback); } catch (Throwable e1) { handleThrowable(generator, e1, e); } } private static void handleThrowable(AnnotationProcessor<?> generator, Throwable t, Element e) { String message = "Uncaught error in " + generator.getClass().getSimpleName() + " while processing " + e + " "; ProcessorContext.getInstance().getEnvironment().getMessager().printMessage(Kind.ERROR, message + ": " + ElementUtils.printException(t), e); } @Override public void callback(TypeElement template) { for (AnnotationProcessor<?> generator : generators) { Class<? extends Annotation> annotationType = generator.getParser().getAnnotationType(); if (annotationType != null) { Annotation annotation = template.getAnnotation(annotationType); if (annotation != null) { processElement(generator, template, true); } } } } @SuppressWarnings("deprecation") @Override public Set<String> getSupportedAnnotationTypes() { Set<String> annotations = new HashSet<>(); addAnnotations(annotations, Arrays.asList(Fallback.class, TypeSystemReference.class, com.oracle.truffle.api.dsl.ShortCircuit.class, Specialization.class, NodeChild.class, NodeChildren.class)); addAnnotations(annotations, Arrays.asList(TypeSystem.class)); return annotations; } private static void addAnnotations(Set<String> annotations, List<? extends Class<? extends Annotation>> annotationClasses) { if (annotationClasses != null) { for (Class<? extends Annotation> type : annotationClasses) { annotations.add(type.getCanonicalName()); } } } private List<AnnotationProcessor<?>> getGenerators() { if (generators == null && processingEnv != null) { generators = new ArrayList<>(); generators.add(new AnnotationProcessor<>(new TypeSystemParser(), new TypeSystemCodeGenerator())); generators.add(new AnnotationProcessor<>(new NodeParser(), new NodeCodeGenerator())); } return generators; } @Override public synchronized void init(ProcessingEnvironment env) { this.processingEnv = env; super.init(env); } }