Skip to content

io_nats_jparse_parser_functable

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

io.nats.jparse.parser.functable

class diagram

JsonParserFunctions

The JsonParserFunctions class is a collection of functions that are utilized by the JsonFuncParser to parse JSON.

public static boolean parseKeyNoQuote(final CharSource source, final TokenList tokens)

public static boolean parseKeyNoQuote(final CharSource source, final TokenList tokens) {
    int ch = source.nextSkipWhiteSpace();
    final int startIndex = source.getIndex() - 1;
    final int tokenListIndex = tokens.getIndex();
    tokens.placeHolder();
    boolean found = false;
    switch(ch) {
        case ParseConstants.STRING_START_TOKEN:
            final int strStartIndex = startIndex + 1;
            final int strEndIndex = source.findEndOfEncodedString();
            tokens.add(new Token(strStartIndex + 1, strEndIndex, TokenTypes.STRING_TOKEN));
            found = true;
            break;
        case ParseConstants.OBJECT_END_TOKEN:
            tokens.undoPlaceholder();
            return true;
        default:
            if (Character.isAlphabetic(ch)) {
                final int start = source.getIndex();
                final int end = source.findAttributeEnd();
                tokens.add(new Token(start, end, TokenTypes.STRING_TOKEN));
                found = true;
            } else {
                throw new UnexpectedCharacterException("Parsing key", "Unexpected character found", source);
            }
    }
    boolean done = source.findObjectEndOrAttributeSep();
    if (!done && found) {
        tokens.set(tokenListIndex, new Token(startIndex + 1, source.getIndex(), TokenTypes.ATTRIBUTE_KEY_TOKEN));
    } else if (found && done) {
        throw new UnexpectedCharacterException("Parsing key", "Not found", source);
    }
    return done;
}

The method parseKeyNoQuote in the JsonParserFunctions class takes two parameters: source of type CharSource and tokens of type TokenList. It returns a boolean value.

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

  1. It retrieves the next character from the source and skips any leading white spaces.
  2. It saves the current index of the source minus 1 as startIndex.
  3. It saves the current index of the tokens as tokenListIndex.
  4. It adds a placeholder token to the tokens list.
  5. It initializes a boolean variable found as false.
  6. It enters a switch statement based on the value of the character ch.
    • If ch is equal to ParseConstants.STRING_START_TOKEN:
      • It calculates the start index of the string as strStartIndex by adding 1 to startIndex.
      • It calculates the end index of the string as strEndIndex by calling the findEndOfEncodedString method on the source object.
      • It adds a new Token object to the tokens list with the start index, end index, and type TokenTypes.STRING_TOKEN.
      • It sets found to true.
    • If ch is equal to ParseConstants.OBJECT_END_TOKEN:
      • It undoes the placeholder token added to the tokens list.
      • It returns true.
    • If ch is neither ParseConstants.STRING_START_TOKEN nor ParseConstants.OBJECT_END_TOKEN:
      • If ch is an alphabetic character:
        • It saves the current index of the source as start.
        • It finds the end index of the attribute by calling the findAttributeEnd method on the source object and saves it as end.
        • It adds a new Token object to the tokens list with the start index, end index, and type TokenTypes.STRING_TOKEN.
        • It sets found to true.
      • If ch is not an alphabetic character:
        • It throws an UnexpectedCharacterException with the message "Unexpected character found" and the source object as arguments.
  7. It checks if it needs to find the end of the object or the attribute separator by calling the findObjectEndOrAttributeSep method on the source object. The result is saved in the done variable.
  8. If done is false and found is true:
    • It updates the placeholder token in the tokens list with the start index as startIndex + 1 and the current index of the source as the end index, and the type TokenTypes.ATTRIBUTE_KEY_TOKEN.
  9. If found is true and done is true:
    • It throws an UnexpectedCharacterException with the message "Not found" and the source object as arguments.
  10. It returns the value of done. sequence diagram

public static boolean parseKeyWithEncode(final CharSource source, final TokenList tokens)

