View Javadoc
1   /*
2    * Themis: Java Project Framework
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.themis.lethe.analysis;
18  
19  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
20  import io.github.tonywasher.joceanus.themis.exc.ThemisDataException;
21  
22  import java.util.ArrayDeque;
23  import java.util.Deque;
24  
25  /**
26   * Method Representation.
27   */
28  public class ThemisAnalysisMethod
29          implements ThemisAnalysisContainer {
30      /**
31       * The name of the class.
32       */
33      private final String theName;
34  
35      /**
36       * The reference of the class.
37       */
38      private final ThemisAnalysisReference theReference;
39  
40      /**
41       * The parent.
42       */
43      private ThemisAnalysisContainer theParent;
44  
45      /**
46       * The properties.
47       */
48      private final ThemisAnalysisProperties theProperties;
49  
50      /**
51       * The contents.
52       */
53      private final Deque<ThemisAnalysisElement> theContents;
54  
55      /**
56       * The dataMap.
57       */
58      private ThemisAnalysisDataMap theDataMap;
59  
60      /**
61       * The parameters.
62       */
63      private final ThemisAnalysisParameters theParameters;
64  
65      /**
66       * The number of lines.
67       */
68      private final int theNumLines;
69  
70      /**
71       * Is this an initialiser?
72       */
73      private final boolean isInitializer;
74  
75      /**
76       * Constructor.
77       *
78       * @param pParser    the parser
79       * @param pName      the method name
80       * @param pReference the reference
81       * @param pLine      the initial method line
82       * @throws OceanusException on error
83       */
84      ThemisAnalysisMethod(final ThemisAnalysisParser pParser,
85                           final String pName,
86                           final ThemisAnalysisReference pReference,
87                           final ThemisAnalysisLine pLine) throws OceanusException {
88          /* Store parameters */
89          isInitializer = pName.length() == 0;
90          theName = isInitializer ? pReference.toString() : pName;
91          theReference = pReference;
92          theProperties = pLine.getProperties();
93  
94          /* Access details from parser */
95          theParent = pParser.getParent();
96          theDataMap = new ThemisAnalysisDataMap(theParent.getDataMap());
97  
98          /* Determine whether this method is abstract */
99          final boolean isInterface = theParent instanceof ThemisAnalysisInterface;
100         final boolean markedDefault = theProperties.hasModifier(ThemisAnalysisModifier.DEFAULT);
101         final boolean markedStatic = theProperties.hasModifier(ThemisAnalysisModifier.STATIC);
102         final boolean markedAbstract = theProperties.hasModifier(ThemisAnalysisModifier.ABSTRACT);
103         final boolean isAbstract = markedAbstract || (isInterface && !markedDefault && !markedStatic);
104 
105         /* Parse the headers */
106         theContents = new ArrayDeque<>();
107         final Deque<ThemisAnalysisElement> myHeaders = isAbstract
108                 ? ThemisAnalysisBuilder.parseTrailers(pParser, pLine)
109                 : parseHeaders(pParser, pLine);
110         theNumLines = myHeaders.size() + (isAbstract ? 0 : 1);
111 
112         /* Create a parser */
113         final ThemisAnalysisParser myParser = new ThemisAnalysisParser(myHeaders, theContents, this);
114 
115         /* Resolve the generics */
116         theProperties.resolveGeneric(myParser);
117         theReference.resolveGeneric(myParser);
118 
119         /* resolve the parameters */
120         theParameters = new ThemisAnalysisParameters(myParser, myHeaders);
121 
122         /* Post process the lines */
123         postProcessLines();
124     }
125 
126     /**
127      * Constructor.
128      *
129      * @param pParser    the parser
130      * @param pName      the method name
131      * @param pReference the reference
132      * @param pBody      the method body
133      * @throws OceanusException on error
134      */
135     ThemisAnalysisMethod(final ThemisAnalysisParser pParser,
136                          final String pName,
137                          final ThemisAnalysisReference pReference,
138                          final ThemisAnalysisMethodBody pBody) throws OceanusException {
139         /* Store parameters */
140         final ThemisAnalysisLine myLine = pBody.getHeader();
141         isInitializer = pName.length() == 0;
142         theName = isInitializer ? pReference.toString() : pName;
143         theReference = pReference;
144         theProperties = myLine.getProperties();
145 
146         /* Access details from body */
147         theParent = pBody.getParent();
148         theDataMap = pBody.getDataMap();
149 
150         /* Record the headers */
151         final Deque<ThemisAnalysisElement> myHeaders = new ArrayDeque<>();
152         myHeaders.add(myLine);
153         theNumLines = 2;
154 
155         /* Access the contents */
156         theContents = pBody.getContents();
157 
158         /* Create a parser */
159         final ThemisAnalysisParser myParser = new ThemisAnalysisParser(myHeaders, theContents, this);
160 
161         /* Resolve the generics */
162         theProperties.resolveGeneric(myParser);
163         theReference.resolveGeneric(myParser);
164 
165         /* resolve the parameters */
166         theParameters = new ThemisAnalysisParameters(myParser, myHeaders);
167 
168         /* Post process the lines */
169         postProcessLines();
170     }
171 
172     /**
173      * Parse Headers.
174      *
175      * @param pParser the parser
176      * @param pLine   the line
177      * @return the headers
178      * @throws OceanusException on error
179      */
180     private Deque<ThemisAnalysisElement> parseHeaders(final ThemisAnalysisParser pParser,
181                                                       final ThemisAnalysisLine pLine) throws OceanusException {
182         /* Initialise details */
183         final Deque<ThemisAnalysisElement> myHeaders = new ArrayDeque<>();
184         ThemisAnalysisElement myElement = pLine;
185 
186         /* Add lines to header */
187         while (myElement instanceof ThemisAnalysisLine) {
188             myHeaders.add(myElement);
189             myElement = pParser.popNextLine();
190         }
191 
192         /* Must end with a method body */
193         if (!(myElement instanceof ThemisAnalysisMethodBody)) {
194             throw new ThemisDataException("Unexpected dataType");
195         }
196 
197         /* Copy details from method body */
198         final ThemisAnalysisMethodBody myBody = (ThemisAnalysisMethodBody) myElement;
199         myHeaders.add(myBody.getHeader());
200         theContents.addAll(myBody.getContents());
201         theParent = myBody.getParent();
202         theDataMap = myBody.getDataMap();
203 
204         /* return the headers */
205         return myHeaders;
206     }
207 
208     /**
209      * Obtain the name.
210      *
211      * @return the name
212      */
213     public String getName() {
214         return theName;
215     }
216 
217     @Override
218     public Deque<ThemisAnalysisElement> getContents() {
219         return theContents;
220     }
221 
222     @Override
223     public ThemisAnalysisContainer getParent() {
224         return this;
225     }
226 
227     @Override
228     public ThemisAnalysisDataMap getDataMap() {
229         return theDataMap;
230     }
231 
232     @Override
233     public int getNumLines() {
234         return theNumLines;
235     }
236 
237     @Override
238     public String toString() {
239         return isInitializer
240                 ? getName() + theParameters.toString()
241                 : theReference.toString() + " " + getName() + theParameters.toString();
242     }
243 }