docs: private AstNode parseCreateIndex( final DdlTokenStream tokens,
                                        final AstNode parentNode ) throws ParsingException {
          assert tokens != null;
          assert parentNode != null;
          assert (tokens.matches(STMT_CREATE_INDEX) || tokens.matches(STMT_CREATE_UNIQUE_INDEX) || tokens.matches(STMT_CREATE_BITMAP_INDEX));
  
          markStartOfStatement(tokens);
          tokens.consume(CREATE);
  
          final boolean isUnique = tokens.canConsume(UNIQUE);
          final boolean isBitmap = tokens.canConsume("BITMAP");
  
          tokens.consume(INDEX);
          final String indexName = parseName(tokens);
  
          tokens.consume(ON);
  
          AstNode indexNode = null;
  
          if (tokens.canConsume("CLUSTER")) {
              // table-cluster_index_clause
              indexNode = nodeFactory().node(indexName, parentNode, TYPE_CREATE_CLUSTER_INDEX_STATEMENT);
              indexNode.setProperty(OracleDdlLexicon.INDEX_TYPE, OracleDdlConstants.IndexTypes.CLUSTER);
  
              final String clusterName = parseName(tokens);
              indexNode.setProperty(OracleDdlLexicon.CLUSTER_NAME, clusterName);
          } else {
              final String tableName = parseName(tokens);
  
              if (!tokens.matches('(')) {
                  // must be a table-index-clause as this has to be table-alias
                  final String tableAlias = tokens.consume();
                  indexNode = nodeFactory().node(indexName, parentNode, TYPE_CREATE_TABLE_INDEX_STATEMENT);
                  indexNode.setProperty(OracleDdlLexicon.INDEX_TYPE, OracleDdlConstants.IndexTypes.TABLE);
                  indexNode.setProperty(OracleDdlLexicon.TABLE_ALIAS, tableAlias);
              }
  
              // parse left-paren content right-paren
              final String columnExpressionList = parseContentBetweenParens(tokens);
  
              // must have FROM and WHERE clauses
              if (tokens.canConsume("FROM")) {
                  indexNode = nodeFactory().node(indexName, parentNode, TYPE_CREATE_BITMAP_JOIN_INDEX_STATEMENT);
                  indexNode.setProperty(OracleDdlLexicon.INDEX_TYPE, OracleDdlConstants.IndexTypes.BITMAP_JOIN);
                  parseTableReferenceList(tokens, indexNode);
  
                  tokens.consume("WHERE");
                  final String whereClause = parseUntilTerminator(tokens); // this will have index attributes also:-(
                  indexNode.setProperty(OracleDdlLexicon.WHERE_CLAUSE, whereClause);
              } else {
                  indexNode = nodeFactory().node(indexName, parentNode, TYPE_CREATE_TABLE_INDEX_STATEMENT);
                  indexNode.setProperty(OracleDdlLexicon.INDEX_TYPE, OracleDdlConstants.IndexTypes.TABLE);
              }
  
              indexNode.setProperty(OracleDdlLexicon.TABLE_NAME, tableName);
              parseIndexColumnExpressionList('(' + columnExpressionList + ')', indexNode);
          }
  
          indexNode.setProperty(UNIQUE_INDEX, isUnique);
          indexNode.setProperty(BITMAP_INDEX, isBitmap);
  
          // index attributes are optional as is UNUSABLE
          if (tokens.hasNext()) {
              boolean unusable = false;
              final List<String> indexAttributes = new ArrayList<String>();
  
              while (tokens.hasNext() && !isTerminator(tokens)) {
                  String token = tokens.consume();
  
                  if ("UNUSABLE".equalsIgnoreCase(token)) {
                      unusable = true;
                      break; // must be last token found before terminator
                  }
  
                  // if number add it to previous
                  boolean processed = false;
  
                  if (token.matches("\\b\\d+\\b")) {
                      if (!indexAttributes.isEmpty()) {
                          final int index = (indexAttributes.size() - 1);
                          final String value = indexAttributes.get(index);
                          final String newValue = (value + SPACE + token);
                          indexAttributes.set(index, newValue);
                          processed = true;
                      }
                  }
  
                  if (!processed) {
                      indexAttributes.add(token);
                  }
              }
  
              if (!indexAttributes.isEmpty()) {
                  indexNode.setProperty(OracleDdlLexicon.INDEX_ATTRIBUTES, indexAttributes);
              }
  
              indexNode.setProperty(OracleDdlLexicon.UNUSABLE_INDEX, unusable);
          }
  
          markEndOfStatement(tokens, indexNode);
          return indexNode;
      }