Extension.Command
Interface for specifying commands.
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
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).
args t $ t'
extends the grammar specification t
with t'
.
argument t
declares a positional argument of type t
.
The grammar of args $ term $ argument t
:
G = term, [t] | [t], term
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 K
th 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 K
th 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.
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.