Advertisement
jmk12341234

Untitled

Mar 13th, 2020
1,856
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
OCaml 3.68 KB | None | 0 0
  1.  
  2. (* type declarations *)
  3. type argspec =
  4.     | Literal of string
  5.     | Arg of string
  6.     | IntArg of string
  7.  
  8. type argvalue =
  9.     | ParsedLiteral
  10.     | ParsedArg of string
  11.     | ParsedIntArg of int
  12.  
  13. type parsed_command = { args: (string * argvalue) list ; remainder: string list }
  14. type command        = { argspecs: argspec list ; func: (parsed_command -> unit) }
  15.  
  16. (* record related utilities *)
  17. let get_arg pc name = List.assoc name pc.args
  18.  
  19. let argspec_to_string value =
  20.     match value with
  21.     | Literal l -> Printf.sprintf "%s " l
  22.     | Arg a     -> Printf.sprintf "<%s> " a
  23.     | IntArg a  -> Printf.sprintf "<%s:int> " a
  24.  
  25. (* help printer *)
  26. let print_help (commands:command list) =
  27.     Printf.printf("available commands:\n\n");
  28.     let print_command command =
  29.         Printf.printf(" - ");
  30.         List.iter (fun x -> x |> argspec_to_string |> (Printf.printf "%s")) command.argspecs; (* I wish we had . operator from Haskell? *)
  31.         Printf.printf("\n") in
  32.     List.iter print_command commands
  33.  
  34. (* parse a single arg against spec *)
  35. let parse_token spec arg =
  36.     match spec with
  37.     | Literal name -> if String.equal name arg then Some (name, ParsedLiteral) else None (* raw string equality doesn't seem to work?>? *)
  38.     | Arg name     -> Some (name, ParsedArg arg)
  39.     | IntArg name  -> (
  40.         match int_of_string_opt arg with
  41.         | Some value -> Some (name, ParsedIntArg value)
  42.         | None -> None)
  43.  
  44. (* parse a list of tokens against a command definition. Returns None if fails *)
  45. let parse_command cmd args =
  46.     (* mutually recursive functions ooh *)
  47.     let rec parse specs args = match specs, args with
  48.         | (shd :: stl), (ahd :: atl) -> parse_step shd stl ahd atl
  49.         | [], _ -> Some { args = []; remainder = args }
  50.         | _, _  -> None
  51.     and parse_step shd stl ahd atl = match parse_token shd ahd with
  52.         | None    -> None
  53.         | Some _p -> match parse stl atl with
  54.             | Some {args; remainder} -> Some {args = (_p :: args); remainder = remainder}
  55.             | None                   -> None in
  56.     match parse cmd.argspecs args with
  57.     | Some parsed -> Some (cmd, parsed)
  58.     | None        -> None (* lots of None -> None s hanging around.. is that fixable? *)
  59.  
  60. (* find the matching function and execute it *)
  61. let handle (commands:command list) args =
  62.     let rec first_some f lst = match lst with (* helper function *)
  63.         | []       -> None
  64.         | hd :: tl -> match f hd with
  65.                 | Some r -> Some r
  66.                 | None   -> first_some f tl in
  67.     let first_match = first_some (fun cmd -> parse_command cmd args) commands in
  68.         match first_match with
  69.         | Some (cmd, parsed) -> cmd.func parsed
  70.         | None               -> print_help commands
  71.  
  72. (* finally, some command definitions - looks a bit ugly *)
  73. let commands = [
  74.     {
  75.         argspecs = [ Literal "hello" ] ;
  76.         func = (fun _ -> Printf.printf("hello received\n"))
  77.     } ;
  78.     {
  79.         argspecs = [ Literal "max_orders+=" ; IntArg "n" ] ;
  80.         func = (fun _ -> Printf.printf("max_order+= received\n"))
  81.     } ;
  82.     {
  83.         argspecs = [ Literal "set_user" ; Arg "name"; IntArg "age" ] ;
  84.         func = (
  85.             fun pc ->
  86.                 match (get_arg pc "name"), (get_arg pc "age") with (* the validation was already done for us, any better API than this? hmm *)
  87.                     | ParsedArg name, ParsedIntArg age -> Printf.printf "set user name=%s age=%d\n" name age
  88.                     | _, _ -> Printf.printf("wtf?\n");
  89.         )
  90.     } ;
  91. ]
  92.  
  93. let () =
  94.     let rec to_list arr i = if i == Array.length arr then [] else arr.(i) :: (to_list arr (i+1)) in
  95.     handle commands (to_list Sys.argv 1)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement