ThemisAnalysisBuilder.java

/*
 * Themis: Java Project Framework
 * Copyright 2012-2026. Tony Washer
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License.  You may obtain a copy
 * of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package io.github.tonywasher.joceanus.themis.lethe.analysis;

import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
import io.github.tonywasher.joceanus.themis.lethe.analysis.ThemisAnalysisContainer.ThemisAnalysisAdoptable;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * Builder utilities.
 */
public final class ThemisAnalysisBuilder {
    /**
     * Constructor.
     */
    private ThemisAnalysisBuilder() {
    }

    /**
     * Parse headers.
     *
     * @param pParser the parser
     * @param pLine   the current line
     * @return the headers
     * @throws OceanusException on error
     */
    static Deque<ThemisAnalysisElement> parseHeaders(final ThemisAnalysisParser pParser,
                                                     final ThemisAnalysisLine pLine) throws OceanusException {
        /* Allocate scanner */
        final ThemisAnalysisScanner myScanner = new ThemisAnalysisScanner(pParser);
        return myScanner.scanForTerminator(pLine, ThemisAnalysisChar.BRACE_OPEN);
    }

    /**
     * Process trailers.
     *
     * @param pParser the parser
     * @param pLine   the current line
     * @return the trailers
     * @throws OceanusException on error
     */
    static Deque<ThemisAnalysisElement> parseTrailers(final ThemisAnalysisParser pParser,
                                                      final ThemisAnalysisLine pLine) throws OceanusException {
        /* Allocate scanner */
        final ThemisAnalysisScanner myScanner = new ThemisAnalysisScanner(pParser);
        return myScanner.scanForTerminator(pLine, ThemisAnalysisChar.SEMICOLON);
    }

    /**
     * Process body.
     *
     * @param pParser the parser
     * @return the body
     * @throws OceanusException on error
     */
    static Deque<ThemisAnalysisElement> processBody(final ThemisAnalysisParser pParser) throws OceanusException {
        /* Allocate queue */
        final Deque<ThemisAnalysisElement> myBody = new ArrayDeque<>();

        /* Loop through the lines */
        int myNest = 1;
        while (myNest > 0 && pParser.hasLines()) {
            /* Access as line */
            final ThemisAnalysisLine myLine = (ThemisAnalysisLine) pParser.popNextLine();

            /* If we have a closing brace */
            if (myLine.startsWithChar(ThemisAnalysisChar.BRACE_CLOSE)) {
                /* Decrement nesting */
                myNest--;

                /* If we have finished the class */
                if (myNest == 0) {
                    /* Strip start sequence from line */
                    myLine.stripStartChar(ThemisAnalysisChar.BRACE_CLOSE);

                    /* Return a non-blank line to the stack and break loop */
                    if (!ThemisAnalysisBlank.isBlank(myLine)) {
                        pParser.pushLine(myLine);
                    }
                    break;
                }
            }

            /* Handle start of nested sequence */
            if (myLine.endsWithChar(ThemisAnalysisChar.BRACE_OPEN)) {
                /* Strip trailing comments */
                myLine.stripTrailingComments();
                if (myLine.endsWithChar(ThemisAnalysisChar.BRACE_OPEN)) {
                    myNest++;
                }
            }

            /* Add the line */
            myBody.add(myLine);
        }

        /* return the body */
        return myBody;
    }

    /**
     * Process method body.
     *
     * @param pParser the parser
     * @param pOwner  the owning method
     * @return the body
     * @throws OceanusException on error
     */
    static Deque<ThemisAnalysisElement> processMethodBody(final ThemisAnalysisParser pParser,
                                                          final ThemisAnalysisMethod pOwner) throws OceanusException {
        /* Allocate queue */
        final Deque<ThemisAnalysisElement> myBody = new ArrayDeque<>();

        /* Loop through the lines */
        int myNest = 1;
        while (myNest > 0 && pParser.hasLines()) {
            /* Access next line */
            final ThemisAnalysisElement myElement = pParser.popNextLine();

            /* Skip already processed items */
            if (myElement instanceof ThemisAnalysisProcessed) {
                /* Adopt the element if required */
                if (myElement instanceof ThemisAnalysisAdoptable myAdoptable) {
                    myAdoptable.setParent(pOwner);
                }

                /* Add to body */
                myBody.add(myElement);
                continue;
            }

            /* Access as line */
            final ThemisAnalysisLine myLine = (ThemisAnalysisLine) myElement;

            /* If we have a closing brace */
            if (myLine.startsWithChar(ThemisAnalysisChar.BRACE_CLOSE)) {
                /* Decrement nesting */
                myNest--;

                /* If we have finished the class */
                if (myNest == 0) {
                    /* Strip start sequence from line */
                    myLine.stripStartChar(ThemisAnalysisChar.BRACE_CLOSE);

                    /* Return a non-blank line to the stack and break loop */
                    if (!ThemisAnalysisBlank.isBlank(myLine)) {
                        pParser.pushLine(myLine);
                    }
                    break;
                }
            }

            /* Handle start of nested sequence */
            if (myLine.endsWithChar(ThemisAnalysisChar.BRACE_OPEN)) {
                /* Strip trailing comments */
                myLine.stripTrailingComments();
                if (myLine.endsWithChar(ThemisAnalysisChar.BRACE_OPEN)) {
                    myNest++;
                }
            }

            /* Add the line */
            myBody.add(myLine);
        }

        /* return the body */
        return myBody;
    }

    /**
     * format lines.
     *
     * @param pLines the lines to format
     * @return the formatted lines
     */
    public static String formatLines(final Deque<ThemisAnalysisElement> pLines) {
        /* Start parameters */
        final StringBuilder myBuilder = new StringBuilder();

        /* Build parameters */
        boolean bFirst = true;
        for (ThemisAnalysisElement myLine : pLines) {
            /* Handle separators */
            if (!bFirst) {
                myBuilder.append(ThemisAnalysisChar.LF);
            } else {
                bFirst = false;
            }

            /* Add parameter */
            myBuilder.append(myLine);
        }

        /* Return the string */
        return myBuilder.toString();
    }
}