docs: public IonType next()
      {
          if (has_next_helper() == false) {
              return null;
          }
          int new_state;
  
          switch (_current_state)
          {
          case S_BOF:
              new_state = S_STRUCT;
              break;
  
          case S_STRUCT:
              new_state = S_EOF;
              break;
  
          case S_IN_STRUCT:
              new_state = stateFirstInStruct();
              loadStateData(new_state);
              break;
  
          case S_NAME:
              assert(hasVersion());
              new_state = S_VERSION;
              loadStateData(new_state);
              break;
  
          case S_VERSION:
              if (hasMaxId()) {
                  new_state = S_MAX_ID;
                  loadStateData(new_state);
              }
              else {
                  new_state = stateFollowingMaxId();
              }
              break;
  
          case S_MAX_ID:
              new_state = stateFollowingMaxId();
              break;
  
          case S_IMPORT_LIST:
              new_state = this.stateFollowingImportList(Op.NEXT);
              break;
  
          case S_IN_IMPORTS:
          case S_IMPORT_STRUCT:
              // we only need to get the import list once, which we
              // do as we step into the import list, so it should
              // be waiting for us here.
              assert(_import_iterator != null);
              new_state = nextImport();
              break;
  
          case S_IN_IMPORT_STRUCT:
              // shared tables have to have a name
              new_state = S_IMPORT_NAME;
              loadStateData(new_state);
              break;
  
          case S_IMPORT_NAME:
              // shared tables have to have a version
              new_state = S_IMPORT_VERSION;
              loadStateData(new_state);
              break;
  
          case S_IMPORT_VERSION:
              // and they also always have a max id - so we set up
              // for it
              new_state = S_IMPORT_MAX_ID;
              loadStateData(new_state);
              break;
  
          case S_IMPORT_MAX_ID:
              new_state = S_IMPORT_STRUCT_CLOSE;
              break;
  
          case S_IMPORT_STRUCT_CLOSE:
              // no change here - we just bump up against this local eof
              new_state = S_IMPORT_STRUCT_CLOSE;
              break;
  
          case S_IMPORT_LIST_CLOSE:
              // no change here - we just bump up against this local eof
              new_state = S_IMPORT_LIST_CLOSE;
              break;
  
          case S_AFTER_IMPORT_LIST:
              assert(_symbol_table.getImportedMaxId() < _maxId);
              new_state = S_SYMBOL_LIST;
              break;
  
          case S_SYMBOL_LIST:
              assert(_symbol_table.getImportedMaxId() < _maxId);
              new_state = stateFollowingLocalSymbols();
              break;
  
          case S_IN_SYMBOLS:
              // we have some symbols - so we'll set up to read them,
              // which we *have* to do once and *need* to do only once.
              assert(_local_symbols != null);
              // since we only get into the symbol list if
              // there are some symbols - our next state
              // is at the first symbol
              assert(_local_symbols.hasNext() == true);
              // so we just fall through to and let the S_SYMBOL
              // state do it's thing (which it will do every time
              // we move to the next symbol)
          case S_SYMBOL:
              if (_local_symbols.hasNext())
              {
                  _string_value = _local_symbols.next();
                  // null means this symbol isn't defined
                  new_state = S_SYMBOL;
              }
              else {
                  new_state = S_SYMBOL_LIST_CLOSE;
              }
              break;
  
          case S_SYMBOL_LIST_CLOSE:
              // no change here - we just bump up against this local eof
              new_state = S_SYMBOL_LIST_CLOSE;
              break;
  
          case S_STRUCT_CLOSE:
              // no change here - we just bump up against this local eof
              new_state = S_STRUCT_CLOSE;
              break;
  
          case S_EOF:
              new_state = S_EOF;
              break;
  
          default:
              throwUnrecognizedState(_current_state);
              new_state = -1;
              break;
          }
  
          _current_state = new_state;
          return stateType(_current_state);
      }