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  import io.github.tonywasher.joceanus.themis.lethe.analysis.ThemisAnalysisScanner.ThemisAnalysisSource;
22  
23  import java.util.ArrayDeque;
24  import java.util.Deque;
25  
26  /**
27   * Stack of Analysis Elements.
28   */
29  public class ThemisAnalysisStack
30          implements ThemisAnalysisSource {
31      /**
32       * The stack of lines.
33       */
34      private final Deque<ThemisAnalysisElement> theStack;
35  
36      /**
37       * Constructor.
38       *
39       * @param pStack the stack
40       */
41      ThemisAnalysisStack(final Deque<ThemisAnalysisElement> pStack) {
42          theStack = pStack;
43      }
44  
45      /**
46       * Constructor.
47       *
48       * @param pElement the element
49       */
50      ThemisAnalysisStack(final ThemisAnalysisElement pElement) {
51          theStack = new ArrayDeque<>();
52          theStack.add(pElement);
53      }
54  
55      @Override
56      public boolean hasLines() {
57          return !theStack.isEmpty();
58      }
59  
60      @Override
61      public ThemisAnalysisElement popNextLine() throws OceanusException {
62          /* Check that there is a line to pop */
63          if (theStack.isEmpty()) {
64              throw new ThemisDataException("No more lines");
65          }
66  
67          /* Access the first line and remove from the list */
68          return theStack.removeFirst();
69      }
70  
71      @Override
72      public void pushLine(final ThemisAnalysisElement pLine) {
73          /* Insert the line at the front of the stack */
74          theStack.offerFirst(pLine);
75      }
76  
77      /**
78       * Is the stack empty?
79       *
80       * @return true/false
81       */
82      public boolean isEmpty() {
83          return theStack.isEmpty()
84                  || (theStack.size() == 1 && theStack.peekFirst().toString().length() == 0);
85      }
86  
87      /**
88       * Obtain the last line in the stack.
89       *
90       * @return the line
91       */
92      ThemisAnalysisElement peekLastLine() {
93          return theStack.peekLast();
94      }
95  
96      /**
97       * Obtain the size of the stack.
98       *
99       * @return the size
100      */
101     public int size() {
102         return theStack.size();
103     }
104 
105     /**
106      * Strip parentheses.
107      *
108      * @return a new stack with stripped parentheses
109      * @throws OceanusException on error
110      */
111     public ThemisAnalysisStack extractParentheses() throws OceanusException {
112         /* Extract the parenthesised block */
113         final ThemisAnalysisLine myLine = (ThemisAnalysisLine) popNextLine();
114         final ThemisAnalysisScanner myScanner = new ThemisAnalysisScanner(this);
115         final Deque<ThemisAnalysisElement> myParenthesised = myScanner.scanForParenthesis(myLine);
116         final ThemisAnalysisStack myResult = new ThemisAnalysisStack(myParenthesised);
117 
118         /* Strip the parentheses */
119         myResult.stripStartChar(ThemisAnalysisChar.PARENTHESIS_OPEN);
120         myResult.stripEndChar(ThemisAnalysisChar.PARENTHESIS_CLOSE);
121 
122         /* Return the result */
123         return myResult;
124     }
125 
126     /**
127      * Strip parentheses.
128      *
129      * @return a new stack with stripped parentheses
130      * @throws OceanusException on error
131      */
132     public ThemisAnalysisStack extractArray() throws OceanusException {
133         /* Extract the parenthesised block */
134         final ThemisAnalysisLine myLine = (ThemisAnalysisLine) popNextLine();
135         final ThemisAnalysisScanner myScanner = new ThemisAnalysisScanner(this);
136         final Deque<ThemisAnalysisElement> myArray = myScanner.scanForArray(myLine);
137         final ThemisAnalysisStack myResult = new ThemisAnalysisStack(myArray);
138 
139         /* Strip the parentheses */
140         myResult.stripStartChar(ThemisAnalysisChar.ARRAY_OPEN);
141         myResult.stripEndChar(ThemisAnalysisChar.ARRAY_CLOSE);
142 
143         /* Return the result */
144         return myResult;
145     }
146 
147     /**
148      * Does the stack start with this character?
149      *
150      * @param pChar the character
151      * @return true/false
152      */
153     public boolean startsWithChar(final char pChar) {
154         return !theStack.isEmpty()
155                 && ((ThemisAnalysisLine) theStack.peekFirst()).startsWithChar(pChar);
156     }
157 
158     /**
159      * Strip the starting character.
160      *
161      * @param pChar the character
162      */
163     public void stripStartChar(final char pChar) {
164         if (!theStack.isEmpty()) {
165             ((ThemisAnalysisLine) theStack.peekFirst()).stripStartChar(pChar);
166         }
167     }
168 
169     /**
170      * Strip the ending character.
171      *
172      * @param pChar the character
173      */
174     public void stripEndChar(final char pChar) {
175         if (!theStack.isEmpty()) {
176             ((ThemisAnalysisLine) theStack.peekLast()).stripEndChar(pChar);
177         }
178     }
179 
180     /**
181      * Rebuild the stack.
182      *
183      * @param pSource the source to rebuild from
184      */
185     public void rebuild(final Deque<ThemisAnalysisElement> pSource) {
186         /* Clear the existing stack */
187         theStack.clear();
188 
189         /* Loop through the source */
190         for (ThemisAnalysisElement myElement : pSource) {
191             theStack.offerLast(myElement);
192         }
193     }
194 
195     @Override
196     public String toString() {
197         return ThemisAnalysisBuilder.formatLines(theStack);
198     }
199 }