fun parse()

in rd-kt/rd-gen/src/main/kotlin/com/jetbrains/rd/util/kli/Kli.kt [130:238]


    fun parse(cmdline: Array<String>): String? {
        require (state == Init) { "Parsed already" }

        var argumentIdx = 0

        val commands = cmdline.iterator()
        var chars = PushBackCharIterator("") //fake

        val err = { msg:String ->
            error = msg
            Fin
        }

        val parseOption = { option: Option<*>?, presentableName: String ->
            if (option == null) err("Unknown option: $presentableName")
            else when(option) {
                is Option.Flag -> {
                    option._value = true
                    ShortOption
                }
                is Option.Valued<*> -> {
                    val rawValue =
                        if (chars.rem.isEmpty())
                            if (commands.hasNext()) commands.next()
                            else null
                        else
                            chars.rem

                    if (rawValue == null) err("No value provided for option $presentableName")
                    else if (!option.tryParse(rawValue)) err("Can't parse value '$rawValue' for option $presentableName")
                    else StartCmd
                }
            }
        }

        cycle@while (true) {

            state = when (state) {

                Init -> StartCmd

                StartCmd ->
                    if (!commands.hasNext()) Fin
                    else {
                        chars = PushBackCharIterator(commands.next())

                        if (!chars.moveNext()) err("Empty argument")
                        else if (chars.cur == '-') Minus
                        else {
                            chars.pushBack()
                            Argument
                        }
                    }

                Minus ->
                    if (!chars.moveNext()) err("Standalone '-' is not allowed")
                    else if (chars.cur == '-') DoubleMinus
                    else {
                        chars.pushBack()
                        ShortOption
                    }

                DoubleMinus ->
                    if (!chars.moveNext()) err("Standalone '--' is not allowed")
                    else if (chars.cur == '-') err("Triple minus '---' is not allowed")
                    else {
                        chars.pushBack()
                        LongOption
                    }

                ShortOption ->
                    if (!chars.moveNext()) StartCmd //if it's not first long option in a row
                    else {
                        val option = options.firstOrNull {it.short == chars.cur}
                        parseOption(option, "'-${chars.cur}'")
                    }

                LongOption -> {
                    val rawName = buildString {
                        while (chars.moveNext()) {
                            if (chars.cur == '=') break
                            else append(chars.cur)
                        }
                    }
                    if (rawName.isEmpty()) err("Invalid option pattern: '${chars.str}'")
                    else {
                        val option = options.firstOrNull {it.long == rawName}
                        parseOption(option, "'--$rawName'")
                    }
                }

                Argument -> {
                    val rawValue = chars.rem
                    if (argumentIdx >= arguments.size) err("Too many arguments: '$rawValue'")
                    else {
                        val argument = arguments[argumentIdx++]
                        if (!argument.parseValue(rawValue)) err("Can't parse value '$rawValue' for argument '${argument.name}'")
                        else StartCmd
                    }
                }


                Fin -> break@cycle
            }
        }

        if (error == null && argumentIdx < arguments.size) error = "Value of argument '${arguments[argumentIdx].name}' undefined"
        return error
    }