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.ThemisAnalysisDataMap.ThemisAnalysisDataType;
22  import io.github.tonywasher.joceanus.themis.lethe.analysis.ThemisAnalysisEmbedded.ThemisAnalysisEmbedType;
23  import io.github.tonywasher.joceanus.themis.lethe.analysis.ThemisAnalysisGeneric.ThemisAnalysisGenericBase;
24  import io.github.tonywasher.joceanus.themis.lethe.analysis.ThemisAnalysisScanner.ThemisAnalysisSource;
25  
26  import java.util.ArrayList;
27  import java.util.Deque;
28  import java.util.HashMap;
29  import java.util.LinkedHashMap;
30  import java.util.List;
31  import java.util.Map;
32  
33  /**
34   * Parser.
35   */
36  public class ThemisAnalysisParser
37          implements ThemisAnalysisSource {
38      /**
39       * The keyWordMap.
40       */
41      static final Map<String, Object> KEYWORDS = createKeyWordMap();
42  
43      /**
44       * The parent container.
45       */
46      private final ThemisAnalysisContainer theParent;
47  
48      /**
49       * The list of source lines.
50       */
51      private final Deque<ThemisAnalysisElement> theLines;
52  
53      /**
54       * The list of output contents lines.
55       */
56      private final Deque<ThemisAnalysisElement> theContents;
57  
58      /**
59       * The dataMap.
60       */
61      private final ThemisAnalysisDataMap theDataMap;
62  
63      /**
64       * Temporary parser?
65       */
66      private final boolean isTemporary;
67  
68      /**
69       * Constructor.
70       *
71       * @param pLines     the source lines.
72       * @param pContents  the processed contents
73       * @param pContainer the container
74       */
75      ThemisAnalysisParser(final Deque<ThemisAnalysisElement> pLines,
76                           final Deque<ThemisAnalysisElement> pContents,
77                           final ThemisAnalysisContainer pContainer) {
78          /* Store parameters */
79          theLines = pLines;
80          theContents = pContents;
81          theParent = pContainer;
82  
83          /* Create the dataTypeMap */
84          theDataMap = pContainer.getDataMap();
85          isTemporary = false;
86      }
87  
88      /**
89       * Constructor.
90       *
91       * @param pParser    the source parser.
92       * @param pProcessed the processed output
93       */
94      ThemisAnalysisParser(final ThemisAnalysisParser pParser,
95                           final Deque<ThemisAnalysisElement> pProcessed) {
96          this(pParser.theLines, pProcessed, pParser.getParent());
97      }
98  
99      /**
100      * Temporary parser constructor.
101      *
102      * @param pParser the base parser.
103      */
104     ThemisAnalysisParser(final ThemisAnalysisParser pParser) {
105         /* Store parameters */
106         theLines = pParser.theLines;
107         theContents = pParser.theContents;
108         theParent = pParser.theParent;
109 
110         /* Create the dataTypeMap */
111         theDataMap = new ThemisAnalysisDataMap(pParser.getDataMap());
112         isTemporary = true;
113     }
114 
115     @Override
116     public boolean hasLines() {
117         return !theLines.isEmpty();
118     }
119 
120     /**
121      * Is this a temporary parser?
122      *
123      * @return true/false
124      */
125     boolean isTemporary() {
126         return isTemporary;
127     }
128 
129     /**
130      * Obtain the parent container.
131      *
132      * @return the parent
133      */
134     ThemisAnalysisContainer getParent() {
135         return theParent;
136     }
137 
138     /**
139      * Obtain the dataTypes map.
140      *
141      * @return the dataTypesMap
142      */
143     ThemisAnalysisDataMap getDataMap() {
144         return theDataMap;
145     }
146 
147     @Override
148     public ThemisAnalysisElement popNextLine() throws OceanusException {
149         /* Check that there is a line to pop */
150         if (theLines.isEmpty()) {
151             throw new ThemisDataException("No more lines");
152         }
153 
154         /* Access the first line and remove from the list */
155         return theLines.removeFirst();
156     }
157 
158     /**
159      * Peek next line from list.
160      *
161      * @return the next line
162      * @throws OceanusException on error
163      */
164     ThemisAnalysisElement peekNextLine() throws OceanusException {
165         /* Check that there is a line to pop */
166         if (theLines.isEmpty()) {
167             throw new ThemisDataException("No more lines");
168         }
169 
170         /* Return the first line in the list */
171         return theLines.getFirst();
172     }
173 
174     @Override
175     public void pushLine(final ThemisAnalysisElement pLine) {
176         /* Insert the line at the front of the stack */
177         theLines.offerFirst(pLine);
178     }
179 
180     /**
181      * Process a potential comment/blank line.
182      *
183      * @param pLine the line
184      * @return have we processed the line?
185      * @throws OceanusException on error
186      */
187     boolean processCommentsAndBlanks(final ThemisAnalysisLine pLine) throws OceanusException {
188         /* If this is a starting comment */
189         if (ThemisAnalysisComment.isStartComment(pLine)) {
190             /* Process the comment lines */
191             final ThemisAnalysisComment myComment = new ThemisAnalysisComment(this, pLine);
192             theContents.add(myComment);
193             return true;
194         }
195 
196         /* Strip Trailing comments and modifiers */
197         pLine.stripTrailingComments();
198         pLine.stripModifiers();
199 
200         /* If this is a blank line */
201         if (ThemisAnalysisBlank.isBlank(pLine)) {
202             /* Process the blank lines */
203             final ThemisAnalysisBlank myBlank = new ThemisAnalysisBlank(this, pLine);
204             theContents.add(myBlank);
205             return true;
206         }
207 
208         /* If this is an annotation line */
209         if (ThemisAnalysisAnnotation.isAnnotation(pLine)) {
210             /* Process the annotation lines */
211             final ThemisAnalysisAnnotation myAnnotation = new ThemisAnalysisAnnotation(this, pLine);
212             theContents.add(myAnnotation);
213             return true;
214         }
215 
216         /* Not processed */
217         return false;
218     }
219 
220     /**
221      * Process a potential import line.
222      *
223      * @param pLine the line
224      * @return have we processed the line?
225      * @throws OceanusException on error
226      */
227     boolean processImports(final ThemisAnalysisLine pLine) throws OceanusException {
228         /* If this is an import line */
229         if (ThemisAnalysisImports.isImport(pLine)) {
230             /* Process the import lines */
231             final ThemisAnalysisImports myImports = new ThemisAnalysisImports(this, pLine);
232             theContents.add(myImports);
233             return true;
234         }
235 
236         /* Not processed */
237         return false;
238     }
239 
240     /**
241      * Process a class/enum/interface line.
242      *
243      * @param pLine the line
244      * @return have we processed the line?
245      * @throws OceanusException on error
246      */
247     boolean processClass(final ThemisAnalysisLine pLine) throws OceanusException {
248         /* Access class type */
249         final String myToken = pLine.peekNextToken();
250         final Object myType = KEYWORDS.get(myToken);
251 
252         /* If we have a keyWord */
253         if (myType instanceof ThemisAnalysisKeyWord myKeyWord) {
254             /* If this is a class */
255             switch (myKeyWord) {
256                 case CLASS:
257                     /* Create the class */
258                     pLine.stripStartSequence(myToken);
259                     theContents.add(new ThemisAnalysisClass(this, pLine));
260                     return true;
261 
262                 /* If this is an interface/annotation */
263                 case INTERFACE:
264                 case ANNOTATION:
265                     /* Create the interface */
266                     pLine.stripStartSequence(myToken);
267                     theContents.add(new ThemisAnalysisInterface(this, myType.equals(ThemisAnalysisKeyWord.ANNOTATION), pLine));
268                     return true;
269 
270                 /* If this is an enum */
271                 case ENUM:
272                     /* Create the enum */
273                     pLine.stripStartSequence(myToken);
274                     theContents.add(new ThemisAnalysisEnum(this, pLine));
275                     return true;
276 
277                 default:
278                     break;
279             }
280         }
281 
282         /* Not processed */
283         return false;
284     }
285 
286     /**
287      * Process language constructs.
288      *
289      * @param pLine the line
290      * @return have we processed the line?
291      * @throws OceanusException on error
292      */
293     boolean processLanguage(final ThemisAnalysisLine pLine) throws OceanusException {
294         /* Access class type */
295         final String myToken = pLine.peekNextToken();
296         final Object myType = KEYWORDS.get(myToken);
297 
298         /* If we have a keyWord */
299         if (myType instanceof ThemisAnalysisKeyWord myKeyWord) {
300             /* Switch on the type */
301             switch (myKeyWord) {
302                 /* If this is a while */
303                 case WHILE:
304                     /* Create the while */
305                     pLine.stripStartSequence(myToken);
306                     theContents.add(new ThemisAnalysisWhile(this, pLine));
307                     return true;
308 
309                 /* If this is a doWhile */
310                 case DO:
311                     /* Create the while */
312                     pLine.stripStartSequence(myToken);
313                     theContents.add(new ThemisAnalysisDoWhile(this));
314                     return true;
315 
316                 /* If this is a switch */
317                 case SWITCH:
318                     /* Create the switch */
319                     pLine.stripStartSequence(myToken);
320                     theContents.add(new ThemisAnalysisSwitch(this, pLine));
321                     return true;
322 
323                 /* If this is a for */
324                 case FOR:
325                     /* Create the for */
326                     pLine.stripStartSequence(myToken);
327                     theContents.add(new ThemisAnalysisFor(this, pLine));
328                     return true;
329 
330                 /* If this is an if */
331                 case IF:
332                     /* Create the if */
333                     pLine.stripStartSequence(myToken);
334                     theContents.add(new ThemisAnalysisIf(this, pLine));
335                     return true;
336 
337                 /* If this is a try */
338                 case TRY:
339                     /* Create the try */
340                     pLine.stripStartSequence(myToken);
341                     theContents.add(new ThemisAnalysisTry(this, pLine));
342                     return true;
343 
344                 default:
345                     break;
346             }
347         }
348 
349         /* Not processed */
350         return false;
351     }
352 
353     /**
354      * Process blocks.
355      *
356      * @param pLine the line
357      * @return have we processed the line?
358      * @throws OceanusException on error
359      */
360     boolean processBlocks(final ThemisAnalysisLine pLine) throws OceanusException {
361         /* handle a standard block */
362         if (ThemisAnalysisBlock.checkBlock(pLine)) {
363             theContents.add(new ThemisAnalysisBlock(this, pLine));
364             return true;
365         }
366 
367         /* check for an embedded lambda/Anonymous class/ArrayInit */
368         final ThemisAnalysisEmbedType myEmbed = ThemisAnalysisEmbedded.checkForEmbedded(pLine);
369         switch (myEmbed) {
370             case LAMBDA:
371             case ANON:
372             case ARRAY:
373                 /* Process an embedded lambda/anon/init */
374                 theContents.add(new ThemisAnalysisEmbedded(this, myEmbed, pLine));
375                 return true;
376             case METHOD:
377                 /* Process an embedded methodBody */
378                 theContents.add(new ThemisAnalysisMethodBody(this, pLine));
379                 return true;
380             default:
381                 break;
382         }
383 
384         /* Not processed */
385         return false;
386     }
387 
388     /**
389      * Process a case/default line.
390      *
391      * @param pOwner the owning switch
392      * @param pLine  the line
393      * @return have we processed the line?
394      * @throws OceanusException on error
395      */
396     boolean processCase(final ThemisAnalysisContainer pOwner,
397                         final ThemisAnalysisLine pLine) throws OceanusException {
398         /* Access case type */
399         final Object myCase = parseCase(pLine);
400 
401         /* If we have a case */
402         if (myCase != null) {
403             theContents.add(new ThemisAnalysisCase(this, pOwner, myCase));
404             return true;
405         }
406 
407         /* Not processed */
408         return false;
409     }
410 
411     /**
412      * Process a case/default line.
413      *
414      * @param pLine the line
415      * @return have we processed the line?
416      */
417     static Object parseCase(final ThemisAnalysisLine pLine) {
418         /* Handle default clause */
419         if (pLine.getProperties().hasModifier(ThemisAnalysisModifier.DEFAULT)) {
420             return ThemisAnalysisKeyWord.DEFAULT;
421         }
422 
423         /* Access case type */
424         final String myToken = pLine.peekNextToken();
425         final Object myType = KEYWORDS.get(myToken);
426 
427         /* If we have a keyWord */
428         if (myType instanceof ThemisAnalysisKeyWord myKeyWord) {
429             /* If this is a case/default */
430             switch (myKeyWord) {
431                 case CASE:
432                     pLine.stripStartSequence(myToken);
433                     return pLine.stripNextToken();
434 
435                 case DEFAULT:
436                     pLine.stripStartSequence(myToken);
437                     return myKeyWord;
438 
439                 default:
440                     return null;
441 
442             }
443         }
444 
445         /* Not processed */
446         return null;
447     }
448 
449     /**
450      * Process extra constructs.
451      *
452      * @param pOwner   the owning construct
453      * @param pKeyWord the keyWord
454      * @return have we processed the line?
455      * @throws OceanusException on error
456      */
457     ThemisAnalysisElement processExtra(final ThemisAnalysisContainer pOwner,
458                                        final ThemisAnalysisKeyWord pKeyWord) throws OceanusException {
459         /* Just return if there are no more lines */
460         if (!hasLines()) {
461             return null;
462         }
463 
464         /* Access keyWord */
465         final ThemisAnalysisLine myLine = (ThemisAnalysisLine) popNextLine();
466         final String myToken = myLine.peekNextToken();
467         final Object myType = KEYWORDS.get(myToken);
468 
469         /* If we have a keyWord */
470         if (pKeyWord.equals(myType)) {
471             /* Switch on the type */
472             switch ((ThemisAnalysisKeyWord) myType) {
473                 /* If this is an else */
474                 case ELSE:
475                     /* Create the else */
476                     myLine.stripStartSequence(myToken);
477                     return new ThemisAnalysisElse(this, pOwner, myLine);
478 
479                 /* If this is a catch */
480                 case CATCH:
481                     /* Create the switch */
482                     myLine.stripStartSequence(myToken);
483                     return new ThemisAnalysisCatch(this, pOwner, myLine);
484 
485                 /* If this is a finally */
486                 case FINALLY:
487                     /* Create the finally */
488                     myLine.stripStartSequence(myToken);
489                     return new ThemisAnalysisFinally(this, pOwner, myLine);
490 
491                 default:
492                     break;
493             }
494         }
495 
496         /* Not processed */
497         pushLine(myLine);
498         return null;
499     }
500 
501     /**
502      * Process embedded block construct.
503      *
504      * @param pEmbedded the embedded block
505      * @return the field/statement
506      * @throws OceanusException on error
507      */
508     ThemisAnalysisElement processEmbedded(final ThemisAnalysisEmbedded pEmbedded) throws OceanusException {
509         /* Look for a reference */
510         final ThemisAnalysisLine myLine = pEmbedded.getHeader();
511         final ThemisAnalysisReference myReference = parsePotentialDataType(myLine);
512 
513         /* If we have a reference */
514         if (myReference != null) {
515             /* Create as field */
516             final String myName = myLine.stripNextToken();
517             return new ThemisAnalysisField(this, myName, myReference, pEmbedded);
518         }
519 
520         /* Just convert to statement */
521         final ThemisAnalysisKeyWord myKeyWord = determineStatementKeyWord(myLine);
522         return new ThemisAnalysisStatement(myKeyWord, pEmbedded);
523     }
524 
525     /**
526      * Process methodBody construct.
527      *
528      * @param pMethod the methodBody
529      * @return the method
530      * @throws OceanusException on error
531      */
532     ThemisAnalysisElement processMethodBody(final ThemisAnalysisMethodBody pMethod) throws OceanusException {
533         /* Look for a reference */
534         final ThemisAnalysisLine myLine = pMethod.getHeader();
535         final ThemisAnalysisReference myReference = parsePotentialDataType(myLine);
536 
537         /* Access the name of the method */
538         final String myName = myLine.stripNextToken();
539         final boolean isMethod = myLine.startsWithChar(ThemisAnalysisChar.PARENTHESIS_OPEN);
540 
541         /* We must have a reference and be a method */
542         if (myReference == null || !isMethod) {
543             throw new ThemisDataException("Invalid Method Body");
544         }
545 
546         /* Create as field */
547         return new ThemisAnalysisMethod(this, myName, myReference, pMethod);
548     }
549 
550     /**
551      * Process field and method constructs.
552      *
553      * @param pLine the line
554      * @return the field/method or null
555      * @throws OceanusException on error
556      */
557     ThemisAnalysisElement processFieldsAndMethods(final ThemisAnalysisLine pLine) throws OceanusException {
558         /* Look for a reference */
559         final ThemisAnalysisReference myReference = parsePotentialDataType(pLine);
560         if (myReference != null) {
561             /* Access the name of the field or method */
562             final String myName = pLine.stripNextToken();
563             final boolean isMethod = pLine.startsWithChar(ThemisAnalysisChar.PARENTHESIS_OPEN);
564             if (!isMethod) {
565                 myReference.resolveGeneric(this);
566                 return new ThemisAnalysisField(this, myName, myReference, pLine);
567             } else {
568                 return new ThemisAnalysisMethod(this, myName, myReference, pLine);
569             }
570         }
571 
572         /* Not processed */
573         return null;
574     }
575 
576     /**
577      * Process a statement.
578      *
579      * @param pLine the line
580      * @return the statement
581      * @throws OceanusException on error
582      */
583     ThemisAnalysisElement processStatement(final ThemisAnalysisLine pLine) throws OceanusException {
584         /* Determine keyWord (if any)  */
585         final ThemisAnalysisKeyWord myKeyWord = determineStatementKeyWord(pLine);
586         return new ThemisAnalysisStatement(this, myKeyWord, pLine);
587     }
588 
589     /**
590      * Process a statement.
591      *
592      * @param pLine the line
593      * @return the statement
594      */
595     private static ThemisAnalysisKeyWord determineStatementKeyWord(final ThemisAnalysisLine pLine) {
596         /* Look for a control keyWord */
597         final String myToken = pLine.peekNextToken();
598         final Object myType = KEYWORDS.get(myToken);
599 
600         /* If we have a keyWord */
601         if (myType instanceof ThemisAnalysisKeyWord myKeyWord) {
602             /* Switch on the type */
603             switch (myKeyWord) {
604                 case RETURN:
605                 case THROW:
606                 case BREAK:
607                 case CONTINUE:
608                 case YIELD:
609                     pLine.stripNextToken();
610                     return myKeyWord;
611                 default:
612                     break;
613             }
614         }
615 
616         /* No keyWord */
617         return null;
618     }
619 
620     /**
621      * Parse a possible dataType.
622      *
623      * @param pLine the line
624      * @return the dataType or null
625      * @throws OceanusException on error
626      */
627     private ThemisAnalysisReference parsePotentialDataType(final ThemisAnalysisLine pLine) throws OceanusException {
628         /* Not a dataType if we start with a keyWord */
629         final String myToken = pLine.peekNextToken();
630         if (KEYWORDS.get(myToken) != null) {
631             return null;
632         }
633 
634         /* Determine whether this is a method call or declaration */
635         final boolean isMethod = pLine.startsWithSequence(myToken + ThemisAnalysisChar.PARENTHESIS_OPEN);
636 
637         /* Look for a valid, existing dataType */
638         ThemisAnalysisDataType myType = theDataMap.lookUpDataType(myToken, isMethod);
639         if (myType == null) {
640             /* If the line has generic definitions */
641             final ThemisAnalysisProperties myProps = pLine.getProperties();
642             if (myProps.hasGeneric()) {
643                 /* Create a temporary parser and resolve against the generics */
644                 final ThemisAnalysisParser myTempParser = new ThemisAnalysisParser(this);
645                 myProps.resolveGeneric(myTempParser);
646                 myType = myTempParser.getDataMap().lookUpTheDataType(myToken);
647             }
648 
649             /* Return null if we haven't resolved it */
650             if (myType == null) {
651                 return null;
652             }
653         }
654         pLine.stripStartSequence(myToken);
655 
656         /* Return the reference */
657         return buildReference(theDataMap, pLine, myType);
658     }
659 
660     /**
661      * Parse a dataType.
662      *
663      * @param pDataMap the dataMap
664      * @param pLine    the line
665      * @return the dataType or null
666      * @throws OceanusException on error
667      */
668     static ThemisAnalysisReference parseDataType(final ThemisAnalysisDataMap pDataMap,
669                                                  final ThemisAnalysisLine pLine) throws OceanusException {
670         /* Cannot be started by a keyWord */
671         String myToken = pLine.peekNextToken();
672         if (KEYWORDS.get(myToken) != null) {
673             throw new ThemisDataException("DataType required but keyWord found");
674         }
675 
676         /* If the token ends with the VARARGS indication */
677         if (myToken.endsWith(ThemisAnalysisArray.VARARGS)) {
678             /* Strip the varArgs indication */
679             myToken = myToken.substring(0, myToken.length() - ThemisAnalysisArray.VARARGS.length());
680         }
681 
682         /* Look for a valid dataType */
683         ThemisAnalysisDataType myType = pDataMap.lookUpDataType(myToken, false);
684         if (myType == null) {
685             /* Declare the unrecognised dataType */
686             myType = pDataMap.declareUnknown(myToken);
687         }
688         pLine.stripStartSequence(myToken);
689 
690         /* Return the reference */
691         return buildReference(pDataMap, pLine, myType);
692     }
693 
694     /**
695      * Create the reference.
696      *
697      * @param pDataMap the dataMap
698      * @param pLine    the line
699      * @param pType    the dataType
700      * @return the dataType or null
701      * @throws OceanusException on error
702      */
703     private static ThemisAnalysisReference buildReference(final ThemisAnalysisDataMap pDataMap,
704                                                           final ThemisAnalysisLine pLine,
705                                                           final ThemisAnalysisDataType pType) throws OceanusException {
706         /* Access any generic/array detail */
707         final ThemisAnalysisGeneric myGeneric = ThemisAnalysisGeneric.isGeneric(pLine)
708                 ? new ThemisAnalysisGenericBase(pLine)
709                 : null;
710         final ThemisAnalysisArray myArray = ThemisAnalysisArray.isArray(pLine)
711                 ? new ThemisAnalysisArray(pLine)
712                 : null;
713 
714         /* Return the reference */
715         final ThemisAnalysisReference myRef = new ThemisAnalysisReference(pType, myGeneric, myArray);
716         pDataMap.declareReference(myRef);
717         return myRef;
718     }
719 
720     /**
721      * process the lines.
722      *
723      * @throws OceanusException on error
724      */
725     void processLines() throws OceanusException {
726         /* Loop through the lines */
727         while (hasLines()) {
728             /* Access next line */
729             final ThemisAnalysisLine myLine = (ThemisAnalysisLine) popNextLine();
730 
731             /* Process comments/blanks/languageConstructs */
732             final boolean processed = processCommentsAndBlanks(myLine)
733                     || processClass(myLine)
734                     || processLanguage(myLine)
735                     || processBlocks(myLine);
736 
737             /* If we haven't processed yet */
738             if (!processed) {
739                 /* Just add the line to contents at present */
740                 theContents.add(myLine);
741             }
742         }
743     }
744 
745     /**
746      * Create the keyWordMap.
747      *
748      * @return the new map
749      */
750     private static Map<String, Object> createKeyWordMap() {
751         /* create the map */
752         final Map<String, Object> myMap = new HashMap<>();
753 
754         /* Add the modifiers */
755         for (ThemisAnalysisModifier myModifier : ThemisAnalysisModifier.values()) {
756             myMap.put(myModifier.toString(), myModifier);
757         }
758 
759         /* Add the keyWords */
760         for (ThemisAnalysisKeyWord myKeyWord : ThemisAnalysisKeyWord.values()) {
761             myMap.put(myKeyWord.toString(), myKeyWord);
762         }
763 
764         /* return the map */
765         return myMap;
766     }
767 
768     /**
769      * Parse ancestors.
770      *
771      * @param pHeaders the headers
772      * @return the list of ancestors
773      * @throws OceanusException on error
774      */
775     List<ThemisAnalysisReference> parseAncestors(final Deque<ThemisAnalysisElement> pHeaders) throws OceanusException {
776         /* Create the list */
777         final List<ThemisAnalysisReference> myAncestors = new ArrayList<>();
778         final ThemisAnalysisLine myHeader = new ThemisAnalysisLine(pHeaders);
779 
780         /* Loop through the line */
781         while (true) {
782             /* Strip leading comma */
783             if (myHeader.startsWithChar(ThemisAnalysisChar.COMMA)) {
784                 myHeader.stripStartChar(ThemisAnalysisChar.COMMA);
785             }
786 
787             /* Access first token */
788             final String myToken = myHeader.peekNextToken();
789             if (myToken.length() == 0) {
790                 return myAncestors;
791             }
792 
793             /* Ignore keywords */
794             if (KEYWORDS.get(myToken) != null) {
795                 /* Strip the token from the line */
796                 myHeader.stripNextToken();
797             } else {
798                 /* Process the ancestor */
799                 final ThemisAnalysisReference myReference = parseDataType(theDataMap, myHeader);
800                 myReference.resolveGeneric(this);
801                 myAncestors.add(myReference);
802             }
803         }
804     }
805 
806     /**
807      * Parse parameters.
808      *
809      * @param pParams the parameters
810      * @return the parameter map
811      * @throws OceanusException on error
812      */
813     Map<String, ThemisAnalysisReference> parseParameters(final ThemisAnalysisLine pParams) throws OceanusException {
814         /* Create the list */
815         final Map<String, ThemisAnalysisReference> myParams = new LinkedHashMap<>();
816 
817         /* Loop through the lines */
818         while (true) {
819             /* Strip leading comma */
820             if (pParams.startsWithChar(ThemisAnalysisChar.COMMA)) {
821                 pParams.stripStartChar(ThemisAnalysisChar.COMMA);
822             }
823 
824             /* Access first token */
825             final String myToken = pParams.peekNextToken();
826             if (myToken.length() == 0) {
827                 return myParams;
828             }
829 
830             /* Ignore keywords */
831             if (KEYWORDS.get(myToken) != null) {
832                 /* Strip the token from the line */
833                 pParams.stripNextToken();
834             } else {
835                 /* Process the parameter */
836                 final ThemisAnalysisReference myReference = parseDataType(theDataMap, pParams);
837                 myReference.resolveGeneric(this);
838                 final String myVar = pParams.stripNextToken();
839                 myParams.put(myVar, myReference);
840             }
841         }
842     }
843 }