2022-06-05 20:31:02 +00:00
|
|
|
#include <emscripten.h>
|
|
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2022-10-28 19:32:33 +00:00
|
|
|
#include "../../src/apfl.h"
|
|
|
|
|
#include "../../src/format.h"
|
2022-06-05 20:31:02 +00:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-24 21:13:44 +00:00
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-05 20:31:02 +00:00
|
|
|
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};
|
|
|
|
|
|
2022-10-28 19:32:17 +00:00
|
|
|
apfl_ctx ctx = apfl_ctx_new((struct apfl_config) {
|
|
|
|
|
.allocator = apfl_allocator_default(),
|
|
|
|
|
.output_writer = w_ok,
|
|
|
|
|
});
|
2022-06-05 20:31:02 +00:00
|
|
|
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 :
|
2022-10-30 21:43:38 +00:00
|
|
|
if (apfl_get_type(ctx, -1) == APFL_VALUE_NIL) {
|
|
|
|
|
apfl_drop(ctx, -1);
|
|
|
|
|
} else {
|
|
|
|
|
assert(apfl_debug_print_val(ctx, -1, w_ok));
|
|
|
|
|
}
|
2022-06-05 20:31:02 +00:00
|
|
|
break;
|
|
|
|
|
case APFL_RESULT_ERR:
|
2022-06-24 21:13:44 +00:00
|
|
|
dump_stack_error(ctx, runner, w_err);
|
2022-06-05 20:31:02 +00:00
|
|
|
assert(apfl_format_put_string(w_err, "Error occurred during evaluation.\n"));
|
|
|
|
|
break;
|
2022-12-09 20:22:50 +00:00
|
|
|
case APFL_RESULT_ERR_ALLOC:
|
|
|
|
|
assert(apfl_format_put_string(w_err, "Fatal: Could not allocate memory.\n"));
|
2022-06-05 20:31:02 +00:00
|
|
|
rv = 1;
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-08 20:35:41 +00:00
|
|
|
if (apfl_iterative_runner_stopped_because_of_error(runner)) {
|
|
|
|
|
assert(apfl_format_put_string(w_err, "Runner stopped due to error.\n"));
|
|
|
|
|
rv = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-05 20:31:02 +00:00
|
|
|
exit:
|
|
|
|
|
free(source_reader_data.str);
|
|
|
|
|
apfl_iterative_runner_destroy(runner);
|
|
|
|
|
apfl_ctx_destroy(ctx);
|
|
|
|
|
return rv;
|
|
|
|
|
}
|