public static boolean parseKeyWithEncode(final CharSource source, final TokenList tokens) {
    int ch = source.nextSkipWhiteSpace();
    final int startIndex = source.getIndex() - 1;
    final int tokenListIndex = tokens.getIndex();
    tokens.placeHolder();
    boolean found = false;
    switch(ch) {
        case ParseConstants.STRING_START_TOKEN:
            final int strStartIndex = startIndex + 1;
            final int strEndIndex = source.findEndOfEncodedString();
            tokens.add(new Token(strStartIndex + 1, strEndIndex, TokenTypes.STRING_TOKEN));
            found = true;
            break;
        case ParseConstants.OBJECT_END_TOKEN:
            tokens.undoPlaceholder();
            return true;
        default:
            throw new UnexpectedCharacterException("Parsing key", "Unexpected character found", source);
    }
    boolean done = source.findObjectEndOrAttributeSep();
    if (!done && found) {
        tokens.set(tokenListIndex, new Token(startIndex + 1, source.getIndex(), TokenTypes.ATTRIBUTE_KEY_TOKEN));
    } else if (found && done) {
        throw new UnexpectedCharacterException("Parsing key", "Not found", source);
    }
    return done;
}

parseKeyWithEncode Method Description

The parseKeyWithEncode method is defined in the io.nats.jparse.parser.functable.JsonParserFunctions class. It takes two parameters: source of type CharSource and tokens of type TokenList. The method has a return type of boolean.

The purpose of this method is to parse a key while encoding it, given a character source (source) and a list of tokens (tokens).

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

  1. The method starts by retrieving the next character from the source, skipping any white space characters.

  2. It initializes two variables: startIndex to hold the index of the character in the source minus 1 and tokenListIndex to hold the current index of the tokens list.

  3. A placeholder token is added to the tokens list.

  4. The method enters a switch statement based on the value of the retrieved character.

  5. If the retrieved character is equal to the constant ParseConstants.STRING_START_TOKEN, the method proceeds to parse a string. It initializes two variables: strStartIndex to hold the index of the start of the string plus 1 and strEndIndex to hold the index of the end of the encoded string. A new Token object is created with the start and end indexes, and a token type of TokenTypes.STRING_TOKEN. The newly created token is added to the tokens list. The found variable is set to true.

  6. If the retrieved character is equal to the constant ParseConstants.OBJECT_END_TOKEN, the method undoes the placeholder token and returns true.

  7. If none of the above cases match, an UnexpectedCharacterException is thrown, indicating that an unexpected character was found while parsing the key.

  8. The method then tries to find the end of the object or the attribute separator. The done variable is set to true if the end is found.

  9. If done is false and found is true, the method updates the token at the tokenListIndex in the tokens list with a new Token object that has the updated start and end indexes, and a token type of TokenTypes.ATTRIBUTE_KEY_TOKEN.

  10. If found is true and done is true, an UnexpectedCharacterException is thrown, indicating that the key was not found.

  11. Finally, the method returns the value of the done variable.

This method is used to parse a key while encoding it, and it handles different cases based on the character read from the source. If the key is successfully parsed, the method updates the tokens list accordingly. However, if an unexpected character is encountered or the key is not found, an exception is thrown. sequence diagram

public static boolean parseKeyNoEncode(final CharSource source, final TokenList tokens)

public static boolean parseKeyNoEncode(final CharSource source, final TokenList tokens) {
    int ch = source.nextSkipWhiteSpace();
    final int startIndex = source.getIndex() - 1;
    final int tokenListIndex = tokens.getIndex();
    tokens.placeHolder();
    boolean found = false;
    switch(ch) {
        case ParseConstants.STRING_START_TOKEN:
            final int strStartIndex = startIndex + 1;
            final int strEndIndex = source.findEndString();
            tokens.add(new Token(strStartIndex + 1, strEndIndex, TokenTypes.STRING_TOKEN));
            found = true;
            break;
        case ParseConstants.OBJECT_END_TOKEN:
            tokens.undoPlaceholder();
            return true;
        default:
            throw new UnexpectedCharacterException("Parsing key", "Unexpected character found", source);
    }
    boolean done = source.findObjectEndOrAttributeSep();
    if (!done && found) {
        tokens.set(tokenListIndex, new Token(startIndex + 1, source.getIndex(), TokenTypes.ATTRIBUTE_KEY_TOKEN));
    } else if (found && done) {
        throw new UnexpectedCharacterException("Parsing key", "Not found", source);
    }
    return done;
}

sequence diagram

JsonFuncParser

The JsonFuncParser class is an implementation of the JsonParser interface. It uses a function table to define the behavior of the parser. The function table, which is an array of ParseFunction objects, determines which function to call when parsing a specific character. The function table can be customized by subclassing this class and overriding the initFuncTable method. Additionally, the function table can be configured using the JsonParserBuilder.

private void doParse(final CharSource source, final TokenList tokens, final int ch)

private void doParse(final CharSource source, final TokenList tokens, final int ch) {
    if (ch < 256) {
        funcTable[ch].parse(source, tokens);
    } else {
        defaultFunc.parse(source, tokens);
    }
}

