Files
bshell/bshell.runtime/script-block.c
T

355 lines
7.2 KiB
C

#include <bshell/runtime/script-block.h>
#include <bshell/status.h>
#include <fx/reflection/function.h>
#include <fx/string.h>
#include <fx/vector.h>
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 void cache_entry_cleanup(fx_namemap_entry *e)
{
struct string_cache_entry *entry
= fx_unbox(struct string_cache_entry, e, e_entry);
free(entry);
}
static void scriptblock_fini(fx_object *obj, void *priv)
{
struct bshell_scriptblock_p *block = priv;
fx_namemap_cleanup(&block->b_strings, cache_entry_cleanup);
fx_value_unset_array(block->b_pool.items, block->b_pool.count);
fx_vector_destroy(block->b_pool, NULL);
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, NULL);
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;
}
memset(cache_entry, 0x0, sizeof *cache_entry);
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, NULL);
if (!slot) {
goto cleanup;
}
*slot = FX_VALUE_OBJECT(str);
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;
}
static unsigned long scriptblock_get_double(
struct bshell_scriptblock_p *block,
double v)
{
fx_value value = FX_DOUBLE(v);
return scriptblock_add_pool_value(block, &value);
}
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);
}
unsigned long bshell_scriptblock_get_double(bshell_scriptblock *block, double v)
{
FX_CLASS_DISPATCH_STATIC(
BSHELL_TYPE_SCRIPTBLOCK,
scriptblock_get_double,
block,
v);
}
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.runtime.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)