#include "scope.h" #include #include #include #include #include #include #include #include #include #include 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_get_cstr(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_STRING); 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_scope_define_variable( bshell_runtime_get_current_scope(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_get_cstr(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) { bshell_cmdcall_unref(result); 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; fx_value record = FX_VALUE_EMPTY; bshell_runtime_begin_output(rt); 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; } bshell_runtime_output_value(rt, &record); fx_value_unset(&record); } bshell_runtime_end_output(rt); 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); fx_value result = runtime_eval(rt); bshell_runtime_scope_set_block(rt->rt_global, NULL); return result; } 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; }