diff --git a/bshell/script-block.c b/bshell/script-block.c new file mode 100644 index 0000000..d496c01 --- /dev/null +++ b/bshell/script-block.c @@ -0,0 +1,338 @@ +#include "script-block.h" + +#include "status.h" + +#include +#include +#include + +struct string_cache_entry { + unsigned long e_index; + fx_namemap_entry e_entry; +}; + +struct bshell_scriptblock_p { + /* pool values referenced by the text */ + FX_VECTOR_DECLARE(fx_value, b_pool); + /* bytecode instructions */ + FX_VECTOR_DECLARE(bshell_instruction, b_text); + /* string value cache */ + fx_namemap b_strings; +}; + +static fx_status pool_destroy(void *p) +{ + fx_value_unset(p); + return FX_SUCCESS; +} + +static fx_vector_ops pool_ops = { + .v_destroy = pool_destroy, +}; + +static void scriptblock_fini(fx_object *obj, void *priv) +{ + struct bshell_scriptblock_p *block = priv; + + fx_vector_destroy(block->b_pool, &pool_ops); + fx_vector_destroy(block->b_text, NULL); +} + +static size_t scriptblock_push_instruction( + struct bshell_scriptblock_p *block, + enum bshell_opcode opcode, + uint32_t arg) +{ + size_t offset = block->b_text.count * sizeof(bshell_instruction); + uint32_t instr = bshell_instruction_encode(opcode, arg); + fx_vector_push_back(block->b_text, &instr, NULL); + return offset; +} + +static enum bshell_status scriptblock_read_instruction( + struct bshell_scriptblock_p *block, + size_t offset, + enum bshell_opcode *out_opcode, + uint32_t *out_arg) +{ + offset /= sizeof(bshell_instruction); + if (offset >= block->b_text.count) { + return BSHELL_ERR_INVALID_ARGUMENT; + } + + enum bshell_opcode opcode; + uint32_t arg; + bshell_instruction_decode(block->b_text.items[offset], &opcode, &arg); + + if (out_opcode) { + *out_opcode = opcode; + } + + if (out_arg) { + *out_arg = arg; + } + + return BSHELL_SUCCESS; +} + +static void scriptblock_patch_instruction( + struct bshell_scriptblock_p *block, + size_t offset, + enum bshell_opcode opcode, + uint32_t arg) +{ + offset /= sizeof(bshell_instruction); + if (offset >= block->b_text.count) { + return; + } + + block->b_text.items[offset] = bshell_instruction_encode(opcode, arg); +} + +static void scriptblock_clear_text(struct bshell_scriptblock_p *block) +{ + block->b_text.count = 0; +} + +static void scriptblock_get_text( + const struct bshell_scriptblock_p *block, + bshell_instruction **out_ptr, + size_t *out_count) +{ + if (out_ptr) { + *out_ptr = block->b_text.items; + } + + if (out_count) { + *out_count = block->b_text.count; + } +} + +static void scriptblock_get_pool( + const struct bshell_scriptblock_p *block, + fx_value **out_ptr, + size_t *out_count) +{ + if (out_ptr) { + *out_ptr = block->b_pool.items; + } + + if (out_count) { + *out_count = block->b_pool.count; + } +} + +static unsigned long scriptblock_add_pool_value( + struct bshell_scriptblock_p *block, + fx_value *value) +{ + unsigned long id = block->b_pool.count; + fx_value *slot = fx_vector_emplace_back(block->b_pool, &pool_ops); + if (!slot) { + return (unsigned long)-1; + } + + fx_value_copy(slot, value); + return id; +} + +static fx_value *scriptblock_get_pool_value( + const struct bshell_scriptblock_p *block, + unsigned long index, + fx_type_id expected_type) +{ + if (index >= block->b_pool.count) { + return NULL; + } + + fx_value *value = &block->b_pool.items[index]; + if (expected_type + && fx_type_id_compare(value->v_type, expected_type) != 0) { + return NULL; + } + + return value; +} + +static unsigned long scriptblock_get_string( + struct bshell_scriptblock_p *block, + const char *s) +{ + struct string_cache_entry *cache_entry = NULL; + fx_string *str = NULL; + + fx_namemap_entry *e = fx_namemap_get(&block->b_strings, s); + if (e) { + cache_entry = fx_unbox(struct string_cache_entry, e, e_entry); + return cache_entry->e_index; + } + + cache_entry = malloc(sizeof *cache_entry); + if (!cache_entry) { + goto cleanup; + } + + str = fx_string_create_from_cstr(s); + if (!str) { + goto cleanup; + } + + unsigned long index = block->b_pool.count; + fx_value *slot = fx_vector_emplace_back(block->b_pool, &pool_ops); + if (!slot) { + goto cleanup; + } + + *slot = FX_CSTR(s); + + cache_entry->e_index = index; + fx_namemap_put( + &block->b_strings, + fx_string_get_cstr(str), + &cache_entry->e_entry); + + return index; + +cleanup: + if (str) { + fx_string_unref(str); + } + + if (cache_entry) { + free(cache_entry); + } + + return POOL_INDEX_INVALID; +} + +size_t bshell_scriptblock_push_instruction( + bshell_scriptblock *block, + enum bshell_opcode opcode, + uint32_t arg) +{ + FX_CLASS_DISPATCH_STATIC( + BSHELL_TYPE_SCRIPTBLOCK, + scriptblock_push_instruction, + block, + opcode, + arg); +} + +enum bshell_status bshell_scriptblock_read_instruction( + bshell_scriptblock *block, + size_t offset, + enum bshell_opcode *out_opcode, + uint32_t *out_arg) +{ + FX_CLASS_DISPATCH_STATIC( + BSHELL_TYPE_SCRIPTBLOCK, + scriptblock_read_instruction, + block, + offset, + out_opcode, + out_arg); +} + +void bshell_scriptblock_patch_instruction( + bshell_scriptblock *block, + size_t offset, + enum bshell_opcode opcode, + uint32_t arg) +{ + FX_CLASS_DISPATCH_STATIC_V( + BSHELL_TYPE_SCRIPTBLOCK, + scriptblock_patch_instruction, + block, + offset, + opcode, + arg); +} + +void bshell_scriptblock_clear_text(bshell_scriptblock *block) +{ + FX_CLASS_DISPATCH_STATIC_V0( + BSHELL_TYPE_SCRIPTBLOCK, + scriptblock_clear_text, + block); +} + +void bshell_scriptblock_get_text( + const bshell_scriptblock *block, + bshell_instruction **out_ptr, + size_t *out_count) +{ + FX_CLASS_DISPATCH_STATIC( + BSHELL_TYPE_SCRIPTBLOCK, + scriptblock_get_text, + block, + out_ptr, + out_count); +} + +void bshell_scriptblock_get_pool( + const bshell_scriptblock *block, + fx_value **out_ptr, + size_t *out_count) +{ + FX_CLASS_DISPATCH_STATIC( + BSHELL_TYPE_SCRIPTBLOCK, + scriptblock_get_pool, + block, + out_ptr, + out_count); +} + +unsigned long bshell_scriptblock_add_pool_value( + bshell_scriptblock *block, + fx_value *value) +{ + FX_CLASS_DISPATCH_STATIC( + BSHELL_TYPE_SCRIPTBLOCK, + scriptblock_add_pool_value, + block, + value); +} + +fx_value *bshell_scriptblock_get_pool_value( + const bshell_scriptblock *block, + unsigned long index, + fx_type_id expected_type) +{ + FX_CLASS_DISPATCH_STATIC( + BSHELL_TYPE_SCRIPTBLOCK, + scriptblock_get_pool_value, + block, + index, + expected_type); +} + +unsigned long bshell_scriptblock_get_string( + bshell_scriptblock *block, + const char *s) +{ + FX_CLASS_DISPATCH_STATIC( + BSHELL_TYPE_SCRIPTBLOCK, + scriptblock_get_string, + block, + s); +} + +FX_TYPE_CLASS_BEGIN(bshell_scriptblock) + FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT) + FX_INTERFACE_ENTRY(to_string) = NULL; + FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT) + + FX_TYPE_CONSTRUCTOR( + "create", + bshell_scriptblock_create, + 0, + FX_TYPE_VOID); +FX_TYPE_CLASS_END(bshell_scriptblock) + +FX_TYPE_DEFINITION_BEGIN(bshell_scriptblock) + FX_TYPE_ID(0x02b87313, 0x83f6, 0x4a57, 0xa573, 0x62cf492391ce); + FX_TYPE_NAME("bshell.scriptblock"); + FX_TYPE_CLASS(bshell_scriptblock_class); + FX_TYPE_INSTANCE_PRIVATE(struct bshell_scriptblock_p); + FX_TYPE_INSTANCE_FINI(scriptblock_fini); +FX_TYPE_DEFINITION_END(bshell_scriptblock) diff --git a/bshell/script-block.h b/bshell/script-block.h new file mode 100644 index 0000000..10e3451 --- /dev/null +++ b/bshell/script-block.h @@ -0,0 +1,62 @@ +#ifndef SCRIPT_BLOCK_H_ +#define SCRIPT_BLOCK_H_ + +#include "runtime/opcode.h" + +#include +#include + +FX_DECLS_BEGIN; + +enum bshell_opcode; + +#define POOL_INDEX_INVALID ((unsigned long)-1) +#define BSHELL_TYPE_SCRIPTBLOCK (bshell_scriptblock_get_type()) + +FX_DECLARE_TYPE(bshell_scriptblock); + +FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_scriptblock) +FX_TYPE_CLASS_DECLARATION_END(bshell_scriptblock) + +FX_DECLS_END; + +extern fx_type_id bshell_scriptblock_get_type(void); + +FX_TYPE_DEFAULT_CONSTRUCTOR(bshell_scriptblock, BSHELL_TYPE_SCRIPTBLOCK); + +extern size_t bshell_scriptblock_push_instruction( + bshell_scriptblock *block, + enum bshell_opcode opcode, + uint32_t arg); +extern enum bshell_status bshell_scriptblock_read_instruction( + bshell_scriptblock *block, + size_t offset, + enum bshell_opcode *out_opcode, + uint32_t *out_arg); +extern void bshell_scriptblock_patch_instruction( + bshell_scriptblock *block, + size_t offset, + enum bshell_opcode opcode, + uint32_t arg); + +extern void bshell_scriptblock_clear_text(bshell_scriptblock *block); +extern void bshell_scriptblock_get_text( + const bshell_scriptblock *block, + bshell_instruction **out_ptr, + size_t *out_count); +extern void bshell_scriptblock_get_pool( + const bshell_scriptblock *block, + fx_value **out_ptr, + size_t *out_count); +extern unsigned long bshell_scriptblock_add_pool_value( + bshell_scriptblock *block, + fx_value *value); +extern fx_value *bshell_scriptblock_get_pool_value( + const bshell_scriptblock *block, + unsigned long index, + fx_type_id expected_type); +extern unsigned long bshell_scriptblock_get_string( + bshell_scriptblock *block, + const char *s); + +#endif