#ifndef APFL_CONTEXT_H #define APFL_CONTEXT_H #ifdef __cplusplus extern "C" { #endif #include #include #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 `{:}`, where `:` * 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