apfl/src/context.h
Laria Carolin Chabowski 874638748b Make iterative runner not panic on OOM
The iterative runner used functions that could throw errors on OOM before
protecting itself using apfl_call_protected. An error at that point would
have resulted in calling the panic handler as a last resort.

This now introduces the apfl_do_protected function which allows running C
code protected without needing to wrap it in a cfunc value, thus removing
the need for the functions that could throw in the iterative runner.
2022-11-20 21:44:00 +01:00

208 lines
4.8 KiB
C

#ifndef APFL_CONTEXT_H
#define APFL_CONTEXT_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <setjmp.h>
#include "bytecode.h"
#include "hashmap.h"
#include "gc.h"
#include "value.h"
#include "scope.h"
#define RESULT_OFF_FOR_LONGJMP 1
struct scopes {
// Both scope and closure_scope can be null
struct scope *local;
struct scope *closure;
};
struct matcher_capture_transfer {
struct apfl_string *var;
size_t path_start;
size_t path_len;
bool local;
};
struct matcher {
struct matcher_instruction_list *instructions;
size_t value_count;
struct apfl_value *values;
};
struct stack {
struct apfl_value *items;
size_t len;
size_t cap;
};
struct matcher_stack {
struct matcher **items;
size_t len;
size_t cap;
};
enum call_stack_entry_type {
CSE_FUNCTION,
CSE_CFUNCTION,
CSE_MATCHER,
CSE_FUNCTION_DISPATCH,
};
struct func_call_stack_entry {
size_t pc;
struct instruction_list *instructions;
// scopes.scope will be created lazily
struct scopes scopes;
int execution_line;
struct matcher_stack matcher_stack;
bool returning_from_matcher;
bool matcher_result;
};
struct cfunc_call_stack_entry {
struct cfunction *func;
};
enum matcher_mode {
MATCHER_MODE_VALUE,
MATCHER_MODE_STOP,
MATCHER_MODE_LIST_START,
MATCHER_MODE_LIST_END,
MATCHER_MODE_LIST_REMAINING,
MATCHER_MODE_LIST_UNDERFLOW,
};
struct matcher_state {
enum matcher_mode mode;
size_t lower;
size_t upper;
};
struct matcher_call_stack_entry {
size_t pc;
bool from_predicate;
struct matcher *matcher;
struct scopes scopes;
size_t capture_index;
size_t capture_count;
struct apfl_value *captures;
struct matcher_capture_transfer *transfers;
struct matcher_state *matcher_state_stack;
size_t matcher_state_stack_len;
size_t matcher_state_stack_cap;
};
struct func_dispatch_call_stack_entry {
size_t subfunc;
struct scopes scopes;
bool returning_from_matcher;
bool matcher_result;
struct function *function;
};
struct call_stack_entry {
enum call_stack_entry_type type;
struct stack stack;
union {
struct func_call_stack_entry func;
struct cfunc_call_stack_entry cfunc;
struct matcher_call_stack_entry matcher;
struct func_dispatch_call_stack_entry func_dispatch;
};
};
struct call_stack {
struct call_stack_entry *items;
size_t len;
size_t cap;
};
struct error_handler {
jmp_buf jump;
bool with_error_on_stack;
};
struct iterative_runners_list {
apfl_iterative_runner *items;
size_t len;
size_t cap;
};
struct apfl_ctx_data {
struct gc gc;
apfl_panic_callback panic_callback;
void *panic_callback_data;
struct stack toplevel_stack;
struct scope *globals;
struct call_stack call_stack;
struct error_handler *error_handler;
struct iterative_runners_list iterative_runners;
struct apfl_format_writer output_writer;
};
void apfl_matcher_call_stack_entry_deinit(struct apfl_allocator, struct matcher_call_stack_entry *);
void apfl_call_stack_entry_deinit(struct apfl_allocator, struct call_stack_entry *);
struct stack apfl_stack_new(void);
bool apfl_stack_push(apfl_ctx, struct apfl_value);
void apfl_stack_must_push(apfl_ctx ctx, struct apfl_value value);
bool apfl_stack_check_index(apfl_ctx, apfl_stackidx *);
bool apfl_stack_has_index(apfl_ctx, apfl_stackidx);
bool apfl_stack_pop(apfl_ctx, struct apfl_value *value, apfl_stackidx);
struct apfl_value apfl_stack_must_pop(apfl_ctx, apfl_stackidx);
bool apfl_stack_get(apfl_ctx, struct apfl_value *value, apfl_stackidx);
struct apfl_value apfl_stack_must_get(apfl_ctx, apfl_stackidx);
bool apfl_stack_drop(apfl_ctx, apfl_stackidx);
bool apfl_stack_drop_multi(apfl_ctx ctx, size_t count, apfl_stackidx *indices);
void apfl_stack_clear(apfl_ctx);
struct apfl_value *apfl_stack_push_placeholder(apfl_ctx);
bool apfl_move_string_onto_stack(apfl_ctx, struct apfl_string);
struct call_stack_entry *apfl_call_stack_cur_entry(apfl_ctx);
struct scope *apfl_closure_scope_for_func(apfl_ctx, struct scopes);
struct apfl_format_writer apfl_get_output_writer(apfl_ctx);
enum apfl_result apfl_do_protected(
apfl_ctx ctx,
void (*callback)(apfl_ctx, void *),
void *opaque,
bool *with_error_on_stack
);
bool apfl_ctx_register_iterative_runner(apfl_ctx, apfl_iterative_runner);
void apfl_ctx_unregister_iterative_runner(apfl_ctx, apfl_iterative_runner);
struct matcher *apfl_matcher_new(struct gc *, struct matcher_instruction_list *);
void apfl_matcher_deinit(struct apfl_allocator, struct matcher *);
void apfl_gc_matcher_traverse(struct matcher *, gc_visitor, void *);
void apfl_iterative_runner_visit_gc_objects(apfl_iterative_runner, gc_visitor, void *);
#ifdef __cplusplus
}
#endif
#endif