Skip to content

io_nats_jparse_path

Rick Hightower edited this page Jul 18, 2023 · 1 revision

io.nats.jparse.path

class diagram

PathNode

The PathNode class is a representation of a node in the parsed path of a structured data source, such as JSON or XML. It is a subclass of AbstractList and implements the CollectionNode interface.

@Override

public List<List> childrenTokens()

@Override
public List<List<Token>> childrenTokens() {
    if (childrenTokens == null) {
        childrenTokens = Arrays.stream(tokens.toArray()).map(Collections::singletonList).collect(Collectors.toList());
    }
    return childrenTokens;
}

The childrenTokens method in the PathNode class is responsible for returning a list of token lists. Here is a step-by-step description of what this method is doing:

  1. The method overrides the childrenTokens method from the superclass, indicating that it provides a custom implementation for this method.

  2. The method checks if the childrenTokens variable is null. This variable is an instance variable of the PathNode class.

  3. If the childrenTokens variable is indeed null, the method proceeds to the next step. Otherwise, it directly returns the childrenTokens variable.

  4. Within the if block, the method creates a stream from the tokens list using the Arrays.stream method. The tokens list is an instance variable of the PathNode class.

  5. The stream of tokens is then mapped to a list of single-element lists using the map method. Each token is wrapped in a singleton list using the Collections::singletonList method reference.

  6. The resulting mapped stream is collected into a list of token lists using the collect method. The Collectors.toList() method is used to collect the elements into a List.

  7. The childrenTokens variable is assigned the newly created list of token lists.

  8. Finally, the method returns the childrenTokens variable.

In summary, the childrenTokens method returns a list of token lists. If the childrenTokens variable is null, it creates a new list by wrapping each token in the tokens list in a singleton list. This list is then assigned to the childrenTokens variable and returned. If the childrenTokens variable is not null, it is directly returned.

The childrenTokens method in the io.nats.jparse.path.PathNode class is overridden to return a list of token lists.

Within the method, it first checks if the childrenTokens variable is null. If it is null, it performs the following logic: it converts the array of tokens to a stream, maps each token to a singleton list using the Collections::singletonList method, and finally collects the singleton lists into a list using the Collectors.toList method.

Once the childrenTokens list is created, it is stored in the childrenTokens variable for future use. Finally, the method returns the childrenTokens list.

In summary, the childrenTokens method returns a list of token lists, where each token list represents a child of the PathNode.

sequence diagram

Node[] elements()

Node[] elements() {
    if (elements == null) {
        elements = new Node[tokens.size()];
    }
    return elements;
}

The elements method defined in the class io.nats.jparse.path.PathNode returns an array of Node objects.

Here is a step-by-step description of what this method is doing based on its body:

  1. Check if the variable elements is null.

  2. If elements is null, it means that the array has not been initialized yet.

  3. In this case, we create a new array of Node objects with a size equal to the number of elements in the tokens list.

  4. Assign the newly created array to the elements variable.

  5. Finally, return the elements array.

Essentially, this method ensures that the elements array is initialized and properly sized before returning it. If the array is already initialized, the method simply returns the existing array without any modification.

The method elements() in the io.nats.jparse.path.PathNode class is used to retrieve an array of Node objects.

First, it checks if the elements array is null. If it is null, it creates a new array with a size equal to the number of tokens. This is done to ensure that the elements array is initialized and has the same size as the list of tokens.

Finally, it returns the elements array, which may be either the newly created array or the already existing array.

sequence diagram

@Override

public Iterator iterator()

@Override
public Iterator<PathElement> iterator() {
    return new Iterator<PathElement>() {

        int index = 0;

        @Override
        public boolean hasNext() {
            return index < tokens().size();
        }

        @Override
        public PathElement next() {
            return (PathElement) getNodeAt(index++);
        }
    };
}

The iterator() method in the class io.nats.jparse.path.PathNode returns an iterator for iterating over the PathElement objects in the tokens list.

Here is a step by step description of what the method is doing:

  1. The method defines an anonymous inner class that implements the Iterator interface.
  2. The inner class has a variable index initialized to 0, which represents the current index in the tokens list.
  3. The hasNext() method is overridden to check if the index is less than the size of the tokens list, indicating whether there are more elements to iterate over.
  4. The next() method is overridden to return the PathElement object at the current index in the tokens list using the getNodeAt() method, and then increments the index by 1.
  5. The inner class is instantiated and returned as the iterator for the PathNode object.

