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:
parent
f8bab311d7
commit
0f6f136873
10 changed files with 97 additions and 19 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
10
src/error.c
10
src/error.c
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
32
src/eval.c
32
src/eval.c
|
|
@ -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;
|
||||
|
|
|
|||
16
src/format.c
16
src/format.c
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue