class InnerVisitor extends AnalyzedStatementVisitor<Context, AllocationCommand> {

        @Override
        protected AllocationCommand visitAnalyzedStatement(AnalyzedStatement analyzedStatement, Context context) {
            throw new UnsupportedOperationException(
                String.format(Locale.ENGLISH, "Can't handle \"%s\"", analyzedStatement));
        }

        @Override
        public AllocationCommand visitReroutePromoteReplica(AnalyzedPromoteReplica statement,
                                                            Context context) {<FILL_FUNCTION_BODY>}

        @Override
        protected AllocationCommand visitRerouteMoveShard(AnalyzedRerouteMoveShard statement,
                                                          Context context) {
            var boundedMoveShard = statement.rerouteMoveShard().map(context.eval);
            validateShardId(boundedMoveShard.shardId());

            String index = getRerouteIndex(
                statement.shardedTable(),
                Lists.map(statement.partitionProperties(), x -> x.map(context.eval)));
            String toNodeId = resolveNodeId(
                context.nodes,
                DataTypes.STRING.sanitizeValue(boundedMoveShard.toNodeIdOrName()));

            return new MoveAllocationCommand(
                index,
                DataTypes.INTEGER.sanitizeValue(boundedMoveShard.shardId()),
                DataTypes.STRING.sanitizeValue(boundedMoveShard.fromNodeIdOrName()),
                toNodeId
            );
        }

        @Override
        protected AllocationCommand visitRerouteAllocateReplicaShard(AnalyzedRerouteAllocateReplicaShard statement,
                                                                     Context context) {
            var boundedRerouteAllocateReplicaShard = statement
                .rerouteAllocateReplicaShard()
                .map(context.eval);
            validateShardId(boundedRerouteAllocateReplicaShard.shardId());

            String index = getRerouteIndex(
                statement.shardedTable(),
                Lists.map(statement.partitionProperties(), x -> x.map(context.eval)));
            String toNodeId = resolveNodeId(
                context.nodes,
                DataTypes.STRING.sanitizeValue(boundedRerouteAllocateReplicaShard.nodeIdOrName()));

            return new AllocateReplicaAllocationCommand(
                index,
                DataTypes.INTEGER.sanitizeValue(boundedRerouteAllocateReplicaShard.shardId()),
                toNodeId
            );
        }

        @Override
        protected AllocationCommand visitRerouteCancelShard(AnalyzedRerouteCancelShard statement,
                                                            Context context) {
            var boundedRerouteCancelShard = statement
                .rerouteCancelShard()
                .map(context.eval);
            validateShardId(boundedRerouteCancelShard.shardId());

            boolean allowPrimary = validateCancelRerouteProperty(
                "allow_primary", boundedRerouteCancelShard.properties());

            String index = getRerouteIndex(
                statement.shardedTable(),
                Lists.map(statement.partitionProperties(), x -> x.map(context.eval)));
            String nodeId = resolveNodeId(
                context.nodes,
                DataTypes.STRING.sanitizeValue(boundedRerouteCancelShard.nodeIdOrName()));

            return new CancelAllocationCommand(
                index,
                DataTypes.INTEGER.sanitizeValue(boundedRerouteCancelShard.shardId()),
                nodeId,
                allowPrimary
            );
        }

        private static String getRerouteIndex(ShardedTable shardedTable,
                                              List<Assignment<Object>> partitionsProperties) {
            if (shardedTable instanceof DocTableInfo) {
                DocTableInfo docTableInfo = (DocTableInfo) shardedTable;

                String indexName = docTableInfo.ident().indexNameOrAlias();
                PartitionName partitionName = PartitionPropertiesAnalyzer
                    .createPartitionName(partitionsProperties, docTableInfo);
                if (partitionName != null) {
                    indexName = partitionName.asIndexName();
                } else if (docTableInfo.isPartitioned()) {
                    throw new IllegalArgumentException(
                        "table is partitioned however no partition clause has been specified");
                }

                return indexName;
            }

            // Table is a blob table
            assert shardedTable.concreteIndices().length == 1 : "table has to contain only 1 index name";
            return shardedTable.concreteIndices()[0];
        }

        private static boolean validateCancelRerouteProperty(String propertyKey,
                                                             GenericProperties<Object> properties) {
            for (String key : properties.keys()) {
                if (propertyKey.equals(key)) {
                    return DataTypes.BOOLEAN.sanitizeValue(properties.get(propertyKey));
                } else {
                    throw new IllegalArgumentException(
                        String.format(Locale.ENGLISH, "\"%s\" is not a valid setting for CANCEL SHARD", key));
                }
            }
            return false;
        }

        private void validateShardId(Object shardId) {
            if (shardId == null) {
                throw new IllegalArgumentException("Shard Id cannot be [null]");
            }
        }
    }

            var boundedPromoteReplica = statement.promoteReplica().map(context.eval);
            validateShardId(boundedPromoteReplica.shardId());

            String index = getRerouteIndex(
                statement.shardedTable(),
                Lists.map(statement.partitionProperties(), x -> x.map(context.eval)));
            String toNodeId = resolveNodeId(
                context.nodes,
                DataTypes.STRING.sanitizeValue(boundedPromoteReplica.node()));

            return new AllocateStalePrimaryAllocationCommand(
                index,
                DataTypes.INTEGER.sanitizeValue(boundedPromoteReplica.shardId()),
                toNodeId,
                DataTypes.BOOLEAN.sanitizeValue(context.eval.apply(statement.acceptDataLoss()))
            );

        
<no_super_class>