Table of Contents
This chapter explains the strategies available in the library for controlling file and console I/O.
The need for traditionally file I/O is somewhat diminished
for typical applications of Stratego. Normally, Stratego
programs are designed to worktogether connected by Unix
pipes. The programs employ
io-wrap (or similar
strategies) that automatically take care of the input and
output. See Chapter 26 for details.
The primitive layer of Stratego I/O inherits its
characteristics from Unix. The basic I/O strategies
recognize the special files
stderr. Streams are
fopen and closed with
fclose On top of this, a collection of
more convient strategies have been built.
The basic strategies for console I/O
printnl are used to write terms to
stderr (or any
other opened file). They both take a tuple. The first
element of the tuple is the file to write to, the
second is a list of terms. Each term in the list be
converted to a string, and and these strings will
be concatenated together to form the resulting output.
printnl will also append a newline to
the end of the resulting string.
The following module should be compiled with strc, as usual.
module example imports libstratego-lib strategies main = <print> (stdout, ["baz"]) ; <printnl> (stdout, [ "foo", 0, "bar" ])
After compiling this file, running it will give the following result:
Notice how the string
baz will be written
without a newline (or other space). Also, notice how the
terms in the list argument were concatenated.
When using these strategies in the Stratego Shell, some care must
be taken when using the
std* files, as the following
stratego><printnl> (stdout(), [ "foo", 0, "bar" ]) foo0bar
The shell requires that you put an extra parenthesis after the
error are convenience
printnl. They will always write
their result to
strategy is defined as:
error = where(<printnl> (stderr, <id>))
It is used similarly to the
stratego><error> ["foo", 0, "bar"] foo0bar
debug strategy accepts any term, i.e.
not only lists of terms. The term will be written
stratego><debug> [ "foo", 0, "bar" ] ["foo",0,"bar"]
The library provides a small set of simple file and directory
manipulation operations. Assume the directory
/tmp only contains the files
baz. Elementary directory operations
can be done as illustrated below:
stratego><readdir> "/tmp" ["foo","bar","baz"]
stratego><rename-file> ("/tmp/foo", "/tmp/bax") "/tmp/bax"
stratego><remove-file> "/tmp/baz" 
stratego><link-file> ("/tmp/bar", "/tmp/foo") "/tmp/foo"
stratego><link-file> ("/tmp/bar", "/tmp/foo") "/tmp/foo"
stratego><new-temp-dir> "/tmp" "/tmp/StrategoXTnsGplS"
The library contains a family of strategies which must be applied
File, and will return information about it.
islnk which are predicates
checking if a file is a directory, TTY, FIFO or a symbolic
link, respectively. To obtain a
File object in the
first place, we should call
filemode. Thus, checking if
is a directory is done as follows:
stratego><file-exists ; filemode ; isdir> "/etc"
The library also has another family of strategies for getting
information about files. These must be applied to a string
containing the filename. The family includes
stratego><is-executable> "/bin/bash" "/bin/bash"
Finally, the directory strategies also include the usual suspects for dealing with paths.
stratego><is-abspath> "../foo" command failed
stratego><dirname> "/foo/bar/baz" "/foo/bar"
stratego><base-filename> "/foo/bar/baz" "baz"
stratego><get-extension "/tmp/foo.trm" "trm"
stratego><abspath> "../foo" /home/karltk/source/oss/stratego/strategoxt-manual/trunk/../foo
There are also a few strategies for finding files. We shall
find-file(s). The other variants of
find-file are described in the library
documentation. The strategy
find-file(s) finds one
file with a specific file extension in a list of directories. It
takes a two-element tuple. The first element is a file name as a
string, then second element is a list of paths, i.e.
[d*]). The extension of
f will be
replaced by what is produced by
s, and the
directories given in
[d*]. Consider the code below.
stratego><find-file(!"rtree")> ("file.str", ["."])
This snippet will consider the filename
replace its extension with
rtree and look through
the directories in the list
["."]. Effectively, it will
file.rtree in the current directory.
Opening a file is done with the
fopen strategy. It takes
a two-element tuple, the first element is the filename as a string,
the second is the open mode, which is also a string. The most important
modes are read (
r); write ("w") which opens and empty file
for writing, truncating any existing file with the same name; and
a) which appends to the file if it already exists.
After all file operations stream have been finished, it should be closed
fclose, which will flush and close the file. Explicit
flushing can also be done with
It should be pointed out that reading and writing text files with Stratego
is rather rare. Normally, text files are read with a parser generated from
an SDF description and written using a pretty-printer defined in the
Box formalism. In rare cases, this may turn out be too heavy handed,
especially if the file format is simplistic and line-based. In this
instance, we can come up with an easier solution using
Assume the file
/tmp/foo contains the following
one two three
We can read this file in one big chunk into a string with the
read-text-file strategy, which must be applied to
stratego> <read-text-file> "/tmp/foo" "one\ntwo\nthree\n"
Alternatively, for example if the file is large, we can read it line by line. In this scenario, we must open the file and get a handle to a stream.
stratego><fopen> ("foo.txt", "r") => inp Stream(136788400)
stratego><read-text-line> inp "one"
The primary form of file I/O you will be using in Stratego is
reading and writing terms. As explained earlier, the terms
are stored on disk as either binary, compressed text or
plain text ATerms. Reading a term, no matter which storage
format, is done with the
It is applied to a filename.
stratego><ReadFromFile> "/tmp/foo.trm" Foo(Bar)
To write a term to file, you can use
WriteToBinaryFile. The binary format is
approximately eight times more space-efficient on average. Both
strategies take a two-element tuple where the first element is
the filename and second is the term to write. Writing the current
term requires a minor twist, which is shown here:
stratego><WriteToBinaryFile> ("/tmp/bar.trm", <id>) Foo(Bar)
It is also possible to read and write terms from and to strings,
Chapter 23 contains explanation of how these
The strategies for logging are used pervasively throughout the Stratego
toolchain. They are easy to use in your own applications, too. The
logging system is built on top of the
log(|severity, msg) and
log(|severity, msg, term)
strategies. It is possible to use these directory, as the following
stratego>log(|Error(), "my error")
However, it is preferrable to use the high-level wrapper strategies
fatal-err-msg, these strategies will
return with the current term untouched, and write the message
as a side effect. The
fatal-err-msg strategy will
also terminate the program with error code
writing the message.