From 92e58ec7c6ba902c7590b2dca6b56a40208dd8c1 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Sun, 24 May 2026 20:22:05 +0100 Subject: [PATCH] runtime: implement opcodes to run commands and load/store variables and properties --- bshell/runtime/eval.c | 388 ++++++++++++++++++++++++++++++++++++++- bshell/runtime/opcode.h | 1 + bshell/runtime/runtime.c | 83 +++++++++ bshell/runtime/runtime.h | 21 +++ bshell/runtime/scope.c | 13 +- bshell/runtime/scope.h | 7 +- 6 files changed, 499 insertions(+), 14 deletions(-) diff --git a/bshell/runtime/eval.c b/bshell/runtime/eval.c index e716fd6..8a11422 100644 --- a/bshell/runtime/eval.c +++ b/bshell/runtime/eval.c @@ -1,7 +1,13 @@ +#include "../format/format.h" #include "../status.h" +#include "cmdcall.h" +#include "pipeline.h" #include "runtime.h" #include "scope.h" +#include +#include +#include #include static enum bshell_status eval_instruction( @@ -11,38 +17,378 @@ static enum bshell_status eval_instruction( { 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 OPCODE_LDC_INT: x = FX_INT(arg); - runtime_scope_push_value(scope, x); + runtime_scope_push_value(scope, &x); + fx_value_unset(&x); + break; + case OPCODE_LDC_FP: + pool_value = bshell_scriptblock_get_pool_value( + scope->s_block, + arg, + FX_TYPE_DOUBLE); + if (pool_value) { + runtime_scope_push_value(scope, pool_value); + } else { + fprintf(stderr, "RUNTIME: invalid ldc.fp operand\n"); + return BSHELL_ERR_BAD_SYNTAX; + } + break; + case 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) { + runtime_scope_push_value(scope, pool_value); + } else { + fprintf(stderr, "RUNTIME: invalid ldc.str operand\n"); + return BSHELL_ERR_BAD_SYNTAX; + } break; case OPCODE_ADD: x = runtime_scope_pop_value(scope); y = runtime_scope_pop_value(scope); - z = FX_INT(y.v_int + x.v_int); - runtime_scope_push_value(scope, z); + 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; + } + runtime_scope_push_value(scope, &z); + fx_value_unset(&z); break; case OPCODE_SUB: x = runtime_scope_pop_value(scope); y = runtime_scope_pop_value(scope); - z = FX_INT(y.v_int - x.v_int); - runtime_scope_push_value(scope, z); + 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; + } + runtime_scope_push_value(scope, &z); + fx_value_unset(&z); break; case OPCODE_MUL: x = runtime_scope_pop_value(scope); y = runtime_scope_pop_value(scope); - z = FX_INT(y.v_int * x.v_int); - runtime_scope_push_value(scope, z); + 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; + } + runtime_scope_push_value(scope, &z); + fx_value_unset(&z); break; case OPCODE_DIV: x = runtime_scope_pop_value(scope); y = runtime_scope_pop_value(scope); - z = FX_INT(y.v_int / x.v_int); - runtime_scope_push_value(scope, z); + 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; + } + runtime_scope_push_value(scope, &z); + fx_value_unset(&z); break; + case 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) { + runtime_scope_push_value( + scope, + bshell_variable_get_value(var)); + } else { + runtime_scope_push_value(scope, &FX_VALUE_EMPTY); + } + + break; + case 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; + } + + runtime_scope_push_value(scope, pool_value); + + break; + case OPCODE_LDPROP: { + /* container */ + x = runtime_scope_pop_value(scope); + /* property */ + y = 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); + 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); + runtime_scope_push_value(scope, &FX_VALUE_EMPTY); + break; + } + + fx_property_get_value(prop, &x, &z); + fx_value_unset(&x); + runtime_scope_push_value(scope, &z); + fx_value_unset(&z); + + break; + } + case OPCODE_STLOCAL: + x = 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); + runtime_scope_push_value(scope, &x); + fx_value_unset(&x); + break; + case OPCODE_MK_STR: { + fx_string *result = fx_string_create(); + fx_stringstream *strm = fx_stringstream_create(); + + while (arg > 0) { + x = 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); + runtime_scope_push_value(scope, &y); + fx_value_unset(&y); + break; + } + case OPCODE_MK_HTAB: { + fx_hashtable *result = fx_hashtable_create(); + + while (arg > 0) { + fx_value key = runtime_scope_pop_value(scope); + fx_value value = 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); + runtime_scope_push_value(scope, &y); + fx_value_unset(&y); + break; + } + case OPCODE_MK_ARRAY: { + fx_array *result = fx_array_create(); + + while (arg > 0) { + fx_value value = runtime_scope_pop_value(scope); + fx_array_push_front(result, value); + fx_value_unset(&value); + arg--; + } + + y = FX_VALUE_OBJECT(result); + runtime_scope_push_value(scope, &y); + fx_value_unset(&y); + break; + } + case OPCODE_LDCMD: { + bshell_cmdcall *result = bshell_cmdcall_create(); + + while (arg > 0) { + fx_value cmd_arg = 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); + runtime_scope_push_value(scope, &y); + fx_value_unset(&y); + break; + } + case OPCODE_PEXEC: { + bshell_pipeline *pipeline = bshell_pipeline_create(); + bool single = (arg == 1); + while (arg > 0) { + fx_value cmd = 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 table_format_ctx table_ctx; + table_format_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); + table_format_ctx_prepare_columns_from_format( + &table_ctx, + ty, + NULL); + table_format_ctx_print_headers(&table_ctx); + columns_initialised = true; + } + + table_format_ctx_print_record(&table_ctx, &record); + fx_value_unset(&record); + } + + table_format_ctx_cleanup(&table_ctx); + bshell_pipeline_unref(pipeline); + break; + } default: fprintf(stderr, "RUNTIME: encountered unknown opcode %02x\n", @@ -51,7 +397,7 @@ static enum bshell_status eval_instruction( } scope->s_ip++; - return BSHELL_SUCCESS; + return bstatus; } static fx_value runtime_eval(struct bshell_runtime *rt) @@ -89,3 +435,25 @@ fx_value bshell_runtime_eval_script( 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 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; +} diff --git a/bshell/runtime/opcode.h b/bshell/runtime/opcode.h index 5e17929..f6df813 100644 --- a/bshell/runtime/opcode.h +++ b/bshell/runtime/opcode.h @@ -11,6 +11,7 @@ enum bshell_opcode { OPCODE_NOP = 0, OPCODE_LDC_INT, OPCODE_LDC_STR, + OPCODE_LDC_FP, OPCODE_LDGLOBAL, OPCODE_LDLOCAL, OPCODE_LDBLOCK, diff --git a/bshell/runtime/runtime.c b/bshell/runtime/runtime.c index 6659978..326e2d8 100644 --- a/bshell/runtime/runtime.c +++ b/bshell/runtime/runtime.c @@ -15,11 +15,94 @@ struct bshell_runtime *bshell_runtime_create(void) 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 runtime_scope *scope = fx_unbox( + struct 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 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 runtime_scope *scope = fx_unbox( + struct 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; +} diff --git a/bshell/runtime/runtime.h b/bshell/runtime/runtime.h index ac459a5..0f23dc8 100644 --- a/bshell/runtime/runtime.h +++ b/bshell/runtime/runtime.h @@ -1,8 +1,11 @@ #ifndef RUNTIME_RUNTIME_H_ #define RUNTIME_RUNTIME_H_ +#include "../command/command.h" #include "../script-block.h" +#include "var.h" +#include #include #include @@ -10,6 +13,7 @@ struct runtime_scope; struct bshell_runtime { struct runtime_scope *rt_global; + fx_hashtable *rt_aliases; fx_queue rt_scope; }; @@ -23,4 +27,21 @@ extern fx_value bshell_runtime_eval_script( struct bshell_runtime *rt, bshell_scriptblock *block); +extern bshell_variable *bshell_runtime_find_var( + struct bshell_runtime *rt, + const char *name); +extern bshell_variable *bshell_runtime_define_var( + struct bshell_runtime *rt, + const char *name); + +extern bshell_command *bshell_runtime_find_command( + struct bshell_runtime *rt, + const char *callable_name); + +extern enum bshell_status bshell_runtime_push_scope( + struct bshell_runtime *rt, + bshell_scriptblock *block); +extern enum bshell_status bshell_runtime_pop_scope(struct bshell_runtime *rt); +extern fx_value bshell_runtime_eval(struct bshell_runtime *rt); + #endif diff --git a/bshell/runtime/scope.c b/bshell/runtime/scope.c index 5cb6ffd..8e70ab4 100644 --- a/bshell/runtime/scope.c +++ b/bshell/runtime/scope.c @@ -19,6 +19,7 @@ struct runtime_scope *runtime_push_scope( memset(out, 0x0, sizeof *out); out->s_type = type; + out->s_functions = fx_hashtable_create(); if (block) { runtime_scope_set_block(out, block); @@ -40,6 +41,7 @@ void runtime_pop_scope(struct bshell_runtime *rt) entry, s_entry); /* TODO */ + fx_hashtable_unref(scope->s_functions); free(scope); } @@ -53,18 +55,24 @@ struct runtime_scope *runtime_get_scope(struct bshell_runtime *rt) return fx_unbox(struct runtime_scope, entry, s_entry); } -void runtime_scope_push_value(struct runtime_scope *scope, fx_value value) +void runtime_scope_push_value( + struct runtime_scope *scope, + const fx_value *value) { fx_value *slot = fx_vector_emplace_back(scope->s_stack, NULL); if (!slot) { return; } - memcpy(slot, &value, sizeof value); + fx_value_copy(slot, value); } fx_value runtime_scope_pop_value(struct 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; @@ -75,6 +83,7 @@ void runtime_scope_set_block( 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); } diff --git a/bshell/runtime/scope.h b/bshell/runtime/scope.h index 7fcb269..f92cd8d 100644 --- a/bshell/runtime/scope.h +++ b/bshell/runtime/scope.h @@ -2,7 +2,9 @@ #define RUNTIME_SCOPE_H_ #include "../script-block.h" +#include "var-map.h" +#include #include #include #include @@ -18,7 +20,8 @@ enum runtime_scope_type { struct runtime_scope { enum runtime_scope_type s_type; fx_queue_entry s_entry; - fx_namemap s_vars; + struct var_map s_vars; + fx_hashtable *s_functions; FX_VECTOR_DECLARE(fx_value, s_stack); size_t s_ip; @@ -38,7 +41,7 @@ extern struct runtime_scope *runtime_get_scope(struct bshell_runtime *rt); extern void runtime_scope_push_value( struct runtime_scope *scope, - fx_value value); + const fx_value *value); extern fx_value runtime_scope_pop_value(struct runtime_scope *scope); extern void runtime_scope_set_block(