#include #include #include #include #include #include "../../src/apfl.h" #include "../../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((struct apfl_config) { .allocator = apfl_allocator_default(), .output_writer = w_ok, }); 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 : if (apfl_get_type(ctx, -1) == APFL_VALUE_NIL) { apfl_drop(ctx, -1); } else { 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; }