The method doParse defined in class io.nats.jparse.parser.functable.JsonFuncParser is a private method with the following step-by-step description:

  1. Accepts three parameters: source of type CharSource, tokens of type TokenList, and ch of type int.
  2. Checks if the value of ch is less than 256.
  3. If ch is less than 256: a. Retrieves the appropriate parser from the funcTable array at index ch. b. Invokes the parse method on the retrieved parser, passing source and tokens as arguments.
  4. If ch is not less than 256: a. Invokes the parse method on the defaultFunc, passing source and tokens as arguments.

This method essentially determines the appropriate parser to use based on the value of ch and delegates the parsing task to the selected parser using the parse method. sequence diagram

private void parseArray(final CharSource source, final TokenList tokens)

private void parseArray(final CharSource source, final TokenList tokens) {
    final int startSourceIndex = source.getIndex();
    final int tokenListIndex = tokens.getIndex();
    tokens.placeHolder();
    boolean done = false;
    while (!done) {
        done = parseArrayItem(source, tokens);
    }
    final Token arrayToken = new Token(startSourceIndex, source.getIndex(), TokenTypes.ARRAY_TOKEN);
    tokens.set(tokenListIndex, arrayToken);
}

The method parseArray is defined in the class io.nats.jparse.parser.functable.JsonFuncParser. It takes two parameters: source of type CharSource and tokens of type TokenList.

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

  1. It stores the current index of the source in a variable called startSourceIndex.
  2. It also stores the current index of the tokens in a variable called tokenListIndex.
  3. It inserts a placeholder token in the tokens list using the placeHolder() method.
  4. It initializes a boolean variable called done to false.
  5. It enters a while loop that continues until done becomes true.
  6. Inside the while loop, it calls the parseArrayItem() method passing source and tokens as parameters. The parseArrayItem() method is responsible for parsing each item in the array.
  7. After parseArrayItem() returns, it checks the value of done and updates it accordingly.
  8. Once all the items in the array have been parsed, it creates a new Token object called arrayToken using the startSourceIndex, current index of the source, and the type TokenTypes.ARRAY_TOKEN.
  9. Finally, it updates the token at tokenListIndex in the tokens list with the newly created arrayToken.

That's the step-by-step description of what the parseArray method does based on its body. sequence diagram

private boolean parseArrayItem(CharSource source, TokenList tokens)

private boolean parseArrayItem(CharSource source, TokenList tokens) {
    char ch = (char) source.nextSkipWhiteSpace();
    forLoop: for (; ch != ETX; ch = (char) source.nextSkipWhiteSpace()) {
        switch(ch) {
            case ARRAY_END_TOKEN:
                source.next();
                return true;
            case ARRAY_SEP:
                source.next();
                return false;
            default:
                doParse(source, tokens, ch);
                break forLoop;
        }
    }
    if (source.getCurrentChar() == ARRAY_END_TOKEN) {
        source.next();
        return true;
    }
    return false;
}

The parseArrayItem method is defined in the JsonFuncParser class, which is located in the package io.nats.jparse.parser.functable.

This method takes two parameters:

  • source of type CharSource, which represents the source of characters to parse.
  • tokens of type TokenList, which represents the list of tokens that have been parsed so far.

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

  1. Retrieve the next character from the source and assign it to the variable ch. Skip any whitespace characters.
  2. Start a for loop that iterates until the character ETX (end of text) is encountered.
  3. Within the for loop, check the value of ch using a switch statement.
  4. If ch is equal to ARRAY_END_TOKEN (representing the end of the array), move the source to the next character and return true to indicate that the array item has been successfully parsed.
  5. If ch is equal to ARRAY_SEP (representing the separator between array items), move the source to the next character and return false to indicate that more array items need to be parsed.
  6. If none of the above cases match (i.e., ch is any other character), call the doParse method to further parse the item using the current character ch. Then, break out of the for loop to stop parsing the current array item and move on to the next one.
  7. After the for loop ends, check if the current character in the source is equal to ARRAY_END_TOKEN.
  8. If it is, move the source to the next character and return true to indicate that the array item has been successfully parsed.
  9. If the current character in the source is not equal to ARRAY_END_TOKEN, return false to indicate that the array item has not been fully parsed yet.

That's the step-by-step description of what the parseArrayItem method does based on its body. sequence diagram

private boolean parseValue(final CharSource source, TokenList tokens)

