apfl/src/repl.c

174 lines
4.2 KiB
C
Raw Normal View History

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "alloc.h"
#include "repl.h"
struct repl_data {
apfl_ctx ctx;
struct apfl_allocator alloc;
char *buf;
size_t buf_len;
size_t buf_cap;
struct apfl_io_writer w_out;
struct apfl_io_writer w_err;
};
static bool
null_writer(void *opaque, const unsigned char *buf, size_t len)
{
(void)opaque;
(void)buf;
(void)len;
return true;
}
static bool
redirect_writer(void *opaque, const unsigned char *buf, size_t len)
{
repl r = opaque;
return r->w_out.write(r->w_out.opaque, buf, len);
}
repl
repl_new(struct apfl_allocator alloc)
{
repl r = ALLOC_OBJ(alloc, struct repl_data);
if (r == NULL) {
return NULL;
}
r->alloc = alloc;
r->buf = NULL;
r->buf_len = 0;
r->buf_cap = 0;
r->w_out = (struct apfl_io_writer){.write = null_writer};
r->w_err = (struct apfl_io_writer){.write = null_writer};
r->ctx = apfl_ctx_new((struct apfl_config) {
.allocator = alloc,
.output_writer = (struct apfl_io_writer){.write = redirect_writer, .opaque = r},
});
if (r->ctx == NULL) {
repl_destroy(r);
return NULL;
}
return r;
}
void
repl_set_w_out(repl r, struct apfl_io_writer w)
{
r->w_out = w;
}
void
repl_set_w_err(repl r, struct apfl_io_writer w)
{
r->w_err = w;
}
static void
protected_callback(apfl_ctx ctx, void *opaque)
{
(void)opaque;
apfl_run_in_top_scope(ctx, -1);
}
static enum repl_result
report_error(repl r, struct apfl_error error)
{
apfl_error_print(error, r->w_err);
return (error.type == APFL_ERR_MALLOC_FAILED || error.type == APFL_ERR_INPUT_ERROR)
? REPL_FATAL
: REPL_ERR;
}
enum repl_result
repl_run(repl r, char *input)
{
if (input != NULL) {
size_t input_len = strlen(input);
size_t needed = r->buf_len + input_len;
if (r->buf_cap < needed) {
char *newbuf = REALLOC_BYTES(r->alloc, r->buf, r->buf_cap, needed);
if (newbuf == NULL) {
return REPL_FATAL;
}
r->buf = newbuf;
r->buf_cap = needed;
}
memcpy(r->buf + r->buf_len, input, input_len);
r->buf_len += input_len;
}
struct apfl_io_string_reader_data sr = apfl_io_string_reader_create(
(struct apfl_string_view) {
(unsigned char *)r->buf,
r->buf_len,
}
);
struct apfl_error error;
apfl_push_const_string(r->ctx, "<toplevel>");
if (!apfl_load_try(r->ctx, apfl_io_string_reader(&sr), -1, &error)) {
if (
error.type == APFL_ERR_UNEXPECTED_EOF
|| error.type == APFL_ERR_UNEXPECTED_EOF_AFTER_TOKEN
) {
if (input == NULL) {
(void)report_error(r, error);
return REPL_FATAL;
} else {
return REPL_MORE_INPUT;
}
} else {
return report_error(r, error);
}
}
r->buf_len = 0;
switch (apfl_do_protected(r->ctx, protected_callback, NULL, apfl_error_decorate_with_backtrace)) {
case APFL_RESULT_OK :
if (apfl_get_type(r->ctx, -1) == APFL_VALUE_NIL) {
apfl_drop(r->ctx, -1);
} else {
apfl_debug_print_val(r->ctx, -1, r->w_out);
}
return REPL_OK;
case APFL_RESULT_ERR:
apfl_io_write_string(r->w_err, "Error occurred during evaluation:\n");
if (apfl_get_type(r->ctx, -1) == APFL_VALUE_STRING) {
apfl_io_write_string(r->w_err, apfl_get_string(r->ctx, -1));
apfl_drop(r->ctx, -1);
} else {
apfl_debug_print_val(r->ctx, -1, r->w_err);
}
apfl_io_write_byte(r->w_err, '\n');
return REPL_ERR;
case APFL_RESULT_ERRERR:
apfl_io_write_string(r->w_err, "Error occurred during error handling.\n");
return REPL_FATAL;
case APFL_RESULT_ERR_ALLOC:
apfl_io_write_string(r->w_err, "Fatal: Could not allocate memory.\n");
return REPL_FATAL;
}
assert(false && "unreachable");
return REPL_FATAL;
}
void
repl_destroy(repl r)
{
apfl_ctx_destroy(r->ctx);
FREE_BYTES(r->alloc, r->buf, r->buf_cap);
FREE_OBJ(r->alloc, r);
}