docs: function parseData() {
      var current;
  
      while (true) {
        current = input[i++];
        if (!current) {
          break;
        }
  
        parser.pos_++;
  
        switch (parser.state_) {
          case State.INIT:
            if (current === '{') {
              parser.state_ = State.OBJECT_OPEN;
            } else if (current === '[') {
              parser.state_ = State.ARRAY_OPEN;
            } else if (!isWhitespace(current)) {
              parser.error_(input, i);
            }
            continue;
  
          case State.KEY_START:
          case State.OBJECT_OPEN:
            if (isWhitespace(current)) {
              continue;
            }
            if (parser.state_ === State.KEY_START) {
              stack.push(State.KEY_END);
            } else {
              if (current === '}') {
                addMessage({});
                parser.state_ = nextState();
                continue;
              } else {
                stack.push(State.OBJECT_END);
              }
            }
            if (current === '"') {
              parser.state_ = State.STRING;
            } else {
              parser.error_(input, i);
            }
            continue;
  
  
          case State.KEY_END:
          case State.OBJECT_END:
            if (isWhitespace(current)) {
              continue;
            }
            if (current === ':') {
              if (parser.state_ === State.OBJECT_END) {
                stack.push(State.OBJECT_END);
                parser.depth_++;
              }
              parser.state_ = State.VALUE;
            } else if (current === '}') {
              parser.depth_--;
              addMessage();
              parser.state_ = nextState();
            } else if (current === ',') {
              if (parser.state_ === State.OBJECT_END) {
                stack.push(State.OBJECT_END);
              }
              parser.state_ = State.KEY_START;
            } else {
              parser.error_(input, i);
            }
            continue;
  
          case State.ARRAY_OPEN:
          case State.VALUE:
            if (isWhitespace(current)) {
              continue;
            }
            if (parser.state_ === State.ARRAY_OPEN) {
              parser.depth_++;
              parser.state_ = State.VALUE;
              if (current === ']') {
                parser.depth_--;
                if (parser.depth_ === 0) {
                  parser.state_ = State.ARRAY_END;
                  break;
                }
  
                addMessage([]);
  
                parser.state_ = nextState();
                continue;
              } else {
                stack.push(State.ARRAY_END);
              }
            }
            if (current === '"')
              parser.state_ = State.STRING;
            else if (current === '{')
              parser.state_ = State.OBJECT_OPEN;
            else if (current === '[')
              parser.state_ = State.ARRAY_OPEN;
            else if (current === 't')
              parser.state_ = State.TRUE1;
            else if (current === 'f')
              parser.state_ = State.FALSE1;
            else if (current === 'n')
              parser.state_ = State.NULL1;
            else if (current === '-') {
              // continue
            } else if ('0123456789'.indexOf(current) !== -1) {
              parser.state_ = State.NUM_DIGIT;
            } else {
              parser.error_(input, i);
            }
            continue;
  
          case State.ARRAY_END:
            if (current === ',') {
              stack.push(State.ARRAY_END);
              parser.state_ = State.VALUE;
  
              if (parser.depth_ === 1) {
                msgStart = i;  // skip ',', including a leading one
              }
            } else if (current === ']') {
              parser.depth_--;
              if (parser.depth_ === 0) break;
  
              addMessage();
              parser.state_ = nextState();
            } else if (isWhitespace(current)) {
              continue;
            } else {
              parser.error_(input, i);
            }
            continue;
  
          case State.STRING:
            var start = i - 1;
            var old = i;
  
            STRING_LOOP: while (true) {
              while (parser.unicodeCount_ > 0) {
                current = input[i++];
                if (parser.unicodeCount_ === 4) {
                  parser.unicodeCount_ = 0;
                  start = i - 1;
                } else {
                  parser.unicodeCount_++;
                }
                if (!current) {
                  break STRING_LOOP;
                }
              }
  
              if (current === '"' && !parser.slashed_) {
                parser.state_ = nextState();
                break;
              }
              if (current === '\\' && !parser.slashed_) {
                parser.slashed_ = true;
                current = input[i++];
                if (!current) {
                  break;
                }
              }
              if (parser.slashed_) {
                parser.slashed_ = false;
                if (current === 'u') {
                  parser.unicodeCount_ = 1;
                }
                current = input[i++];
                start = i - 1;
                if (!current) {
                  break;
                } else {
                  continue;
                }
              }
  
              pattern.lastIndex = i;
              var patternResult = pattern.exec(input);
              if (!patternResult) {
                i = input.length + 1;
                break;
              }
              i = patternResult.index + 1;
              current = input[patternResult.index];
              if (!current) {
                break;
              }
            }
  
            parser.pos_ += (i - old);
  
            continue;
  
          case State.TRUE1:
            if (!current) {
              continue;
            }
            if (current === 'r') {
              parser.state_ = State.TRUE2;
            } else {
              parser.error_(input, i);
            }
            continue;
  
          case State.TRUE2:
            if (!current) {
              continue;
            }
            if (current === 'u') {
              parser.state_ = State.TRUE3;
            } else {
              parser.error_(input, i);
            }
            continue;
  
          case State.TRUE3:
            if (!current) {
              continue;
            }
            if (current === 'e') {
              parser.state_ = nextState();
            } else {
              parser.error_(input, i);
            }
            continue;
  
          case State.FALSE1:
            if (!current) {
              continue;
            }
            if (current === 'a') {
              parser.state_ = State.FALSE2;
            } else {
              parser.error_(input, i);
            }
            continue;
  
          case State.FALSE2:
            if (!current) {
              continue;
            }
            if (current === 'l') {
              parser.state_ = State.FALSE3;
            } else {
              parser.error_(input, i);
            }
            continue;
  
          case State.FALSE3:
            if (!current) {
              continue;
            }
            if (current === 's') {
              parser.state_ = State.FALSE4;
            } else {
              parser.error_(input, i);
            }
            continue;
  
          case State.FALSE4:
            if (!current) {
              continue;
            }
            if (current === 'e') {
              parser.state_ = nextState();
            } else {
              parser.error_(input, i);
            }
            continue;
  
          case State.NULL1:
            if (!current) {
              continue;
            }
            if (current === 'u') {
              parser.state_ = State.NULL2;
            } else {
              parser.error_(input, i);
            }
            continue;
  
          case State.NULL2:
            if (!current) {
              continue;
            }
            if (current === 'l') {
              parser.state_ = State.NULL3;
            } else {
              parser.error_(input, i);
            }
            continue;
  
          case State.NULL3:
            if (!current) {
              continue;
            }
            if (current === 'l') {
              parser.state_ = nextState();
            } else {
              parser.error_(input, i);
            }
            continue;
  
          case State.NUM_DECIMAL_POINT:
            if (current === '.') {
              parser.state_ = State.NUM_DIGIT;
            } else {
              parser.error_(input, i);
            }
            continue;
  
          case State.NUM_DIGIT:  // no need for a full validation here
            if ('0123456789.eE+-'.indexOf(current) !== -1) {
              continue;
            } else {
              i--;
              parser.pos_--;
              parser.state_ = nextState();
            }
            continue;
  
          default:
            parser.error_(input, i);
        }
      }
    }