code: public JsonToken nextToken() {
  
          int c = buffer.read();
          while (c != -1 && Character.isWhitespace(c)) {
              c = buffer.read();
          }
          if (c == -1) {
              return new JsonToken(JsonTokenType.END_OF_FILE, "<eof>");
          }
  
          switch (c) {
              case '{':
                  return new JsonToken(JsonTokenType.BEGIN_OBJECT, "{");
              case '}':
                  return new JsonToken(JsonTokenType.END_OBJECT, "}");
              case '[':
                  return new JsonToken(JsonTokenType.BEGIN_ARRAY, "[");
              case ']':
                  return new JsonToken(JsonTokenType.END_ARRAY, "]");
              case '(':
                  return new JsonToken(JsonTokenType.LEFT_PAREN, "(");
              case ')':
                  return new JsonToken(JsonTokenType.RIGHT_PAREN, ")");
              case ':':
                  return new JsonToken(JsonTokenType.COLON, ":");
              case ',':
                  return new JsonToken(JsonTokenType.COMMA, ",");
              case '\'':
              case '"':
                  return scanString((char) c);
              case '/':
                  return scanRegularExpression();
              default:
                  if (c == '-' || Character.isDigit(c)) {
                      return scanNumber((char) c);
                  } else if (c == '$' || c == '_' || Character.isLetter(c)) {
                      return scanUnquotedString((char) c);
                  } else {
                      int position = buffer.getPosition();
                      buffer.unread(c);
                      throw new JsonParseException("Invalid JSON input. Position: %d. Character: '%c'.", position, c);
                  }
          }
      }
docs: Finds and returns the next complete token from this scanner. If scanner reached the end of the source, it will return a token with
  {@code JSONTokenType.END_OF_FILE} type.
  
  @return The next token.
  @throws JsonParseException if source is invalid.