Module Extension.Command

Interface for specifying commands.

type ('f, 'r) t

description of the command line syntax.

The 'f parameter is the type of function that is evaluated when the command is selected.

The 'r is the value returned by 'f (and so 'r is always included in 'f.

For example,

type s =
  (int -> ctxt -> (unit,error) result,
   ctxt -> (unit,error) result) t

is a type of a function that takes two input arguments of type int and ctxt respectively, and must evaluate to a value of type unit,error result

type 'a param

'a param command line parameter represented with the OCaml value of type 'a.

val declare : ?doc:string -> ?requires:string list -> string -> ('f, ctxt -> (unit, error) Stdlib.result) t -> 'f -> unit

declare grammar name command declares a command.

Declares to BAP that a command with the given name should be invoked when a user specifies the name or :name as the first argument in the command line. The grammar defines the command line grammar of this command.

where <command1> ... <commandN> are the names of declared commands, grammar1 ... grammarN are corresponding grammars for each command, and G' is the global

When the command is selected and command line arguments are parsed successfully, the command function is applied to the specified command line arguments. The result of evaluation of the command will become the result of the Bap_main.init () expression in the host program.

If the function with the given name is already registered, then the command is not registered and BAP initialization will terminate abnormally with the configuration error condition.

Examples

Note, the examples below assume the following preamble:

open Core_kernel[@@warning "-D"]
open Bap_main.Extension

1) Declare a command with no arguments:

let () =
  Command.(declare "hello" args) @@
  fun ctxt ->
  printf "the `hello' command is called\n";
  Ok ()

2) Declaring a command with one positional argument

let input = Command.argument Type.int
let () =
  Command.(declare "hello" (args $input)) @@
  fun input ctxt ->
  printf "called as `hello %d'\n" input

3) Declaring a command with an optional named parameter, and many positional arguments.

let inputs = Command.arguments Type.string
let output = Command.parameter Type.string "output"
let () =
  Command.(declare "copy" (args $output $inputs)) @@
  fun output inputs ->
  printf "copying %s inputs to %s\n"
    (String.concat ~sep:" " inputs) output

@parameter doc defines the documentation for the declared command, it could be as simple one-line description or a full featured manual in the markdown syntax. See the corresponding parameter in the Bap_main.init function for the description of the accepted.

@parameter requires defines the set of features that are required by the implementation of this command. It defaults to the set of all possible features. The context value passed to the command function will be refined to the context of extensions which are providing the specified features, i.e., between different invocations of BAP it will not change if the configuration parameters of extensions on which the command depends didn't change.

val args : ('a, 'a) t

args is the empty grammar. Useful to define commands that do not take arguments or as the initial grammar which is later extended with parameters using the $ operator (see below).

val ($) : ('a, 'b -> 'c) t -> 'b param -> ('a, 'c) t

args t $ t' extends the grammar specification t with t'.

val argument : ?doc:string -> 'a typ -> 'a param

argument t declares a positional argument of type t.

The grammar of args $ term $ argument t:

          G = term, [t] | [t], term
val arguments : ?doc:string -> 'a typ -> 'a list param

arguments t declares an infinite number of positional arguments of type t.

The grammar of args $ term $ arguments t:

          G = term, {t} | {t}, term

Note, no positional arguments could be appended to the command line specification after this one, e.g., the following is not well formed:

(* Warning! Ill-formed code *)

let inputs = Command.arguments Type.string
let output = Command.parameter Type.string "output"
let () =
  Command.(declare "copy" (args $inputs $output)) @@
  fun output inputs ->
  printf "copying %s inputs to %s\n"
    (String.concat ~sep:" " inputs) output
val switch : ?doc:('a -> string) -> ?aliases:('a -> string list) -> 'a list -> ('a -> string) -> 'a option param

switch values name declares a switch-type parameter.

The grammar of args $ term $ switch values name:

          G  = term, G' | G', term
          G' = ["--<name v0>" | .. | "--<name vN>"]

where <name vK> is the result of application of the name function to the Kth element of the values list.

The switch-type parameters enables a selection from a list of choices. If --<name vK> is specified on the command line, then Some vK will be passed to the command, otherwise, the None value will be passed.

The name function could be non-injective, so that several names can correspond to the same value in the choice list.

The name function shall return syntactically valid command line keys, i.e., non-empty strings that do not contain whitespaces.

val switches : ?doc:('a -> string) -> ?aliases:('a -> string list) -> 'a list -> ('a -> string) -> 'a list param

switches values name is multiple choice switch-type parameter.

The grammar of args $ term $ switches values name is

          G  = term, G' | G', term
          G' = {"--<name v0>" | .. | "--<name vN>"}

