Mercurial > hg > graal-jvmci-8
diff graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/LanguageRegistrationProcessor.java @ 21481:bb51b9a142b3
Enforcing public, one parameter constructor for each TruffleLanguage by annotation processor and required call to super.
author | Jaroslav Tulach <jaroslav.tulach@oracle.com> |
---|---|
date | Mon, 25 May 2015 12:26:53 +0200 |
parents | 99942eac9c6d |
children | f5b49d881909 b1530a6cce8c |
line wrap: on
line diff
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/LanguageRegistrationProcessor.java Mon May 25 10:36:30 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/LanguageRegistrationProcessor.java Mon May 25 12:26:53 2015 +0200 @@ -22,19 +22,27 @@ */ package com.oracle.truffle.dsl.processor; +import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.TruffleLanguage.Registration; +import com.oracle.truffle.api.dsl.ExpectError; import java.io.IOException; import java.io.OutputStream; +import java.util.List; +import java.util.Map; import java.util.Properties; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.lang.model.SourceVersion; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic.Kind; import javax.tools.FileObject; import javax.tools.StandardLocation; @@ -72,12 +80,78 @@ Registration annotation = e.getAnnotation(Registration.class); if (annotation != null && e.getKind() == ElementKind.CLASS) { if (!e.getModifiers().contains(Modifier.PUBLIC)) { - processingEnv.getMessager().printMessage(Kind.ERROR, "Registered language class must be public", e); + emitError("Registered language class must be public", e); + continue; + } + if (e.getEnclosingElement().getKind() != ElementKind.PACKAGE && !e.getModifiers().contains(Modifier.STATIC)) { + emitError("Registered language inner-class must be static", e); + continue; + } + TypeMirror truffleLang = processingEnv.getElementUtils().getTypeElement(TruffleLanguage.class.getName()).asType(); + if (!processingEnv.getTypeUtils().isAssignable(e.asType(), truffleLang)) { + emitError("Registered language class must subclass TruffleLanguage", e); + continue; } + boolean found = false; + for (Element mem : e.getEnclosedElements()) { + if (mem.getKind() != ElementKind.CONSTRUCTOR) { + continue; + } + ExecutableElement ee = (ExecutableElement) mem; + if (ee.getParameters().size() != 1) { + continue; + } + if (!ee.getModifiers().contains(Modifier.PUBLIC)) { + continue; + } + TypeMirror env = processingEnv.getElementUtils().getTypeElement(TruffleLanguage.Env.class.getCanonicalName()).asType(); + if (processingEnv.getTypeUtils().isSameType(ee.getParameters().get(0).asType(), env)) { + found = true; + break; + } + } + if (!found) { + emitError("Language must have a public constructor accepting TruffleLanguage.Env as parameter", e); + continue; + } + assertNoErrorExpected(e); createProviderFile((TypeElement) e, annotation); } } return true; } + + void assertNoErrorExpected(Element e) { + TypeElement eee = processingEnv.getElementUtils().getTypeElement(ExpectError.class.getName()); + for (AnnotationMirror am : e.getAnnotationMirrors()) { + if (am.getAnnotationType().asElement().equals(eee)) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Expected an error, but none found!", e); + } + } + } + + void emitError(String msg, Element e) { + TypeElement eee = processingEnv.getElementUtils().getTypeElement(ExpectError.class.getName()); + for (AnnotationMirror am : e.getAnnotationMirrors()) { + if (am.getAnnotationType().asElement().equals(eee)) { + Map<? extends ExecutableElement, ? extends AnnotationValue> vals = am.getElementValues(); + if (vals.size() == 1) { + AnnotationValue av = vals.values().iterator().next(); + if (av.getValue() instanceof List) { + List<?> arr = (List<?>) av.getValue(); + for (Object o : arr) { + if (o instanceof AnnotationValue) { + AnnotationValue ov = (AnnotationValue) o; + if (msg.equals(ov.getValue())) { + return; + } + } + } + } + } + } + } + processingEnv.getMessager().printMessage(Kind.ERROR, msg, e); + } }