Push formatted parser error on stack during evaluation

This way we can see the parse errors again in evaluation mode

Not fully fleshed out yet: We simply use apfl_debug_print_val to dump the
top of the stack (the formatted error) to stderr but don't nicely handle
if there is nothing on the stack (apfl_debug_print_val will print a rather
cryptic "stack index invalid" error). Also the whole dance we need to do to
put the formatted error onto the stack feels rather awkward (there should
probably a function for this) and we also should probably try to push an
error description on the stack in case this moving-string-to-stack business
fails.

Now "only" all other errors need to be put on the stack as a string :)
This commit is contained in:
Laria 2022-04-21 22:40:27 +02:00
parent f8bab311d7
commit 0f6f136873
10 changed files with 97 additions and 19 deletions

View file

@ -192,6 +192,7 @@ struct apfl_error {
};
bool apfl_error_print(struct apfl_error, FILE *);
bool apfl_error_as_string(struct apfl_error, struct apfl_allocator, struct apfl_string *out);
struct apfl_error apfl_error_simple(enum apfl_error_type);
bool apfl_error_is_fatal_type(enum apfl_error_type);

View file

@ -150,8 +150,8 @@ apfl_stack_get(apfl_ctx ctx, struct apfl_value *value, apfl_stackidx index)
return stack_get_and_adjust_index(ctx, value, &index);
}
static struct apfl_value *
stack_push_placeholder(apfl_ctx ctx)
struct apfl_value *
apfl_stack_push_placeholder(apfl_ctx ctx)
{
if (!apfl_stack_push(ctx, (struct apfl_value) {.type = VALUE_NIL})) {
return NULL;
@ -224,20 +224,20 @@ apfl_ctx_destroy(apfl_ctx ctx)
FREE_OBJ(base_allocator, ctx);
}
#define CREATE_GC_OBJECT_VALUE_ON_STACK(ctx, TYPE, MEMB, NEW) \
struct apfl_value *value = stack_push_placeholder(ctx); \
if (value == NULL) { \
return APFL_RESULT_ERR_FATAL; \
} \
\
struct apfl_value new_value = {.type = TYPE}; \
if ((new_value.MEMB = NEW) == NULL) { \
assert(apfl_stack_drop(ctx, -1)); \
return APFL_RESULT_ERR_FATAL; \
} \
\
*value = new_value; \
\
#define CREATE_GC_OBJECT_VALUE_ON_STACK(ctx, TYPE, MEMB, NEW) \
struct apfl_value *value = apfl_stack_push_placeholder(ctx); \
if (value == NULL) { \
return APFL_RESULT_ERR_FATAL; \
} \
\
struct apfl_value new_value = {.type = TYPE}; \
if ((new_value.MEMB = NEW) == NULL) { \
assert(apfl_stack_drop(ctx, -1)); \
return APFL_RESULT_ERR_FATAL; \
} \
\
*value = new_value; \
\
return APFL_RESULT_OK;
enum apfl_result
@ -371,7 +371,7 @@ apfl_get_member_inner(
struct apfl_value container,
struct apfl_value k
) {
struct apfl_value *value = stack_push_placeholder(ctx);
struct apfl_value *value = apfl_stack_push_placeholder(ctx);
if (value == NULL) {
return APFL_RESULT_ERR;
}

View file

@ -37,6 +37,7 @@ bool apfl_stack_pop(apfl_ctx, struct apfl_value *value, apfl_stackidx);
bool apfl_stack_get(apfl_ctx, struct apfl_value *value, apfl_stackidx);
bool apfl_stack_drop(apfl_ctx, apfl_stackidx);
void apfl_stack_clear(apfl_ctx);
struct apfl_value *apfl_stack_push_placeholder(apfl_ctx);
#ifdef __cplusplus
}

View file

@ -197,6 +197,16 @@ apfl_error_print(struct apfl_error error, FILE *file)
return true;
}
bool
apfl_error_as_string(struct apfl_error error, struct apfl_allocator allocator, struct apfl_string *out)
{
struct apfl_string_builder builder;
apfl_string_builder_init(allocator, &builder);
TRY(format_error(apfl_format_string_writer(&builder), error));
*out = apfl_string_builder_move_string(&builder);
return true;
}
struct apfl_error
apfl_error_simple(enum apfl_error_type type)
{

View file

@ -241,6 +241,36 @@ apfl_iterative_runner_new(apfl_ctx ctx, struct apfl_source_reader reader)
return runner;
}
static enum apfl_result
handle_parse_error(apfl_ctx ctx, struct apfl_error error)
{
enum apfl_result result = APFL_RESULT_ERR;
if (apfl_error_is_fatal_type(error.type)) {
result = APFL_RESULT_ERR_FATAL;
}
// TODO: Putting the string on the stack should be easier. It's rather awkward now...
struct apfl_string string;
if (!apfl_error_as_string(error, ctx->gc.allocator, &string)) {
// TODO: Maybe try to push something on the stack in case of error (also for other error cases below)?
return APFL_RESULT_ERR_FATAL;
}
struct apfl_value *value = apfl_stack_push_placeholder(ctx);
if (value == NULL) {
return APFL_RESULT_ERR_FATAL;
}
if ((value->string = apfl_string_move_into_new_gc_string(&ctx->gc, &string)) == NULL) {
return APFL_RESULT_ERR_FATAL;
}
value->type = VALUE_STRING;
return result;
}
bool
apfl_iterative_runner_next(apfl_iterative_runner runner)
{
@ -254,7 +284,7 @@ apfl_iterative_runner_next(apfl_iterative_runner runner)
case APFL_PARSE_OK:
goto ok;
case APFL_PARSE_ERROR:
runner->result = APFL_RESULT_ERR;
runner->result = handle_parse_error(runner->ctx, apfl_parser_get_error(runner->parser));
return true;
case APFL_PARSE_EOF:
runner->end = true;

View file

@ -17,6 +17,13 @@ write_file(void *opaque, const char *buf, size_t len)
return fwrite(buf, len, 1, f) == 1;
}
static bool
write_string(void *opaque, const char *buf, size_t len)
{
struct apfl_string_builder *sb = opaque;
return apfl_string_builder_append(sb, (struct apfl_string_view) {.bytes = buf, .len = len});
}
struct apfl_format_writer
apfl_format_file_writer(FILE *f)
{
@ -26,6 +33,15 @@ apfl_format_file_writer(FILE *f)
};
}
struct apfl_format_writer
apfl_format_string_writer(struct apfl_string_builder *sb)
{
return (struct apfl_format_writer) {
.write = write_string,
.opaque = sb,
};
}
bool
apfl_format_put_string_view(struct apfl_format_writer w, struct apfl_string_view sv)
{

View file

@ -18,6 +18,8 @@ struct apfl_format_writer {
struct apfl_format_writer apfl_format_file_writer(FILE *f);
struct apfl_format_writer apfl_format_string_writer(struct apfl_string_builder *sb);
bool apfl_format_put_string_view(struct apfl_format_writer, struct apfl_string_view);
#define apfl_format_put_string(w, s) apfl_format_put_string_view((w), apfl_string_view_from(s))
bool apfl_format_put_int(struct apfl_format_writer, int);

View file

@ -8,6 +8,8 @@ extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include "gc.h"
#define DEINIT_CAP_LIST(allocator, items, len, cap, item_deinit) \
do { \
if ((items) == NULL) { \
@ -87,6 +89,8 @@ do { \
void apfl_print_indented(unsigned indent, FILE *, const char* fmt, ...);
struct apfl_string *apfl_string_move_into_new_gc_string(struct gc *gc, struct apfl_string *in);
#ifdef __cplusplus
}
#endif

View file

@ -158,10 +158,11 @@ repl_eval(void)
while (apfl_iterative_runner_next(runner)) {
switch (apfl_iterative_runner_get_result(runner)) {
case APFL_RESULT_OK:
case APFL_RESULT_OK :
apfl_debug_print_val(ctx, -1, stdout);
break;
case APFL_RESULT_ERR:
apfl_debug_print_val(ctx, -1, stderr);
fprintf(stderr, "Error occurred during evaluation.\n");
break;
case APFL_RESULT_ERR_FATAL:

View file

@ -6,6 +6,7 @@
#include "apfl.h"
#include "alloc.h"
#include "gc.h"
#include "internal.h"
#include "resizable.h"
@ -153,3 +154,15 @@ apfl_string_builder_move_string(struct apfl_string_builder *builder)
return str;
}
struct apfl_string *
apfl_string_move_into_new_gc_string(struct gc *gc, struct apfl_string *in)
{
struct apfl_string *str = apfl_gc_new_string(gc);
if (str == NULL) {
return NULL;
}
*str = apfl_string_move(in);
return str;
}