diff --git a/ConsumePlugin/GeneratedArgs.fs b/ConsumePlugin/GeneratedArgs.fs index b8fcb42..ce7f2b7 100644 --- a/ConsumePlugin/GeneratedArgs.fs +++ b/ConsumePlugin/GeneratedArgs.fs @@ -218,6 +218,8 @@ module internal ArgParseHelpers_ConsumePlugin = Unchecked.defaultof<_> let arg3 : string list = + positionalConsumers.Add (sprintf "--%s" "rest") + positionals |> Seq.map (fun x -> match x with @@ -390,6 +392,8 @@ module internal ArgParseHelpers_ConsumePlugin = Unchecked.defaultof<_> let arg3 : int list = + positionalConsumers.Add (sprintf "--%s" "rest") + positionals |> Seq.map (fun x -> match x with @@ -591,6 +595,8 @@ module internal ArgParseHelpers_ConsumePlugin = let arg6 : int option = this.OptionalThingWithNoDefault let arg7 : int list = + positionalConsumers.Add (sprintf "--%s" "positionals") + positionals |> Seq.map (fun x -> match x with @@ -1727,6 +1733,8 @@ module internal ArgParseHelpers_ConsumePlugin = Unchecked.defaultof<_> let arg1 : Uri list = + positionalConsumers.Add (sprintf "--%s" "thing2") + positionals |> Seq.map (fun x -> match x with @@ -1971,6 +1979,8 @@ module internal ArgParseHelpers_ConsumePlugin = Unchecked.defaultof<_> let arg1 : bool list = + positionalConsumers.Add (sprintf "--%s" "and-another") + positionals |> Seq.map (fun x -> match x with @@ -2821,6 +2831,8 @@ module internal ArgParseHelpers_ConsumePlugin = Unchecked.defaultof<_> let arg1 : string list = + positionalConsumers.Add (sprintf "--%s" "grab-everything") + positionals |> Seq.map (fun x -> match x with @@ -3034,6 +3046,8 @@ module internal ArgParseHelpers_ConsumePlugin = Unchecked.defaultof<_> let arg1 : int list = + positionalConsumers.Add (sprintf "--%s" "grab-everything") + positionals |> Seq.map (fun x -> match x with @@ -3255,6 +3269,8 @@ module internal ArgParseHelpers_ConsumePlugin = Unchecked.defaultof<_> let arg1 : string list = + positionalConsumers.Add (sprintf "--%s" "dont-grab-everything") + positionals |> Seq.map (fun x -> match x with @@ -3479,11 +3495,8 @@ module PassThruArgParse = | Error x -> match x with | None -> - failwithf - "Unable to process argument %s as key %s and value %s" - arg - key - value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_PassThru.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_PassThru.AwaitingKey args @@ -3513,7 +3526,15 @@ module PassThruArgParse = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -3589,11 +3610,8 @@ module FlagsIntoPositionalArgs'ArgParse = | Error x -> match x with | None -> - failwithf - "Unable to process argument %s as key %s and value %s" - arg - key - value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_FlagsIntoPositionalArgs'.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_FlagsIntoPositionalArgs'.AwaitingKey args @@ -3623,7 +3641,15 @@ module FlagsIntoPositionalArgs'ArgParse = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -3701,11 +3727,12 @@ module FlagsIntoPositionalArgsIntChoiceArgParse = | Error x -> match x with | None -> - failwithf - "Unable to process argument %s as key %s and value %s" - arg - key - value + positionals.Add (Choice1Of2 (arg, argNum_)) + + go + (argNum_ + 1) + ParseState_FlagsIntoPositionalArgsIntChoice.AwaitingKey + args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add @@ -3739,7 +3766,15 @@ module FlagsIntoPositionalArgsIntChoiceArgParse = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -3816,11 +3851,8 @@ module FlagsIntoPositionalArgsIntArgParse = | Error x -> match x with | None -> - failwithf - "Unable to process argument %s as key %s and value %s" - arg - key - value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_FlagsIntoPositionalArgsInt.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_FlagsIntoPositionalArgsInt.AwaitingKey args @@ -3850,7 +3882,15 @@ module FlagsIntoPositionalArgsIntArgParse = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -3928,11 +3968,8 @@ module FlagsIntoPositionalArgsChoiceArgParse = | Error x -> match x with | None -> - failwithf - "Unable to process argument %s as key %s and value %s" - arg - key - value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_FlagsIntoPositionalArgsChoice.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_FlagsIntoPositionalArgsChoice.AwaitingKey args @@ -3962,7 +3999,15 @@ module FlagsIntoPositionalArgsChoiceArgParse = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -4038,11 +4083,8 @@ module FlagsIntoPositionalArgsArgParse = | Error x -> match x with | None -> - failwithf - "Unable to process argument %s as key %s and value %s" - arg - key - value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_FlagsIntoPositionalArgs.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_FlagsIntoPositionalArgs.AwaitingKey args @@ -4072,7 +4114,15 @@ module FlagsIntoPositionalArgsArgParse = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -4142,11 +4192,8 @@ module ManyLongFormsArgParse = | Error x -> match x with | None -> - failwithf - "Unable to process argument %s as key %s and value %s" - arg - key - value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_ManyLongForms.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_ManyLongForms.AwaitingKey args @@ -4176,7 +4223,15 @@ module ManyLongFormsArgParse = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -4252,11 +4307,8 @@ module ContainsFlagDefaultValueArgParse = | Error x -> match x with | None -> - failwithf - "Unable to process argument %s as key %s and value %s" - arg - key - value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_ContainsFlagDefaultValue.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_ContainsFlagDefaultValue.AwaitingKey args @@ -4286,7 +4338,15 @@ module ContainsFlagDefaultValueArgParse = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -4358,11 +4418,8 @@ module ContainsFlagEnvVarArgParse = | Error x -> match x with | None -> - failwithf - "Unable to process argument %s as key %s and value %s" - arg - key - value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_ContainsFlagEnvVar.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_ContainsFlagEnvVar.AwaitingKey args @@ -4392,7 +4449,15 @@ module ContainsFlagEnvVarArgParse = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -4462,11 +4527,8 @@ module WithFlagDuArgParse = | Error x -> match x with | None -> - failwithf - "Unable to process argument %s as key %s and value %s" - arg - key - value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_WithFlagDu.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_WithFlagDu.AwaitingKey args @@ -4496,7 +4558,15 @@ module WithFlagDuArgParse = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -4568,11 +4638,8 @@ module ContainsBoolEnvVarArgParse = | Error x -> match x with | None -> - failwithf - "Unable to process argument %s as key %s and value %s" - arg - key - value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_ContainsBoolEnvVar.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_ContainsBoolEnvVar.AwaitingKey args @@ -4602,7 +4669,15 @@ module ContainsBoolEnvVarArgParse = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -4674,11 +4749,8 @@ module ChoicePositionalsArgParse = | Error x -> match x with | None -> - failwithf - "Unable to process argument %s as key %s and value %s" - arg - key - value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_ChoicePositionals.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_ChoicePositionals.AwaitingKey args @@ -4708,7 +4780,15 @@ module ChoicePositionalsArgParse = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -4780,11 +4860,8 @@ module ParentRecordSelfPosArgParse = | Error x -> match x with | None -> - failwithf - "Unable to process argument %s as key %s and value %s" - arg - key - value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_ParentRecordSelfPos.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_ParentRecordSelfPos.AwaitingKey args @@ -4814,7 +4891,15 @@ module ParentRecordSelfPosArgParse = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -4886,11 +4971,8 @@ module ParentRecordChildPosArgParse = | Error x -> match x with | None -> - failwithf - "Unable to process argument %s as key %s and value %s" - arg - key - value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_ParentRecordChildPos.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_ParentRecordChildPos.AwaitingKey args @@ -4920,7 +5002,15 @@ module ParentRecordChildPosArgParse = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -4990,11 +5080,8 @@ module ParentRecordArgParse = | Error x -> match x with | None -> - failwithf - "Unable to process argument %s as key %s and value %s" - arg - key - value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_ParentRecord.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_ParentRecord.AwaitingKey args @@ -5024,7 +5111,15 @@ module ParentRecordArgParse = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -5094,11 +5189,8 @@ module DatesAndTimesArgParse = | Error x -> match x with | None -> - failwithf - "Unable to process argument %s as key %s and value %s" - arg - key - value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_DatesAndTimes.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_DatesAndTimes.AwaitingKey args @@ -5128,7 +5220,15 @@ module DatesAndTimesArgParse = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -5197,7 +5297,8 @@ module LoadsOfTypesNoPositionals = | Error x -> match x with | None -> - failwithf "Unable to process argument %s as key %s and value %s" arg key value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_LoadsOfTypesNoPositionals.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_LoadsOfTypesNoPositionals.AwaitingKey args @@ -5227,7 +5328,15 @@ module LoadsOfTypesNoPositionals = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -5293,7 +5402,8 @@ module LoadsOfTypes = | Error x -> match x with | None -> - failwithf "Unable to process argument %s as key %s and value %s" arg key value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_LoadsOfTypes.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_LoadsOfTypes.AwaitingKey args @@ -5323,7 +5433,15 @@ module LoadsOfTypes = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -5391,7 +5509,8 @@ module BasicWithIntPositionals = | Error x -> match x with | None -> - failwithf "Unable to process argument %s as key %s and value %s" arg key value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_BasicWithIntPositionals.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_BasicWithIntPositionals.AwaitingKey args @@ -5421,7 +5540,15 @@ module BasicWithIntPositionals = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -5487,7 +5614,8 @@ module Basic = | Error x -> match x with | None -> - failwithf "Unable to process argument %s as key %s and value %s" arg key value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_Basic.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_Basic.AwaitingKey args @@ -5517,7 +5645,15 @@ module Basic = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> @@ -5585,7 +5721,8 @@ module BasicNoPositionals = | Error x -> match x with | None -> - failwithf "Unable to process argument %s as key %s and value %s" arg key value + positionals.Add (Choice1Of2 (arg, argNum_)) + go (argNum_ + 1) ParseState_BasicNoPositionals.AwaitingKey args | Some msg -> sprintf "%s (at arg %s)" msg arg |> errors_.Add go (argNum_ + 1) ParseState_BasicNoPositionals.AwaitingKey args @@ -5615,7 +5752,15 @@ module BasicNoPositionals = match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with | Ok (result, posConsumer) -> if positionals.Count > 0 && posConsumer.IsNone then - failwith "TODO" + positionals + |> Seq.map (fun choiceValue -> + match choiceValue with + | Choice1Of2 (arg, _) -> arg + | Choice2Of2 (arg, _) -> arg + ) + |> String.concat " " + |> sprintf "Parse error: The following arguments were not consumed: %s" + |> failwith else result | Error e -> diff --git a/WoofWare.Myriad.Plugins.Test/TestArgParser/TestArgParser.fs b/WoofWare.Myriad.Plugins.Test/TestArgParser/TestArgParser.fs index dde77cb..e4643bb 100644 --- a/WoofWare.Myriad.Plugins.Test/TestArgParser/TestArgParser.fs +++ b/WoofWare.Myriad.Plugins.Test/TestArgParser/TestArgParser.fs @@ -79,7 +79,7 @@ module TestArgParser = exc.Message |> shouldEqual - """Unable to process supplied arg --non-existent. Help text follows. + """Parse error: The following arguments were not consumed: --non-existent. to process supplied arg --non-existent. Help text follows. --foo int32 : This is a foo! --bar string --baz bool @@ -692,7 +692,7 @@ Required argument '--exact' received no value""" ) exc.Message - |> shouldEqual """Unable to process argument --b=false as key --b and value false""" + |> shouldEqual """Parse error: The following positional arguments were not consumed: --b=false --c hi --help""" let exc = Assert.Throws (fun () -> @@ -703,4 +703,4 @@ Required argument '--exact' received no value""" // Again perhaps eccentric! // Again, we don't try to detect that the user has missed out the desired argument to `--a`. exc.Message - |> shouldEqual """Unable to process argument --c=hi as key --c and value hi""" + |> shouldEqual """Parse error: The following arguments were not consumed: --c=hi""" diff --git a/WoofWare.Myriad.Plugins/ShibaGenerator.fs b/WoofWare.Myriad.Plugins/ShibaGenerator.fs index e21bff4..fbde806 100644 --- a/WoofWare.Myriad.Plugins/ShibaGenerator.fs +++ b/WoofWare.Myriad.Plugins/ShibaGenerator.fs @@ -47,44 +47,6 @@ type internal Accumulation<'choice> = | ChoicePositional of attrContents : SynExpr option | List of Accumulation<'choice> -type private ParseFunction<'acc> = - { - FieldName : Ident - TargetVariable : Ident - /// Any of the forms in this set are acceptable, but make sure they all start with a dash, or we might - /// get confused with positional args or something! I haven't thought that hard about this. - /// In the default case, this is `Const("arg-name")` for the `ArgName : blah` field; note that we have - /// omitted the initial `--` that will be required at runtime. - ArgForm : SynExpr list - /// If this is a boolean-like field (e.g. a bool or a flag DU), the help text should look a bit different: - /// we should lie to the user about the value of the cases there. - /// Similarly, if we're reading from an environment variable with the laxer parsing rules of accepting e.g. - /// "0" instead of "false", we need to know if we're reading a bool. - /// In that case, `boolCases` is Some, and contains the construction of the flag (or boolean, in which case - /// you get no data). - BoolCases : Choice option - Help : SynExpr option - /// A function string -> %TargetType%, where TargetVariable is probably a `%TargetType% option`. - /// (Depending on `Accumulation`, we'll remove the `option` at the end of the parse, asserting that the - /// argument was supplied.) - /// This is allowed to throw if it fails to parse. - Parser : SynExpr - /// If `Accumulation` is `List`, then this is the type of the list *element*; analogously for optionals - /// and choices and so on. - TargetType : SynType - Accumulation : 'acc - } - - /// A SynExpr of type `string` which we can display to the user at generated-program runtime to display all - /// the ways they can refer to this arg. - member arg.HumanReadableArgForm : SynExpr = - let formatString = List.replicate arg.ArgForm.Length "--%s" |> String.concat " / " - - (SynExpr.applyFunction (SynExpr.createIdent "sprintf") (SynExpr.CreateConst formatString), arg.ArgForm) - ||> List.fold SynExpr.applyFunction - |> SynExpr.paren - - module internal ShibaGenerator = //let log (s : string) = System.IO.File.AppendAllText ("/tmp/myriad.log", s + "\n") let private choice1Of2 = SynExpr.createIdent "Choice1Of2" @@ -974,108 +936,25 @@ module internal ShibaGenerator = match leaf.Positional with // TODO: account for includeFlagLike | Some includeFlagLike -> - // Positional args carried in from external argument. - // TODO: register whether they came before or after separator - match leaf.Acc with - | List acc -> - match acc with - | Accumulation.List _ -> - failwith "unexpected: positional args should not be a list of lists" - | Accumulation.Required -> - // TODO: we need to preserve the ordering on these with respect to - // the explicitly passed `--foo=` positionals - SynExpr.createIdent "positionals" - |> SynExpr.pipeThroughFunction ( - SynExpr.applyFunction - (SynExpr.createLongIdent [ "Seq" ; "map" ]) - (SynExpr.createLambda - "x" - (SynExpr.createMatch - (SynExpr.createIdent "x") - [ - SynMatchClause.create - (SynPat.identWithArgs - [ Ident.create "Choice1Of2" ] - (SynArgPats.createNamed [ "x" ])) - (SynExpr.createIdent "x") - SynMatchClause.create - (SynPat.identWithArgs - [ Ident.create "Choice2Of2" ] - (SynArgPats.createNamed [ "x" ])) - (SynExpr.createIdent "x") - ])) - ) - |> SynExpr.pipeThroughFunction ( - let body = - SynExpr.tupleNoParen - [ - SynExpr.pipeThroughFunction - leaf.ParseFn - (SynExpr.createIdent "str") - SynExpr.createIdent "argNum_" - ] - - SynExpr.applyFunction - (SynExpr.createLongIdent [ "Seq" ; "map" ]) - (SynExpr.Lambda ( - false, - false, - SynSimplePats.create - [ - SynSimplePat.createId (Ident.create "str") - SynSimplePat.createId (Ident.create "argNum_") - ], - body, - Some ( - [ - SynPat.tuple - [ SynPat.named "str" ; SynPat.named "argNum_" ] - ], - body - ), - range0, - { - ArrowRange = Some range0 - } - ) - |> SynExpr.paren) - ) - |> SynExpr.pipeThroughFunction ( - SynExpr.createLambda - "x" - (SynExpr.createLongIdent [ "Seq" ; "append" ] - |> SynExpr.applyTo ( - SynExpr.createLongIdent' - [ Ident.create "this" ; leaf.TargetConstructionField ] - ) - |> SynExpr.applyTo (SynExpr.createIdent "x")) - ) - |> SynExpr.pipeThroughFunction ( - SynExpr.applyFunction - (SynExpr.createLongIdent [ "Seq" ; "sortBy" ]) - (SynExpr.createIdent "snd") - ) - |> SynExpr.pipeThroughFunction ( - SynExpr.applyFunction - (SynExpr.createLongIdent [ "Seq" ; "map" ]) - (SynExpr.createIdent "fst") - ) - |> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "Seq" ; "toList" ]) - | Accumulation.Optional -> - failwith "unexpected: positional args should not be a list of options" - | Accumulation.Choice _ -> - failwith - "internal error: positional args, if Choicey, should be a ChoicePositional" - | Accumulation.ChoicePositional attrContents -> - [ - SynExpr.callMethodArg - "Add" - leaf.HumanReadableArgForm - (SynExpr.createIdent "positionalConsumers") + [ + SynExpr.callMethodArg + "Add" + leaf.HumanReadableArgForm + (SynExpr.createIdent "positionalConsumers") + // Positional args carried in from external argument. + // TODO: register whether they came before or after separator + match leaf.Acc with + | List acc -> + match acc with + | Accumulation.List _ -> + failwith "unexpected: positional args should not be a list of lists" + | Accumulation.Required -> + // TODO: we need to preserve the ordering on these with respect to + // the explicitly passed `--foo=` positionals SynExpr.createIdent "positionals" |> SynExpr.pipeThroughFunction ( SynExpr.applyFunction - (SynExpr.createLongIdent [ "List" ; "map" ]) + (SynExpr.createLongIdent [ "Seq" ; "map" ]) (SynExpr.createLambda "x" (SynExpr.createMatch @@ -1084,40 +963,113 @@ module internal ShibaGenerator = SynMatchClause.create (SynPat.identWithArgs [ Ident.create "Choice1Of2" ] - (SynArgPats.create - [ - SynPat.tuple - [ - SynPat.named "x" - SynPat.named "argPos" - ] - ])) - (SynExpr.applyFunction - leaf.ParseFn - (SynExpr.createIdent "x") - |> SynExpr.pipeThroughFunction choice1Of2) + (SynArgPats.createNamed [ "x" ])) + (SynExpr.createIdent "x") SynMatchClause.create (SynPat.identWithArgs [ Ident.create "Choice2Of2" ] - (SynArgPats.create - [ - SynPat.tuple - [ - SynPat.named "x" - SynPat.named "argPos" - ] - ])) - (SynExpr.applyFunction - leaf.ParseFn - (SynExpr.createIdent "x") - |> SynExpr.pipeThroughFunction ( - SynExpr.createIdent "Choice2Of2" - )) + (SynArgPats.createNamed [ "x" ])) + (SynExpr.createIdent "x") ])) ) - ] - |> SynExpr.sequential - | _ -> failwith "unexpected: positional arguments should be a list" + |> SynExpr.pipeThroughFunction ( + let body = + SynExpr.tupleNoParen + [ + SynExpr.pipeThroughFunction + leaf.ParseFn + (SynExpr.createIdent "str") + SynExpr.createIdent "argNum_" + ] + + SynExpr.applyFunction + (SynExpr.createLongIdent [ "Seq" ; "map" ]) + (SynExpr.Lambda ( + false, + false, + SynSimplePats.create + [ + SynSimplePat.createId (Ident.create "str") + SynSimplePat.createId (Ident.create "argNum_") + ], + body, + Some ( + [ + SynPat.tuple + [ SynPat.named "str" ; SynPat.named "argNum_" ] + ], + body + ), + range0, + { + ArrowRange = Some range0 + } + ) + |> SynExpr.paren) + ) + |> SynExpr.pipeThroughFunction ( + SynExpr.createLambda + "x" + (SynExpr.createLongIdent [ "Seq" ; "append" ] + |> SynExpr.applyTo ( + SynExpr.createLongIdent' + [ Ident.create "this" ; leaf.TargetConstructionField ] + ) + |> SynExpr.applyTo (SynExpr.createIdent "x")) + ) + |> SynExpr.pipeThroughFunction ( + SynExpr.applyFunction + (SynExpr.createLongIdent [ "Seq" ; "sortBy" ]) + (SynExpr.createIdent "snd") + ) + |> SynExpr.pipeThroughFunction ( + SynExpr.applyFunction + (SynExpr.createLongIdent [ "Seq" ; "map" ]) + (SynExpr.createIdent "fst") + ) + |> SynExpr.pipeThroughFunction ( + SynExpr.createLongIdent [ "Seq" ; "toList" ] + ) + | Accumulation.Optional -> + failwith "unexpected: positional args should not be a list of options" + | Accumulation.Choice _ -> + failwith + "internal error: positional args, if Choicey, should be a ChoicePositional" + | Accumulation.ChoicePositional _attrContents -> + SynExpr.createIdent "positionals" + |> SynExpr.pipeThroughFunction ( + [ + SynExpr.applyFunction leaf.ParseFn (SynExpr.createIdent "x") + |> SynExpr.pipeThroughFunction choice1Of2 + |> SynMatchClause.create ( + SynPat.identWithArgs + [ Ident.create "Choice1Of2" ] + (SynArgPats.create + [ + SynPat.tuple + [ SynPat.named "x" ; SynPat.named "argPos" ] + ]) + ) + + SynExpr.applyFunction leaf.ParseFn (SynExpr.createIdent "x") + |> SynExpr.pipeThroughFunction choice2Of2 + |> SynMatchClause.create ( + SynPat.identWithArgs + [ Ident.create "Choice2Of2" ] + (SynArgPats.create + [ + SynPat.tuple + [ SynPat.named "x" ; SynPat.named "argPos" ] + ]) + ) + ] + |> SynExpr.createMatch (SynExpr.createIdent "x") + |> SynExpr.createLambda "x" + |> SynExpr.applyFunction (SynExpr.createLongIdent [ "List" ; "map" ]) + ) + | _ -> failwith "unexpected: positional arguments should be a list" + ] + |> SynExpr.sequential | None -> let parseFn = @@ -1749,13 +1701,19 @@ module internal ShibaGenerator = |> SynExpr.applyTo (SynExpr.createLongIdent' [ parseState ; Ident.create "AwaitingKey" ]) |> SynExpr.applyTo (SynExpr.createIdent "args") - /// `failwithf "Unable to process argument ..."` + /// `positionals.Add arg ; go (argNum_ + 1) AwaitingKey args` let fail = - SynExpr.createIdent "failwithf" - |> SynExpr.applyTo (SynExpr.CreateConst "Unable to process argument %s as key %s and value %s") - |> SynExpr.applyTo (SynExpr.createIdent "arg") - |> SynExpr.applyTo (SynExpr.createIdent "key") - |> SynExpr.applyTo (SynExpr.createIdent "value") + [ + SynExpr.createIdent "positionals" + |> SynExpr.callMethodArg + "Add" + (SynExpr.tuple [ SynExpr.createIdent "arg" ; SynExpr.createIdent "argNum_" ] + |> SynExpr.applyFunction (SynExpr.createIdent "Choice1Of2") + |> SynExpr.paren) + + recurseKey + ] + |> SynExpr.sequential let processAsPositional = SynExpr.sequential @@ -2105,6 +2063,45 @@ module internal ShibaGenerator = ) |> SynExpr.pipeThroughFunction (SynExpr.createIdent "failwith") + // If we reach the end of the parse and there were positionals which were not consumed, + // we call this, which represents a parse failure. + // In scope are `positionals` (a ResizeArray of Choice<(string * int), (string * int)>) + // and `result`, an otherwise successful parsed output. + let printUnmatchedArgs = + SynExpr.createIdent "positionals" + // Map the Choice<_, _> to just the string argument + |> SynExpr.pipeThroughFunction ( + SynExpr.applyFunction + (SynExpr.createLongIdent [ "Seq" ; "map" ]) + (SynExpr.createLambda + "choiceValue" + (SynExpr.createMatch + (SynExpr.createIdent "choiceValue") + [ + // Case for args before '--' + SynMatchClause.create + (SynPat.identWithArgs + [ Ident.create "Choice1Of2" ] + (SynArgPats.create [ SynPat.tuple [ SynPat.named "arg" ; SynPat.anon ] ])) + (SynExpr.createIdent "arg") + // Case for args after '--' + SynMatchClause.create + (SynPat.identWithArgs + [ Ident.create "Choice2Of2" ] + (SynArgPats.create [ SynPat.tuple [ SynPat.named "arg" ; SynPat.anon ] ])) + (SynExpr.createIdent "arg") + ])) + ) + |> SynExpr.pipeThroughFunction ( + SynExpr.applyFunction (SynExpr.createLongIdent [ "String" ; "concat" ]) (SynExpr.CreateConst " ") + ) + |> SynExpr.pipeThroughFunction ( + SynExpr.applyFunction + (SynExpr.createIdent "sprintf") + (SynExpr.CreateConst "Parse error: The following arguments were not consumed: %s") + ) + |> SynExpr.pipeThroughFunction (SynExpr.createIdent "failwith") + let parsePrime = [ SynExpr.applyFunction @@ -2129,7 +2126,7 @@ module internal ShibaGenerator = |> SynExpr.greaterThan (SynExpr.CreateConst 0)) (SynExpr.dotGet "IsNone" (SynExpr.createIdent "posConsumer"))) (SynExpr.createIdent "result") - (SynExpr.applyFunction (SynExpr.createIdent "failwith") (SynExpr.CreateConst "TODO"))) + printUnmatchedArgs) SynMatchClause.create (SynPat.nameWithArgs "Error" [ SynPat.named "e" ]) (raiseErrors (Ident.create "e"))