@@ -593,6 +593,13 @@ module private ArgParserRuntime_DuArgs =
593593 | NoForms of leafId : int
594594 /// A leaf accepts ` --no- ` negation but is not boolean-like.
595595 | NegationOnNonBool of leafId : int
596+ /// A form is the empty string: its token would be ` -- ` , which the scanner always
597+ /// treats as the positional separator, so the argument could never be addressed.
598+ | EmptyForm of claimant : string
599+ /// A form contains an equals sign: the scanner splits a ` --key=value ` token at its
600+ /// * first* ` = ` , so such a form can never match. An argument required under such a form
601+ /// makes the schema (or a union case of it) permanently unsatisfiable.
602+ | FormContainsEquals of claimant : string * form : string
596603 /// Two distinct claimants respond to the same ` --token ` under the scanner's
597604 /// case-insensitive matching (so e.g. forms ` foo ` and ` FOO ` collide, as do a literal
598605 /// form ` no-foo ` and the negated variant of a negatable ` foo ` ). The token is reported
@@ -616,6 +623,13 @@ module private ArgParserRuntime_DuArgs =
616623 | SchemaError.NoForms leafId -> sprintf " argument id %i has no names" leafId
617624 | SchemaError.NegationOnNonBool leafId ->
618625 sprintf " argument id %i accepts --no- negation but is not boolean-like" leafId
626+ | SchemaError.EmptyForm claimant ->
627+ sprintf " %s has an empty name: its token would be '--', which is the positional separator" claimant
628+ | SchemaError.FormContainsEquals ( claimant, form) ->
629+ sprintf
630+ " %s has the name '%s ', which contains '='; a --key=value token splits at its first '=', so this argument could never be addressed"
631+ claimant
632+ form
619633 | SchemaError.TokenCollision ( token, claimants) ->
620634 sprintf
621635 " the token '%s ' is claimed by: %s (argument names are matched case-insensitively)"
@@ -718,13 +732,60 @@ module private ArgParserRuntime_DuArgs =
718732 @ [ " --help" , " the built-in help flag" ]
719733
720734 let collisions =
721- claims
722- |> List.groupBy ( fun ( token , _ ) -> token.ToUpperInvariant ())
723- |> List.choose ( fun ( _ , group ) ->
724- match group with
725- | []
726- | [ _ ] -> None
727- | ( token, _) :: _ -> Some ( SchemaError.TokenCollision ( token, group |> List.map snd))
735+ let indexOf =
736+ System.Collections.Generic.Dictionary< string, int> ( StringComparer.OrdinalIgnoreCase)
737+
738+ let buckets = ResizeArray< ResizeArray< string * string>> ()
739+
740+ for token, claimant in claims do
741+ match indexOf.TryGetValue token with
742+ | true , index -> buckets.[ index]. Add (( token, claimant))
743+ | false , _ ->
744+ indexOf.[ token] <- buckets.Count
745+ let bucket = ResizeArray ()
746+ bucket.Add (( token, claimant))
747+ buckets.Add bucket
748+
749+ buckets
750+ |> Seq.choose ( fun bucket ->
751+ if bucket.Count < 2 then
752+ None
753+ else
754+ let token , _ = bucket.[ 0 ]
755+ Some ( SchemaError.TokenCollision ( token, bucket |> Seq.map snd |> List.ofSeq))
756+ )
757+ |> List.ofSeq
758+
759+ let unaddressable =
760+ ( schema.Leaves
761+ |> List.collect ( fun leaf ->
762+ let claimant = sprintf " argument id %i " leaf.Id
763+
764+ leaf.Forms
765+ |> List.collect ( fun form ->
766+ if form = " " then
767+ [ SchemaError.EmptyForm claimant ]
768+ elif form.Contains " =" then
769+ [ SchemaError.FormContainsEquals ( claimant, form) ]
770+ else
771+ []
772+ )
773+ ))
774+ @ (
775+ match schema.Positional with
776+ | None -> []
777+ | Some positional ->
778+ let claimant = " the positional-args sink"
779+
780+ positional.Forms
781+ |> List.collect ( fun form ->
782+ if form = " " then
783+ [ SchemaError.EmptyForm claimant ]
784+ elif form.Contains " =" then
785+ [ SchemaError.FormContainsEquals ( claimant, form) ]
786+ else
787+ []
788+ )
728789 )
729790
730791 duplicateLeafIds
@@ -734,6 +795,7 @@ module private ArgParserRuntime_DuArgs =
734795 @ duplicateSumIds
735796 @ noForms
736797 @ negationOnNonBool
798+ @ unaddressable
737799 @ collisions
738800
739801 /// Check the invariants which the scanning and selection semantics rely on.
@@ -964,9 +1026,12 @@ module DuArgs =
9641026 let parse ' ( getEnvironmentVariable : string -> string option ) ( args : string list ) : DuArgs =
9651027 let helpText () =
9661028 [
967- ( sprintf " %s int32%s%s " ( sprintf " --%s " " foo" ) " " ( sprintf " : %s " ( " The foo argument" )))
968- ( sprintf " %s int32%s%s " ( sprintf " --%s " " bar" ) " " " " )
969- ( sprintf " %s int32%s%s " ( sprintf " --%s " " baz" ) " " " " )
1029+ " exactly one of the following sets of arguments:"
1030+ " FooCase:"
1031+ ( sprintf " %s int32%s%s " ( sprintf " --%s " " foo" ) " " ( sprintf " : %s " ( " The foo argument" )))
1032+ " BarCase:"
1033+ ( sprintf " %s int32%s%s " ( sprintf " --%s " " bar" ) " " " " )
1034+ ( sprintf " %s int32%s%s " ( sprintf " --%s " " baz" ) " " " " )
9701035 ]
9711036 |> String.concat " \n "
9721037
@@ -1163,8 +1228,11 @@ module WithModeArgs =
11631228 let helpText () =
11641229 [
11651230 ( sprintf " %s bool%s%s " ( sprintf " --%s " " verbose" ) " " " " )
1166- ( sprintf " %s bool%s%s " ( sprintf " --%s " " quiet" ) " (optional)" " " )
1167- ( sprintf " %s int32%s%s " ( sprintf " --%s " " level" ) " " " " )
1231+ " exactly one of the following sets of arguments:"
1232+ " Auto:"
1233+ ( sprintf " %s bool%s%s " ( sprintf " --%s " " quiet" ) " (optional)" " " )
1234+ " Manual:"
1235+ ( sprintf " %s int32%s%s " ( sprintf " --%s " " level" ) " " " " )
11681236 ]
11691237 |> String.concat " \n "
11701238
@@ -1356,3 +1424,174 @@ module WithModeArgs =
13561424
13571425 let parse ( args : string list ) : WithModeArgs =
13581426 parse' ( System.Environment.GetEnvironmentVariable >> Option.ofObj) args
1427+ namespace ConsumePlugin
1428+
1429+ open WoofWare.Myriad .Plugins
1430+
1431+ /// Methods to parse arguments for the type DuWithDefaultArgs
1432+ [<RequireQualifiedAccess ; CompilationRepresentation( CompilationRepresentationFlags.ModuleSuffix) >]
1433+ module DuWithDefaultArgs =
1434+ let parse ' ( getEnvironmentVariable : string -> string option ) ( args : string list ) : DuWithDefaultArgs =
1435+ let helpText () =
1436+ [
1437+ " exactly one of the following sets of arguments:"
1438+ " Defaulted:"
1439+
1440+ ( sprintf
1441+ " %s int32%s%s "
1442+ ( sprintf " --%s " " retries" )
1443+ ( DefaultedArgs.DefaultRetries ()
1444+ |> ( fun x -> x.ToString ())
1445+ |> sprintf " (default value: %s )" )
1446+ " " )
1447+
1448+ " Plain:"
1449+ ( sprintf " %s int32%s%s " ( sprintf " --%s " " value" ) " " " " )
1450+ ]
1451+ |> String.concat " \n "
1452+
1453+ let parser_LeftoverArgs : string ResizeArray = ResizeArray ()
1454+ let mutable arg_1 : Choice < int , int > option = None
1455+ let mutable arg_2 : int option = None
1456+
1457+ let parser_schema : ArgParserRuntime_DuArgs.ErasedSchema =
1458+ {
1459+ Leaves =
1460+ [
1461+ {
1462+ Id = 0
1463+ Forms = [ " retries" ]
1464+ AcceptsNegation = false
1465+ Arity = ArgParserRuntime_ DuArgs.ErasedArity.One
1466+ Repeatable = false
1467+ Requirement = ArgParserRuntime_ DuArgs.ErasedRequirement.HasDefault
1468+ TypeDescription = " "
1469+ Help = None
1470+ }
1471+ {
1472+ Id = 1
1473+ Forms = [ " value" ]
1474+ AcceptsNegation = false
1475+ Arity = ArgParserRuntime_ DuArgs.ErasedArity.One
1476+ Repeatable = false
1477+ Requirement = ArgParserRuntime_ DuArgs.ErasedRequirement.Required
1478+ TypeDescription = " "
1479+ Help = None
1480+ }
1481+ ]
1482+ Tree =
1483+ ( ArgParserRuntime_ DuArgs.ErasedTree.Sum (
1484+ ( 0 ,
1485+ [
1486+ ( " Defaulted" ,
1487+ ArgParserRuntime_ DuArgs.ErasedTree.Product ([ ArgParserRuntime_ DuArgs.ErasedTree.Leaf 0 ]))
1488+ ( " Plain" ,
1489+ ArgParserRuntime_ DuArgs.ErasedTree.Product ([ ArgParserRuntime_ DuArgs.ErasedTree.Leaf 1 ]))
1490+ ])
1491+ ))
1492+ Positional = None
1493+ }
1494+
1495+ let parser_storeOccurrence ( occurrence : ArgParserRuntime_DuArgs.ErasedOccurrence ) : string option =
1496+ match occurrence.LeafId with
1497+ | 0 ->
1498+ match arg_ 1 with
1499+ | Some _ -> None
1500+ | None ->
1501+ match occurrence.Value with
1502+ | Some value ->
1503+ try
1504+ arg_ 1 <- Some ( Choice1Of2 ( value |> ( fun x -> System.Int32.Parse x)))
1505+ None
1506+ with _ as exc ->
1507+ ( sprintf " %s (at arg %s )" exc.Message occurrence.Source) |> Some
1508+ | None ->
1509+ failwith
1510+ " WoofWare.Myriad internal error in generated parser: arity-one occurrence with no value"
1511+ | 1 ->
1512+ match arg_ 2 with
1513+ | Some _ -> None
1514+ | None ->
1515+ match occurrence.Value with
1516+ | Some value ->
1517+ try
1518+ arg_ 2 <- Some ( value |> ( fun x -> System.Int32.Parse x))
1519+ None
1520+ with _ as exc ->
1521+ ( sprintf " %s (at arg %s )" exc.Message occurrence.Source) |> Some
1522+ | None ->
1523+ failwith
1524+ " WoofWare.Myriad internal error in generated parser: arity-one occurrence with no value"
1525+ | _ -> failwith " WoofWare.Myriad internal error in generated parser: unknown argument id"
1526+
1527+ let parser_storePositional ( value : string ) ( afterSeparator : bool ) : string option = None
1528+
1529+ let parser_renderStored ( leafId : int ) : string =
1530+ match leafId with
1531+ | 0 ->
1532+ match arg_ 1 with
1533+ | Some ( Choice1Of2 x) -> x.ToString ()
1534+ | Some ( Choice2Of2 x) -> x.ToString ()
1535+ | None -> " <no value>"
1536+ | 1 ->
1537+ match arg_ 2 with
1538+ | Some x -> x.ToString ()
1539+ | None -> " <no value>"
1540+ | _ -> " <no value>"
1541+
1542+ let parser_applyDefault ( leafId : int ) : string option =
1543+ match leafId with
1544+ | 0 ->
1545+ arg_ 1 <- Some ( Choice2Of2 ( DefaultedArgs.DefaultRetries ()))
1546+ None
1547+ | _ -> failwith " WoofWare.Myriad internal error in generated parser: unknown defaulted argument id"
1548+
1549+ let parser_callbacks : ArgParserRuntime_DuArgs.TypedCallbacks =
1550+ {
1551+ StoreOccurrence = parser_ storeOccurrence
1552+ StorePositional = parser_ storePositional
1553+ HelpText = helpText
1554+ RenderStored = parser_ renderStored
1555+ ApplyDefault = parser_ applyDefault
1556+ }
1557+
1558+ match
1559+ ArgParserRuntime_ DuArgs.runParse
1560+ ( ArgParserRuntime_ DuArgs.WellFormedSchema.checkOrFail parser_ schema)
1561+ parser_ callbacks
1562+ args
1563+ with
1564+ | ArgParserRuntime_ DuArgs.ParseOutcome.Success parser_ selection ->
1565+ match Map.tryFind 0 parser_ selection.Choices with
1566+ | Some 0 ->
1567+ DuWithDefaultArgs.Defaulted (
1568+ {
1569+ Retries =
1570+ ( match arg_ 1 with
1571+ | Some x -> x
1572+ | None ->
1573+ failwith
1574+ " WoofWare.Myriad internal error in generated parser: required argument missing after successful parse" )
1575+ }
1576+ )
1577+ | Some 1 ->
1578+ DuWithDefaultArgs.Plain (
1579+ {
1580+ Value =
1581+ ( match arg_ 2 with
1582+ | Some x -> x
1583+ | None ->
1584+ failwith
1585+ " WoofWare.Myriad internal error in generated parser: required argument missing after successful parse" )
1586+ }
1587+ )
1588+ | _ ->
1589+ failwith
1590+ " WoofWare.Myriad internal error in generated parser: no case selected despite a successful parse"
1591+ | ArgParserRuntime_ DuArgs.ParseOutcome.HelpRequested -> helpText () |> failwithf " Help text requested.\n %s "
1592+ | ArgParserRuntime_ DuArgs.ParseOutcome.Fatal message -> failwith message
1593+ | ArgParserRuntime_ DuArgs.ParseOutcome.Errors errors ->
1594+ errors |> String.concat " \n " |> failwithf " Errors during parse!\n %s "
1595+
1596+ let parse ( args : string list ) : DuWithDefaultArgs =
1597+ parse' ( System.Environment.GetEnvironmentVariable >> Option.ofObj) args
0 commit comments