001package Torello.JavaDoc.Annotations;
002
003import Torello.Java.StrSource;
004import Torello.Java.StringParse;
005
006import Torello.Java.Additional.EffectivelyFinal;
007
008import Torello.JavaDoc.Annotations.hidden.LJSRepeatable;
009
010import javax.annotation.processing.Messager;
011
012import javax.lang.model.element.Element;
013import javax.lang.model.element.ExecutableElement;
014import javax.lang.model.element.AnnotationMirror;
015import javax.lang.model.element.AnnotationValue;
016
017import javax.tools.Diagnostic;
018
019import java.util.List;
020
021// EXPORTS:
022// 
023//     public String    handle();
024//     public String    typeName()      default "";
025//     public Entity    entity();
026//     public String    name();
027//     public byte      paramCount()    default -1;
028//     public String[]  paramNames()    default { };
029//     public String[]  paramTypesJOW() default { };
030// 
031// 
032// The following files are relatedf to this Annotation-Mirror Data-Class:
033// 
034// * Torello.JavaDoc.LinkJavaSource
035//      For the actual annotation definition.
036//      This is the actual @interface for the @LinkJavaSource Annotation
037// 
038// * package Torello.JDUInternal.Features.LINK_JAVA_SOURCE
039//      This package does the "vast majority" of the work that is needed process a User's
040//      Annotation-Placement.  The classes in the packages in this class look for, and load, all 
041//      of the External '.java'-Files which have been specified by the programmer's annotation
042//      uses.  These classes also perform the Source-Code HiLiting, and save the output to the
043//      appropriate packge's '[pkg-javadoc]/ljs-hilite-files/' directory.  They finally, also,
044//      generate the appropriate "HREF=..." so that an appropriate '<A HREF...>' link may be
045//      inserted
046
047
048@Torello.JavaDoc.Annotations.JDHeaderBackgroundImg(EmbedTagFileID="ANNOT_PROC_JDHBI")
049public class LJSProcessor
050{
051    private LJSProcessor() { }
052
053    // This is used by the Error-Message Printer
054    private static final String LJS_NAME = LinkJavaSource.class.getSimpleName();
055
056    static boolean process(
057            Element             ciet,
058            AnnotationMirror    am,
059            javax.annotation.processing.Messager messager
060        )
061    {
062        EffectivelyFinal<Boolean> errors = new EffectivelyFinal<>(false);
063
064        EffectivelyFinal<Boolean>
065            name            = new EffectivelyFinal<>(false),
066            paramNames      = new EffectivelyFinal<>(false),
067            paramTypesJOW   = new EffectivelyFinal<>(false),
068            paramCount      = new EffectivelyFinal<>(false);
069
070        am.getElementValues().forEach((ExecutableElement ee, AnnotationValue av) ->
071        {
072            // Understanding the 'terminology' in Annotations and Annotation-Processor's is half of
073            // the work in using it.
074
075            final Object val  = av.getValue();
076
077            switch (ee.toString())
078            {
079                case "handle()" :
080                    errors.f |= checkIdentifierAE(messager, ciet, "handle()", (String) val);
081                    break;
082
083                case "typeName()" :
084                    errors.f |= checkTypeStr(messager, ciet, (String) val);
085                    break;
086
087                case "entity()" :
088                    break;
089
090                case "name()" :
091                    name.f = true;
092                    errors.f |= checkIdentifierAE(messager, ciet, "name()", (String) val);
093                    break;
094
095                case "paramCount()":
096                    paramCount.f = true;
097                    errors.f |= checkParamCount(messager, ciet, (Byte) val);
098                    break;
099
100                case "paramNames()":
101                    paramNames.f = true;
102                    errors.f |= checkParamList(messager, ciet, "paramNames()", (List) val);
103                    break;
104
105                case "paramTypesJOW()":
106                    paramTypesJOW.f = true;
107                    errors.f |= checkParamList(messager, ciet, "paramTypesJOW()", (List) val);
108                    break;
109
110                default: 
111
112                    // This should be UNREACHABLE-CODE.  The Java-Compiler, itself, should do the
113                    // complaining that the user supplied an Annotation-Element name that is not
114                    // among those listed above.  Unless 'javac' changes, this cannot execute.
115
116                    throw new InternalError(
117                        "There was an annotation parameter whose name wasn't recognized: " +
118                        ee.toString() + "\n" +
119                        "The only parameter's that may be passed to @LinkJavaSource:\n" +
120                        "'handle()', 'typeName()', 'entity()', 'name()', 'paramCount()', " +
121                        "'paramNames()' and 'paramTypesJOW()'"
122                    );
123            }
124        });        
125
126        return errors.f;
127    }
128
129
130    // ********************************************************************************************
131    // ********************************************************************************************
132    // Checks both the "name()" and "handle()" Annotation-Elements
133    // ********************************************************************************************
134    // ********************************************************************************************
135
136
137    private static boolean checkIdentifierAE(
138            javax.annotation.processing.Messager messager,
139            Element ciet,
140            String  aeName,
141            String  aeValAsStr
142        )
143    {
144        if (StrSource.isValidJavaIdentifier(aeValAsStr)) return true;
145
146        // NOTE: Torello.JDUInternal.Messager **DOES NOT** ALLOW '\t'
147        messager.printMessage(
148            Diagnostic.Kind.ERROR,
149            HELPER.LOCATION(ciet, LJS_NAME) +
150            "\tString Annotation-Parameter '" + aeName + "' was passed " +
151                "[" + aeValAsStr + "]\n" +
152            "\tHowever, this is not a valid Java-Identifier."
153        );
154
155        return false;
156    }
157
158
159    // ********************************************************************************************
160    // ********************************************************************************************
161    // Checks the "typeName()" Annotation-Elements
162    // ********************************************************************************************
163    // ********************************************************************************************
164
165
166    private static boolean checkTypeStr
167        (javax.annotation.processing.Messager messager, Element ciet, String aeValAsStr)
168    {
169        if (! StrSource.isJavaTypeStr(aeValAsStr))
170        {
171            messager.printMessage(
172                Diagnostic.Kind.ERROR,
173                HELPER.LOCATION(ciet, LJS_NAME) +
174
175                // NOTE: Torello.JDUInternal.Messager **DOES NOT** ALLOW '\t'
176                "\tString Annotation-Parameter 'typeName()' was passed " +
177                    "[" + aeValAsStr + "]\n" +
178                "\tHowever, this is not a valid Java Type-Name."
179            );
180
181            return false;
182        }
183
184        return true;
185    }
186
187
188    // ********************************************************************************************
189    // ********************************************************************************************
190    // Check "paramCount()"
191    // ********************************************************************************************
192    // ********************************************************************************************
193
194
195    private static boolean checkParamCount
196        (javax.annotation.processing.Messager messager, Element ciet, byte paramCount)
197    {
198        if (paramCount < 0)
199        {
200            // NOTE: Torello.JDUInternal.Messager **DOES NOT** ALLOW '\t'
201            messager.printMessage(
202                Diagnostic.Kind.ERROR,
203                HELPER.LOCATION(ciet, LJS_NAME) +
204                "\t'paramCount' was passed a negative number: [" + paramCount + "]"
205            );
206
207            return false;
208        }
209
210        return true;
211    }
212
213
214    // ********************************************************************************************
215    // ********************************************************************************************
216    // Check the "paramNames()" and "paramTypes()" Annotation-Elements
217    // ********************************************************************************************
218    // ********************************************************************************************
219
220
221    @SuppressWarnings("rawtypes")
222    private static boolean checkParamList(
223            javax.annotation.processing.Messager messager,
224            Element ciet,
225            String  aeName,
226            List    aeValList
227        )
228    {
229        String aeValAsStr;
230
231        for (Object val : aeValList)
232
233            if (! StrSource.isValidJavaIdentifier
234                (aeValAsStr = StringParse.ifQuotesStripQuotes(val.toString()))
235            )
236            {
237                messager.printMessage(
238                    Diagnostic.Kind.ERROR,
239                    HELPER.LOCATION(ciet, LJS_NAME) +
240
241                    // NOTE: Torello.JDUInternal.Messager **DOES NOT** ALLOW '\t'
242                    "\tString Annotation-Parameter '" + aeName + "' was passed " +
243                        "String[]-Array Element [" + aeValAsStr + "]\n" +
244                    "\tHowever, this is not a valid Java-Identifier."
245                );
246
247                return false;
248            }
249
250        return true;
251    }
252}