apfl/src/context.h
Laria Carolin Chabowski 63d64b0778 Add regex module "re"
This uses the PCRE2 library to implement regexes in apfl
2023-07-03 23:53:09 +02:00

239 lines
6.1 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;
};
struct func_call_stack_entry {
size_t pc;
struct instruction_list *instructions;
// scopes.scope will be created lazily
struct scopes scopes;
size_t execution_line;
struct function *function; // Can be NULL, in that case it's the toplevel
size_t subfunction_index; // Not set, if function == NULL
struct matcher_stack matcher_stack;
bool returning_from_matcher;
bool matcher_result;
};
struct cfunc_deferred {
apfl_cfunc_defer_callback cb;
void *opaque;
};
struct cfunc_call_stack_entry {
struct cfunction *func;
struct cfunc_deferred *deferred_list;
size_t deferred_len;
size_t deferred_cap;
};
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,
MATCHER_MODE_PAIR_L,
MATCHER_MODE_PAIR_R,
};
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 apfl_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;
};
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_io_writer output_writer;
struct apfl_hashmap *registry;
};
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 *);
void apfl_cfunc_run_deferred(apfl_ctx ctx, struct call_stack_entry *cse);
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);
// Like apfl_tostring, but ensures it's a dynamically allocated string and returns the underlying string.
struct apfl_string *apfl_to_dynamic_string(apfl_ctx ctx, apfl_stackidx index);
/* Raise an error with a message formatted according to fmt.
*
* fmt allows placeholders in the form of `{<param>:<type>}`, where `<param>:`
* is optional. Each of these placeholders then takes a vararg. The following
* placeholders are implemented:
*
* - string: Expects a `struct apfl_string_view` parameter and replaces the
* placeholder with that string. With the param `c`, a C `char *` string is
* expected instead.
* - type: Expects an `enum apfl_type` and will replace the placeholder with the
* name of that type. With the param `value` a `struct apfl_value` is expected
* instead and the type of that value is used. With the param `stack` a
* `apfl_stackidx` is expected instead and the type of the value at the given
* stack index is used instead.
*/
noreturn void apfl_raise_errorfmt(apfl_ctx ctx, const char *fmt, ...);
struct call_stack_entry *apfl_call_stack_cur_entry(apfl_ctx);
struct scope *apfl_closure_scope_for_func(apfl_ctx, struct scopes);
struct apfl_io_writer apfl_get_output_writer(apfl_ctx);
enum apfl_result apfl_do_protected(
apfl_ctx ctx,
void (*callback)(apfl_ctx, void *),
void *opaque,
void (*errcallback)(apfl_ctx, void *)
);
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 *);
void apfl_load_bytecode(apfl_ctx, struct apfl_io_reader);
#ifdef __cplusplus
}
#endif
#endif