Skip to content

io_nats_jparse_node_support

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

io.nats.jparse.node.support

PathUtils

The PathUtils class is a public class that provides utility methods for working with file paths.

private static Object walkFull(Object object, AtomicInteger i)

private static Object walkFull(Object object, AtomicInteger i) {
    if (object instanceof Map) {
        Map map = (Map) object;
        ((Map<?, ?>) object).keySet().forEach(key -> {
            walkFull(map.get(key), i);
            i.incrementAndGet();
        });
    } else if (object instanceof List) {
        List list = (List) object;
        list.forEach(o -> {
            walkFull(o, i);
            i.incrementAndGet();
        });
    } else {
        return i.incrementAndGet();
    }
    return i;
}

The walkFull method in class io.nats.jparse.node.support.PathUtils is a recursive method that performs a full traversal of an input object and returns the total number of nodes visited.

Here is a step-by-step description of what the walkFull method does:

  1. The method takes two parameters:

    • object - the input object to be traversed
    • i - an AtomicInteger used to track the number of nodes visited
  2. The method checks if the input object is an instance of a Map:

    • If object is a Map, it casts it to a Map and proceeds to step 3.
    • If not, it checks if the input object is an instance of a List:
      • If object is a List, it casts it to a List and proceeds to step 4.
      • If not, it proceeds to step 5.
  3. When object is a Map, it iterates over all the keys in the map using the keySet().forEach method:

    • For each key, it recursively calls the walkFull method passing the value associated with that key and the i parameter.
    • After the recursive call, it increments the value of i by calling i.incrementAndGet().
  4. When object is a List, it iterates over all the elements in the list using the forEach method:

    • For each element, it recursively calls the walkFull method passing the element and the i parameter.
    • After the recursive call, it increments the value of i by calling i.incrementAndGet().
  5. When object is neither a Map nor a List, it means it is a leaf node in the traversal and cannot be further traversed.

    • In this case, it returns the current value of i incremented by calling i.incrementAndGet().
  6. After traversing all the nodes in the input object, the method returns the final value of i.

The purpose of this method is to recursively traverse a given object and count the number of nodes (maps, lists, and leaf nodes) present in the object.

sequence diagram

MockTokenSubList

MockTokenSubList Class

The MockTokenSubList class is a public class that extends the TokenSubList class. This class serves as a mock implementation of the TokenSubList class. It provides a subset view of a list of tokens, allowing for efficient processing and manipulation of the token data. By extending the TokenSubList class, the MockTokenSubList class inherits the behavior and functionality of the parent class, while also providing additional mock functionality for testing purposes.

CharArrayUtils

The CharArrayUtils class is a utility class designed for working with character arrays. It provides various methods and functions that can be used to manipulate and perform operations on character arrays efficiently.

public static String decodeJsonString(char[] chars, int startIndex, int endIndex)

public static String decodeJsonString(char[] chars, int startIndex, int endIndex) {
    int length = endIndex - startIndex;
    char[] builder = new char[calculateLengthAfterEncoding(chars, startIndex, endIndex, length)];
    char c;
    int index = startIndex;
    int idx = 0;
    while (true) {
        c = chars[index];
        if (c == '\\' && index < (endIndex - 1)) {
            index++;
            c = chars[index];
            if (c != 'u') {
                builder[idx] = controlMap[c];
                idx++;
            } else {
                if (index + 4 < endIndex) {
                    char unicode = getUnicode(chars, index);
                    builder[idx] = unicode;
                    index += 4;
                    idx++;
                }
            }
        } else {
            builder[idx] = c;
            idx++;
        }
        if (index >= (endIndex - 1)) {
            break;
        }
        index++;
    }
    return new String(builder);
}

