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.ThemisAnalysisStatement.ThemisAnalysisStatementHolder;
22  
23  import java.util.ArrayDeque;
24  import java.util.Collections;
25  import java.util.Deque;
26  import java.util.Iterator;
27  
28  /**
29   * If construct.
30   */
31  public class ThemisAnalysisIf
32          implements ThemisAnalysisContainer, ThemisAnalysisAdoptable, ThemisAnalysisStatementHolder {
33      /**
34       * The condition.
35       */
36      private final ThemisAnalysisStatement theCondition;
37  
38      /**
39       * The contents.
40       */
41      private final Deque<ThemisAnalysisElement> theContents;
42  
43      /**
44       * The else clause.
45       */
46      private final ThemisAnalysisElse theElse;
47  
48      /**
49       * The number of lines.
50       */
51      private final int theNumLines;
52  
53      /**
54       * The dataMap.
55       */
56      private final ThemisAnalysisDataMap theDataMap;
57  
58      /**
59       * The parent.
60       */
61      private ThemisAnalysisContainer theParent;
62  
63      /**
64       * Constructor.
65       *
66       * @param pParser the parser
67       * @param pLine   the initial if line
68       * @throws OceanusException on error
69       */
70      ThemisAnalysisIf(final ThemisAnalysisParser pParser,
71                       final ThemisAnalysisLine pLine) throws OceanusException {
72          /* Access details from parser */
73          theParent = pParser.getParent();
74          theDataMap = new ThemisAnalysisDataMap(theParent.getDataMap());
75  
76          /* Parse the condition */
77          final Deque<ThemisAnalysisElement> myHeaders = ThemisAnalysisBuilder.parseHeaders(pParser, pLine);
78          theNumLines = myHeaders.size() + 1;
79          theCondition = new ThemisAnalysisStatement(myHeaders);
80  
81          /* Parse the body */
82          final Deque<ThemisAnalysisElement> myLines = ThemisAnalysisBuilder.processBody(pParser);
83  
84          /* Look for else clauses */
85          theElse = (ThemisAnalysisElse) pParser.processExtra(this, ThemisAnalysisKeyWord.ELSE);
86  
87          /* Create a parser */
88          theContents = new ArrayDeque<>();
89          final ThemisAnalysisParser myParser = new ThemisAnalysisParser(myLines, theContents, this);
90          myParser.processLines();
91      }
92  
93      @Override
94      public Deque<ThemisAnalysisElement> getContents() {
95          return theContents;
96      }
97  
98      @Override
99      public Iterator<ThemisAnalysisStatement> statementIterator() {
100         final Iterator<ThemisAnalysisStatement> myLocal = Collections.singleton(theCondition).iterator();
101         return theElse == null ? myLocal : new ThemisIteratorChain<>(myLocal, theElse.statementIterator());
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         if (theElse != null) {
114             theElse.setParent(pParent);
115         }
116     }
117 
118     @Override
119     public ThemisAnalysisDataMap getDataMap() {
120         return theDataMap;
121     }
122 
123     @Override
124     public void postProcessExtras() throws OceanusException {
125         /* Process the else clause if required */
126         if (theElse != null) {
127             theElse.postProcessLines();
128         }
129     }
130 
131     /**
132      * Obtain the additional else clause (if any).
133      *
134      * @return the else clause
135      */
136     public ThemisAnalysisElse getElse() {
137         return theElse;
138     }
139 
140     @Override
141     public Iterator<ThemisAnalysisContainer> containerIterator() {
142         return theElse == null
143                 ? Collections.emptyIterator()
144                 : theElse.containerIterator();
145     }
146 
147     @Override
148     public int getNumLines() {
149         return theNumLines;
150     }
151 
152     @Override
153     public String toString() {
154         return theCondition.toString();
155     }
156 
157     /**
158      * Chained Iterator.
159      *
160      * @param <T> the item class
161      */
162     public static class ThemisIteratorChain<T> implements Iterator<T> {
163         /**
164          * Local Iterator.
165          */
166         private final Iterator<T> theLocal;
167 
168         /**
169          * Chained Iterator.
170          */
171         private final Iterator<T> theChained;
172 
173         /**
174          * Constructor.
175          *
176          * @param pLocal   the local iterator
177          * @param pChained the chained iterator
178          */
179         public ThemisIteratorChain(final Iterator<T> pLocal,
180                                    final Iterator<T> pChained) {
181             theLocal = pLocal;
182             theChained = pChained;
183         }
184 
185         @Override
186         public boolean hasNext() {
187             return theLocal.hasNext() || theChained.hasNext();
188         }
189 
190         @Override
191         public T next() {
192             return theLocal.hasNext() ? theLocal.next() : theChained.next();
193         }
194     }
195 
196     /**
197      * Reduced Iterator.
198      *
199      * @param <T> the item class
200      */
201     public static class ThemisReducedIterator<T> implements Iterator<T> {
202         /**
203          * Local Iterator.
204          */
205         private final Iterator<? extends T> theBase;
206 
207         /**
208          * Constructor.
209          *
210          * @param pBase the base iterator
211          */
212         public ThemisReducedIterator(final Iterator<? extends T> pBase) {
213             theBase = pBase;
214         }
215 
216         @Override
217         public boolean hasNext() {
218             return theBase.hasNext();
219         }
220 
221         @Override
222         public T next() {
223             return theBase.next();
224         }
225     }
226 }