So, the iterator() method creates an iterator that allows iterating over the PathElement objects in the tokens list by implementing the hasNext() and next() methods.

The iterator method in the io.nats.jparse.path.PathNode class returns an iterator object that allows iterating over a collection of PathElement objects.

The implementation overrides the hasNext method to check if there are more elements in the collection to iterate through, and the next method returns the next PathElement object in the collection.

The iterator is implemented as an anonymous inner class that keeps track of the current index in the collection and returns the element at that index when next is called.

sequence diagram

PathParser

The PathParser class is a public class that implements the JsonParser interface. It provides similar functionality for parsing Json Paths as JSONPath expressions.

private List scan(CharSource source, TokenList tokens)

private List<Token> scan(CharSource source, TokenList tokens) {
    char ch = ' ';
    loop: while (true) {
        ch = (char) source.next();
        switch(ch) {
            case ParseConstants.INDEX_BRACKET_START_TOKEN:
                parseIndexOrKey(source, (char) source.next(), tokens);
                break;
            //'A';
            case ParseConstants.A:
            //'B';
            case ParseConstants.B:
            //'C';
            case ParseConstants.C:
            //'D';
            case ParseConstants.D:
            //'E';
            case ParseConstants.E:
            //'F';
            case ParseConstants.F:
            //'G';
            case ParseConstants.G:
            //'H';
            case ParseConstants.H:
            //'I';
            case ParseConstants.I:
            //'J';
            case ParseConstants.J:
            //'K';
            case ParseConstants.K:
            //'L';
            case ParseConstants.L:
            //'M';
            case ParseConstants.M:
            //'N';
            case ParseConstants.N:
            //'O';
            case ParseConstants.O:
            //'P';
            case ParseConstants.P:
            //'Q';
            case ParseConstants.Q:
            //'R';
            case ParseConstants.R:
            //'S';
            case ParseConstants.S:
            //'T';
            case ParseConstants.T:
            //'U';
            case ParseConstants.U:
            //'V';
            case ParseConstants.V:
            //'W';
            case ParseConstants.W:
            //'X';
            case ParseConstants.X:
            //'Y';
            case ParseConstants.Y:
            //'Z';
            case ParseConstants.Z:
            // = 'a';
            case ParseConstants.A_:
            //'b';
            case ParseConstants.B_:
            //'c';
            case ParseConstants.C_:
            //'d';
            case ParseConstants.D_:
            //'e';
            case ParseConstants.E_:
            //'f';
            case ParseConstants.F_:
            //'g';
            case ParseConstants.G_:
            //'h';
            case ParseConstants.H_:
            //'i';
            case ParseConstants.I_:
            //'j';
            case ParseConstants.J_:
            //'k';
            case ParseConstants.K_:
            //'l';
            case ParseConstants.L_:
            //'m';
            case ParseConstants.M_:
            //'n';
            case ParseConstants.N_:
            //'o';
            case ParseConstants.O_:
            //'p';
            case ParseConstants.P_:
            //'q';
            case ParseConstants.Q_:
            //'r';
            case ParseConstants.R_:
            //'s';
            case ParseConstants.S_:
            //'t';
            case ParseConstants.T_:
            //'u';
            case ParseConstants.U_:
            //'v';
            case ParseConstants.V_:
            //'w';
            case ParseConstants.W_:
            //'x';
            case ParseConstants.X_:
            //'y';
            case ParseConstants.Y_:
            case //'z';
            ParseConstants.Z_:
                parseKeyName(source, ch, tokens);
                break;
            case ParseConstants.DOT:
                parseKeyName(source, (char) source.next(), tokens);
                break;
            case ParseConstants.ETX:
                break loop;
            default:
                throw new IllegalStateException("Unable to understand char " + ch + " index " + source.getIndex());
        }
    }
    return tokens;
}

Method: scan

This method is defined in the class io.nats.jparse.path.PathParser.

Purpose

The purpose of the scan method is to scan a CharSource and tokenize it, storing the tokens in a TokenList. The method performs a series of checks on each character in the input source and determines the appropriate action based on the character.

Parameters

  • source (type: CharSource): The source containing the characters to be scanned.
  • tokens (type: TokenList): The list to store the generated tokens.

