miking-lang / miking

Miking - the meta viking: a meta-language system for creating embedded languages
Other
51 stars 31 forks source link

Argparser does not handle one argument being a prefix of another #574

Open lingmar opened 2 years ago

lingmar commented 2 years ago

In the argparser, it is currently not possible to name an argument as a prefix of another argument. For instance, the following program having one argument called --a and one --aa

include "arg.mc"
include "common.mc"

mexpr

type Options = {
  a: Bool,
  aa: Bool
} in

let default = {
  a = false,
  aa = false
} in

let config = [
  ([("--a", "", "")],
    "This is a boolean option. ",
    lam p : ArgPart Options. let o : Options = p.options in {o with prefix = true}),
  ([("--aa", "", "")],
    "This is a boolean option. ",
    lam p : ArgPart Options. let o : Options = p.options in {o with prefixSuffix = true})
] in

let testOptions = {
  argParse_defaults with
  args = [
    "--aa"
  ]
} in
let argParseCustom = argParse_general testOptions in
printLn (argPrintErrorString (argParseCustom default config))

gives

Unknown option --aa

The error goes away by using eqString instead of isPrefix in the function matchOption in arg.mc.

diff --git a/stdlib/arg.mc b/stdlib/arg.mc
index 547b09d..b2c6150 100644
--- a/stdlib/arg.mc
+++ b/stdlib/arg.mc
@@ -160,7 +160,7 @@ let argParse_general : all a. Options_argParse -> a -> ParseConfig a -> ParseRes
     let matchOption = lam str. lam confLst : ParseConfig a.
      match confLst with [(opLst, _, f)] ++ rest then
        match find (lam x. match x with (s, _, _)
-                          then isPrefix eqChar s str else never) opLst
+                          then eqString s str else never) opLst
        with Some (s, sep, _)
        then Some (s, sep, f)
        else matchOption str rest

but maybe there is a good reason isPrefix is used?

larshum commented 1 year ago

I think this is the same problem as reported in #498.