package com.redhat.ceylon.model.loader; import java.util.ArrayList; import java.util.Collections; import java.util.List; import com.redhat.ceylon.model.loader.mirror.AnnotationMirror; import com.redhat.ceylon.model.typechecker.model.Annotation; /** * Enumerates the language module annotations and allows them to be loaded from mirrors */ public enum LanguageAnnotation { /* modifier annotations */ ANNOTATION("annotation", 1L<<0, AbstractModelLoader.CEYLON_LANGUAGE_ANNOTATION_ANNOTATION), SHARED("shared", 1L<<1, AbstractModelLoader.CEYLON_LANGUAGE_SHARED_ANNOTATION), VARIABLE("variable", 1L<<2, AbstractModelLoader.CEYLON_LANGUAGE_VARIABLE_ANNOTATION), ABSTRACT("abstract", 1L<<3, AbstractModelLoader.CEYLON_LANGUAGE_ABSTRACT_ANNOTATION), SEALED("sealed", 1L<<4, AbstractModelLoader.CEYLON_LANGUAGE_SEALED_ANNOTATION), FINAL("final", 1L<<5, AbstractModelLoader.CEYLON_LANGUAGE_FINAL_ANNOTATION), ACTUAL("actual", 1L<<6, AbstractModelLoader.CEYLON_LANGUAGE_ACTUAL_ANNOTATION), FORMAL("formal", 1L<<7, AbstractModelLoader.CEYLON_LANGUAGE_FORMAL_ANNOTATION), DEFAULT("default", 1L<<8, AbstractModelLoader.CEYLON_LANGUAGE_DEFAULT_ANNOTATION), LATE("late", 1L<<9, AbstractModelLoader.CEYLON_LANGUAGE_LATE_ANNOTATION), OPTIONAL("optional", 1L<<11, AbstractModelLoader.CEYLON_LANGUAGE_OPTIONAL_ANNOTATION), SERIALIZABLE("serializable", 1L<<12, AbstractModelLoader.CEYLON_LANGUAGE_SERIALIZABLE_ANNOTATION), /* documentation annotations */ DOC("doc", 0, AbstractModelLoader.CEYLON_LANGUAGE_DOC_ANNOTATION) { public List<Annotation> makeFromCeylonAnnotation(AnnotationMirror mirror) { Annotation anno = new Annotation(name); anno.addPositionalArgment((String)mirror.getValue("description")); return Collections.singletonList(anno); } }, THROWS("throws", 0, AbstractModelLoader.CEYLON_LANGUAGE_THROWS_ANNOTATIONS) { public List<Annotation> makeFromCeylonAnnotation(AnnotationMirror mirror) { @SuppressWarnings("unchecked") List<AnnotationMirror> thrownExceptions = (List<AnnotationMirror>)mirror.getValue("value"); List<Annotation> result = new ArrayList<Annotation>(thrownExceptions.size()); for (AnnotationMirror thrown : thrownExceptions) { Annotation anno = new Annotation(name); // can't decode the declaration anno.addPositionalArgment(parseMetamodelReference((String)thrown.getValue("type"))); anno.addPositionalArgment((String)thrown.getValue("when")); result.add(anno); } return result; } }, BY("by", 0, AbstractModelLoader.CEYLON_LANGUAGE_AUTHORS_ANNOTATION) { public List<Annotation> makeFromCeylonAnnotation(AnnotationMirror mirror) { Annotation anno = new Annotation(name); @SuppressWarnings("unchecked") List<String> authors = (List<String>)mirror.getValue("authors"); for (String author : authors) { anno.addPositionalArgment(author); } return Collections.singletonList(anno); } }, NATIVE("native", 0, AbstractModelLoader.CEYLON_LANGUAGE_NATIVE_ANNOTATION) { public List<Annotation> makeFromCeylonAnnotation(AnnotationMirror mirror) { Annotation anno = new Annotation(name); @SuppressWarnings("unchecked") List<String> backends = (List<String>)mirror.getValue("backends"); if (backends != null) { for (String backend : backends) { anno.addPositionalArgment(backend); } } return Collections.singletonList(anno); } }, SEE("see", 0, AbstractModelLoader.CEYLON_LANGUAGE_SEE_ANNOTATIONS) { public List<Annotation> makeFromCeylonAnnotation(AnnotationMirror mirror) { @SuppressWarnings("unchecked") List<AnnotationMirror> sees = (List<AnnotationMirror>)mirror.getValue("value"); List<Annotation> result = new ArrayList<Annotation>(sees.size()); for (AnnotationMirror see : sees) { Annotation anno = new Annotation(name); // can't decode the declaration @SuppressWarnings("unchecked") List<String> elements = (List<String>)see.getValue("programElements"); for (String s : elements) { anno.addPositionalArgment(parseMetamodelReference(s)); } result.add(anno); } return result; } }, LICENSE("license", 0, AbstractModelLoader.CEYLON_LANGUAGE_LICENSE_ANNOTATION) { public List<Annotation> makeFromCeylonAnnotation(AnnotationMirror mirror) { Annotation anno = new Annotation(name); anno.addPositionalArgment((String)mirror.getValue("description")); return Collections.singletonList(anno); } }, DEPRECATED("deprecated", 0, AbstractModelLoader.CEYLON_LANGUAGE_DEPRECATED_ANNOTATION) { public List<Annotation> makeFromCeylonAnnotation(AnnotationMirror mirror) { Annotation anno = new Annotation(name); anno.addPositionalArgment((String)mirror.getValue("description")); return Collections.singletonList(anno); } }, TAGGED("tagged", 0, AbstractModelLoader.CEYLON_LANGUAGE_TAGS_ANNOTATION) { public List<Annotation> makeFromCeylonAnnotation(AnnotationMirror mirror) { Annotation anno = new Annotation(name); @SuppressWarnings("unchecked") List<String> tags = (List<String>)mirror.getValue("tags"); for (String tag : tags) { anno.addPositionalArgment(tag); } return Collections.singletonList(anno); } }, SUPPRESS_WARNINGS("suppressWarnings", 0, AbstractModelLoader.CEYLON_LANGUAGE_SUPPRESS_WARNINGS_ANNOTATION) { public List<Annotation> makeFromCeylonAnnotation(AnnotationMirror mirror) { Annotation anno = new Annotation(name); @SuppressWarnings("unchecked") List<String> warnings = (List<String>)mirror.getValue("warnings"); for (String tag : warnings) { anno.addPositionalArgment(tag); } return Collections.singletonList(anno); } }, // the name of the function is "aliased" but its type is "AliasesAnnotation" ALIASES("aliased", 0, AbstractModelLoader.CEYLON_LANGUAGE_ALIASES_ANNOTATION){ public List<Annotation> makeFromCeylonAnnotation(AnnotationMirror mirror) { Annotation anno = new Annotation(name); @SuppressWarnings("unchecked") List<String> aliases = (List<String>)mirror.getValue("aliases"); for (String alias : aliases) { anno.addPositionalArgment(alias); } return Collections.singletonList(anno); } }; /** * The unqualified Ceylon name of the annotation, e.g. {@code shared} */ public final String name; /** * The mask used to address this modifier when encoded as a long. * zero if this annotation is not a model annotation */ public final long mask; /** * The qualifier Java name of the annotation type, e.g. {@code ceylon.language.Shared$annotation$} */ public final String annotationType; LanguageAnnotation(String name, long mask, String annotationType) { this.name = name; this.mask = mask; this.annotationType = annotationType; } /** * Whether this annotation is a <em>modifier annotation</em> * (i.e. one whose annotation class is nullary, and * therefore whose presence/absence is all that matters) */ public boolean isModifier() { return mask != 0; } /** * Construct a Ceylon annotation model from the information stored in * the mirror of the Ceylon annotation. * @param mirror The mirror of the Ceylon annotation. * @return */ public List<Annotation> makeFromCeylonAnnotation(AnnotationMirror mirror) { return Collections.singletonList(new Annotation(name)); } protected String parseMetamodelReference(String s) { // Ugly hack to save us having to actually parse the output of // ExpressionTransfomer.serializeReferenceable() in order to get the // unqualified name return s.replaceAll("^.*::[CIAVFP]", "").replaceAll("^.*\\.[CIAVFP]", ""); } }