Steps

  1. Initialize the variable ch with a space character ' '.
  2. Enter an infinite loop labeled "loop".
  3. Inside the loop:
    • Assign the next character from the source to ch.
    • Start a switch statement based on the value of ch.
    1. Case: ParseConstants.INDEX_BRACKET_START_TOKEN
      • Call the method parseIndexOrKey with the source, the next character from source, and tokens as arguments.
      • Break out of the switch statement.
    2. Cases: ParseConstants.A, ParseConstants.B, ..., ParseConstants.Z, ParseConstants.A_, ParseConstants.B_, ..., ParseConstants.Z_
      • Call the method parseKeyName with the source, ch, and tokens as arguments.
      • Break out of the switch statement.
    3. Case: ParseConstants.DOT
      • Call the method parseKeyName with the source and the next character from source as arguments.
      • Break out of the switch statement.
    4. Case: ParseConstants.ETX
      • Break out of the loop labeled "loop".
    5. Default case:
      • Throw an IllegalStateException with a message indicating that the character ch cannot be understood with its index in the source.
  4. Return the tokens list.

Note: The method scans each character in the source one by one until it encounters an ETX character, which signifies the end of the input. During the scanning process, it performs specific actions based on the type of character encountered, such as parsing index, key, or throwing an exception for an unknown character.

The method scan in the class PathParser is used to scan the given source character by character and tokenize it based on certain conditions.

The method starts by initializing a loop that continues until it encounters a break statement. Inside the loop, it reads the next character from the source and assigns it to the variable ch.

