233 lines
6 KiB
C
233 lines
6 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);
|
|
bool apfl_call_stack_try_push(apfl_ctx ctx, struct call_stack_entry cse);
|
|
void apfl_call_stack_push(apfl_ctx ctx, struct call_stack_entry cse);
|
|
|
|
struct scope *apfl_closure_scope_for_func(apfl_ctx, struct scopes);
|
|
|
|
struct apfl_io_writer apfl_get_output_writer(apfl_ctx);
|
|
|
|
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_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
|