where v1 .. vN are elements of values, and <name vK> is the result of application of the name function to the Kth element of the values list.

The switch-type parameters enables a selection from a list of choices, however unlike it switch counterpart, the selector can occur more than once on the command line. For every occurrence --<name vK> on the command line, the corresponding vK value will be added to the list that will be passed as an argument to the command. The order of elements in the list will match with the order of selectors on the command line.

The name function could be non-injective, so that several names can correspond to the same value in the choice list.

The name function shall return syntactically valid command line keys, i.e., non-empty strings that do not contain whitespaces.

val dictionary : ?doc:('k -> string) -> ?as_flag:('k -> 'd) -> ?aliases:('k -> string list) -> 'k list -> 'd typ -> ('k -> string) -> ('k * 'd) list param

dictionary keys t name declares a dictionary-style parameter.

The grammar of args $ term $ dictionary keys t name is

          G  = term, G' | G', term
          G' = ["--<name k0>" [=] t] | .. | ["--<name kN>" [=] t]

where k0 .. kN are elements of the keys list and <name kN> is the result of application of the name function to the kN element of the keys list.

For each occurrence of --<name k> [=] v on the specified command line a binding (k,v) will be added to the dictionary, which is passed as an argument to the command.

Each key-value pair can occur at most once on the command line. If a key-value pair is omitted, then the default t will be added to the dictionary for that key. The length of the passed dictionary is the same as the length of the keys list.

The name function could be non-injective, so that several names can correspond to the same value in the choice list.

The name function shall return syntactically valid command line keys, i.e., non-empty strings that do not contain whitespaces.

Keys as flags

When the as_flag option is specified makes the value part of the grammar becomes optional, thus the grammar of args $ term $ dictionary ~as_flag:s keys t name becomes

          G  = term, G' | G', term
          G' = ["--<name k0>" [[=] t]] | .. | ["--<name kN>" [[=] t]]

If the value is omitted on the command line, by the key k is specified, then the (k,s) will be added to the dictionary.

@parameter as_flag enables the "Keys as flags" mode.

@parameter docv is the name that will be used to reference values in the documentation string.

@parameter doc if specified then doc k will be the documentation string for the --<key k> parameter.

val parameter : ?doc:string -> ?as_flag:'a -> ?aliases:string list -> 'a typ -> string -> 'a param

parameter t name declares a generic command line parameter.

The grammar of args $ term $ parameter t name

          G  = term, G' | G', term
          G' = ["--<name>" [=] t]

If --<name>=v is specified, then v will be passed to the command, otherwise the default t value will be passed.

Parameters as flags

When the as_flag option specified, then the value part of becomes optional and the parameter could be specified without it, as a flag, e.g., --<name>, in that case the value passed to the as_flag parameter will be passed as an argument to the command.

Short keys

The aliases parameter may additionally contain one-character-long names, which will be interpreted as short keys, that should be specified with only one dash character, i.e.,

The grammar of args $ term $ parameter ~aliases:["<k>"] t name

          G  = term, G' | G', term
          G' = ["--<name>" [=] t | "-<k>" [=] t]

where <k> is a single character.

@parameter as_flag enables the "Parameters as flags" mode.

@parameter doc is the documentation string.

@parameter docv is the name used to reference the parameter value in its documentation.

@parameter aliases is a list of additional aliases of the parameter.

val parameters : ?doc:string -> ?as_flag:'a -> ?aliases:string list -> 'a typ -> string -> 'a list param

parameters declares a generic command line parameter.

The grammar of args $ term $ parameters t name

          G  = term, G' | G', term
          G' = {"--<name>" [=] t}

This command line parameter behaves the same as its parameter counterpart, but it could be specified more than once on the command line. For each occurrence of --<name>=v, v will be added to the list (in the order of occurrence), which will be passed as an argument to the command.

See the parameter function for more details.

val flag : ?doc:string -> ?aliases:string list -> string -> bool param

flag name declares a flag-style parameter.

The flag-style parameter is like a normal parameter, except that it is not possible to specify its value.

The grammar of args $ term $ flag name is

          G  = term, G' | G', term
          G' = ["--<name>"]

The flag could be specified at most once on the command line, and if specified then the true value will be passed to the command.

The rest of parameters of the flag function have the same meaning as described in the parameter function.

val flags : ?doc:string -> ?aliases:string list -> string -> int param

flags declares a muti-occurring flag-style parameter.

The grammar of args $ term $ flag name is

          G  = term, G' | G', term
          G' = {"--<name>"}

Unlike it flag counterparts parameters declared as flags make occur more than once on the command line. The number of occurrences will be passed to the command.