Then, based on the value of ch, it performs different actions. If ch is equal to [ character, it calls the parseIndexOrKey method passing the next character from the source and the tokens list.

If ch is equal to any uppercase or lowercase letter (A to Z, a to z), it calls the parseKeyName method passing the source, ch, and tokens as arguments.

If ch is equal to . character, it calls the parseKeyName method passing the next character from the source and the tokens list.

If ch is equal to ETX character, it breaks the loop and the method returns the tokens list.

If ch does not match any of the above cases, it throws an IllegalStateException with an error message indicating the character ch and its index in the source.

private void parseIndexOrKey(CharSource source, char ch, TokenList tokens)

private void parseIndexOrKey(CharSource source, char ch, TokenList tokens) {
    final int startIndex = source.getIndex();
    switch(ch) {
        case ParseConstants.NUM_0:
        case ParseConstants.NUM_1:
        case ParseConstants.NUM_2:
        case ParseConstants.NUM_3:
        case ParseConstants.NUM_4:
        case ParseConstants.NUM_5:
        case ParseConstants.NUM_6:
        case ParseConstants.NUM_7:
        case ParseConstants.NUM_8:
        case ParseConstants.NUM_9:
            parseIndex(source, startIndex, tokens, ch);
            break;
        case ParseConstants.SINGLE_QUOTE:
            parseKeyWithQuotes(source, startIndex + 1, tokens, ch);
            break;
        case ParseConstants.ETX:
            throw new IllegalStateException("reached end");
        default:
            throw new IllegalStateException("Unable to understand char " + ch + " index " + source.getIndex());
    }
}

Method: parseIndexOrKey

Description:

The parseIndexOrKey method is a private method defined in the PathParser class in the io.nats.jparse.path package. This method is responsible for parsing an index or a key from a given character source.

Parameters:

  • source: The character source from which to parse the index or key.
  • ch: The current character being processed.
  • tokens: The list of tokens where the parsed index or key will be added.

Steps:

  1. Get the start index of the character source.
  2. Switch based on the value of ch:
    • If ch is one of the constant values ParseConstants.NUM_0, ParseConstants.NUM_1, ParseConstants.NUM_2, ParseConstants.NUM_3, ParseConstants.NUM_4, ParseConstants.NUM_5, ParseConstants.NUM_6, ParseConstants.NUM_7, ParseConstants.NUM_8, ParseConstants.NUM_9, then call the parseIndex method with the source, startIndex, tokens, and ch as parameters.
    • If ch is equal to the constant value ParseConstants.SINGLE_QUOTE, then call the parseKeyWithQuotes method with the source, startIndex + 1, tokens, and ch as parameters.
    • If ch is equal to the constant value ParseConstants.ETX, then throw an IllegalStateException with the message "reached end".
    • If none of the above conditions are met, then throw an IllegalStateException with the message "Unable to understand char <ch> index <source.getIndex()>".

Return Type:

This method does not have a return type.

The parseIndexOrKey method, defined in the class PathParser in the io.nats.jparse.path package, is responsible for parsing an index or key from a given CharSource and adding it to the provided TokenList.

The method takes three parameters: source, which represents the source of characters to parse; ch, which is the current character to be processed; and tokens, which is the list where the parsed index or key will be added.

Inside the method, it first determines the startIndex of the current CharSource. Then, based on the value of ch, it performs one of the following actions:

  • If ch is a digit from 0 to 9, the method calls the parseIndex method passing the source, startIndex, tokens, and ch as parameters. This indicates that an index is being parsed.
  • If ch is a single quote ('), the method calls the parseKeyWithQuotes method passing the source, startIndex + 1, tokens, and ch as parameters. This indicates that a key enclosed in quotes is being parsed.
  • If ch is the end of text (ETX), the method throws an IllegalStateException with the message "reached end". This indicates that the end of the input has been reached unexpectedly.
  • If none of the above conditions are met, the method throws an IllegalStateException with the message "Unable to understand char [ch] index [source.getIndex()]". This indicates that the provided character is not recognized and cannot be parsed.

In summary, the parseIndexOrKey method in the PathParser class parses either an index or a key from a given CharSource based on the provided character. Depending on the character value, it either calls parseIndex, parseKeyWithQuotes, or throws an exception if the character is not recognized.

sequence diagram

private void parseKeyWithQuotes(CharSource source, int startIndex, TokenList tokens, char ch)

private void parseKeyWithQuotes(CharSource source, int startIndex, TokenList tokens, char ch) {
    loop: while (true) {
        ch = (char) source.next();
        switch(ch) {
            //'A';
            case ParseConstants.A:
            //'B';
            case ParseConstants.B:
            //'C';
            case ParseConstants.C:
            //'D';
            case ParseConstants.D:
            //'E';
            case ParseConstants.E:
            //'F';
            case ParseConstants.F:
            //'G';
            case ParseConstants.G:
            //'H';
            case ParseConstants.H:
            //'I';
            case ParseConstants.I:
            //'J';
            case ParseConstants.J:
            //'K';
            case ParseConstants.K:
            //'L';
            case ParseConstants.L:
            //'M';
            case ParseConstants.M:
            //'N';
            case ParseConstants.N:
            //'O';
            case ParseConstants.O:
            //'P';
            case ParseConstants.P:
            //'Q';
            case ParseConstants.Q:
            //'R';
            case ParseConstants.R:
            //'S';
            case ParseConstants.S:
            //'T';
            case ParseConstants.T:
            //'U';
            case ParseConstants.U:
            //'V';
            case ParseConstants.V:
            //'W';
            case ParseConstants.W:
            //'X';
            case ParseConstants.X:
            //'Y';
            case ParseConstants.Y:
            //'Z';
            case ParseConstants.Z:
            // = 'a';
            case ParseConstants.A_:
            //'b';
            case ParseConstants.B_:
            //'c';
            case ParseConstants.C_:
            //'d';
            case ParseConstants.D_:
            //'e';
            case ParseConstants.E_:
            //'f';
            case ParseConstants.F_:
            //'g';
            case ParseConstants.G_:
            //'h';
            case ParseConstants.H_:
            //'i';
            case ParseConstants.I_:
            //'j';
            case ParseConstants.J_:
            //'k';
            case ParseConstants.K_:
            //'l';
            case ParseConstants.L_:
            //'m';
            case ParseConstants.M_:
            //'n';
            case ParseConstants.N_:
            //'o';
            case ParseConstants.O_:
            //'p';
            case ParseConstants.P_:
            //'q';
            case ParseConstants.Q_:
            //'r';
            case ParseConstants.R_:
            //'s';
            case ParseConstants.S_:
            //'t';
            case ParseConstants.T_:
            //'u';
            case ParseConstants.U_:
            //'v';
            case ParseConstants.V_:
            //'w';
            case ParseConstants.W_:
            //'x';
            case ParseConstants.X_:
            //'y';
            case ParseConstants.Y_:
            //'z';
            case ParseConstants.Z_:
            case ParseConstants.NEW_LINE_WS:
            case ParseConstants.CARRIAGE_RETURN_WS:
            case ParseConstants.TAB_WS:
            case ParseConstants.SPACE_WS:
                continue;
            case ParseConstants.SINGLE_QUOTE:
                break loop;
            case ParseConstants.ETX:
                throw new IllegalStateException("reached end");
            default:
                if (ch > 20 && ch < 127) {
                    break;
                } else {
                    throw new IllegalStateException("Unable to understand char " + ch + " index " + source.getIndex());
                }
        }
    }
    final int endIndex = source.getIndex();
    int i = source.nextSkipWhiteSpace();
    if (i == ParseConstants.INDEX_BRACKET_END_TOKEN) {
        tokens.add(new Token(startIndex, endIndex, TokenTypes.PATH_KEY_TOKEN));
    } else {
        throw new IllegalStateException("Unable to understand char " + ch + " index " + source.getIndex());
    }
}

The parseKeyWithQuotes method is defined in the io.nats.jparse.path.PathParser class. It is responsible for parsing a key with quotes from a given source of characters. Here is a step-by-step description of what the method does:

  1. The method takes four parameters: source, startIndex, tokens, and ch.
  2. The method starts an infinite loop using a while statement with the label loop.
  3. Inside the loop, it retrieves the next character from the source using source.next() and assigns it to ch.
  4. It then checks the value of ch using a switch statement.
  5. If ch matches any of the constants defined in the ParseConstants class corresponding to characters from 'A' to 'Z', 'a' to 'z', or whitespace characters, it continues to the next iteration of the loop.
  6. If ch matches the constant ParseConstants.SINGLE_QUOTE, it breaks out of the loop using the break statement with the label loop.
  7. If ch matches the constant ParseConstants.ETX, it throws an IllegalStateException with the message "reached end".
  8. If none of the above conditions match, it checks if ch is a printable ASCII character by comparing its value with the range of 20 to 127. If it is, it breaks out of the loop. Otherwise, it throws an IllegalStateException with the message "Unable to understand char " + ch + " index " + source.getIndex()".
  9. After breaking out of the loop, it assigns the current index of the source to the variable endIndex.
  10. It then calls the nextSkipWhiteSpace() method on the source to get the next non-whitespace character and assigns it to the variable i.
  11. If i equals the constant ParseConstants.INDEX_BRACKET_END_TOKEN, it adds a new Token object to the tokens list with the startIndex, endIndex, and TokenTypes.PATH_KEY_TOKEN.
  12. If i does not match the constant ParseConstants.INDEX_BRACKET_END_TOKEN, it throws an IllegalStateException with the message "Unable to understand char " + ch + " index " + source.getIndex()".

Note: The exact behavior and purpose of the method may depend on the implementation details of the CharSource and TokenList classes, which are not provided in the given code snippet.

The parseKeyWithQuotes method in the PathParser class is responsible for parsing a key with quotes from a given character source. It iterates through the characters in the source and performs various checks and validations. If the character is a valid key character (including upper and lower case letters and the underscore), or a whitespace character, it continues to the next character. If the character is a single quote, it breaks out of the loop. If the character is the ETX (end of transmission) character, it throws an exception. If the character is not a valid key character or whitespace, it throws an exception indicating that it is unable to understand the character.

Finally, it retrieves the end index from the character source and checks the next character after skipping whitespace. If the next character is the closing bracket token, it adds a new token to the token list representing the parsed key. Otherwise, it throws an exception indicating that it is unable to understand the character.

private void parseKeyName(CharSource source, char ch, TokenList tokens)

private void parseKeyName(CharSource source, char ch, TokenList tokens) {
    final int startIndex = source.getIndex();
    loop: while (true) {
        ch = (char) source.next();
        switch(ch) {
            //'A';
            case ParseConstants.A:
            //'B';
            case ParseConstants.B:
            //'C';
            case ParseConstants.C:
            //'D';
            case ParseConstants.D:
            //'E';
            case ParseConstants.E:
            //'F';
            case ParseConstants.F:
            //'G';
            case ParseConstants.G:
            //'H';
            case ParseConstants.H:
            //'I';
            case ParseConstants.I:
            //'J';
            case ParseConstants.J:
            //'K';
            case ParseConstants.K:
            //'L';
            case ParseConstants.L:
            //'M';
            case ParseConstants.M:
            //'N';
            case ParseConstants.N:
            //'O';
            case ParseConstants.O:
            //'P';
            case ParseConstants.P:
            //'Q';
            case ParseConstants.Q:
            //'R';
            case ParseConstants.R:
            //'S';
            case ParseConstants.S:
            //'T';
            case ParseConstants.T:
            //'U';
            case ParseConstants.U:
            //'V';
            case ParseConstants.V:
            //'W';
            case ParseConstants.W:
            //'X';
            case ParseConstants.X:
            //'Y';
            case ParseConstants.Y:
            //'Z';
            case ParseConstants.Z:
            // = 'a';
            case ParseConstants.A_:
            //'b';
            case ParseConstants.B_:
            //'c';
            case ParseConstants.C_:
            //'d';
            case ParseConstants.D_:
            //'e';
            case ParseConstants.E_:
            //'f';
            case ParseConstants.F_:
            //'g';
            case ParseConstants.G_:
            //'h';
            case ParseConstants.H_:
            //'i';
            case ParseConstants.I_:
            //'j';
            case ParseConstants.J_:
            //'k';
            case ParseConstants.K_:
            //'l';
            case ParseConstants.L_:
            //'m';
            case ParseConstants.M_:
            //'n';
            case ParseConstants.N_:
            //'o';
            case ParseConstants.O_:
            //'p';
            case ParseConstants.P_:
            //'q';
            case ParseConstants.Q_:
            //'r';
            case ParseConstants.R_:
            //'s';
            case ParseConstants.S_:
            //'t';
            case ParseConstants.T_:
            //'u';
            case ParseConstants.U_:
            //'v';
            case ParseConstants.V_:
            //'w';
            case ParseConstants.W_:
            //'x';
            case ParseConstants.X_:
            //'y';
            case ParseConstants.Y_:
            case //'z';
            ParseConstants.Z_:
                continue;
            case ParseConstants.ETX:
                break loop;
            case ParseConstants.DOT:
                break loop;
            case ParseConstants.INDEX_BRACKET_START_TOKEN:
                final int endIndex = source.getIndex();
                tokens.add(new Token(startIndex, endIndex, TokenTypes.PATH_KEY_TOKEN));
                parseIndexOrKey(source, (char) source.next(), tokens);
                return;
            default:
                throw new IllegalStateException("Unable to understand char " + ch + " index " + source.getIndex());
        }
    }
    final int endIndex = source.getIndex();
    tokens.add(new Token(startIndex, endIndex, TokenTypes.PATH_KEY_TOKEN));
}

The parseKeyName method in the PathParser class is responsible for parsing a key name from a character source. It follows these steps:

  1. Start a loop that continues indefinitely.
  2. Get the next character from the character source.
  3. Check the value of the character using a switch statement.
  4. If the character is one of the uppercase letters from 'A' to 'Z' or the lowercase letter 'a', 'b', 'c', ..., 'z', continue to the next iteration of the loop.
  5. If the character is the end-of-text character (represented by ParseConstants.ETX) or a dot character (represented by ParseConstants.DOT), break out of the loop.
  6. If the character is an opening square bracket (represented by ParseConstants.INDEX_BRACKET_START_TOKEN), create a token for the current key name, add it to the token list, and call the parseIndexOrKey method to parse the index or key that follows the square bracket.
  7. Return from the method.
  8. If none of the above cases match, throw an IllegalStateException with an error message indicating that the character is not recognized.
  9. After breaking out of the loop, create a token for the current key name, add it to the token list, and return from the method.

The parseKeyName method is responsible for parsing a key name from a given source of characters. It iterates over the characters in the source and checks each character against a set of predefined constants representing valid key name characters. If the character is a valid key name character, the iteration continues. If the character is a delimiter, like a dot or an index bracket start token, the method adds a token representing the key name to a list of tokens and calls another method to parse the index or key following the delimiter. If the character is neither a valid key name character nor a delimiter, an exception is thrown indicating that the character is not understood. Once the iteration is complete, the method adds a final key name token to the list and returns.

sequence diagram

private void parseIndex(CharSource source, int startIndex, TokenList tokens, char ch)

private void parseIndex(CharSource source, int startIndex, TokenList tokens, char ch) {
    loop: while (true) {
        ch = (char) source.next();
        switch(ch) {
            case ParseConstants.NUM_0:
            case ParseConstants.NUM_1:
            case ParseConstants.NUM_2:
            case ParseConstants.NUM_3:
            case ParseConstants.NUM_4:
            case ParseConstants.NUM_5:
            case ParseConstants.NUM_6:
            case ParseConstants.NUM_7:
            case ParseConstants.NUM_8:
            case ParseConstants.NUM_9:
                break;
            case ParseConstants.INDEX_BRACKET_END_TOKEN:
                break loop;
            case ParseConstants.ETX:
                throw new IllegalStateException("reached end");
            default:
                throw new IllegalStateException("Unable to understand char " + ch + " index " + source.getIndex());
        }
    }
    final int endIndex = source.getIndex();
    tokens.add(new Token(startIndex, endIndex, TokenTypes.PATH_INDEX_TOKEN));
}

Method: parseIndex

This method is defined in the io.nats.jparse.path.PathParser class and is used to parse an index from a CharSource object.

Steps:

  1. The method starts by entering an infinite loop using a while (true) statement. This loop will break only when a specific condition is met.

  2. Inside the loop, the next character from the CharSource object is retrieved using the source.next() method and assigned to the variable ch.

  3. A switch statement is used to check the value of ch and perform different actions based on its value. The following cases are handled:

    • If ch is '0', '1', '2', '3', '4', '5', '6', '7', '8', or '9', no action is taken.

    • If ch is ']', the loop is broken using the break loop; statement.

    • If ch is ParseConstants.ETX, an IllegalStateException is thrown with the message "reached end".

    • If none of the above cases match, an IllegalStateException is thrown with the message "Unable to understand char " + ch + " index " + source.getIndex()".

  4. After the loop is exited, the final index of the CharSource object is retrieved using the source.getIndex() method and assigned to the variable endIndex.

  5. A new Token object is created with the startIndex, endIndex, and TokenTypes.PATH_INDEX_TOKEN. This token is then added to the tokens list using the tokens.add() method.

Note: The TokenList and Token objects mentioned here are assumed to be defined elsewhere and are not shown in the given code snippet.

The parseIndex method in the io.nats.jparse.path.PathParser class is used to parse an index from a character source (CharSource).

The method iterates through the characters in the source until it reaches a specific condition. It checks if each character is a digit from 0 to 9 and if so, continues to the next character. If the character is the end token for an index bracket, it breaks out of the loop. If the character is the ETX (end of text) constant, it throws an IllegalStateException with the message "reached end". If none of these conditions are met, it throws an IllegalStateException with the message "Unable to understand char [char] index [index]".

Once the loop is broken, the method retrieves the current index from the source and adds a new token to the tokens list. This token represents the parsed index and is defined by the TOKEN_INDEX constant.

Overall, the parseIndex method is responsible for parsing an index from a character source and adding it as a token to a list.

sequence diagram

KeyPathNode

The KeyPathNode class is a public class that represents a key element of a JSON Path expression. It implements the ScalarNode and PathElement interfaces. It provides methods for determining the type of element and for converting it to a key representation.

IndexPathNode

The IndexPathNode class is a public class that represents an index element of a JSON Path expression. It is a node in the parse tree that implements the ScalarNode, CharSequence, and PathElement interfaces.

// Overridden Number class methods with their appropriate Javadoc comments

/**

  • Returns the value of this node as an int.
  • @return The int value represented by this object. */ @Override public int intValue()
// Overridden Number class methods with their appropriate Javadoc comments
/**
 * Returns the value of this node as an int.
 *
 * @return The int value represented by this object.
 */
@Override
public int intValue() {
    return source.getInt(token.startIndex, token.endIndex);
}

The intValue method, which is defined in the io.nats.jparse.path.IndexPathNode class, is responsible for returning the value of the node as an int. Here is a step-by-step description of what the method is doing based on its body:

  1. The method is overridden with appropriate Javadoc comments to explain its functionality.

  2. The method signature specifies that the return type is int.

  3. Inside the method body, a call to the source.getInt() method is made, passing two parameters: token.startIndex and token.endIndex. This indicates that the source object has a method called getInt() that accepts the start and end indexes of the token.

  4. The return value of the source.getInt() method is used as the return value of the intValue() method.

Overall, the intValue() method is retrieving the int value from the source object by passing the start and end indexes of the token and returning that value as the result of the method call.

The intValue method in the IndexPathNode class, located in the io.nats.jparse.path package, returns the value of this node as an integer. It retrieves the integer value from the source object, using the start and end indices of the token associated with this node.

sequence diagram

Clone this wiki locally