<commit_before>package me.sargunvohra.lib.klap

import me.sargunvohra.lib.cakeparse.api.*
import me.sargunvohra.lib.cakeparse.lexer.TokenInstance
import me.sargunvohra.lib.klap.internal.KlapResult
import me.sargunvohra.lib.klap.annotation.ListArg
import me.sargunvohra.lib.klap.exception.KlapInvalidArgException
import me.sargunvohra.lib.klap.exception.KlapMissingKeyException
import me.sargunvohra.lib.klap.exception.MissingConstructorException
import me.sargunvohra.lib.klap.internal.Arg
import me.sargunvohra.lib.klap.internal.KlapGrammar
import kotlin.reflect.*
import kotlin.reflect.jvm.jvmName

object Klap {

    private fun Iterable<String>.toTokens() = map {
        when {
            it.startsWith("--") -> TokenInstance(KlapGrammar.longFlag, it.substring(2), -1, -1, -1)
            it.startsWith("-") -> TokenInstance(KlapGrammar.shortFlag, it.substring(1), -1, -1, -1)
            else -> TokenInstance(KlapGrammar.word, it, -1, -1, -1)
        }
    }.asSequence()

    private fun Sequence<TokenInstance>.toParsed() = parseToEnd(KlapGrammar.goal).value

    private fun List<Arg>.toInitialResult() = fold(KlapResult()) { total, arg ->
        when (arg) {
            is Arg.FlagArgs -> total.copy(
                    flagArgs = total.flagArgs + arg.keys
            )
            is Arg.ValueArgs -> total.copy(
                    valueArgs = total.valueArgs + arg.pair,
                    flagArgs = total.flagArgs + arg.extraFlags.keys
            )
            is Arg.WordArgs -> total.copy(
                    wordArgs = total.wordArgs + arg.values
            )
        }
    }

    private fun List<Arg>.toResult(flags: Set<String>, keys: Set<String>): KlapResult {
        val initial = toInitialResult()
        var current = initial

        current.valueArgs.forEach {
            val (key, value) = it
            if (!keys.contains(key))
                current = current.copy(
                        flagArgs = current.flagArgs + key,
                        valueArgs = current.valueArgs.toSortedMap().apply { remove(key) },
                        wordArgs = current.wordArgs + value
                )
        }

        current.flagArgs.forEach {
            require(flags.contains(it)) { throw KlapInvalidArgException(if (it.length == 1) "-$it" else "--$it") }
        }

        return current
    }

    fun <T: Any> parseArgs(input: Iterable<String>, target: KClass<T>): T {
        val constructor = target.primaryConstructor
                ?: throw MissingConstructorException(target.simpleName ?: target.jvmName)

        val nameToParameter = constructor.parameters.associate { it.name!! to it }

        val groups = nameToParameter.toList().groupBy { it.second.type }

        val flagToParameter = groups[Boolean::class.defaultType]?.toMap() ?: emptyMap()
        val keyToParameter = groups[String::class.defaultType]?.toMap() ?: emptyMap()
        val listParameter = constructor.parameters.find { it.annotations.any { it.annotationClass == ListArg::class } }<commit_msg>fix bug causing test to fail<commit_after>package me.sargunvohra.lib.klap

import me.sargunvohra.lib.cakeparse.api.*
import me.sargunvohra.lib.cakeparse.lexer.TokenInstance
import me.sargunvohra.lib.klap.internal.KlapResult
import me.sargunvohra.lib.klap.annotation.ListArg
import me.sargunvohra.lib.klap.exception.KlapInvalidArgException
import me.sargunvohra.lib.klap.exception.KlapMissingKeyException
import me.sargunvohra.lib.klap.exception.MissingConstructorException
import me.sargunvohra.lib.klap.internal.Arg
import me.sargunvohra.lib.klap.internal.KlapGrammar
import kotlin.reflect.*
import kotlin.reflect.jvm.jvmName

object Klap {

    private fun Iterable<String>.toTokens() = map {
        when {
            it.startsWith("--") -> TokenInstance(KlapGrammar.longFlag, it.substring(2), -1, -1, -1)
            it.startsWith("-") -> TokenInstance(KlapGrammar.shortFlag, it.substring(1), -1, -1, -1)
            else -> TokenInstance(KlapGrammar.word, it, -1, -1, -1)
        }
    }.asSequence()

    private fun Sequence<TokenInstance>.toParsed() = parseToEnd(KlapGrammar.goal).value

    private fun List<Arg>.toInitialResult() = fold(KlapResult()) { total, arg ->
        when (arg) {
            is Arg.FlagArgs -> total.copy(
                    flagArgs = total.flagArgs + arg.keys
            )
            is Arg.ValueArgs -> total.copy(
                    valueArgs = total.valueArgs + arg.pair,
                    flagArgs = total.flagArgs + arg.extraFlags.keys
            )
            is Arg.WordArgs -> total.copy(
                    wordArgs = total.wordArgs + arg.values
            )
        }
    }

    private fun List<Arg>.toResult(flags: Set<String>, keys: Set<String>): KlapResult {
        val initial = toInitialResult()
        var current = initial

        val hold = current.wordArgs
        current = current.copy(wordArgs = emptyList())

        current.valueArgs.forEach {
            val (key, value) = it
            if (!keys.contains(key))
                current = current.copy(
                        flagArgs = current.flagArgs + key,
                        valueArgs = current.valueArgs.toSortedMap().apply { remove(key) },
                        wordArgs = current.wordArgs + value
                )
        }

        current = current.copy(wordArgs = current.wordArgs + hold)

        current.flagArgs.forEach {
            require(flags.contains(it)) { throw KlapInvalidArgException(if (it.length == 1) "-$it" else "--$it") }
        }

        return current
    }

    fun <T: Any> parseArgs(input: Iterable<String>, target: KClass<T>): T {
        val constructor = target.primaryConstructor
                ?: throw MissingConstructorException(target.simpleName ?: target.jvmName)

        val nameToParameter = constructor.parameters.associate { it.name!! to it }

        val groups = nameToParameter.toList().groupBy { it.second.type }

        val flagToParameter = groups[Boolean::class.defaultType]?.toMap() ?: emptyMap()
        val keyToParameter = groups[String::class.defaultType]?.toMap() ?: emptyMap()
        val listParameter = constructor.parameters.find { it.annotations.any { it.annotationClass == ListArg::class } }
{'fraction_non_alphanumeric': 0.11734447837968172, 'fraction_numerical': 0.003857900659058029, 'mean_word_length': 2.385201305767138, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7652138', 'n_tokens_mistral': 1899, 'n_tokens_neox': 1846, 'n_words': 341}