Table of Contents
As Part II explained, the world of Stratego is one of small programs tied together using Unix pipes. The pipes carry the data, while configuration and control is passed between programs in the form of command line arguments. Incidentally, this is the same mechanism used by humans to invoke programs, and this eases understanding and debugging of XT compositions tremendously. Details about debugging is covered in Chapter 30. In this chapter, we will cover the mechanism available in Stratego for working with command line arguments.
When a compiled Stratego program is first started, the initial value of the current term is a list containing the command line arguments to the program. Fhe following program, foo, is a genuine "do nothing" program.
module foo imports liblib strategies main = id
In the course of this chapter, we will extend this program with new options and even a help screen for the user to enjoy. But first, let us compile and run foo with some arguments, to get an idea of where we stand.
$strc -i foo.str ...
$./foo --help ["./foo","--help"]
$./foo -i foo.str --extra --option -s ["./foo","-i","foo.str","--extra","--option","-s"]
From this interaction, we see that a list of the
arguments provided on the command line becomes the
initial term of the program. Each command line argument
becomes its own string element in the list, and the first
element of the list is the command used to invoke the
foo itself. Clearly, this list must be
interpreted somehow, for the arguments to have any meaning.
The library contains a collection of robust strategies
that deal with just this. The option handling strategies
will parse the argument list, let you set default values
for options and transparently deal with long and short
forms of the same option. Even more interesting, the
library provides so-called
that abstract away all of the dreary details of this
option handling, and also provide a default set of
options with some basic functionality.
Perhaps the most frequently used wrap strategy is
io-wrap (or its XTC equivalent,
xtc-io-wrap, which is not covered here).
io-wrap is a family of strategy,
io-wrap(opts, s) and
io-wrap(opts, usage, about, s). All of
these variants provide the same basic functionality. The
increasing number parameters allows you to override
default bevhavior, when you need to. When using
one of these strategies, a standard package of
command line handling will be provided to your users
through your program. Let us start with the simplest
io-wrap(s) and work our way from
there. Consider a revised edition of foo,
module foo imports liblib strategies main = io-wrap(id)
Here, we wrap the core logic of our program (just
in our case) inside the
io-wraper. If we run
foo with the
this time around, we will get a more instructive reply than
$./foo --help Options: -i f|--input f Read input from f -o f|--output f Write output to f -b Write binary output -S|--silent Silent execution (same as --verbose 0) --verbose i Verbosity level i (default 1) ( i as a number or as a verbosity descriptor: emergency, alert, critical, error, warning, notice, info, debug, vomit ) -k i | --keep i Keep intermediates (default 0) --statistics i Print statistics (default 0 = none) -h|-?|--help Display usage information --about Display information about this program --version Same as --about Description:
All of a sudden, our program is a well-behaved citizen
in the command line world. It answers to
--help, and appears to have a few other
tricks up its sleeve to. For example, the input term
to foo can now be specified using the
-i option, and output can be stored to
a file using the
So does this actually work? All for free? Let's test with
putting the following term into the file
Bursting with excitement, we try:
$./foo -i term.trm Yes(It(Works))
And if that's not enough, there is even a bit of extra
convenience provided by
-i is not provided,
stdin is read. Similarly,
stdout is written to if
-o is not specified.
io-wrap is all you have to do for your program
to gain a minimal, but functional set of command line options. As a
bonus, these options also make your program compatible with XTC; it
can be composed with other XTC components.
It is often necessary for programs to expose switches to turn
functionality on and off, or to read extra configuration knowledge
from external files. All these cases require additional command
line options, so we need a mechanism for extending
io-wrap(s) strategy. The preferred way of
adding new options is to use the
strategy, providing it with a strategy encoding the options.
When adding a new option, we must decide whether this option
will require a argument of its own, or not. The term
ArgOption is used to construct options that take
Option is the term used for on/off
switches. Suppose we want to expose an option
--verify that enables the user to run our
transformation in a self-verifying mode. This is clearly an
on/off switch, and therefore a job for
Adding this option to our program foo gives us the following code:
module foo imports liblib signature constructors Verify : Option strategies main = io-wrap( Option( "--verify" , <set-config> (Verify(), "on") , !"--verify Turn on verification") , do-foo) do-foo = ...
Note that we made a new term type,
Verify, to serve as
our switch symbol. Inside the real logic of program,
do-foo, we would write
<get-config> Verify to get the state of the
Verify switch. In the case where the user had specified
--verify on the command line,
get-config would result in the term
taken from the declaration of our verify
the did not add
--verify to his command line
<get-config> Verify will fail.
Options with arguments is provided through
The use is pretty much identical to that of
Assume our transformation needs a bit of help from configurable
processing tables (whatever that might be), and that we want these
tables configured at runtime, using the
We want to add another alternative to the
main = io-wrap( Option(....) + ArgOption( "-p" , where(<extend-config> ("-p", [<id>])) , !"-p file Use processing table in file") , id)
Note how we compose options with the choice operator (
With this addition, our users can now specify their elusive processing
tables with the
-p. The arity of this option is checked
automatically. That is, if the user adds
-p to his
argument list without specifying a file afterwards, this will be signaled
as an error, and the usage screen will be printed. Once the user has
read this and corrected the error of his ways, the value (the filename)
-p can be obtained using the
get-option strategy. If no
get-option will fail. Sometimes, this failure
may be inappropriate, and a default value is desired instead. If you
browse through Stratego code, you may come across the following idiom
for dealing with this situation:
get-config-p = <get-config> "-p" <+ !
This is all you need to know about basic command-line option processing. When in doubt, you are advised to refer to the detailed API documentation is available in the API reference.
If your program is primarily intended for human use, you are encouraged to complete your program's option configuration with a short description of what your tool does.
We can easily add a short description and also an about section.
The description is shown as part of the help screen
--help), whereas the about
section is displayed when the arguments to foo
--about. It is customary for the about
screen to contain copyright notices and credits.
main = io-wrap( ... , foo-tool-usage , foo-tool-about , id) foo-tool-usage = default-system-usage( !["Usage: foo -p proctbl [options]"] , ![ "This program verifies the input against a processing table.\n"] ) foo-tool-about = <echo> "Written by Alan Turing <email@example.com>"
After compiling this version of foo, invoking
--help give the following help screen:
$./foo --help Usage: foo -p proctbl [options] Options: --verify Turn on verification -p file Use processing table in file -i f|--input f Read input from f -o f|--output f Write output to f -b Write binary output -S|--silent Silent execution (same as --verbose 0) --verbose i Verbosity level i (default 1) ( i as a number or as a verbosity descriptor: emergency, alert, critical, error, warning, notice, info, debug, vomit ) -k i | --keep i Keep intermediates (default 0) --statistics i Print statistics (default 0 = none) -h|-?|--help Display usage information --about Display information about this program --version Same as --about Description: This program verifies the input against a processing table.
If we invoke our splendid program foo with
--about option, we can now observe:
$./foo --about Written by Alan Turing <firstname.lastname@example.org>
Not all programs written in Stratego intended for processing ATerms.
For these programs, the full I/O functionality provided by
io-wrap may often turn out to be inappropriate. An
alternative way of dealing with parameters is also provided by
the library, centered around the
option-wrap family of
option-wrap works analogously to
io-wrap, but does not provide the
-o options, nor does it read anything from
The default set of options provided by
is shown below:
--verify Turn on verification -h|-?|--help Display usage information --about Display information about this program --version Same as --about
Adding new options is identical to what we already explained