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.lethe.analysis.ThemisAnalysisContainer.ThemisAnalysisAdoptable;
21  import io.github.tonywasher.joceanus.themis.lethe.analysis.ThemisAnalysisIf.ThemisIteratorChain;
22  import io.github.tonywasher.joceanus.themis.lethe.analysis.ThemisAnalysisStatement.ThemisAnalysisStatementHolder;
23  
24  import java.util.ArrayDeque;
25  import java.util.ArrayList;
26  import java.util.Deque;
27  import java.util.Iterator;
28  import java.util.List;
29  
30  /**
31   * For construct.
32   */
33  public class ThemisAnalysisFor
34          implements ThemisAnalysisContainer, ThemisAnalysisAdoptable, ThemisAnalysisStatementHolder {
35      /**
36       * The contents.
37       */
38      private final Deque<ThemisAnalysisElement> theContents;
39  
40      /**
41       * The headers.
42       */
43      private final ThemisAnalysisStack theHeaders;
44  
45      /**
46       * The fields.
47       */
48      private final List<ThemisAnalysisField> theFields;
49  
50      /**
51       * The statements.
52       */
53      private final List<ThemisAnalysisStatement> theStatements;
54  
55      /**
56       * The number of lines.
57       */
58      private final int theNumLines;
59  
60      /**
61       * The dataMap.
62       */
63      private final ThemisAnalysisDataMap theDataMap;
64  
65      /**
66       * The parent.
67       */
68      private ThemisAnalysisContainer theParent;
69  
70      /**
71       * Constructor.
72       *
73       * @param pParser the parser
74       * @param pLine   the initial for line
75       * @throws OceanusException on error
76       */
77      ThemisAnalysisFor(final ThemisAnalysisParser pParser,
78                        final ThemisAnalysisLine pLine) throws OceanusException {
79          /* Access details from parser */
80          theParent = pParser.getParent();
81          theDataMap = new ThemisAnalysisDataMap(theParent.getDataMap());
82  
83          /* Create the arrays */
84          final Deque<ThemisAnalysisElement> myHeaders = ThemisAnalysisBuilder.parseHeaders(pParser, pLine);
85          final Deque<ThemisAnalysisElement> myLines = ThemisAnalysisBuilder.processBody(pParser);
86          theNumLines = myHeaders.size() + 1;
87  
88          /* Create a parser */
89          theContents = new ArrayDeque<>();
90          final ThemisAnalysisParser myParser = new ThemisAnalysisParser(myLines, theContents, this);
91          myParser.processLines();
92  
93          /* Parse the headers */
94          theFields = new ArrayList<>();
95          theStatements = new ArrayList<>();
96          theHeaders = new ThemisAnalysisStack(myHeaders);
97      }
98  
99      @Override
100     public Deque<ThemisAnalysisElement> getContents() {
101         return theContents;
102     }
103 
104     @Override
105     public ThemisAnalysisContainer getParent() {
106         return theParent;
107     }
108 
109     @Override
110     public void setParent(final ThemisAnalysisContainer pParent) {
111         theParent = pParent;
112         theDataMap.setParent(pParent.getDataMap());
113     }
114 
115     @Override
116     public ThemisAnalysisDataMap getDataMap() {
117         return theDataMap;
118     }
119 
120     @Override
121     public int getNumLines() {
122         return theNumLines;
123     }
124 
125     @Override
126     public void postProcessExtras() throws OceanusException {
127         parseHeaders();
128     }
129 
130     @Override
131     public Iterator<ThemisAnalysisStatement> statementIterator() {
132         final Iterator<ThemisAnalysisStatement> myField = ThemisAnalysisField.statementIteratorForFields(theFields);
133         final Iterator<ThemisAnalysisStatement> myStatement = theStatements.iterator();
134         return new ThemisIteratorChain<>(myField, myStatement);
135     }
136 
137     /**
138      * Parse headers.
139      *
140      * @throws OceanusException on error
141      */
142     private void parseHeaders() throws OceanusException {
143         /* Strip parentheses and create scanner */
144         final ThemisAnalysisStack myParts = theHeaders.extractParentheses();
145         final ThemisAnalysisScanner myScanner = new ThemisAnalysisScanner(myParts);
146 
147         /* Determine separator */
148         char mySep = ThemisAnalysisChar.COLON;
149         if (!myScanner.checkForSeparator(mySep)) {
150             mySep = ThemisAnalysisChar.SEMICOLON;
151         }
152 
153         /* Loop through the items */
154         boolean isField = true;
155         while (myParts.hasLines()) {
156             /* Access next part */
157             final Deque<ThemisAnalysisElement> myPart = myScanner.scanForSeparator(mySep);
158             final ThemisAnalysisStack myStack = new ThemisAnalysisStack(myPart);
159             if (myStack.isEmpty()) {
160                 continue;
161             }
162 
163             /* Process as field/statement */
164             if (isField) {
165                 parseField(myStack);
166             } else {
167                 parseStatement(myStack);
168             }
169             isField = false;
170         }
171     }
172 
173     /**
174      * Parse field.
175      *
176      * @param pField the field
177      * @throws OceanusException on error
178      */
179     private void parseField(final ThemisAnalysisStack pField) throws OceanusException {
180         /* Create field for each resource */
181         final ThemisAnalysisScanner myScanner = new ThemisAnalysisScanner(pField);
182         myScanner.skipGenerics();
183         ThemisAnalysisField myLast = null;
184         while (pField.hasLines()) {
185             final Deque<ThemisAnalysisElement> myResource = myScanner.scanForSeparator(ThemisAnalysisChar.COMMA);
186             myLast = myLast == null
187                     ? new ThemisAnalysisField(getDataMap(), new ThemisAnalysisStack(myResource))
188                     : new ThemisAnalysisField(myLast, new ThemisAnalysisStack(myResource));
189             theFields.add(myLast);
190         }
191     }
192 
193     /**
194      * Parse statements.
195      *
196      * @param pStatement the statement
197      * @throws OceanusException on error
198      */
199     private void parseStatement(final ThemisAnalysisStack pStatement) throws OceanusException {
200         /* Create field for each resource */
201         final ThemisAnalysisScanner myScanner = new ThemisAnalysisScanner(pStatement);
202         while (pStatement.hasLines()) {
203             final Deque<ThemisAnalysisElement> myResource = myScanner.scanForSeparator(ThemisAnalysisChar.COMMA);
204             theStatements.add(new ThemisAnalysisStatement(myResource));
205         }
206     }
207 
208     @Override
209     public String toString() {
210         /* Start parameters */
211         final StringBuilder myBuilder = new StringBuilder();
212 
213         /* Build fields */
214         boolean bFirst = true;
215         for (ThemisAnalysisField myField : theFields) {
216             /* Handle separators */
217             if (!bFirst) {
218                 myBuilder.append(ThemisAnalysisChar.LF);
219             } else {
220                 bFirst = false;
221             }
222 
223             /* Add parameter */
224             myBuilder.append(myField);
225         }
226 
227         /* Build fields */
228         for (ThemisAnalysisStatement myStatement : theStatements) {
229             /* Handle separators */
230             if (!bFirst) {
231                 myBuilder.append(ThemisAnalysisChar.LF);
232             } else {
233                 bFirst = false;
234             }
235 
236             /* Add parameter */
237             myBuilder.append(myStatement);
238         }
239 
240         /* Return the string */
241         return myBuilder.toString();
242     }
243 }