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.
208 lines
4.8 KiB
C
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
|