The decodeJsonString method, defined in the io.nats.jparse.node.support.CharArrayUtils class, decodes a JSON string from a character array. Here's a step-by-step description of what the method does:

  1. The method takes three parameters: chars is the character array containing the JSON string, startIndex is the starting index of the substring to decode, and endIndex is the ending index of the substring to decode.

  2. It calculates the length of the substring by subtracting the startIndex from the endIndex.

  3. It creates a new character array called builder with a length determined by the calculateLengthAfterEncoding method, passing in the chars, startIndex, endIndex, and length parameters.

  4. It initializes a variable c to store the current character being processed, an index variable to keep track of the current index in the chars array, and an idx variable to keep track of the current index in the builder array.

  5. Enter a loop that continues until break is called:

    1. Get the current character c from the chars array at the current index.
    2. Check if the current character c is a single quote (') and if the index is less than (<) (endIndex - 1).
    3. If the above conditions are satisfied, increment the index by 1 and get the next character c from the chars array.
      • If the next character c is not a lowercase 'u', it means it is not a Unicode character, so it can be converted to its corresponding control character using the controlMap array. The converted character is then stored in the builder array at the current idx index, and idx is incremented by 1.
      • If the next character c is a lowercase 'u', it means it is a Unicode character. Check if there are at least 4 more characters (index + 4 < endIndex) in the chars array to form a complete Unicode escape sequence. If so, call the getUnicode method to convert the escape sequence to the corresponding Unicode character, store it in the builder array at the current idx index, and increment both index and idx by 1.
    4. If the current character c is not a single quote, store it in the builder array at the current idx index, and increment idx by 1.
    5. Check if the index is greater than or equal to (endIndex - 1). If so, break the loop.
  6. Convert the builder character array to a string using the String constructor and return the decoded JSON string.

Note: The specific details of the calculateLengthAfterEncoding and getUnicode methods are not provided in the given code snippet, so their functionality cannot be described accurately.

sequence diagram

private static int calculateLengthAfterEncoding(char[] chars, int startIndex, int endIndex, int length)

private static int calculateLengthAfterEncoding(char[] chars, int startIndex, int endIndex, int length) {
    char c;
    int index = startIndex;
    int controlCharCount = length;
    while (true) {
        c = chars[index];
        if (c == '\\' && index < (endIndex - 1)) {
            index++;
            c = chars[index];
            if (c != 'u') {
                controlCharCount -= 1;
            } else {
                if (index + 4 < endIndex) {
                    controlCharCount -= 5;
                    index += 4;
                }
            }
        }
        if (index >= (endIndex - 1)) {
            break;
        }
        index++;
    }
    return controlCharCount;
}

The calculateLengthAfterEncoding method in the CharArrayUtils class is used to calculate the length of a character array after encoding.

Here is a step-by-step description of what this method does:

  1. Start by initializing the variables c, index, and controlCharCount with the given startIndex, length, and startIndex, respectively.

  2. Enter an infinite while loop.

  3. At each iteration of the loop, get the character c at the current index index from the chars array.

  4. Check if the character c is a single quote (') and if the current index index is less than the endIndex - 1. If both conditions are true, proceed further.

  5. Increment the index by 1 and get the next character c at the updated index.

  6. Check if the character c is not equal to the letter 'u'. If true, decrement the controlCharCount by 1.

  7. If the character c is equal to 'u', check if the current index index plus 4 is less than the endIndex. If true, proceed further.

  8. Decrement the controlCharCount by 5.

  9. Increment the index by 4 to skip over the following 4 characters.

  10. Check if the index is greater than or equal to endIndex - 1. If true, break out of the loop and exit.

  11. Increment the index by 1.

  12. Go back to the start of the loop.

  13. After exiting the loop, return the final value of controlCharCount.

Note: This method is used to calculate the length of the character array after encoding by subtracting the length of certain special characters.

sequence diagram

public static boolean hasEscapeChar(char[] array, int startIndex, int endIndex)

public static boolean hasEscapeChar(char[] array, int startIndex, int endIndex) {
    char currentChar;
    for (int index = startIndex; index < endIndex; index++) {
        currentChar = array[index];
        if (currentChar == ESCAPE) {
            return true;
        }
    }
    return false;
}

Method Name: hasEscapeChar

Description:

This method, hasEscapeChar, is defined in the io.nats.jparse.node.support.CharArrayUtils class. It takes in a character array array, a start index startIndex, and an end index endIndex as parameters.

The method iterates through the array from the startIndex to the endIndex (exclusive) using a for loop. For each character currentChar in the array, it checks if it is equal to a constant called ESCAPE.

If the currentChar is equal to ESCAPE, the method returns true. Otherwise, it continues to the next character in the array.

If no character in the range from startIndex to endIndex is equal to ESCAPE, the method returns false.

sequence diagram

TokenSubList

A TokenSubList is a Java class that extends the AbstractList<Token> interface. It represents a sublist implementation for storing a portion of tokens from a TokenList. This class provides methods for accessing tokens within the sublist, getting the size of the sublist, creating sublists, converting the sublist to an array, and counting the number of children tokens within a specified range relative to a root token. It is designed to be used as part of tokenization or parsing processes in software engineering.

public int countChildren(final int from, final Token rootToken)

public int countChildren(final int from, final Token rootToken) {
    int idx = from;
    int count = 0;
    final Token[] tokens = this.tokens;
    final int length = this.size;
    final int offset = this.offset;
    final int rootTokenStart = rootToken.startIndex;
    final int rootTokenEnd = rootToken.endIndex;
    for (; idx < length; idx++) {
        Token token = tokens[idx + offset];
        if (token.startIndex >= rootTokenStart && token.endIndex <= rootTokenEnd) {
            count++;
        } else {
            break;
        }
    }
    return count;
}

The countChildren method in the TokenSubList class, defined in the io.nats.jparse.node.support package, counts the number of child tokens within a specified range, starting from a given index.

Here are the step-by-step details of what the method does based on its body:

  1. Declare two integer variables, idx and count, and initialize them to the values of the from parameter, which represents the starting index, and 0 respectively.
  2. Create a reference to the tokens array of the current TokenSubList instance.
  3. Assign the size of the TokenSubList object to the length variable for easier access.
  4. Assign the offset of the TokenSubList object to the offset variable for easier access.
  5. Get the startIndex and endIndex of the provided rootToken object.
  6. Start a loop which iterates from idx to length - 1.
  7. Inside the loop: a. Get the Token object at the current idx + offset index from the tokens array. b. Check if the startIndex of the token is greater than or equal to the rootTokenStart and the endIndex is less than or equal to the rootTokenEnd. c. If the above condition is true, increment the count variable by one. d. If the above condition is false, break out of the loop.
  8. Return the final value of the count variable, which represents the number of child tokens within the specified range and starting from the given index.

sequence diagram

TokenList

The TokenList class is an implementation of a list that stores tokens. It provides methods for adding tokens, accessing tokens by index, clearing the list, creating sub lists, and more. The class also includes methods for managing placeholder tokens and creating compact clones of the list.

@Override

public final boolean add(Token token)

@Override
public final boolean add(Token token) {
    final int length = tokens.length;
    if (index >= length) {
        final Token[] newTokens = new Token[length * 2];
        System.arraycopy(tokens, 0, newTokens, 0, length);
        tokens = newTokens;
    }
    tokens[index] = token;
    index++;
    return true;
}

The add method in class io.nats.jparse.node.support.TokenList is used to add a Token object to the list of tokens.

Here is a step-by-step description of how the method works:

  1. The method is marked as @Override, indicating that it is overriding a method from a superclass or interface.

  2. The method signature indicates that it returns a boolean value.

  3. The method takes a single parameter, token, which is of type Token. This is the object that will be added to the list.

  4. The method begins by getting the length of the current tokens array.

  5. It checks if the index variable (which presumably tracks the current index where the next token will be added) is greater than or equal to the length of the array. If it is, this means that the array is full and needs to be expanded.

  6. If the array needs to be expanded, a new array, newTokens, is created with a length that is double the current length of the array.

  7. The System.arraycopy method is then used to copy the contents of the tokens array into the newTokens array. This ensures that the existing tokens are retained in the new array.

  8. The tokens member variable is then updated to point to the new array.

  9. The token parameter is added to the tokens array at the current index position.

  10. The index variable is incremented to prepare for the next token to be added.

  11. Finally, the method returns true, indicating that the token was successfully added to the list.

Overall, the add method ensures that the list of tokens has sufficient capacity to accommodate new tokens, and adds the specified token to the list, updating the index accordingly.

sequence diagram

public void placeHolder()

public void placeHolder() {
    final int length = tokens.length;
    if (index >= length) {
        final Token[] newTokens = new Token[length * 2];
        System.arraycopy(tokens, 0, newTokens, 0, length);
        tokens = newTokens;
    }
    index++;
}

The placeHolder method in the io.nats.jparse.node.support.TokenList class is used to increment the index of the TokenList object and potentially expand its internal array if the index is greater than or equal to the length of the array.

Here is a step-by-step description of what the placeHolder method does based on its body:

  1. Get the length of the tokens array using the length field.
  2. Check if the current value of the index field is greater than or equal to the length of the tokens array.
  3. If the condition is true, it means that the TokenList object has reached the end of its internal array.
  4. In this case, create a new array of Token objects named newTokens with a length of twice the current length of the tokens array.
  5. Use the System.arraycopy method to copy the elements from the existing tokens array to the newTokens array.
    • The starting index for copying is 0 (meaning copying from the beginning of the array).
    • The destination array is the newTokens array.
    • The starting index for pasting in the destination array is also 0.
    • The number of elements to copy is equal to the length of the tokens array.
  6. Set the tokens field of the TokenList object to the newTokens array. This effectively expands the internal array.
  7. Increment the value of the index field by 1.

The purpose of this method is to provide a mechanism for adding new Token objects to the TokenList object. If the index is already at the end of the array, the method will automatically expand the array to accommodate the new elements.

sequence diagram

public TokenList compactClone()

public TokenList compactClone() {
    final int length = index;
    final Token[] newTokens = new Token[index];
    System.arraycopy(tokens, 0, newTokens, 0, length);
    return new TokenList(newTokens);
}

The compactClone method in the TokenList class is used to create a new instance of TokenList that contains a compact clone of the tokens in the original TokenList object.

Here is a step-by-step description of what the method does:

  1. It starts by creating a local variable length and assigning it the value of the index field of the current object. This index field represents the number of tokens currently stored in the TokenList object.

  2. It then creates a new array of Token objects called newTokens with a length equal to the index field. This ensures that the new array is large enough to hold all the tokens.

  3. It uses the System.arraycopy method to copy the contents of the tokens array from the original TokenList object to the newTokens array. This ensures that the newTokens array contains a clone of the tokens in the original array.

  4. Finally, it creates a new TokenList object by passing the newTokens array to its constructor and returns this new object.

In summary, the compactClone method creates a new TokenList object that contains a compact clone of the tokens in the original TokenList object by copying the contents of the tokens array to a new array.

sequence diagram

CharSequenceUtils

The CharSequenceUtils class is a utility class that provides various methods for working with CharSequence objects. It offers convenient functions to manipulate and process character sequences efficiently.

NodeUtils

The NodeUtils class is a utility class that provides functionality for working with Node objects. It provides various methods to perform operations on nodes, making it easier to manipulate and interact with these objects.

public static Node createNode(final List tokens, final CharSource source, boolean objectsKeysCanBeEncoded)

public static Node createNode(final List<Token> tokens, final CharSource source, boolean objectsKeysCanBeEncoded) {
    final NodeType nodeType = NodeType.tokenTypeToElement(tokens.get(0).type);
    switch(nodeType) {
        case ARRAY:
            return new ArrayNode((TokenSubList) tokens, source, objectsKeysCanBeEncoded);
        case INT:
            return new NumberNode(tokens.get(0), source, NodeType.INT);
        case FLOAT:
            return new NumberNode(tokens.get(0), source, NodeType.FLOAT);
        case OBJECT:
            return new ObjectNode((TokenSubList) tokens, source, objectsKeysCanBeEncoded);
        case STRING:
            return new StringNode(tokens.get(0), source);
        case BOOLEAN:
            return new BooleanNode(tokens.get(0), source);
        case NULL:
            return new NullNode(tokens.get(0), source);
        case PATH_INDEX:
            return new IndexPathNode(tokens.get(0), source);
        case PATH_KEY:
            return new KeyPathNode(tokens.get(0), source);
        default:
            throw new IllegalStateException();
    }
}

The createNode method in the NodeUtils class is responsible for creating a Node object based on the provided list of tokens and other parameters. Here is a step-by-step explanation of what this method does:

  1. The method takes three parameters:

    • tokens - a list of Token objects
    • source - a CharSource object
    • objectsKeysCanBeEncoded - a boolean value indicating whether object keys can be encoded
  2. It extracts the type of the first token in the list using the type field of the Token object and maps it to a corresponding NodeType using NodeType.tokenTypeToElement(tokens.get(0).type).

  3. It uses a switch statement to determine the type of Node object to create based on the mapped NodeType.

  4. If the NodeType is ARRAY, it creates a new ArrayNode object using the tokens, source, and objectsKeysCanBeEncoded parameters, and returns it.

  5. If the NodeType is INT, it creates a new NumberNode object with the first token, source, and NodeType.INT, and returns it.

  6. If the NodeType is FLOAT, it creates a new NumberNode object with the first token, source, and NodeType.FLOAT, and returns it.

  7. If the NodeType is OBJECT, it creates a new ObjectNode object using the tokens, source, and objectsKeysCanBeEncoded parameters, and returns it.

  8. If the NodeType is STRING, it creates a new StringNode object with the first token and source, and returns it.

  9. If the NodeType is BOOLEAN, it creates a new BooleanNode object with the first token and source, and returns it.

  10. If the NodeType is NULL, it creates a new NullNode object with the first token and source, and returns it.

  11. If the NodeType is PATH_INDEX, it creates a new IndexPathNode object with the first token and source, and returns it.

  12. If the NodeType is PATH_KEY, it creates a new KeyPathNode object with the first token and source, and returns it.

  13. If none of the above NodeType cases match, it throws an IllegalStateException.

That's the step-by-step description of the createNode method in the NodeUtils class.

sequence diagram

public static Node createNodeForObject(final List theTokens, final CharSource source, boolean objectsKeysCanBeEncoded)

public static Node createNodeForObject(final List<Token> theTokens, final CharSource source, boolean objectsKeysCanBeEncoded) {
    final Token rootToken = theTokens.get(1);
    final List<Token> tokens = theTokens.subList(1, theTokens.size());
    final NodeType nodeType = NodeType.tokenTypeToElement(rootToken.type);
    switch(nodeType) {
        case ARRAY:
            return new ArrayNode((TokenSubList) tokens, source, objectsKeysCanBeEncoded);
        case INT:
            return new NumberNode(tokens.get(0), source, NodeType.INT);
        case FLOAT:
            return new NumberNode(tokens.get(0), source, NodeType.FLOAT);
        case OBJECT:
            return new ObjectNode((TokenSubList) tokens, source, objectsKeysCanBeEncoded);
        case STRING:
            return new StringNode(tokens.get(0), source);
        case BOOLEAN:
            return new BooleanNode(tokens.get(0), source);
        case NULL:
            return new NullNode(tokens.get(0), source);
        default:
            throw new IllegalStateException();
    }
}

The createNodeForObject method, defined in the NodeUtils class in the io.nats.jparse.node.support package, takes in a list of tokens, a character source, and a boolean indicating whether object keys can be encoded. It returns a Node object based on the type of the root token.

Here is a step-by-step description of what the method does:

  1. It retrieves the root token from the input list of tokens and assigns it to the local variable rootToken.
  2. It creates a new sublist of tokens (tokens) by excluding the first token (root token) from the input list using the subList method.
  3. It determines the NodeType (enumeration) corresponding to the type of the root token using the tokenTypeToElement method and assigns it to the local variable nodeType.
  4. It uses a switch statement on the nodeType to handle different cases:
    • If the nodeType is ARRAY, it creates a new ArrayNode object passing in the tokens, source, and objectsKeysCanBeEncoded arguments and returns it.
    • If the nodeType is INT, it creates a new NumberNode object passing in the first token from tokens, source, and the NodeType.INT enum value, and returns it.
    • If the nodeType is FLOAT, it creates a new NumberNode object passing in the first token from tokens, source, and the NodeType.FLOAT enum value, and returns it.
    • If the nodeType is OBJECT, it creates a new ObjectNode object passing in the tokens, source, and objectsKeysCanBeEncoded arguments and returns it.
    • If the nodeType is STRING, it creates a new StringNode object passing in the first token from tokens and source, and returns it.
    • If the nodeType is BOOLEAN, it creates a new BooleanNode object passing in the first token from tokens and source, and returns it.
    • If the nodeType is NULL, it creates a new NullNode object passing in the first token from tokens and source, and returns it.
    • If none of the above cases match, it throws an IllegalStateException.
  5. The method ends.

This method is responsible for creating and returning different types of Node objects based on the type of the root token.

sequence diagram

NumberParseResult

NumberParseResult

The NumberParseResult class represents the result of a number parsing operation. It provides methods to access the end index of the parsed number and to check if the parsed number was a float. The class also overrides the equals, hashCode, and toString methods for proper object comparison and string representation.

Clone this wiki locally