Input and Output
Note: Silver now has support for Monads, so you may wish to use those instead.
There are no real values of type IOToken
, instead, this is a “token” value
that is passed around in order to preserve the order of execution of
imperative IO actions. You can think of IOToken
values as being the entire
universe, and the IOToken
input to a function is the state before the action
and the IOToken
output of a function is the state after the action.
Since many IO functions will want to return more than the resulting IOToken
token, there is a standard type called IOVal<a>
that IO functions use
to return values of other types in addition.
IOVal
has only one constructor, ioval
.
abstract production ioval
top::IOVal<a> ::= i::IOToken v::a
The first parameter is the IO token, and the second is the value to wrap up.
Note: There is an unofficial convention for Silver standard library functions to place the “primary” value last.
ioval
arguably violates this convention, for legacy reasons.
Example:
function main
IOVal<Integer> ::= args::[String] ioin::IOToken
{
return ioval(printT("Hi\n", ioin), 0);
}
or
fun main IOVal<Integer> ::= args::[String] ioin::IOToken =
ioval(printT("Hi\n", ioin), 0);
is a Silver program that prints
"Hi"
, and exits with a successful error code.
function print
IO ::= s::String i::IOToken
Displays a string on standard out. Newlines are NOT automatically added.
Example:
print("world!\n", print("Hello, ", ioin))
will print
"Hello, world!"
.
function readFile
IOVal<String> ::= s::String i::IOToken
Read the entire contents of a file. All instances of “\r\n” are replaced by “\n” to work around issues on windows. If the read fails, an uncatchable error is thrown.
Example:
local attribute contents :: IOVal<String>;
contents = readFile(head(args), ioin);
will store the contents of the first argument into
contents
.
function writeFile
IO ::= file::String contents::String i::IOToken
Write a string to a file, replacing whatever is there already. If the write fails, an uncatchable error is thrown.
Example:
writeFile("output.txt", tree.pp, ioin)
will write
tree
’s pretty print to"output.txt"
.
function readFile
IOVal<String> ::= i::IOToken
Reads a line from standard input. If the read fails, an uncatchable error is thrown.
Example:
local attribute text :: IOVal<String>;
contents = readLineStdIn(ioin);
will store one line from stdin into
text
.
function exit
IO ::= val::Integer i::IOToken
Terminates immediately with the specified error code.
Example:
print("Hi", exit(-1, ioin))
will terminate with an error before ever printing the string.
function mkdir
IOVal<Boolean> ::= s::String i::IOToken
Creates a directory, including any parents that need to be created along the way. Similar to ‘mkdir -p’. If it fails, it may create only some of them.
Returns true if successful, otherwise returns false.
Example:
mkdir("a/sub/directory", ioin)
will create
./a/sub/directory/
.
function system
IOVal<Integer> ::= s::String i::IOToken
Executes a shell command. Specifically executes bash -c
. (And thus, may not
work on windows, unless executing under Cygwin or similar.)
Avoid using this if possible. If you need to perform some ordinary form of IO Silver does not yet support, please request it on the \texttt{melt-help@cs.umn.edu} mailing list.
Access to command’s output is not directly available, but it is run in a shell. You can redirect to a file and read that.
Example:
system("silver some:grammar && ant > stdout.txt 2> stderr.txt", ioin)
will run the commands, and leave their output in some files.
function appendFile
IO ::= file::String contents::String i::IOToken
Unlike writeFile
, appends
the string to the end of the file instead of truncating the file first.
Example:
appendFile("log.txt", "Oh, my.\n", ioin)
add
"Oh, my."
to the end oflog.txt
.
function fileTime
IOVal<Integer> ::= s::String i::IOToken
The time, in seconds since 1970, when this file (or directory) was last modified. 0 if the file is not found.
Example:
fileTime("log.txt", ioin)
returns the time the file was last modified (wrapped.)
function isFile
IOVal<Boolean> ::= s::String i::IOToken
Checks if a file is an ordinary file. (non-directory, non-special)
Example:
isFile("/etc/passwd", ioin)
returns is true (wrapped). On Linux, anyway.
function isDirectory
IOVal<Boolean> ::= s::String i::IOToken
Checks if a path is a directory.
Example:
isDirectory("/etc/passwd", ioin)
returns is false (wrapped.)
function cwd
IOVal<String> ::= i::IOToken
Return the current working directory. (There is no way to change it.)
Example:
cwd(ioin)
returns the directory the program was run from (wrapped.)
function envVar
IOVal<String> ::= s::String i::IOToken
Obtains the value of an environment variable. (There is no way to set them.)
Example:
envVar("GRAMMAR_PATH", ioin)
returns the value of the grammar path environment variable (wrapped.)
function listContents
IOVal<[String]> ::= s::String i::IOToken
List the contents of a directory. Returns the empty list if not a directory or other IO error.
Example:
listContents(".", ioin)
returns a list of the files (or directories) in the current directory (wrapped.)
function deleteFile
IOVal<Boolean> ::= s::String i::IOToken
Delete a file, or an empty directory. Returns false if an error occurs, or the file does not exist (or the directory is non-empty.)
Example:
deleteFile("doesNotExist.txt", ioin)
will return false (wrapped), or delete that file.
Sometimes, it is necessary to take some action in a place where IO is not available. This occurs most often when some internal error occurs, or when attempting to debug an attribute grammar specification.
function error
a ::= msg::String
Die with the stated error message and a stack trace when evaluated. Note that Silver stacks may be hard to read (it’s a lazy language.)
Note that IOToken
is not involved at all.
Example:
error("Not yet implemented!")
terminates with the error message.
function genInt
Integer ::=
Generate an integer unique to this run of this process. (Starts from 0 and just counts up each call.) This violates the “purity” of Silver code, but it’s incredibly convenient! :)
Example:
abstract production foo
top::Expr ::=
{
production attribute myid::String;
myid = "foo#" ++ toString(genInt());
}
assigns a unique (to this run of the process) id for each instance of the production
foo
.
function unsafeTrace
a ::= val::a act::IOToken
function unsafeIO
IO ::=
When an expression is evaluated by the runtime system, executes the actions associated with the IO token act
(a sequence that should be started by calling unsafeIO()
), and then simply returns the value val
.
Example:
unsafeTrace(foo.pp, print("foo's pp is " ++ foo.pp, unsafeIO()))
prints out
foo
’s pretty print, before returning it.
Example: This usage is STRONGLY DISCOURAGED, but may sometimes be necessary during debugging or testing.
readFile("something.txt", unsafeIO()).iovalue
evaluates to the contents of a file, without having any IO tokens around.
Some of this page should be in a Concept_IO, and the rest is probably just library documentation, but move it here for now.