apfl/webpage/playground/playground.c
Laria Carolin Chabowski 8d947244c9 Implement exceptions-like error handling
Most functzions will no longer return an enum apfl_result, but will raise
an error that bubbles up.
2022-06-26 16:06:14 +02:00

126 lines
3.2 KiB
C

#include <emscripten.h>
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "dist/src/apfl.h"
#include "dist/src/format.h"
struct playground_source_reader_data {
char *str;
size_t len;
size_t off;
bool eof;
};
EM_ASYNC_JS(char *, get_input, (int need), {
var s = await window.playground_get_input(!!need);
var lengthBytes = lengthBytesUTF8(s)+1;
var stringOnWasmHeap = _malloc(lengthBytes);
stringToUTF8(s, stringOnWasmHeap, lengthBytes);
return stringOnWasmHeap;
});
EM_JS(void, web_writer, (int error, const char* str, int size), {
window.playground_write(!!error, UTF8ToString(str, size));
});
static bool
web_fmt_write(void *opaque, const char *buf, size_t len)
{
int error = (int)opaque;
web_writer(error, buf, (int)len);
return true;
}
static bool
playground_source_reader_cb(void *context, char *buf, size_t *len, bool need)
{
struct playground_source_reader_data *r = context;
size_t remain = r->len - r->off;
if (remain == 0) {
free(r->str);
r->str = get_input(need ? 1 : 0);
assert(r->str != NULL);
r->len = strlen(r->str);
r->off = 0;
}
remain = r->len - r->off;
assert(remain > 0);
if (remain < *len) {
*len = remain;
}
memcpy(buf, r->str+r->off, *len);
r->off += *len;
return true;
}
static void
dump_stack_error(apfl_ctx ctx, apfl_iterative_runner runner, struct apfl_format_writer w_err)
{
if (apfl_iterative_runner_has_error_on_stack(runner)) {
assert(apfl_debug_print_val(ctx, -1, w_err));
}
}
int
main(void)
{
int rv = 0;
struct apfl_format_writer w_ok = {.write = web_fmt_write, .opaque = (void *)0};
struct apfl_format_writer w_err = {.write = web_fmt_write, .opaque = (void *)1};
apfl_ctx ctx = apfl_ctx_new(apfl_allocator_default());
if (ctx == NULL) {
assert(apfl_format_put_string(w_err, "Failed to init the context\n"));
return 1;
}
struct playground_source_reader_data source_reader_data = {
.str = NULL,
.len = 0,
.off = 0,
.eof = false,
};
apfl_iterative_runner runner = apfl_iterative_runner_new(ctx, (struct apfl_source_reader) {
.callback = playground_source_reader_cb,
.opaque = &source_reader_data,
});
if (runner == NULL) {
apfl_ctx_destroy(ctx);
assert(apfl_format_put_string(w_err, "Failed to init runner\n"));
return 1;
}
while (apfl_iterative_runner_next(runner)) {
switch (apfl_iterative_runner_get_result(runner)) {
case APFL_RESULT_OK :
assert(apfl_debug_print_val(ctx, -1, w_ok));
break;
case APFL_RESULT_ERR:
dump_stack_error(ctx, runner, w_err);
assert(apfl_format_put_string(w_err, "Error occurred during evaluation.\n"));
break;
case APFL_RESULT_ERR_FATAL:
dump_stack_error(ctx, runner, w_err);
assert(apfl_format_put_string(w_err, "Fatal error occurred during evaluation.\n"));
rv = 1;
goto exit;
}
}
exit:
free(source_reader_data.str);
apfl_iterative_runner_destroy(runner);
apfl_ctx_destroy(ctx);
return rv;
}