bshell: re-organise build into three separate components
bshell: the front-end binary bshell.runtime: contains the parser, compiler, and classes needed to run bshell scripts bshell.core: contains the builtin commandlets and aliases
This commit is contained in:
@@ -0,0 +1,261 @@
|
||||
#include <bshell/command/alias.h>
|
||||
#include <bshell/command/command.h>
|
||||
#include <bshell/runtime/cmdcall.h>
|
||||
#include <bshell/runtime/pipeline.h>
|
||||
#include <bshell/runtime/runtime.h>
|
||||
#include <bshell/status.h>
|
||||
#include <fx/collections/array.h>
|
||||
#include <fx/reflection/assembly.h>
|
||||
#include <fx/reflection/function.h>
|
||||
#include <fx/reflection/type.h>
|
||||
#include <fx/string.h>
|
||||
#include <fx/term/print.h>
|
||||
#include <fx/vector.h>
|
||||
|
||||
enum cmdcall_type {
|
||||
CMDCALL_NONE = 0,
|
||||
CMDCALL_CMDLET,
|
||||
CMDCALL_NATIVE,
|
||||
};
|
||||
|
||||
struct bshell_cmdcall_p {
|
||||
enum cmdcall_type cmd_type;
|
||||
bshell_command *cmd_target;
|
||||
char *cmd_native_path;
|
||||
bool cmd_initialised;
|
||||
FX_VECTOR_DECLARE(fx_value, cmd_args);
|
||||
fx_array *cmd_args_processed;
|
||||
};
|
||||
|
||||
static void cmdcall_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct bshell_cmdcall_p *cmdcall = priv;
|
||||
|
||||
if (cmdcall->cmd_native_path) {
|
||||
free(cmdcall->cmd_native_path);
|
||||
}
|
||||
|
||||
if (cmdcall->cmd_args_processed) {
|
||||
fx_array_unref(cmdcall->cmd_args_processed);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < cmdcall->cmd_args.count; i++) {
|
||||
fx_value_unset(&cmdcall->cmd_args.items[i]);
|
||||
}
|
||||
|
||||
fx_vector_destroy(cmdcall->cmd_args, NULL);
|
||||
|
||||
if (cmdcall->cmd_target) {
|
||||
bshell_command_end_processing(cmdcall->cmd_target);
|
||||
bshell_command_unref(cmdcall->cmd_target);
|
||||
}
|
||||
}
|
||||
|
||||
static enum bshell_status cmdcall_push_arg(
|
||||
struct bshell_cmdcall_p *cmdcall,
|
||||
fx_value arg)
|
||||
{
|
||||
fx_value *slot = fx_vector_emplace_back(cmdcall->cmd_args, NULL);
|
||||
fx_value_copy(slot, &arg);
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
static const fx_value *get_arg(struct bshell_cmdcall_p *cmdcall, size_t index)
|
||||
{
|
||||
if (index >= cmdcall->cmd_args.count) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &cmdcall->cmd_args.items[cmdcall->cmd_args.count - index - 1];
|
||||
}
|
||||
|
||||
static bshell_command *__resolve_call_target(
|
||||
const char *callable_name,
|
||||
struct bshell_runtime *rt)
|
||||
{
|
||||
return bshell_runtime_find_command(rt, callable_name);
|
||||
}
|
||||
|
||||
static enum bshell_status resolve_call_target(
|
||||
struct bshell_cmdcall_p *cmdcall,
|
||||
struct bshell_runtime *rt)
|
||||
{
|
||||
if (cmdcall->cmd_type != CMDCALL_NONE) {
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
fx_value *cmd_name_v = fx_array_get_ref(cmdcall->cmd_args_processed, 0);
|
||||
if (!cmd_name_v) {
|
||||
return BSHELL_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
fx_string *cmd_name_s = NULL;
|
||||
fx_value_get_object(cmd_name_v, &cmd_name_s);
|
||||
|
||||
while (1) {
|
||||
const char *cmd_name_cstr = fx_string_get_cstr(cmd_name_s);
|
||||
bshell_command *cmd
|
||||
= bshell_runtime_find_command(rt, cmd_name_cstr);
|
||||
if (!cmd) {
|
||||
break;
|
||||
}
|
||||
|
||||
bshell_alias_class *alias
|
||||
= fx_object_get_interface(cmd, BSHELL_TYPE_ALIAS);
|
||||
if (alias) {
|
||||
fx_string_clear(cmd_name_s);
|
||||
fx_string_append_cstr(cmd_name_s, alias->a_target_name);
|
||||
bshell_command_unref(cmd);
|
||||
continue;
|
||||
}
|
||||
|
||||
cmdcall->cmd_target = cmd;
|
||||
cmdcall->cmd_type = CMDCALL_CMDLET;
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
const char *cmd_name_cstr = fx_string_get_cstr(cmd_name_s);
|
||||
fx_printf(
|
||||
"[bold,bright_red]%s: The term '%s' is not recognised as a "
|
||||
"name of a cmdlet, "
|
||||
"function, script file, or executable program.[reset]\n",
|
||||
cmd_name_cstr,
|
||||
cmd_name_cstr);
|
||||
return BSHELL_ERR_NO_ENTRY;
|
||||
}
|
||||
|
||||
static enum bshell_status process_args(struct bshell_cmdcall_p *cmdcall)
|
||||
{
|
||||
if (cmdcall->cmd_args_processed) {
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
fx_stringstream *str = fx_stringstream_create();
|
||||
if (!str) {
|
||||
return BSHELL_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
cmdcall->cmd_args_processed = fx_array_create();
|
||||
if (!cmdcall->cmd_args_processed) {
|
||||
fx_stringstream_unref(str);
|
||||
return BSHELL_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (i32 i = cmdcall->cmd_args.count - 1; i >= 0; i--) {
|
||||
fx_stringstream_reset(str);
|
||||
fx_value_to_string(&cmdcall->cmd_args.items[i], str, NULL);
|
||||
fx_string *arg_str
|
||||
= fx_string_create_from_cstr(fx_stringstream_ptr(str));
|
||||
fx_array_push_back(
|
||||
cmdcall->cmd_args_processed,
|
||||
FX_VALUE_OBJECT(arg_str));
|
||||
fx_string_unref(arg_str);
|
||||
}
|
||||
|
||||
fx_stringstream_unref(str);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
static enum bshell_status cmdcall_resolve(
|
||||
struct bshell_cmdcall_p *cmdcall,
|
||||
struct bshell_runtime *rt)
|
||||
{
|
||||
enum bshell_status status = process_args(cmdcall);
|
||||
if (status != BSHELL_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = resolve_call_target(cmdcall, rt);
|
||||
if (status != BSHELL_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
bshell_command_set_args_reverse(
|
||||
cmdcall->cmd_target,
|
||||
cmdcall->cmd_args.items,
|
||||
cmdcall->cmd_args.count);
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
static enum bshell_status cmdcall_execute(struct bshell_cmdcall_p *cmdcall)
|
||||
{
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
static enum bshell_status cmdcall_process_record(
|
||||
struct bshell_cmdcall_p *cmdcall,
|
||||
bshell_pipeline *pipeline,
|
||||
struct bshell_runtime *rt)
|
||||
{
|
||||
if (!cmdcall->cmd_target) {
|
||||
return BSHELL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (!cmdcall->cmd_initialised) {
|
||||
bshell_command_begin_processing(cmdcall->cmd_target);
|
||||
cmdcall->cmd_initialised = true;
|
||||
}
|
||||
|
||||
return bshell_command_process_record(cmdcall->cmd_target, pipeline, rt);
|
||||
}
|
||||
|
||||
enum bshell_status bshell_cmdcall_push_arg(
|
||||
bshell_cmdcall *cmdcall,
|
||||
fx_value arg)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
BSHELL_TYPE_CMDCALL,
|
||||
cmdcall_push_arg,
|
||||
cmdcall,
|
||||
arg);
|
||||
}
|
||||
|
||||
enum bshell_status bshell_cmdcall_resolve(
|
||||
bshell_cmdcall *cmdcall,
|
||||
struct bshell_runtime *rt)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
BSHELL_TYPE_CMDCALL,
|
||||
cmdcall_resolve,
|
||||
cmdcall,
|
||||
rt);
|
||||
}
|
||||
|
||||
enum bshell_status bshell_cmdcall_execute(bshell_cmdcall *cmdcall)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
BSHELL_TYPE_CMDCALL,
|
||||
cmdcall_execute,
|
||||
cmdcall);
|
||||
}
|
||||
|
||||
enum bshell_status bshell_cmdcall_process_record(
|
||||
bshell_cmdcall *cmdcall,
|
||||
bshell_pipeline *pipeline,
|
||||
struct bshell_runtime *rt)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
BSHELL_TYPE_CMDCALL,
|
||||
cmdcall_process_record,
|
||||
cmdcall,
|
||||
pipeline,
|
||||
rt);
|
||||
}
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(bshell_cmdcall)
|
||||
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_cmdcall_create, 0, FX_TYPE_VOID);
|
||||
FX_TYPE_CLASS_END(bshell_cmdcall)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(bshell_cmdcall)
|
||||
FX_TYPE_ID(0x08aeb275, 0xc09b, 0x4c3a, 0xa8df, 0xd9fba0bb4571);
|
||||
FX_TYPE_NAME("bshell.cmdcall");
|
||||
FX_TYPE_CLASS(bshell_cmdcall_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct bshell_cmdcall_p);
|
||||
FX_TYPE_INSTANCE_FINI(cmdcall_fini);
|
||||
FX_TYPE_DEFINITION_END(bshell_cmdcall)
|
||||
@@ -0,0 +1,456 @@
|
||||
#include "scope.h"
|
||||
|
||||
#include <bshell/format.h>
|
||||
#include <bshell/runtime/cmdcall.h>
|
||||
#include <bshell/runtime/pipeline.h>
|
||||
#include <bshell/runtime/runtime.h>
|
||||
#include <bshell/status.h>
|
||||
#include <fx/collections/array.h>
|
||||
#include <fx/collections/hashtable.h>
|
||||
#include <fx/string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static enum bshell_status eval_instruction(
|
||||
struct bshell_runtime *rt,
|
||||
struct bshell_runtime_scope *scope,
|
||||
bshell_instruction instr)
|
||||
{
|
||||
fx_value x, y, z;
|
||||
enum bshell_opcode opcode;
|
||||
fx_status status;
|
||||
enum bshell_status bstatus = BSHELL_SUCCESS;
|
||||
uint32_t arg;
|
||||
fx_type_id type;
|
||||
fx_value *pool_value = NULL;
|
||||
bshell_variable *var = NULL;
|
||||
const char *s = NULL;
|
||||
bshell_instruction_decode(instr, &opcode, &arg);
|
||||
|
||||
switch (opcode) {
|
||||
case BSHELL_OPCODE_LDC_INT:
|
||||
x = FX_INT(arg);
|
||||
bshell_runtime_scope_push_value(scope, &x);
|
||||
fx_value_unset(&x);
|
||||
break;
|
||||
case BSHELL_OPCODE_LDC_FP:
|
||||
pool_value = bshell_scriptblock_get_pool_value(
|
||||
scope->s_block,
|
||||
arg,
|
||||
FX_TYPE_DOUBLE);
|
||||
if (pool_value) {
|
||||
bshell_runtime_scope_push_value(scope, pool_value);
|
||||
} else {
|
||||
fprintf(stderr, "RUNTIME: invalid ldc.fp operand\n");
|
||||
return BSHELL_ERR_BAD_SYNTAX;
|
||||
}
|
||||
break;
|
||||
case BSHELL_OPCODE_LDC_STR:
|
||||
pool_value = bshell_scriptblock_get_pool_value(
|
||||
scope->s_block,
|
||||
arg,
|
||||
FX_TYPE_STRING);
|
||||
if (!pool_value) {
|
||||
pool_value = bshell_scriptblock_get_pool_value(
|
||||
scope->s_block,
|
||||
arg,
|
||||
FX_TYPE_CSTR);
|
||||
}
|
||||
if (pool_value) {
|
||||
bshell_runtime_scope_push_value(scope, pool_value);
|
||||
} else {
|
||||
fprintf(stderr, "RUNTIME: invalid ldc.str operand\n");
|
||||
return BSHELL_ERR_BAD_SYNTAX;
|
||||
}
|
||||
break;
|
||||
case BSHELL_OPCODE_ADD:
|
||||
x = bshell_runtime_scope_pop_value(scope);
|
||||
y = bshell_runtime_scope_pop_value(scope);
|
||||
type = fx_value_get_common_type(&x, &y);
|
||||
if (!type) {
|
||||
fprintf(stderr,
|
||||
"RUNTIME: cannot apply operator to operands of "
|
||||
"incompatible type\n");
|
||||
return BSHELL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
status = fx_value_change_type(&y, &y, type);
|
||||
if (!FX_OK(status)) {
|
||||
fprintf(stderr,
|
||||
"RUNTIME: cannot convert operand to the "
|
||||
"necessary type\n");
|
||||
return BSHELL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
status = fx_value_change_type(&x, &x, type);
|
||||
if (!FX_OK(status)) {
|
||||
fprintf(stderr,
|
||||
"RUNTIME: cannot convert operand to the "
|
||||
"necessary type\n");
|
||||
return BSHELL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
status = fx_value_add(&x, &y, &z);
|
||||
if (!FX_OK(status)) {
|
||||
fprintf(stderr,
|
||||
"RUNTIME: operands do not support specified "
|
||||
"operator\n");
|
||||
return BSHELL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
bshell_runtime_scope_push_value(scope, &z);
|
||||
fx_value_unset(&z);
|
||||
break;
|
||||
case BSHELL_OPCODE_SUB:
|
||||
x = bshell_runtime_scope_pop_value(scope);
|
||||
y = bshell_runtime_scope_pop_value(scope);
|
||||
type = fx_value_get_common_type(&x, &y);
|
||||
if (!type) {
|
||||
fprintf(stderr,
|
||||
"RUNTIME: cannot apply operator to operands of "
|
||||
"incompatible type\n");
|
||||
return BSHELL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
status = fx_value_subtract(&x, &y, &z);
|
||||
if (!FX_OK(status)) {
|
||||
fprintf(stderr,
|
||||
"RUNTIME: operands do not support specified "
|
||||
"operator\n");
|
||||
return BSHELL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
bshell_runtime_scope_push_value(scope, &z);
|
||||
fx_value_unset(&z);
|
||||
break;
|
||||
case BSHELL_OPCODE_MUL:
|
||||
x = bshell_runtime_scope_pop_value(scope);
|
||||
y = bshell_runtime_scope_pop_value(scope);
|
||||
type = fx_value_get_common_type(&x, &y);
|
||||
if (!type) {
|
||||
fprintf(stderr,
|
||||
"RUNTIME: cannot apply operator to operands of "
|
||||
"incompatible type\n");
|
||||
return BSHELL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
status = fx_value_multiply(&x, &y, &z);
|
||||
if (!FX_OK(status)) {
|
||||
fprintf(stderr,
|
||||
"RUNTIME: operands do not support specified "
|
||||
"operator\n");
|
||||
return BSHELL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
bshell_runtime_scope_push_value(scope, &z);
|
||||
fx_value_unset(&z);
|
||||
break;
|
||||
case BSHELL_OPCODE_DIV:
|
||||
x = bshell_runtime_scope_pop_value(scope);
|
||||
y = bshell_runtime_scope_pop_value(scope);
|
||||
status = fx_value_change_type(&x, &x, FX_TYPE_DOUBLE);
|
||||
if (!FX_OK(status)) {
|
||||
fprintf(stderr,
|
||||
"RUNTIME: operands do not support specified "
|
||||
"operator\n");
|
||||
return BSHELL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
status = fx_value_change_type(&y, &y, FX_TYPE_DOUBLE);
|
||||
if (!FX_OK(status)) {
|
||||
fprintf(stderr,
|
||||
"RUNTIME: operands do not support specified "
|
||||
"operator\n");
|
||||
return BSHELL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
status = fx_value_divide(&x, &y, &z);
|
||||
if (!FX_OK(status)) {
|
||||
fprintf(stderr,
|
||||
"RUNTIME: operands do not support specified "
|
||||
"operator\n");
|
||||
return BSHELL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
bshell_runtime_scope_push_value(scope, &z);
|
||||
fx_value_unset(&z);
|
||||
break;
|
||||
case BSHELL_OPCODE_LDLOCAL:
|
||||
pool_value = bshell_scriptblock_get_pool_value(
|
||||
scope->s_block,
|
||||
arg,
|
||||
FX_TYPE_STRING);
|
||||
if (!pool_value) {
|
||||
fprintf(stderr, "RUNTIME: invalid ldlocal operand\n");
|
||||
return BSHELL_ERR_BAD_SYNTAX;
|
||||
}
|
||||
|
||||
fx_value_get_cstr(pool_value, &s);
|
||||
var = bshell_runtime_find_var(rt, s);
|
||||
if (var) {
|
||||
bshell_runtime_scope_push_value(
|
||||
scope,
|
||||
bshell_variable_get_value(var));
|
||||
} else {
|
||||
bshell_runtime_scope_push_value(scope, &FX_VALUE_EMPTY);
|
||||
}
|
||||
|
||||
break;
|
||||
case BSHELL_OPCODE_LDBLOCK:
|
||||
pool_value = bshell_scriptblock_get_pool_value(
|
||||
scope->s_block,
|
||||
arg,
|
||||
BSHELL_TYPE_SCRIPTBLOCK);
|
||||
if (!pool_value) {
|
||||
fprintf(stderr, "RUNTIME: invalid ldblock operand\n");
|
||||
return BSHELL_ERR_BAD_SYNTAX;
|
||||
}
|
||||
|
||||
bshell_runtime_scope_push_value(scope, pool_value);
|
||||
|
||||
break;
|
||||
case BSHELL_OPCODE_LDPROP: {
|
||||
/* container */
|
||||
x = bshell_runtime_scope_pop_value(scope);
|
||||
/* property */
|
||||
y = bshell_runtime_scope_pop_value(scope);
|
||||
|
||||
const fx_type *ty = fx_type_get_by_id(x.v_type);
|
||||
if (!ty) {
|
||||
fx_value_unset(&x);
|
||||
fx_value_unset(&y);
|
||||
bshell_runtime_scope_push_value(scope, &FX_VALUE_EMPTY);
|
||||
break;
|
||||
}
|
||||
|
||||
fx_stringstream *strm = fx_stringstream_create();
|
||||
fx_value_to_string(&y, strm, NULL);
|
||||
fx_value_unset(&y);
|
||||
|
||||
const fx_property *prop
|
||||
= fx_type_get_property(ty, fx_stringstream_ptr(strm));
|
||||
fx_stringstream_unref(strm);
|
||||
|
||||
if (!prop) {
|
||||
fx_value_unset(&x);
|
||||
bshell_runtime_scope_push_value(scope, &FX_VALUE_EMPTY);
|
||||
break;
|
||||
}
|
||||
|
||||
fx_property_get_value(prop, &x, &z);
|
||||
fx_value_unset(&x);
|
||||
bshell_runtime_scope_push_value(scope, &z);
|
||||
fx_value_unset(&z);
|
||||
|
||||
break;
|
||||
}
|
||||
case BSHELL_OPCODE_STLOCAL:
|
||||
x = bshell_runtime_scope_pop_value(scope);
|
||||
pool_value = bshell_scriptblock_get_pool_value(
|
||||
scope->s_block,
|
||||
arg,
|
||||
FX_TYPE_CSTR);
|
||||
if (!pool_value) {
|
||||
fprintf(stderr, "RUNTIME: invalid stlocal operand\n");
|
||||
return BSHELL_ERR_BAD_SYNTAX;
|
||||
}
|
||||
|
||||
fx_value_get_cstr(pool_value, &s);
|
||||
var = bshell_runtime_find_var(rt, s);
|
||||
if (!var) {
|
||||
var = bshell_runtime_define_var(rt, s);
|
||||
}
|
||||
|
||||
bshell_variable_set_value(var, &x);
|
||||
bshell_runtime_scope_push_value(scope, &x);
|
||||
fx_value_unset(&x);
|
||||
break;
|
||||
case BSHELL_OPCODE_MK_STR: {
|
||||
fx_string *result = fx_string_create();
|
||||
fx_stringstream *strm = fx_stringstream_create();
|
||||
|
||||
while (arg > 0) {
|
||||
x = bshell_runtime_scope_pop_value(scope);
|
||||
fx_stringstream_reset(strm);
|
||||
fx_value_to_string(&x, strm, NULL);
|
||||
fx_string_prepend_cstr(
|
||||
result,
|
||||
fx_stringstream_ptr(strm));
|
||||
fx_value_unset(&x);
|
||||
arg--;
|
||||
}
|
||||
|
||||
fx_stringstream_unref(strm);
|
||||
y = FX_VALUE_OBJECT(result);
|
||||
bshell_runtime_scope_push_value(scope, &y);
|
||||
fx_value_unset(&y);
|
||||
break;
|
||||
}
|
||||
case BSHELL_OPCODE_MK_HTAB: {
|
||||
fx_hashtable *result = fx_hashtable_create();
|
||||
|
||||
while (arg > 0) {
|
||||
fx_value key = bshell_runtime_scope_pop_value(scope);
|
||||
fx_value value = bshell_runtime_scope_pop_value(scope);
|
||||
fx_hashtable_put(result, &key, &value);
|
||||
fx_value_unset(&key);
|
||||
fx_value_unset(&value);
|
||||
arg--;
|
||||
}
|
||||
|
||||
y = FX_VALUE_OBJECT(result);
|
||||
bshell_runtime_scope_push_value(scope, &y);
|
||||
fx_value_unset(&y);
|
||||
break;
|
||||
}
|
||||
case BSHELL_OPCODE_MK_ARRAY: {
|
||||
fx_array *result = fx_array_create();
|
||||
|
||||
while (arg > 0) {
|
||||
fx_value value = bshell_runtime_scope_pop_value(scope);
|
||||
fx_array_push_front(result, value);
|
||||
fx_value_unset(&value);
|
||||
arg--;
|
||||
}
|
||||
|
||||
y = FX_VALUE_OBJECT(result);
|
||||
bshell_runtime_scope_push_value(scope, &y);
|
||||
fx_value_unset(&y);
|
||||
break;
|
||||
}
|
||||
case BSHELL_OPCODE_LDCMD: {
|
||||
bshell_cmdcall *result = bshell_cmdcall_create();
|
||||
|
||||
while (arg > 0) {
|
||||
fx_value cmd_arg = bshell_runtime_scope_pop_value(scope);
|
||||
bshell_cmdcall_push_arg(result, cmd_arg);
|
||||
fx_value_unset(&cmd_arg);
|
||||
arg--;
|
||||
}
|
||||
|
||||
bstatus = bshell_cmdcall_resolve(result, rt);
|
||||
if (bstatus != BSHELL_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
y = FX_VALUE_OBJECT(result);
|
||||
bshell_runtime_scope_push_value(scope, &y);
|
||||
fx_value_unset(&y);
|
||||
break;
|
||||
}
|
||||
case BSHELL_OPCODE_PEXEC: {
|
||||
bshell_pipeline *pipeline = bshell_pipeline_create();
|
||||
bool single = (arg == 1);
|
||||
while (arg > 0) {
|
||||
fx_value cmd = bshell_runtime_scope_pop_value(scope);
|
||||
bshell_cmdcall *cmdcall = NULL;
|
||||
if (fx_value_is_type(&cmd, BSHELL_TYPE_CMDCALL)) {
|
||||
fx_value_get_object(&cmd, &cmdcall);
|
||||
bshell_pipeline_add_cmdcall(pipeline, cmdcall);
|
||||
} else {
|
||||
bshell_pipeline_add_input_value(
|
||||
pipeline,
|
||||
cmd,
|
||||
true);
|
||||
}
|
||||
|
||||
fx_value_unset(&cmd);
|
||||
arg--;
|
||||
}
|
||||
|
||||
int end_of_data = 0;
|
||||
bool columns_initialised = false;
|
||||
fx_value record = FX_VALUE_EMPTY;
|
||||
struct bshell_table_ctx table_ctx;
|
||||
bshell_table_ctx_init(&table_ctx, fx_stdout);
|
||||
while (1) {
|
||||
bstatus = bshell_pipeline_pump_record(
|
||||
pipeline,
|
||||
rt,
|
||||
&record,
|
||||
&end_of_data);
|
||||
if (bstatus != BSHELL_SUCCESS || end_of_data) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!record.v_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!columns_initialised) {
|
||||
const fx_type *ty
|
||||
= fx_type_get_by_id(record.v_type);
|
||||
bshell_table_ctx_prepare_columns_from_format(
|
||||
&table_ctx,
|
||||
ty,
|
||||
NULL);
|
||||
bshell_table_ctx_print_headers(&table_ctx);
|
||||
columns_initialised = true;
|
||||
}
|
||||
|
||||
bshell_table_ctx_print_record(&table_ctx, &record);
|
||||
fx_value_unset(&record);
|
||||
}
|
||||
|
||||
bshell_table_ctx_cleanup(&table_ctx);
|
||||
bshell_pipeline_unref(pipeline);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"RUNTIME: encountered unknown opcode %02x\n",
|
||||
opcode);
|
||||
return BSHELL_ERR_BAD_FORMAT;
|
||||
}
|
||||
|
||||
scope->s_ip++;
|
||||
return bstatus;
|
||||
}
|
||||
|
||||
static fx_value runtime_eval(struct bshell_runtime *rt)
|
||||
{
|
||||
enum bshell_status status = BSHELL_SUCCESS;
|
||||
while (status == BSHELL_SUCCESS) {
|
||||
struct bshell_runtime_scope *scope = runtime_get_scope(rt);
|
||||
if (scope->s_ip >= scope->s_nr_instr) {
|
||||
break;
|
||||
}
|
||||
|
||||
bshell_instruction instr = scope->s_instr[scope->s_ip];
|
||||
status = eval_instruction(rt, scope, instr);
|
||||
}
|
||||
|
||||
struct bshell_runtime_scope *scope = runtime_get_scope(rt);
|
||||
return bshell_runtime_scope_pop_value(scope);
|
||||
}
|
||||
|
||||
fx_value bshell_runtime_eval_global(
|
||||
struct bshell_runtime *rt,
|
||||
bshell_scriptblock *block)
|
||||
{
|
||||
enum bshell_status status = BSHELL_SUCCESS;
|
||||
bshell_runtime_scope_set_block(rt->rt_global, block);
|
||||
return runtime_eval(rt);
|
||||
}
|
||||
|
||||
fx_value bshell_runtime_eval_script(
|
||||
struct bshell_runtime *rt,
|
||||
bshell_scriptblock *block)
|
||||
{
|
||||
runtime_push_scope(rt, RUNTIME_SCOPE_SCRIPT, block);
|
||||
fx_value result = runtime_eval(rt);
|
||||
runtime_pop_scope(rt);
|
||||
return result;
|
||||
}
|
||||
|
||||
fx_value bshell_runtime_eval(struct bshell_runtime *rt)
|
||||
{
|
||||
return runtime_eval(rt);
|
||||
}
|
||||
|
||||
enum bshell_status bshell_runtime_push_scope(
|
||||
struct bshell_runtime *rt,
|
||||
bshell_scriptblock *block)
|
||||
{
|
||||
struct bshell_runtime_scope *scope
|
||||
= runtime_push_scope(rt, RUNTIME_SCOPE_SCRIPT, block);
|
||||
return scope ? BSHELL_SUCCESS : BSHELL_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
enum bshell_status bshell_runtime_pop_scope(struct bshell_runtime *rt)
|
||||
{
|
||||
runtime_pop_scope(rt);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#include <bshell/runtime/opcode.h>
|
||||
#include <fx/int.h>
|
||||
|
||||
#define BSHELL_OPCODE_MAX 0xFF
|
||||
#define ARG_MAX 0xFFFFFF
|
||||
|
||||
bshell_instruction bshell_instruction_encode(
|
||||
enum bshell_opcode opcode,
|
||||
uint32_t arg)
|
||||
{
|
||||
if (opcode > BSHELL_OPCODE_MAX) {
|
||||
return BSHELL_INSTRUCTION_INVALID;
|
||||
}
|
||||
|
||||
return fx_u32_htob((opcode & BSHELL_OPCODE_MAX) | (arg & ARG_MAX) << 8);
|
||||
}
|
||||
|
||||
void bshell_instruction_decode(
|
||||
bshell_instruction instr,
|
||||
enum bshell_opcode *out_opcode,
|
||||
uint32_t *out_arg)
|
||||
{
|
||||
instr = fx_u32_btoh(instr);
|
||||
*out_opcode = (instr & BSHELL_OPCODE_MAX);
|
||||
*out_arg = ((instr >> 8) & ARG_MAX);
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
#include <bshell/runtime/cmdcall.h>
|
||||
#include <bshell/runtime/pipeline.h>
|
||||
#include <bshell/status.h>
|
||||
#include <fx/collections/array.h>
|
||||
#include <fx/reflection/function.h>
|
||||
#include <fx/string.h>
|
||||
#include <fx/vector.h>
|
||||
|
||||
struct bshell_pipeline_p {
|
||||
bshell_pipeline *p_self;
|
||||
fx_array *p_in, *p_out;
|
||||
FX_VECTOR_DECLARE(bshell_cmdcall *, p_cmds);
|
||||
};
|
||||
|
||||
static void pipeline_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct bshell_pipeline_p *pipeline = priv;
|
||||
pipeline->p_self = obj;
|
||||
pipeline->p_in = fx_array_create();
|
||||
pipeline->p_out = fx_array_create();
|
||||
}
|
||||
|
||||
static void pipeline_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct bshell_pipeline_p *pipeline = priv;
|
||||
for (size_t i = 0; i < pipeline->p_cmds.count; i++) {
|
||||
bshell_cmdcall_unref(pipeline->p_cmds.items[i]);
|
||||
}
|
||||
|
||||
if (pipeline->p_in) {
|
||||
fx_array_unref(pipeline->p_in);
|
||||
pipeline->p_in = NULL;
|
||||
}
|
||||
|
||||
if (pipeline->p_out) {
|
||||
fx_array_unref(pipeline->p_out);
|
||||
pipeline->p_out = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static enum bshell_status write_value(
|
||||
struct bshell_pipeline_p *pipeline,
|
||||
fx_array *dest,
|
||||
fx_value value,
|
||||
bool enumerate)
|
||||
{
|
||||
if (!enumerate) {
|
||||
fx_array_push_back(dest, value);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
fx_object *container = NULL;
|
||||
fx_value_get_object(&value, &container);
|
||||
if (!container) {
|
||||
fx_array_push_back(dest, value);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
fx_iterator *it = fx_iterator_begin(container);
|
||||
fx_foreach(v, it)
|
||||
{
|
||||
fx_array_push_back(dest, fx_value_copy_return(v));
|
||||
}
|
||||
fx_iterator_unref(it);
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
static enum bshell_status pipeline_add_input_value(
|
||||
struct bshell_pipeline_p *pipeline,
|
||||
fx_value value,
|
||||
bool enumerate)
|
||||
{
|
||||
return write_value(pipeline, pipeline->p_in, value, enumerate);
|
||||
}
|
||||
|
||||
static enum bshell_status pipeline_add_cmdcall(
|
||||
struct bshell_pipeline_p *pipeline,
|
||||
bshell_cmdcall *cmdcall)
|
||||
{
|
||||
bshell_cmdcall **slot = fx_vector_emplace_back(pipeline->p_cmds, NULL);
|
||||
*slot = bshell_cmdcall_ref(cmdcall);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
static enum bshell_status pipeline_execute_single(
|
||||
struct bshell_pipeline_p *pipeline)
|
||||
{
|
||||
return BSHELL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static fx_value pipeline_read_value(struct bshell_pipeline_p *pipeline)
|
||||
{
|
||||
return fx_array_pop_front(pipeline->p_in);
|
||||
}
|
||||
|
||||
static enum bshell_status pipeline_write_value(
|
||||
struct bshell_pipeline_p *pipeline,
|
||||
fx_value value,
|
||||
bool enumerate)
|
||||
{
|
||||
return write_value(pipeline, pipeline->p_out, value, enumerate);
|
||||
}
|
||||
|
||||
static enum bshell_status pipeline_pump_record(
|
||||
struct bshell_pipeline_p *pipeline,
|
||||
struct bshell_runtime *rt,
|
||||
fx_value *result,
|
||||
int *out_end_of_data)
|
||||
{
|
||||
enum bshell_status status = BSHELL_SUCCESS;
|
||||
if (fx_array_get_size(pipeline->p_out)) {
|
||||
fx_value out = fx_array_pop_front(pipeline->p_out);
|
||||
*result = out;
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
for (i = 0; i < pipeline->p_cmds.count;) {
|
||||
status = bshell_cmdcall_process_record(
|
||||
pipeline->p_cmds.items[i],
|
||||
pipeline->p_self,
|
||||
rt);
|
||||
|
||||
if (status != BSHELL_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
bool input_available = fx_array_get_size(pipeline->p_in) != 0;
|
||||
bool output_available = fx_array_get_size(pipeline->p_out) != 0;
|
||||
|
||||
if (input_available) {
|
||||
/* repeat this pipeline stage until all available input
|
||||
* records are consumed */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!output_available) {
|
||||
/* no output produced, and no more input available */
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < pipeline->p_cmds.count - 1) {
|
||||
fx_array *tmp = pipeline->p_in;
|
||||
pipeline->p_in = pipeline->p_out;
|
||||
pipeline->p_out = tmp;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (fx_array_get_size(pipeline->p_out)) {
|
||||
fx_value out = fx_array_pop_front(pipeline->p_out);
|
||||
*result = out;
|
||||
return BSHELL_SUCCESS;
|
||||
} else if (i == 0) {
|
||||
*result = FX_VALUE_EMPTY;
|
||||
*out_end_of_data = 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
size_t i = 0;
|
||||
for (i = 0; i < pipeline->p_cmds.count; i++) {
|
||||
status = bshell_command_process_record(
|
||||
pipeline->p_cmds.items[i],
|
||||
rt);
|
||||
|
||||
if (status != BSHELL_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
fx_array *tmp = pipeline->p_in;
|
||||
pipeline->p_in = pipeline->p_out;
|
||||
pipeline->p_out = tmp;
|
||||
|
||||
if (fx_array_size(pipeline->p_in)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (in->v_type) {
|
||||
fx_value_copy(result, in);
|
||||
} else if (i == 0) {
|
||||
*out_end_of_data = 1;
|
||||
}
|
||||
|
||||
fx_value_unset(in);
|
||||
fx_value_unset(out);
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
enum bshell_status bshell_pipeline_add_input_value(
|
||||
bshell_pipeline *pipeline,
|
||||
fx_value value,
|
||||
bool enumerate)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
BSHELL_TYPE_PIPELINE,
|
||||
pipeline_add_input_value,
|
||||
pipeline,
|
||||
value,
|
||||
enumerate);
|
||||
}
|
||||
|
||||
enum bshell_status bshell_pipeline_add_cmdcall(
|
||||
bshell_pipeline *pipeline,
|
||||
bshell_cmdcall *cmd)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
BSHELL_TYPE_PIPELINE,
|
||||
pipeline_add_cmdcall,
|
||||
pipeline,
|
||||
cmd);
|
||||
}
|
||||
|
||||
enum bshell_status bshell_pipeline_execute_single(bshell_pipeline *pipeline)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
BSHELL_TYPE_PIPELINE,
|
||||
pipeline_execute_single,
|
||||
pipeline);
|
||||
}
|
||||
|
||||
enum bshell_status bshell_pipeline_pump_record(
|
||||
bshell_pipeline *pipeline,
|
||||
struct bshell_runtime *rt,
|
||||
fx_value *out,
|
||||
int *out_end_of_data)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
BSHELL_TYPE_PIPELINE,
|
||||
pipeline_pump_record,
|
||||
pipeline,
|
||||
rt,
|
||||
out,
|
||||
out_end_of_data);
|
||||
}
|
||||
|
||||
fx_value bshell_pipeline_read_value(bshell_pipeline *pipeline)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
BSHELL_TYPE_PIPELINE,
|
||||
pipeline_read_value,
|
||||
pipeline);
|
||||
}
|
||||
|
||||
enum bshell_status bshell_pipeline_write_value(
|
||||
bshell_pipeline *pipeline,
|
||||
fx_value val,
|
||||
bool enumerate)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
BSHELL_TYPE_PIPELINE,
|
||||
pipeline_write_value,
|
||||
pipeline,
|
||||
val,
|
||||
enumerate);
|
||||
}
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(bshell_pipeline)
|
||||
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_pipeline_create, 0, FX_TYPE_VOID);
|
||||
FX_TYPE_CLASS_END(bshell_pipeline)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(bshell_pipeline)
|
||||
FX_TYPE_ID(0x64159f21, 0xb1dd, 0x4838, 0xba62, 0x69fa65cc01d3);
|
||||
FX_TYPE_NAME("bshell.pipeline");
|
||||
FX_TYPE_CLASS(bshell_pipeline_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct bshell_pipeline_p);
|
||||
FX_TYPE_INSTANCE_INIT(pipeline_init);
|
||||
FX_TYPE_INSTANCE_FINI(pipeline_fini);
|
||||
FX_TYPE_DEFINITION_END(bshell_pipeline)
|
||||
@@ -0,0 +1,116 @@
|
||||
#include "scope.h"
|
||||
|
||||
#include <bshell/runtime/runtime.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct bshell_runtime *bshell_runtime_create(void)
|
||||
{
|
||||
struct bshell_runtime *out = malloc(sizeof *out);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
|
||||
out->rt_global = runtime_push_scope(out, RUNTIME_SCOPE_GLOBAL, NULL);
|
||||
out->rt_aliases = fx_hashtable_create();
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void bshell_runtime_destroy(struct bshell_runtime *rt)
|
||||
{
|
||||
fx_hashtable_unref(rt->rt_aliases);
|
||||
free(rt);
|
||||
}
|
||||
|
||||
bshell_variable *bshell_runtime_find_var(
|
||||
struct bshell_runtime *rt,
|
||||
const char *name)
|
||||
{
|
||||
bshell_variable *var = NULL;
|
||||
fx_queue_entry *cur = fx_queue_last(&rt->rt_scope);
|
||||
while (cur) {
|
||||
struct bshell_runtime_scope *scope
|
||||
= fx_unbox(struct bshell_runtime_scope, cur, s_entry);
|
||||
var = var_map_get(&scope->s_vars, name);
|
||||
if (var) {
|
||||
break;
|
||||
}
|
||||
|
||||
cur = fx_queue_prev(cur);
|
||||
}
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
bshell_variable *bshell_runtime_define_var(
|
||||
struct bshell_runtime *rt,
|
||||
const char *name)
|
||||
{
|
||||
struct bshell_runtime_scope *scope = runtime_get_scope(rt);
|
||||
if (!scope) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bshell_variable *var = bshell_variable_create(name);
|
||||
if (!var) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
var_map_put(&scope->s_vars, var);
|
||||
return var;
|
||||
}
|
||||
|
||||
bshell_command *bshell_runtime_find_command(
|
||||
struct bshell_runtime *rt,
|
||||
const char *callable_name)
|
||||
{
|
||||
bshell_command *alias = NULL, *func = NULL;
|
||||
const fx_value *alias_v
|
||||
= fx_hashtable_get(rt->rt_aliases, &FX_CSTR(callable_name));
|
||||
if (alias_v) {
|
||||
fx_value_get_object(alias_v, &alias);
|
||||
bshell_command_ref(alias);
|
||||
return alias;
|
||||
}
|
||||
|
||||
fx_queue_entry *cur = fx_queue_last(&rt->rt_scope);
|
||||
while (cur) {
|
||||
struct bshell_runtime_scope *scope
|
||||
= fx_unbox(struct bshell_runtime_scope, cur, s_entry);
|
||||
const fx_value *func_v = fx_hashtable_get(
|
||||
scope->s_functions,
|
||||
&FX_CSTR(callable_name));
|
||||
if (func_v) {
|
||||
fx_value_get_object(func_v, &func);
|
||||
bshell_command_ref(func);
|
||||
return func;
|
||||
}
|
||||
|
||||
cur = fx_queue_prev(cur);
|
||||
}
|
||||
|
||||
bshell_command *cmd = bshell_command_find_static(callable_name);
|
||||
if (cmd) {
|
||||
return cmd;
|
||||
}
|
||||
|
||||
/* TODO find native executables */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct bshell_runtime_scope *bshell_runtime_get_current_scope(
|
||||
struct bshell_runtime *rt)
|
||||
{
|
||||
return runtime_get_scope(rt);
|
||||
}
|
||||
|
||||
struct bshell_runtime_scope *bshell_runtime_get_parent_scope(
|
||||
struct bshell_runtime *rt,
|
||||
struct bshell_runtime_scope *scope)
|
||||
{
|
||||
fx_queue_entry *parent = fx_queue_prev(&scope->s_entry);
|
||||
return fx_unbox(struct bshell_runtime_scope, parent, s_entry);
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
#include "scope.h"
|
||||
|
||||
#include <bshell/runtime/runtime.h>
|
||||
#include <fx/vector.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct bshell_runtime_scope *runtime_push_scope(
|
||||
struct bshell_runtime *rt,
|
||||
enum bshell_runtime_scope_type type,
|
||||
bshell_scriptblock *block)
|
||||
{
|
||||
struct bshell_runtime_scope *out = malloc(sizeof *out);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
|
||||
out->s_type = type;
|
||||
out->s_functions = fx_hashtable_create();
|
||||
|
||||
if (block) {
|
||||
bshell_runtime_scope_set_block(out, block);
|
||||
}
|
||||
|
||||
fx_queue_push_back(&rt->rt_scope, &out->s_entry);
|
||||
return out;
|
||||
}
|
||||
|
||||
void runtime_pop_scope(struct bshell_runtime *rt)
|
||||
{
|
||||
fx_queue_entry *entry = fx_queue_pop_back(&rt->rt_scope);
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct bshell_runtime_scope *scope
|
||||
= fx_unbox(struct bshell_runtime_scope, entry, s_entry);
|
||||
/* TODO */
|
||||
fx_hashtable_unref(scope->s_functions);
|
||||
free(scope);
|
||||
}
|
||||
|
||||
struct bshell_runtime_scope *runtime_get_scope(struct bshell_runtime *rt)
|
||||
{
|
||||
fx_queue_entry *entry = fx_queue_last(&rt->rt_scope);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fx_unbox(struct bshell_runtime_scope, entry, s_entry);
|
||||
}
|
||||
|
||||
void bshell_runtime_scope_push_value(
|
||||
struct bshell_runtime_scope *scope,
|
||||
const fx_value *value)
|
||||
{
|
||||
fx_value *slot = fx_vector_emplace_back(scope->s_stack, NULL);
|
||||
if (!slot) {
|
||||
return;
|
||||
}
|
||||
|
||||
fx_value_copy(slot, value);
|
||||
}
|
||||
|
||||
fx_value bshell_runtime_scope_pop_value(struct bshell_runtime_scope *scope)
|
||||
{
|
||||
if (scope->s_stack.count == 0) {
|
||||
return FX_VALUE_EMPTY;
|
||||
}
|
||||
|
||||
fx_value v = scope->s_stack.items[scope->s_stack.count - 1];
|
||||
fx_vector_pop_back(scope->s_stack, NULL);
|
||||
return v;
|
||||
}
|
||||
|
||||
void bshell_runtime_scope_set_block(
|
||||
struct bshell_runtime_scope *scope,
|
||||
bshell_scriptblock *block)
|
||||
{
|
||||
scope->s_block = block;
|
||||
scope->s_ip = 0;
|
||||
bshell_scriptblock_get_text(block, &scope->s_instr, &scope->s_nr_instr);
|
||||
bshell_scriptblock_get_pool(block, &scope->s_pool, &scope->s_nr_pool);
|
||||
}
|
||||
|
||||
fx_hashtable *bshell_runtime_scope_get_functions(
|
||||
struct bshell_runtime_scope *scope)
|
||||
{
|
||||
return scope->s_functions;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef BSHELL_RUNTIME_SCOPE_H_
|
||||
#define BSHELL_RUNTIME_SCOPE_H_
|
||||
|
||||
#include "var-map.h"
|
||||
|
||||
#include <bshell/runtime/script-block.h>
|
||||
#include <fx/collections/hashtable.h>
|
||||
#include <fx/namemap.h>
|
||||
#include <fx/queue.h>
|
||||
#include <fx/vector.h>
|
||||
|
||||
struct bshell_runtime;
|
||||
|
||||
enum bshell_runtime_scope_type {
|
||||
RUNTIME_SCOPE_OTHER = 0,
|
||||
RUNTIME_SCOPE_SCRIPT,
|
||||
RUNTIME_SCOPE_GLOBAL,
|
||||
};
|
||||
|
||||
struct bshell_runtime_scope {
|
||||
enum bshell_runtime_scope_type s_type;
|
||||
fx_queue_entry s_entry;
|
||||
struct var_map s_vars;
|
||||
fx_hashtable *s_functions;
|
||||
FX_VECTOR_DECLARE(fx_value, s_stack);
|
||||
size_t s_ip;
|
||||
|
||||
bshell_scriptblock *s_block;
|
||||
bshell_instruction *s_instr;
|
||||
size_t s_nr_instr;
|
||||
fx_value *s_pool;
|
||||
size_t s_nr_pool;
|
||||
};
|
||||
|
||||
extern struct bshell_runtime_scope *runtime_push_scope(
|
||||
struct bshell_runtime *rt,
|
||||
enum bshell_runtime_scope_type type,
|
||||
bshell_scriptblock *block);
|
||||
extern void runtime_pop_scope(struct bshell_runtime *rt);
|
||||
extern struct bshell_runtime_scope *runtime_get_scope(struct bshell_runtime *rt);
|
||||
|
||||
extern void bshell_runtime_scope_push_value(
|
||||
struct bshell_runtime_scope *scope,
|
||||
const fx_value *value);
|
||||
extern fx_value bshell_runtime_scope_pop_value(struct bshell_runtime_scope *scope);
|
||||
|
||||
extern void bshell_runtime_scope_set_block(
|
||||
struct bshell_runtime_scope *scope,
|
||||
bshell_scriptblock *block);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "var-map.h"
|
||||
|
||||
void var_map_cleanup(struct var_map *map)
|
||||
{
|
||||
}
|
||||
|
||||
enum bshell_status var_map_put(struct var_map *map, bshell_variable *var)
|
||||
{
|
||||
const char *name = bshell_variable_get_name(var);
|
||||
struct var_map_entry *entry = malloc(sizeof *entry);
|
||||
if (!entry) {
|
||||
return BSHELL_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
memset(entry, 0x0, sizeof *entry);
|
||||
|
||||
entry->e_var = var;
|
||||
|
||||
fx_namemap_put(&map->m_vars, name, &entry->e_entry);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
bshell_variable *var_map_get(struct var_map *map, const char *name)
|
||||
{
|
||||
fx_namemap_entry *e = fx_namemap_get(&map->m_vars, name);
|
||||
if (!e) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct var_map_entry *entry = fx_unbox(
|
||||
struct var_map_entry,
|
||||
e,
|
||||
e_entry);
|
||||
return entry->e_var;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef BSHELL_RUNTIME_VAR_MAP_H_
|
||||
#define BSHELL_RUNTIME_VAR_MAP_H_
|
||||
|
||||
#include <bshell/runtime/var.h>
|
||||
#include <bshell/status.h>
|
||||
|
||||
struct var_map_entry {
|
||||
bshell_variable *e_var;
|
||||
fx_namemap_entry e_entry;
|
||||
};
|
||||
|
||||
struct var_map {
|
||||
fx_namemap m_vars;
|
||||
};
|
||||
|
||||
extern void var_map_cleanup(struct var_map *map);
|
||||
|
||||
extern enum bshell_status var_map_put(
|
||||
struct var_map *map,
|
||||
bshell_variable *var);
|
||||
extern bshell_variable *var_map_get(struct var_map *map, const char *name);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,96 @@
|
||||
#include <bshell/runtime/var.h>
|
||||
#include <fx/reflection/function.h>
|
||||
#include <fx/string.h>
|
||||
#include <fx/vector.h>
|
||||
|
||||
struct bshell_variable_p {
|
||||
char *var_name;
|
||||
fx_value var_value;
|
||||
};
|
||||
|
||||
static void variable_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct bshell_variable_p *block = priv;
|
||||
|
||||
if (block->var_name) {
|
||||
free(block->var_name);
|
||||
}
|
||||
|
||||
fx_value_unset(&block->var_value);
|
||||
}
|
||||
|
||||
static const char *variable_get_name(struct bshell_variable_p *var)
|
||||
{
|
||||
return var->var_name;
|
||||
}
|
||||
|
||||
static const fx_value *variable_get_value(const struct bshell_variable_p *var)
|
||||
{
|
||||
return &var->var_value;
|
||||
}
|
||||
|
||||
static void variable_set_value(struct bshell_variable_p *var, fx_value *value)
|
||||
{
|
||||
fx_value_unset(&var->var_value);
|
||||
fx_value_copy(&var->var_value, value);
|
||||
}
|
||||
|
||||
bshell_variable *bshell_variable_create(const char *name)
|
||||
{
|
||||
bshell_variable *var = fx_object_create(BSHELL_TYPE_VARIABLE);
|
||||
if (!var) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct bshell_variable_p *p
|
||||
= fx_object_get_private(var, BSHELL_TYPE_VARIABLE);
|
||||
|
||||
p->var_name = fx_strdup(name);
|
||||
if (!p->var_name) {
|
||||
bshell_variable_unref(var);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
const char *bshell_variable_get_name(const bshell_variable *var)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
BSHELL_TYPE_VARIABLE,
|
||||
variable_get_name,
|
||||
var);
|
||||
}
|
||||
|
||||
const fx_value *bshell_variable_get_value(const bshell_variable *var)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
BSHELL_TYPE_VARIABLE,
|
||||
variable_get_value,
|
||||
var);
|
||||
}
|
||||
|
||||
void bshell_variable_set_value(bshell_variable *var, fx_value *value)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_V(
|
||||
BSHELL_TYPE_VARIABLE,
|
||||
variable_set_value,
|
||||
var,
|
||||
value);
|
||||
}
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(bshell_variable)
|
||||
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_variable_create, 1, FX_TYPE_CSTR);
|
||||
FX_TYPE_CLASS_END(bshell_variable)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(bshell_variable)
|
||||
FX_TYPE_ID(0x4e93b9d9, 0x2c11, 0x4fd7, 0xa9ce, 0x41b7cd20f0d4);
|
||||
FX_TYPE_NAME("bshell.variable");
|
||||
FX_TYPE_CLASS(bshell_variable_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct bshell_variable_p);
|
||||
FX_TYPE_INSTANCE_FINI(variable_fini);
|
||||
FX_TYPE_DEFINITION_END(bshell_variable)
|
||||
Reference in New Issue
Block a user