private boolean parseValue(final CharSource source, TokenList tokens) {
    int ch = source.nextSkipWhiteSpace();
    final int startIndex = source.getIndex();
    final int tokenListIndex = tokens.getIndex();
    tokens.placeHolder();
    doParse(source, tokens, ch);
    ch = source.skipWhiteSpace();
    switch(ch) {
        case OBJECT_END_TOKEN:
            if (source.getIndex() == tokenListIndex) {
                throw new UnexpectedCharacterException("Parsing Value", "Key separator before value", source);
            }
            tokens.set(tokenListIndex, new Token(startIndex, source.getIndex(), TokenTypes.ATTRIBUTE_VALUE_TOKEN));
            return true;
        case OBJECT_ATTRIBUTE_SEP:
            if (source.getIndex() == tokenListIndex) {
                throw new UnexpectedCharacterException("Parsing Value", "Key separator before value", source);
            }
            tokens.set(tokenListIndex, new Token(startIndex, source.getIndex(), TokenTypes.ATTRIBUTE_VALUE_TOKEN));
            return false;
        default:
            throw new UnexpectedCharacterException("Parsing Value", "Unexpected character", source, source.getCurrentChar());
    }
}

The parseValue method in the JsonFuncParser class is used to parse a JSON value from a given source and add it to a list of tokens. Here is a step-by-step description of the method's functionality:

  1. Get the next character from the source, skipping any white spaces.
  2. Store the current index of the source as the starting index of the value.
  3. Store the current index of the tokens list.
  4. Create a placeholder token in the tokens list to represent the parsed value. This placeholder will be replaced later with the actual value token.
  5. Call the doParse method to parse the value and update the tokens list.
  6. Get the next character from the source after parsing the value, skipping any white spaces.
  7. Check the value of the next character using a switch statement.
  8. If the next character is an object end token, check that the source index is equal to the token list index. If it is not, throw an UnexpectedCharacterException indicating that there was a key separator before the value. Otherwise, update the placeholder token in the token list with the correct start and end indexes and set its type as ATTRIBUTE_VALUE_TOKEN. Finally, return true to indicate that the parsing is successful.
  9. If the next character is an object attribute separator, perform the same check as in step 8. If the check fails, throw an UnexpectedCharacterException indicating that there was a key separator before the value. Otherwise, update the placeholder token in the token list with the correct start and end indexes and set its type as ATTRIBUTE_VALUE_TOKEN. Finally, return false to indicate that the parsing is not yet complete.
  10. If none of the above cases match, throw an UnexpectedCharacterException indicating that there is an unexpected character in the value, along with the current character from the source.

This method is responsible for parsing a JSON value from a source and adding it to the tokens list, while also handling different scenarios such as object end token and object attribute separator. sequence diagram

private void parseObject(final CharSource source, TokenList tokens)

private void parseObject(final CharSource source, TokenList tokens) {
    final int startSourceIndex = source.getIndex();
    final int tokenListIndex = tokens.getIndex();
    tokens.placeHolder();
    boolean done = false;
    while (!done) {
        done = parseKey.parse(source, tokens);
        if (!done)
            done = parseValue(source, tokens);
    }
    source.next();
    tokens.set(tokenListIndex, new Token(startSourceIndex, source.getIndex(), TokenTypes.OBJECT_TOKEN));
}

The parseObject() method in the class io.nats.jparse.parser.functable.JsonFuncParser is responsible for parsing a JSON object. Here is a step-by-step description of what this method is doing based on its body:

  1. The method begins by creating two local variables: startSourceIndex and tokenListIndex. These variables are assigned the current index of the source and tokens.

  2. The tokens.placeHolder() method is called to create a placeholder token in the tokens list.

  3. A boolean variable named done is declared and initialized as false. This variable is used to indicate whether the parsing of the object is complete.

  4. A while loop is started with the condition !done. This loop continues until the parsing of the object is complete.

  5. The parseKey.parse(source, tokens) method is called to parse a key from the source. If the parsing is successful and returns true, the value of done is set to true, indicating that the parsing of the object is complete. If the parsing of the key is not successful, the method parseValue(source, tokens) is called to parse a value.

  6. Once the parsing of the object is complete, the source.next() method is called to move the index of the source to the next character.

  7. The tokens.set(tokenListIndex, new Token(startSourceIndex, source.getIndex(), TokenTypes.OBJECT_TOKEN)) method is called to set the token at tokenListIndex to a new Token object representing the parsed JSON object. The startSourceIndex is the starting index of the object, and the current index of the source is the ending index of the object. The TokenTypes.OBJECT_TOKEN indicates that the token represents an object.

In summary, the parseObject() method parses a JSON object by repeatedly calling methods to parse keys and values until the entire object is parsed. It then updates the tokens list with a new token representing the parsed object. sequence diagram

Clone this wiki locally