diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 2e57449..f3a180f 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(imp prim.c print.c read.c + repl.c store.c token.c ) diff --git a/lib/include/repl.h b/lib/include/repl.h new file mode 100644 index 0000000..30fa4b2 --- /dev/null +++ b/lib/include/repl.h @@ -0,0 +1,16 @@ +#ifndef REPL_H +#define REPL_H + +#include "am.h" + +#define REPL_IO_BUFFER_SIZE 256U + +typedef struct { + am_t am; + char io_buffer[REPL_IO_BUFFER_SIZE]; +} repl_t; + +void repl_init(repl_t *repl); +int repl_run(repl_t *repl); + +#endif diff --git a/lib/repl.c b/lib/repl.c new file mode 100644 index 0000000..c84904f --- /dev/null +++ b/lib/repl.c @@ -0,0 +1,58 @@ +#include "repl.h" + +#include "eval.h" +#include "memory_stream.h" +#include "print.h" +#include "read.h" + +#include +#include + +#define PROMPT "> " + +static int read_line(char buffer[REPL_IO_BUFFER_SIZE]) +{ + for (unsigned i = 0; i < REPL_IO_BUFFER_SIZE; ++i) { + const int c = getchar(); + switch (c) { + case EOF: + return EOF; + case '\n': + return (int)i; + default: + buffer[i] = (char)c; + break; + } + } + assert(false); + return -2; +} + +void repl_init(repl_t *repl) +{ + am_init(&repl->am); +} + +int repl_run(repl_t *repl) +{ + int len; + memory_stream_t input; + + while (true) { + fputs(PROMPT, stdout); + + len = read_line(repl->io_buffer); + if (len < 0) { + fputc('\n', stdout); + return 0; + } + memory_stream_init(&input, (const uint8_t *)repl->io_buffer, len); + read(&repl->am, (stream_t *)&input); + + eval(&repl->am); + + len = print(&repl->am, repl->io_buffer, REPL_IO_BUFFER_SIZE - 1); + repl->io_buffer[len] = '\n'; + fwrite(repl->io_buffer, 1, len + 1, stdout); + } +}