All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax0.jamal.api.Debugger Maven / Gradle / Ivy

package javax0.jamal.api;

import java.util.Deque;
import java.util.List;

/**
 * Debuggers should implement this interface in order to be loadable via the service loader. Also, debugger classes
 * should have a public argument-less constructor.
 */
public interface Debugger extends AutoCloseable, ServiceLoaded {

    /**
     * Loads the instances that are available via the service loader.
     *
     * @return the different debugger objects as returned by the service loader
     */
    static List getInstances() {
        return ServiceLoaded.getInstances(Debugger.class);
    }

    /**
     * A {@code Debugger.Stub} provides access to functionality, which is not part of the normal operation of a {@link
     * Processor} but are needed and defined in the {@link Debuggable} interface and in the interfaces that are inside.
     * The debugger gets an instance of the implementation of this stub instead of the {@code Processor}, because the
     * debugger does not need the regular processor functionality. On the other hand the processor object the debugger
     * could access implements methods that return objects which need casting to their {@link Debuggable} counterpart
     * and the stub implementation does that and also calls the subsequent methods that the debugger needs. Essentially
     * the implementation of this interface is a facade towards the functionalities from the processor that the debugger
     * needs.
     */
    interface Stub {

        /**
         * Return the current list of the scopes of the processor. Scopes are internal matter of the processor and are
         * not exposed. However, debugging is something that pokes into the internals when the user needs to see what
         * the current state is. For this reason the interface {@link Debuggable} is defined that gives access to those
         * methods that are needed for the debugger.
         *
         * The debugger must not modify this list.
         *
         * @return the list of scopes
         */
        List getScopeList();

        /**
         * Ask the currently debugged processor to evaluate the string at the current state.
         * Note that the evaluation will also trigger the debugger events in a recursive way.
         * If the debugger does not want to stop every time it has to care about this fact
         * maintaining a state signaling when it needs to stop and when it must not.
         *
         * @param in the string to evaluate as macro
         * @return the result of the evaluation. This result is not appended to the output.
         * @throws BadSyntax if the evaluation of the input is erroneous
         */
        String process(String in) throws BadSyntax;

        Deque errors();
    }

    /**
     * The processor calls this method before the evaluation of a macro. The implementation may store the reference and
     * copy the content of {@code input} and the {@code level} and may, at it's own decision stop the execution and
     * interact with the debugger client.
     * 

* Note that the {@code input} is a character sequence and this it is mutable. The processor does mutate the * instance afterwards. So if the debugger wants to save the state of the input it has to make a copy of the * content, for example applying {@link CharSequence#toString() toString()}. The reference itself can later be used, * to get the later state of the input. For example in the method {@link #setAfter(int, CharSequence)} the {@code * input} will already contain the state of the input after the macro evaluation (the macro or the text block from * the start is chopped off.) * * @param level the actual macro nesting level at the time of the method invocation * @param input the input */ void setBefore(int level, CharSequence input); /** * Give the content of the current macro to be evaluated to the debugger before the macro is evaluated. The * processor invokes this method on the debugger before it invokes a macro evaluation, or before it appends a text * segment to the output. *

* Note that the {@code macro} is a character sequence and this it is mutable. The processor does mutate the * instance afterwards. So if the debugger wants to save the state of the input it has to make a copy of the * content, for example applying {@link CharSequence#toString() toString()}. *

* It is guaranteed that this method will be invoked after {@link #setBefore(int, CharSequence) setBefore()} while * still before the evaluation. That way the debugger can be sure the that the {@code macro} belongs to the same * {@code level} as it was passed to {@link #setBefore(int, CharSequence) setBefore()}. * * @param macro the text of the macro to be evaluated */ void setStart(CharSequence macro); /** * Give the content of the evaluation result, {@code output} to the debugger. The processor invokes this method * after it evaluated a macro or appended a text segment to the output. *

* Note that the {@code output} is a character sequence and this it is mutable. The processor does mutate the * instance afterwards. So if the debugger wants to save the state of the input it has to make a copy of the * content, for example applying {@link CharSequence#toString() toString()}. * * @param level the actual macro nesting level at the time of the method invocation * @param output the output */ void setAfter(int level, CharSequence output); /** * Implement this method to close the debugger. This may include closing communication channels with the client and * other possible clean-up. This method is invoked when the processor is closed. */ void close(); /** * The debugger should implement this method to signal its affinity to handle the debugger connection string {@code * s}. *

* The affinity value can be -1, 0 or any other positive value. *

* Affinity -1 means that the debugger cannot handle this connection string. The connection string in this case is * probably for a different debugger. *

* Affinity 0 means that the debugger is absolutely sure that it can handle this connection string and it is the * debugger that has to be used. *

* Values between 0 and {@link Integer#MAX_VALUE Integer.MAX_VALUE} mean a certain affinity expressed numerically. * The processor chooses the debugger that has the smallest affinity value. *

* It is an error if there are more than one debuggers that return the smallest affinity value. *

* The module {@code jamal-engine} implements this interface with the {@code javax0.jamal.engine.NullDebugger}. The * {@code affinity()} method of the {@code NullDebugger} returns {@code Integer.MAX_VALUE-1}. The algorithm * searching for a debugger will find this implementation if no other debugger claims the connection string any * better for themselves. *

* The implementation of this method is also a good place to parse the connection string and to extract the * parameters from it. To do that the implementations can use the {@code javax0.jamal.tools.ConnectionStringParser} * class. An implementation may also decide to store the connection string and parse it only in the {@link * #init(Stub) init()} method. * * @param s the debugger connection string * @return the affinity value of the debugger implementation related to this debugger connection string */ int affinity(String s); /** * Initialize the debugger. This method is called right after the debugger was selected from the list of available * debuggers. The implementation should perform all operations that are needed to set up the debugger. This usually * includes opening some channel that the debugger client can use to communicate with the debugger. * * @param stub the debugger stub (see {@link Debugger.Stub} the debugger should use to implement certain functions. * @throws Exception if the initialization cannot be performed. For example the configured post to bind on is * already bound. */ void init(Stub stub) throws Exception; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy