bshell: add script-block class
bshell_scriptblock acts as a self-contained collection of executable bytecode and associated const value table.
This commit is contained in:
@@ -0,0 +1,338 @@
|
||||
#include "script-block.h"
|
||||
|
||||
#include "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 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)
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef SCRIPT_BLOCK_H_
|
||||
#define SCRIPT_BLOCK_H_
|
||||
|
||||
#include "runtime/opcode.h"
|
||||
|
||||
#include <fx/macros.h>
|
||||
#include <fx/value.h>
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user