This is part of a series of posts about writing a simple interpreter for a small Lisp-like language. Please see here for an overview of the series.
Last time we added the ability to read Sky data from a C stream. This time we’re doing something with a smaller scope: adding some tests for reading and printing, plus a note-quite-REPL (specifically, without the “eval” part).
You can see the code as of this post here, and a comparison against last time here.
The tests
For the tests, we start with a directory containing some valid examples of Sky data. Specifically, we have:
- A string containing every ASCII character
- A list containing every ASCII character
- The most-positive Sky integer (on 64-bit machines)
- The least-positive Sky integer (on 64-bit machines)
Then we have a script that checks whether read
and print
are
consistent. For each of the test files, it uses the sky
binary to read the
file and then print the data to a new file, and then uses diff
to check that
the file we printed is byte-for-byte identical to the file we read. If it’s not,
it exits with an error code.
The final piece of the puzzle is in the makefile, which has a new check
rule:
check:
@tst/run.sh || (echo "Tests failed" && exit 1)
The end result is that we can run make all check
, which will build Sky and
then test that reading and printing are working as we expect.
We could go a lot further with testing, but I’m keeping it minimal for now. Testing will be easier once we can test Sky in Sky itself.
The not-quite-REPL
The function to implement a REPL-minus-eval is very simple now that we have both
the read
and print
parts:
static void run_repl(void)
{
value_t value;
bool eof = false;
fputs("Welcome to Sky. Use control-c to exit.\n", stdout);
for (;;) {
fprintf(stdout, "> ");
fflush(stdout);
value = read_from_stream(stdin, &eof);
if (eof) break;
println(stdout, value);
}
fputs("\nGoodbye\n", stdout);
}
The result is that we can interactively send expressions to Sky, which will read them and print them back. The important thing is that it’s not just echoing the text; the text is being read, resulting in Sky values, which are then printed.
Here’s a brief example session:
~/code/sky/> ./src/sky
Welcome to Sky. Use control-c to exit.
> 1
1
> one
one
> "foo\nbar"
"foo\nbar"
> (#\a #\b #\c)
(#\a #\b #\c)
> ^C
Goodbye
That’s all for this time.
Next time
Next time I think we’ll try to solve the problem I referenced when discussing printing, which is that there are currently some symbols which can be printed but not read.