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 import io.github.tonywasher.joceanus.themis.lethe.analysis.ThemisAnalysisFile.ThemisAnalysisObject;
22
23 import java.util.ArrayDeque;
24 import java.util.Collections;
25 import java.util.Deque;
26 import java.util.Iterator;
27
28 /**
29 * Interface for containers that require postProcessing.
30 */
31 public interface ThemisAnalysisContainer
32 extends ThemisAnalysisProcessed {
33 /**
34 * Adoptable interface.
35 */
36 interface ThemisAnalysisAdoptable {
37 /**
38 * Set the parent of this container.
39 *
40 * @param pParent the parent
41 */
42 void setParent(ThemisAnalysisContainer pParent);
43 }
44
45 /**
46 * Obtain the dataMap.
47 *
48 * @return the map
49 */
50 default ThemisAnalysisDataMap getDataMap() {
51 return getParent().getDataMap();
52 }
53
54 /**
55 * Obtain the contents.
56 *
57 * @return the contents
58 */
59 Deque<ThemisAnalysisElement> getContents();
60
61 /**
62 * Obtain the parent of this container.
63 *
64 * @return the parent
65 */
66 ThemisAnalysisContainer getParent();
67
68 /**
69 * Determine the full name of the child object.
70 *
71 * @param pChildName the child name
72 * @return the fullName
73 */
74 default String determineFullChildName(final String pChildName) {
75 /* Loop */
76 ThemisAnalysisContainer myContainer = this;
77 while (true) {
78 if (myContainer instanceof ThemisAnalysisObject myObject) {
79 return myObject.getFullName() + ThemisAnalysisChar.PERIOD + pChildName;
80 }
81 if (myContainer instanceof ThemisAnalysisFile myFile) {
82 return myFile.getPackageName() + ThemisAnalysisChar.PERIOD + pChildName;
83 }
84 myContainer = myContainer.getParent();
85 }
86 }
87
88 /**
89 * Post process lines.
90 *
91 * @throws OceanusException on error
92 */
93 default void postProcessLines() throws OceanusException {
94 /* Create a copy of the contents list and clear original */
95 final Deque<ThemisAnalysisElement> myContents = getContents();
96 final Deque<ThemisAnalysisElement> myLines = new ArrayDeque<>(myContents);
97 myContents.clear();
98
99 /* Create the new input parser */
100 final ThemisAnalysisParser myParser = new ThemisAnalysisParser(myLines, myContents, getParent());
101
102 /* Loop through the lines */
103 while (myParser.hasLines()) {
104 /* Access next line */
105 final ThemisAnalysisElement myElement = myParser.popNextLine();
106
107 /* If the element is an embedded block */
108 if (myElement instanceof ThemisAnalysisEmbedded myEmbedded) {
109 /* Access and process the block */
110 final ThemisAnalysisElement myResult = myParser.processEmbedded(myEmbedded);
111 myContents.add(myResult);
112
113 /* If the element is a methodBody */
114 } else if (myElement instanceof ThemisAnalysisMethodBody myMethod) {
115 /* Access and process the block */
116 final ThemisAnalysisElement myResult = myParser.processMethodBody(myMethod);
117 myContents.add(myResult);
118
119 /* If the element is a container */
120 } else if (myElement instanceof ThemisAnalysisContainer myContainer) {
121 /* Access and process the container */
122 myContainer.postProcessLines();
123 myContents.add(myContainer);
124
125 /* If the element is already fully processed */
126 } else if (myElement instanceof ThemisAnalysisProcessed) {
127 myContents.add(myElement);
128
129 /* process lines */
130 } else if (myElement instanceof ThemisAnalysisLine myLine) {
131 final ThemisAnalysisElement myResult = myParser.processFieldsAndMethods(myLine);
132
133 /* If we have a field/method */
134 if (myResult != null) {
135 /* Add the element and postProcess any Containers */
136 myContents.add(myResult);
137
138 /* else */
139 } else {
140 /* Process statement */
141 myContents.add(myParser.processStatement(myLine));
142 }
143
144 /* Everything should now be a line. */
145 } else {
146 throw new ThemisDataException("Unexpected dataType");
147 }
148 }
149
150 /* Process extras */
151 postProcessExtras();
152 }
153
154 /**
155 * Post process extra lines.
156 *
157 * @throws OceanusException on error
158 */
159 default void postProcessExtras() throws OceanusException {
160 /* NoOp by default */
161 }
162
163 /**
164 * Obtain iterator for chained containers.
165 *
166 * @return the iterator
167 */
168 default Iterator<ThemisAnalysisContainer> containerIterator() {
169 return Collections.emptyIterator();
170 }
171 }