libcubescript/src/cs_vm.cc

1296 lines
48 KiB
C++
Raw Normal View History

2017-06-20 21:21:39 +02:00
#include <cubescript/cubescript.hh>
2016-08-12 18:38:43 +02:00
#include "cs_vm.hh"
2021-03-23 01:45:35 +01:00
#include "cs_std.hh"
#include "cs_parser.hh"
2016-08-12 18:38:43 +02:00
2021-03-20 06:52:10 +01:00
#include <cstdio>
2021-03-31 02:21:32 +02:00
#include <cmath>
2017-02-09 20:59:14 +01:00
#include <limits>
2016-08-13 01:26:16 +02:00
2021-03-23 23:32:25 +01:00
namespace cubescript {
2016-08-12 18:38:43 +02:00
static inline void push_alias(ident *id, ident_stack &st) {
if (id->is_alias() && !(id->get_flags() & IDENT_FLAG_ARG)) {
auto *aimp = static_cast<alias_impl *>(id);
aimp->push_arg(st);
aimp->p_flags &= ~IDENT_FLAG_UNKNOWN;
2016-08-18 00:06:39 +02:00
}
}
2021-03-23 23:29:32 +01:00
static inline void pop_alias(ident *id) {
if (id->is_alias() && !(id->get_flags() & IDENT_FLAG_ARG)) {
2021-03-23 23:29:32 +01:00
static_cast<alias_impl *>(id)->pop_arg();
2016-08-18 00:06:39 +02:00
}
}
2021-03-23 23:29:32 +01:00
static inline void force_arg(any_value &v, int type) {
2016-08-12 18:38:43 +02:00
switch (type) {
2021-03-23 23:29:32 +01:00
case BC_RET_STRING:
if (v.get_type() != value_type::STRING) {
2016-08-17 04:57:53 +02:00
v.force_str();
}
break;
2021-03-23 23:29:32 +01:00
case BC_RET_INT:
if (v.get_type() != value_type::INT) {
2016-08-17 04:57:53 +02:00
v.force_int();
}
break;
2021-03-23 23:29:32 +01:00
case BC_RET_FLOAT:
if (v.get_type() != value_type::FLOAT) {
2016-08-17 04:57:53 +02:00
v.force_float();
}
break;
2016-08-12 18:38:43 +02:00
}
}
void exec_command(
thread_state &ts, command_impl *id, any_value *args, any_value &res,
std::size_t nargs, bool lookup
2016-08-17 04:57:53 +02:00
) {
int i = -1, fakeargs = 0, numargs = int(nargs);
2016-08-12 18:38:43 +02:00
bool rep = false;
auto fmt = id->get_args();
for (auto it = fmt.begin(); it != fmt.end(); ++it) {
switch (*it) {
2016-08-17 04:57:53 +02:00
case 'i':
if (++i >= numargs) {
if (rep) {
break;
}
args[i].set_int(0);
fakeargs++;
} else {
args[i].force_int();
}
break;
case 'b':
if (++i >= numargs) {
if (rep) {
break;
}
2021-03-23 23:29:32 +01:00
args[i].set_int(std::numeric_limits<integer_type>::min());
2016-08-17 04:57:53 +02:00
fakeargs++;
} else {
args[i].force_int();
}
break;
case 'f':
if (++i >= numargs) {
if (rep) {
break;
}
args[i].set_float(0.0f);
fakeargs++;
} else {
args[i].force_float();
}
break;
case 'F':
if (++i >= numargs) {
if (rep) {
break;
}
args[i].set_float(args[i - 1].get_float());
fakeargs++;
} else {
args[i].force_float();
}
break;
case 's':
if (++i >= numargs) {
if (rep) {
break;
}
args[i].set_str("");
2016-08-17 04:57:53 +02:00
fakeargs++;
} else {
args[i].force_str();
}
break;
case 'T':
case 't':
if (++i >= numargs) {
if (rep) {
break;
}
2021-03-18 20:55:14 +01:00
args[i].set_none();
2016-08-17 04:57:53 +02:00
fakeargs++;
}
break;
case 'E':
if (++i >= numargs) {
if (rep) {
break;
}
2021-03-18 20:55:14 +01:00
args[i].set_none();
2016-08-17 04:57:53 +02:00
fakeargs++;
} else if (args[i].get_type() == value_type::STRING) {
auto str = std::string_view{args[i].get_str()};
if (str.empty()) {
args[i].set_int(0);
} else {
args[i].force_code(*ts.pstate);
}
2016-08-17 04:57:53 +02:00
}
break;
case 'e':
if (++i >= numargs) {
if (rep) {
break;
}
args[i].set_code(
bcode_get_empty(ts.istate->empty, VAL_NULL)
2016-08-17 04:57:53 +02:00
);
fakeargs++;
} else {
args[i].force_code(*ts.pstate);
2016-08-17 04:57:53 +02:00
}
break;
case 'r':
if (++i >= numargs) {
if (rep) {
break;
}
args[i].set_ident(ts.istate->identmap[ID_IDX_DUMMY]);
2016-08-17 04:57:53 +02:00
fakeargs++;
} else {
args[i].force_ident(*ts.pstate);
2016-08-17 04:57:53 +02:00
}
break;
case '$':
2016-09-06 20:48:24 +02:00
i += 1;
2016-08-17 04:57:53 +02:00
args[i].set_ident(id);
break;
case 'N':
2016-09-06 20:48:24 +02:00
i += 1;
2021-03-23 23:29:32 +01:00
args[i].set_int(integer_type(lookup ? -1 : i - fakeargs));
2016-08-17 04:57:53 +02:00
break;
case 'C': {
2017-02-18 17:49:01 +01:00
i = std::max(i + 1, numargs);
any_value tv{*ts.pstate};
2021-03-23 23:29:32 +01:00
tv.set_str(concat_values(
*ts.pstate, std::span{args, std::size_t(i)}, " "
2021-03-20 05:41:25 +01:00
));
2021-03-23 23:29:32 +01:00
static_cast<command_impl *>(id)->call(
*ts.pstate, std::span<any_value>(&tv, &tv + 1), res
2021-03-20 05:41:25 +01:00
);
return;
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
case 'V':
2017-02-18 17:49:01 +01:00
i = std::max(i + 1, numargs);
2021-03-23 23:29:32 +01:00
static_cast<command_impl *>(id)->call(
*ts.pstate, std::span{args, std::size_t(i)}, res
2021-03-20 05:41:25 +01:00
);
return;
2016-08-17 04:57:53 +02:00
case '1':
case '2':
case '3':
case '4':
if (i + 1 < numargs) {
it -= *it - '0' + 1;
2016-08-17 04:57:53 +02:00
rep = true;
}
break;
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
}
2016-08-12 18:38:43 +02:00
++i;
2021-03-23 23:29:32 +01:00
static_cast<command_impl *>(id)->call(
*ts.pstate, std::span<any_value>{args, std::size_t(i)}, res
2021-03-20 05:41:25 +01:00
);
2016-08-17 04:57:53 +02:00
}
void exec_alias(
thread_state &ts, alias *a, any_value *args, any_value &result,
std::size_t callargs, std::size_t &nargs,
std::size_t offset, std::size_t skip, std::uint32_t op
2016-08-17 04:57:53 +02:00
) {
/* excess arguments get ignored (make error maybe?) */
callargs = std::min(callargs, MAX_ARGUMENTS);
integer_var *anargs = static_cast<integer_var *>(
ts.istate->identmap[ID_IDX_NUMARGS]
);
argset uargs{};
std::size_t noff = ts.idstack.size();
for(std::size_t i = 0; i < callargs; i++) {
auto &ap = *static_cast<alias_impl *>(ts.istate->identmap[i]);
ap.push_arg(ts.idstack.emplace_back(*ts.pstate));
ap.p_astack->val_s = std::move(args[offset + i]);
uargs[i] = true;
2016-08-17 04:57:53 +02:00
}
auto oldargs = anargs->get_value();
2021-03-31 02:21:32 +02:00
anargs->set_value(integer_type(callargs));
int oldflags = ts.pstate->identflags;
ts.pstate->identflags |= a->get_flags()&IDENT_FLAG_OVERRIDDEN;
ident_link aliaslink = {a, ts.callstack, uargs};
ts.callstack = &aliaslink;
2021-04-01 05:18:20 +02:00
bcode_ref coderef = static_cast<
alias_impl *
2021-04-01 05:18:20 +02:00
>(a)->compile_code(ts);
2021-03-30 23:49:50 +02:00
auto cleanup = [&]() {
ts.callstack = aliaslink.next;
ts.pstate->identflags = oldflags;
auto amask = aliaslink.usedargs;
for (std::size_t i = 0; i < callargs; i++) {
static_cast<alias_impl *>(ts.istate->identmap[i])->pop_arg();
amask[i] = false;
2016-08-17 04:57:53 +02:00
}
for (; amask.any(); ++callargs) {
if (amask[callargs]) {
2021-03-23 23:29:32 +01:00
static_cast<alias_impl *>(
ts.istate->identmap[callargs]
)->pop_arg();
amask[callargs] = false;
}
}
ts.idstack.resize(noff, ident_stack{*ts.pstate});
2021-03-23 23:29:32 +01:00
force_arg(result, op & BC_INST_RET_MASK);
anargs->set_value(integer_type(oldargs));
nargs = offset - skip;
2021-03-30 23:49:50 +02:00
};
try {
2021-04-01 05:18:20 +02:00
bcode *p = coderef;
vm_exec(ts, p->get_raw(), result);
2021-03-30 23:49:50 +02:00
} catch (...) {
cleanup();
throw;
}
cleanup();
2016-08-12 18:38:43 +02:00
}
static constexpr int MaxRunDepth = 255;
static thread_local int rundepth = 0;
run_depth_guard::run_depth_guard(thread_state &ts) {
if (rundepth >= MaxRunDepth) {
throw error{ts, "exceeded recursion limit"};
2016-09-23 21:04:52 +02:00
}
++rundepth;
}
run_depth_guard::~run_depth_guard() { --rundepth; }
2016-09-23 21:04:52 +02:00
2021-03-25 01:52:03 +01:00
static inline alias *get_lookup_id(thread_state &ts, std::uint32_t op) {
ident *id = ts.istate->identmap[op >> 8];
2021-03-28 00:19:51 +01:00
auto flags = id->get_flags();
if (flags & IDENT_FLAG_ARG) {
if (!ident_is_used_arg(id, ts)) {
return nullptr;
}
} else if (flags & IDENT_FLAG_UNKNOWN) {
2021-03-25 01:52:03 +01:00
throw error{
*ts.pstate, "unknown alias lookup: %s", id->get_name().data()
};
2016-08-17 04:57:53 +02:00
}
2021-03-23 23:29:32 +01:00
return static_cast<alias *>(id);
2016-08-17 04:57:53 +02:00
}
2021-03-23 23:29:32 +01:00
static inline int get_lookupu_type(
thread_state &ts, any_value &arg, ident *&id, std::uint32_t op
2016-08-17 04:57:53 +02:00
) {
2021-03-23 23:29:32 +01:00
if (arg.get_type() != value_type::STRING) {
2016-08-17 04:57:53 +02:00
return -2; /* default case */
}
id = ts.pstate->get_ident(arg.get_str());
2016-08-17 04:57:53 +02:00
if (id) {
2016-08-18 03:53:51 +02:00
switch(id->get_type()) {
2021-03-23 23:29:32 +01:00
case ident_type::ALIAS:
if (id->get_flags() & IDENT_FLAG_UNKNOWN) {
2016-08-17 04:57:53 +02:00
break;
}
if (
(id->get_flags() & IDENT_FLAG_ARG) &&
2021-03-26 02:29:54 +01:00
!ident_is_used_arg(id, ts)
) {
return ID_UNKNOWN;
2016-08-17 04:57:53 +02:00
}
return ID_ALIAS;
2021-03-23 23:29:32 +01:00
case ident_type::SVAR:
return ID_SVAR;
2021-03-23 23:29:32 +01:00
case ident_type::IVAR:
return ID_IVAR;
2021-03-23 23:29:32 +01:00
case ident_type::FVAR:
return ID_FVAR;
2021-03-23 23:29:32 +01:00
case ident_type::COMMAND: {
/* make sure value stack gets restored */
2021-03-25 01:52:03 +01:00
stack_guard s{ts};
2021-03-24 23:30:30 +01:00
auto *cimpl = static_cast<command_impl *>(id);
auto &args = ts.vmstack;
2021-03-24 23:30:30 +01:00
auto osz = args.size();
/* pad with as many empty values as we need */
args.resize(osz + cimpl->get_num_args(), any_value{*ts.pstate});
2021-03-18 20:55:14 +01:00
arg.set_none();
exec_command(ts, cimpl, &args[osz], arg, 0, true);
2021-03-23 23:29:32 +01:00
force_arg(arg, op & BC_INST_RET_MASK);
2016-08-17 04:57:53 +02:00
return -2; /* ignore */
}
default:
return ID_UNKNOWN;
2016-08-17 04:57:53 +02:00
}
}
throw error{*ts.pstate, "unknown alias lookup: %s", arg.get_str().data()};
2016-08-17 04:57:53 +02:00
}
std::uint32_t *vm_exec(
thread_state &ts, std::uint32_t *code, any_value &result
) {
2021-03-18 20:55:14 +01:00
result.set_none();
auto &cs = *ts.pstate;
2021-03-26 02:59:42 +01:00
run_depth_guard level{ts}; /* incr and decr on scope exit */
2021-03-25 01:52:03 +01:00
stack_guard guard{ts}; /* resize back to original */
auto &args = ts.vmstack;
auto &chook = cs.get_call_hook();
if (chook) {
chook(cs);
}
2016-08-12 18:38:43 +02:00
for (;;) {
std::uint32_t op = *code++;
2016-08-12 18:38:43 +02:00
switch (op & 0xFF) {
2021-03-23 23:29:32 +01:00
case BC_INST_START:
case BC_INST_OFFSET:
2016-08-17 04:57:53 +02:00
continue;
2016-08-12 18:38:43 +02:00
2021-03-23 23:29:32 +01:00
case BC_INST_NULL | BC_RET_NULL:
2021-03-18 20:55:14 +01:00
result.set_none();
2016-08-17 04:57:53 +02:00
continue;
2021-03-23 23:29:32 +01:00
case BC_INST_NULL | BC_RET_STRING:
2016-08-17 04:57:53 +02:00
result.set_str("");
continue;
2021-03-23 23:29:32 +01:00
case BC_INST_NULL | BC_RET_INT:
2016-08-17 04:57:53 +02:00
result.set_int(0);
continue;
2021-03-23 23:29:32 +01:00
case BC_INST_NULL | BC_RET_FLOAT:
2016-08-17 04:57:53 +02:00
result.set_float(0.0f);
continue;
2016-08-12 18:38:43 +02:00
2021-03-23 23:29:32 +01:00
case BC_INST_FALSE | BC_RET_STRING:
2016-08-17 04:57:53 +02:00
result.set_str("0");
continue;
2021-03-23 23:29:32 +01:00
case BC_INST_FALSE | BC_RET_NULL:
case BC_INST_FALSE | BC_RET_INT:
2016-08-17 04:57:53 +02:00
result.set_int(0);
continue;
2021-03-23 23:29:32 +01:00
case BC_INST_FALSE | BC_RET_FLOAT:
2016-08-17 04:57:53 +02:00
result.set_float(0.0f);
continue;
2016-08-12 18:38:43 +02:00
2021-03-23 23:29:32 +01:00
case BC_INST_TRUE | BC_RET_STRING:
2016-08-17 04:57:53 +02:00
result.set_str("1");
continue;
2021-03-23 23:29:32 +01:00
case BC_INST_TRUE | BC_RET_NULL:
case BC_INST_TRUE | BC_RET_INT:
2016-08-17 04:57:53 +02:00
result.set_int(1);
continue;
2021-03-23 23:29:32 +01:00
case BC_INST_TRUE | BC_RET_FLOAT:
2016-08-17 04:57:53 +02:00
result.set_float(1.0f);
continue;
2016-08-12 18:38:43 +02:00
2021-03-23 23:29:32 +01:00
case BC_INST_NOT | BC_RET_STRING:
result.set_str(args.back().get_bool() ? "0" : "1");
args.pop_back();
2016-08-17 04:57:53 +02:00
continue;
2021-03-23 23:29:32 +01:00
case BC_INST_NOT | BC_RET_NULL:
case BC_INST_NOT | BC_RET_INT:
result.set_int(!args.back().get_bool());
args.pop_back();
2016-08-17 04:57:53 +02:00
continue;
2021-03-23 23:29:32 +01:00
case BC_INST_NOT | BC_RET_FLOAT:
result.set_float(float_type(!args.back().get_bool()));
args.pop_back();
2016-08-17 04:57:53 +02:00
continue;
2016-08-12 18:38:43 +02:00
2021-03-23 23:29:32 +01:00
case BC_INST_POP:
args.pop_back();
2016-08-17 04:57:53 +02:00
continue;
2021-03-23 23:29:32 +01:00
case BC_INST_ENTER:
code = vm_exec(ts, code, args.emplace_back(cs));
2016-08-17 04:57:53 +02:00
continue;
2021-03-23 23:29:32 +01:00
case BC_INST_ENTER_RESULT:
code = vm_exec(ts, code, result);
2016-08-17 04:57:53 +02:00
continue;
2021-03-23 23:29:32 +01:00
case BC_INST_EXIT | BC_RET_STRING:
case BC_INST_EXIT | BC_RET_INT:
case BC_INST_EXIT | BC_RET_FLOAT:
force_arg(result, op & BC_INST_RET_MASK);
2016-08-17 04:57:53 +02:00
/* fallthrough */
2021-03-23 23:29:32 +01:00
case BC_INST_EXIT | BC_RET_NULL:
2016-09-23 21:06:44 +02:00
return code;
case BC_INST_RESULT | BC_RET_NULL:
result = std::move(args.back());
args.pop_back();
continue;
case BC_INST_RESULT | BC_RET_STRING:
case BC_INST_RESULT | BC_RET_INT:
case BC_INST_RESULT | BC_RET_FLOAT:
result = std::move(args.back());
args.pop_back();
force_arg(result, op & BC_INST_RET_MASK);
continue;
2021-03-23 23:29:32 +01:00
case BC_INST_RESULT_ARG | BC_RET_STRING:
case BC_INST_RESULT_ARG | BC_RET_INT:
case BC_INST_RESULT_ARG | BC_RET_FLOAT:
force_arg(result, op & BC_INST_RET_MASK);
2016-08-17 04:57:53 +02:00
/* fallthrough */
2021-03-23 23:29:32 +01:00
case BC_INST_RESULT_ARG | BC_RET_NULL:
args.emplace_back(std::move(result));
2016-08-17 04:57:53 +02:00
continue;
case BC_INST_FORCE | BC_RET_STRING:
args.back().force_str();
continue;
case BC_INST_FORCE | BC_RET_INT:
args.back().force_int();
continue;
case BC_INST_FORCE | BC_RET_FLOAT:
args.back().force_float();
continue;
case BC_INST_DUP | BC_RET_NULL: {
auto &v = args.back();
v.get_val(args.emplace_back(cs));
continue;
}
case BC_INST_DUP | BC_RET_INT: {
auto &v = args.back();
args.emplace_back(cs).set_int(v.get_int());
continue;
}
case BC_INST_DUP | BC_RET_FLOAT: {
auto &v = args.back();
args.emplace_back(cs).set_float(v.get_float());
continue;
}
case BC_INST_DUP | BC_RET_STRING: {
auto &v = args.back();
auto &nv = args.emplace_back(cs);
nv = v;
nv.force_str();
continue;
}
case BC_INST_VAL | BC_RET_STRING: {
std::uint32_t len = op >> 8;
args.emplace_back(cs).set_str(std::string_view{
reinterpret_cast<char const *>(code), len
});
code += len / sizeof(std::uint32_t) + 1;
continue;
}
case BC_INST_VAL_INT | BC_RET_STRING: {
char s[4] = {
char((op >> 8) & 0xFF),
char((op >> 16) & 0xFF),
char((op >> 24) & 0xFF), '\0'
};
/* gotta cast or r.size() == potentially 3 */
args.emplace_back(cs).set_str(static_cast<char const *>(s));
continue;
}
case BC_INST_VAL | BC_RET_NULL:
case BC_INST_VAL_INT | BC_RET_NULL:
args.emplace_back(cs).set_none();
continue;
case BC_INST_VAL | BC_RET_INT:
args.emplace_back(cs).set_int(
*reinterpret_cast<integer_type const *>(code)
);
code += bc_store_size<integer_type>;
continue;
case BC_INST_VAL_INT | BC_RET_INT:
args.emplace_back(cs).set_int(integer_type(op) >> 8);
continue;
case BC_INST_VAL | BC_RET_FLOAT:
args.emplace_back(cs).set_float(
*reinterpret_cast<float_type const *>(code)
);
code += bc_store_size<float_type>;
continue;
case BC_INST_VAL_INT | BC_RET_FLOAT:
args.emplace_back(cs).set_float(
float_type(integer_type(op) >> 8)
);
continue;
2021-03-23 23:29:32 +01:00
case BC_INST_PRINT:
cs.print_var(*static_cast<global_var *>(ts.istate->identmap[op >> 8]));
2016-08-17 04:57:53 +02:00
continue;
2016-08-12 18:38:43 +02:00
2021-03-23 23:29:32 +01:00
case BC_INST_LOCAL: {
std::size_t numlocals = op >> 8;
std::size_t offset = args.size() - numlocals;
std::size_t idstsz = ts.idstack.size();
for (std::size_t i = 0; i < numlocals; ++i) {
push_alias(
args[offset + i].get_ident(),
ts.idstack.emplace_back(*ts.pstate)
);
2016-08-17 04:57:53 +02:00
}
2021-03-30 23:49:50 +02:00
auto cleanup = [&]() {
for (std::size_t i = offset; i < args.size(); ++i) {
2021-03-23 23:29:32 +01:00
pop_alias(args[i].get_ident());
}
ts.idstack.resize(idstsz, ident_stack{*ts.pstate});
2021-03-30 23:49:50 +02:00
};
try {
code = vm_exec(ts, code, result);
} catch (...) {
cleanup();
throw;
}
cleanup();
2016-09-23 21:06:44 +02:00
return code;
2016-08-17 04:57:53 +02:00
}
2016-08-12 18:38:43 +02:00
2021-03-23 23:29:32 +01:00
case BC_INST_DO_ARGS | BC_RET_NULL:
case BC_INST_DO_ARGS | BC_RET_STRING:
case BC_INST_DO_ARGS | BC_RET_INT:
case BC_INST_DO_ARGS | BC_RET_FLOAT:
call_with_args(ts, [&]() {
auto v = std::move(args.back());
args.pop_back();
cs.run(v.get_code(), result);
2021-03-23 23:29:32 +01:00
force_arg(result, op & BC_INST_RET_MASK);
2016-09-10 19:54:55 +02:00
});
continue;
2016-08-17 04:57:53 +02:00
/* fallthrough */
2021-03-23 23:29:32 +01:00
case BC_INST_DO | BC_RET_NULL:
case BC_INST_DO | BC_RET_STRING:
case BC_INST_DO | BC_RET_INT:
case BC_INST_DO | BC_RET_FLOAT: {
auto v = std::move(args.back());
args.pop_back();
cs.run(v.get_code(), result);
2021-03-23 23:29:32 +01:00
force_arg(result, op & BC_INST_RET_MASK);
2016-08-17 04:57:53 +02:00
continue;
}
2016-08-12 18:38:43 +02:00
2021-03-23 23:29:32 +01:00
case BC_INST_JUMP: {
std::uint32_t len = op >> 8;
2016-08-17 04:57:53 +02:00
code += len;
2016-08-12 18:38:43 +02:00
continue;
}
2021-03-23 23:29:32 +01:00
case BC_INST_JUMP_B | BC_INST_FLAG_TRUE: {
std::uint32_t len = op >> 8;
if (args.back().get_bool()) {
2016-08-17 04:57:53 +02:00
code += len;
}
args.pop_back();
2016-08-17 04:57:53 +02:00
continue;
}
2021-03-23 23:29:32 +01:00
case BC_INST_JUMP_B | BC_INST_FLAG_FALSE: {
std::uint32_t len = op >> 8;
if (!args.back().get_bool()) {
2016-08-17 04:57:53 +02:00
code += len;
}
args.pop_back();
2016-08-17 04:57:53 +02:00
continue;
}
2021-03-23 23:29:32 +01:00
case BC_INST_JUMP_RESULT | BC_INST_FLAG_TRUE: {
std::uint32_t len = op >> 8;
auto v = std::move(args.back());
args.pop_back();
if (v.get_type() == value_type::CODE) {
cs.run(v.get_code(), result);
2016-08-17 04:57:53 +02:00
} else {
result = std::move(v);
2016-08-17 04:57:53 +02:00
}
if (result.get_bool()) {
code += len;
}
continue;
}
2021-03-23 23:29:32 +01:00
case BC_INST_JUMP_RESULT | BC_INST_FLAG_FALSE: {
std::uint32_t len = op >> 8;
auto v = std::move(args.back());
args.pop_back();
if (v.get_type() == value_type::CODE) {
cs.run(v.get_code(), result);
2016-08-17 04:57:53 +02:00
} else {
result = std::move(v);
2016-08-17 04:57:53 +02:00
}
if (!result.get_bool()) {
code += len;
}
continue;
}
2021-03-23 23:29:32 +01:00
case BC_INST_BREAK | BC_INST_FLAG_FALSE:
2016-09-15 02:12:22 +02:00
if (cs.is_in_loop()) {
2021-03-24 02:21:27 +01:00
throw break_exception();
2016-09-15 02:12:22 +02:00
} else {
throw error{cs, "no loop to break"};
2016-09-15 02:12:22 +02:00
}
break;
2021-03-23 23:29:32 +01:00
case BC_INST_BREAK | BC_INST_FLAG_TRUE:
2016-09-15 02:12:22 +02:00
if (cs.is_in_loop()) {
2021-03-24 02:21:27 +01:00
throw continue_exception();
2016-09-15 02:12:22 +02:00
} else {
throw error{cs, "no loop to continue"};
2016-09-15 02:12:22 +02:00
}
break;
2016-08-12 18:38:43 +02:00
2021-03-28 17:11:35 +02:00
case BC_INST_BLOCK: {
std::uint32_t len = op >> 8;
args.emplace_back(cs).set_code(
reinterpret_cast<bcode *>(code + 1)
);
code += len;
continue;
}
2021-03-23 23:29:32 +01:00
case BC_INST_EMPTY | BC_RET_NULL:
args.emplace_back(cs).set_code(
bcode_get_empty(ts.istate->empty, VAL_NULL)
2016-08-17 04:57:53 +02:00
);
2016-08-12 18:38:43 +02:00
break;
2021-03-23 23:29:32 +01:00
case BC_INST_EMPTY | BC_RET_STRING:
args.emplace_back(cs).set_code(
bcode_get_empty(ts.istate->empty, VAL_STRING)
2016-08-17 04:57:53 +02:00
);
2016-08-12 18:38:43 +02:00
break;
2021-03-23 23:29:32 +01:00
case BC_INST_EMPTY | BC_RET_INT:
args.emplace_back(cs).set_code(
bcode_get_empty(ts.istate->empty, VAL_INT)
2016-08-17 04:57:53 +02:00
);
2016-08-12 18:38:43 +02:00
break;
2021-03-23 23:29:32 +01:00
case BC_INST_EMPTY | BC_RET_FLOAT:
args.emplace_back(cs).set_code(
bcode_get_empty(ts.istate->empty, VAL_FLOAT)
2016-08-17 04:57:53 +02:00
);
2016-08-12 18:38:43 +02:00
break;
2021-03-28 17:11:35 +02:00
2021-03-23 23:29:32 +01:00
case BC_INST_COMPILE: {
any_value &arg = args.back();
2021-03-26 02:29:54 +01:00
codegen_state gs{ts};
2016-08-17 04:57:53 +02:00
switch (arg.get_type()) {
2021-03-23 23:29:32 +01:00
case value_type::INT:
2016-08-17 04:57:53 +02:00
gs.code.reserve(8);
2021-03-23 23:29:32 +01:00
gs.code.push_back(BC_INST_START);
2016-08-30 22:55:35 +02:00
gs.gen_int(arg.get_int());
2021-03-23 23:29:32 +01:00
gs.code.push_back(BC_INST_RESULT);
gs.code.push_back(BC_INST_EXIT);
2016-08-17 04:57:53 +02:00
break;
2021-03-23 23:29:32 +01:00
case value_type::FLOAT:
2016-08-17 04:57:53 +02:00
gs.code.reserve(8);
2021-03-23 23:29:32 +01:00
gs.code.push_back(BC_INST_START);
2016-08-30 22:55:35 +02:00
gs.gen_float(arg.get_float());
2021-03-23 23:29:32 +01:00
gs.code.push_back(BC_INST_RESULT);
gs.code.push_back(BC_INST_EXIT);
2016-08-17 04:57:53 +02:00
break;
2021-03-23 23:29:32 +01:00
case value_type::STRING:
2016-08-17 04:57:53 +02:00
gs.code.reserve(64);
2021-03-17 21:57:47 +01:00
gs.gen_main(arg.get_str());
2016-08-17 04:57:53 +02:00
break;
default:
gs.code.reserve(8);
2021-03-23 23:29:32 +01:00
gs.code.push_back(BC_INST_START);
2016-08-17 04:57:53 +02:00
gs.gen_null();
2021-03-23 23:29:32 +01:00
gs.code.push_back(BC_INST_RESULT);
gs.code.push_back(BC_INST_EXIT);
2016-08-17 04:57:53 +02:00
break;
}
gs.done();
2021-03-25 01:52:03 +01:00
std::uint32_t *cbuf = bcode_alloc(ts.istate, gs.code.size());
std::memcpy(
cbuf, gs.code.data(),
gs.code.size() * sizeof(std::uint32_t)
);
2016-08-17 04:57:53 +02:00
arg.set_code(
2021-03-23 23:29:32 +01:00
reinterpret_cast<bcode *>(cbuf + 1)
2016-08-17 04:57:53 +02:00
);
continue;
}
2021-03-28 17:11:35 +02:00
2021-03-23 23:29:32 +01:00
case BC_INST_COND: {
any_value &arg = args.back();
2016-08-17 04:57:53 +02:00
switch (arg.get_type()) {
2021-03-23 23:29:32 +01:00
case value_type::STRING: {
std::string_view s = arg.get_str();
2016-08-30 22:55:35 +02:00
if (!s.empty()) {
2021-03-26 02:29:54 +01:00
codegen_state gs{ts};
2016-08-17 04:57:53 +02:00
gs.code.reserve(64);
2016-08-30 22:55:35 +02:00
gs.gen_main(s);
gs.done();
std::uint32_t *cbuf = bcode_alloc(
2021-03-25 01:52:03 +01:00
ts.istate, gs.code.size()
);
std::memcpy(
2017-01-25 01:18:29 +01:00
cbuf, gs.code.data(),
gs.code.size() * sizeof(std::uint32_t)
2017-01-25 01:18:29 +01:00
);
2021-03-23 23:29:32 +01:00
arg.set_code(reinterpret_cast<bcode *>(cbuf + 1));
2016-08-17 04:57:53 +02:00
} else {
2021-03-18 20:55:14 +01:00
arg.force_none();
2016-08-17 04:57:53 +02:00
}
break;
2016-08-30 22:55:35 +02:00
}
default:
break;
2016-08-17 04:57:53 +02:00
}
continue;
2016-08-12 18:38:43 +02:00
}
2021-03-28 00:19:51 +01:00
case BC_INST_IDENT: {
2021-03-23 23:29:32 +01:00
alias *a = static_cast<alias *>(
ts.istate->identmap[op >> 8]
);
2021-03-28 00:19:51 +01:00
if (
(a->get_flags() & IDENT_FLAG_ARG) &&
!ident_is_used_arg(a, ts)
) {
2021-03-23 23:29:32 +01:00
static_cast<alias_impl *>(a)->push_arg(
ts.idstack.emplace_back(*ts.pstate)
2016-08-18 03:53:51 +02:00
);
ts.callstack->usedargs[a->get_index()] = true;
2016-08-17 04:57:53 +02:00
}
args.emplace_back(cs).set_ident(a);
2016-08-17 04:57:53 +02:00
continue;
2016-08-12 18:38:43 +02:00
}
2021-03-23 23:29:32 +01:00
case BC_INST_IDENT_U: {
any_value &arg = args.back();
ident *id = ts.istate->identmap[ID_IDX_DUMMY];
2021-03-23 23:29:32 +01:00
if (arg.get_type() == value_type::STRING) {
2021-03-28 00:38:41 +01:00
id = cs.new_ident(arg.get_str(), IDENT_FLAG_UNKNOWN);
2016-08-17 04:57:53 +02:00
}
2021-03-26 02:29:54 +01:00
if (
(id->get_flags() & IDENT_FLAG_ARG) &&
2021-03-26 02:29:54 +01:00
!ident_is_used_arg(id, ts)
) {
2021-03-23 23:29:32 +01:00
static_cast<alias_impl *>(id)->push_arg(
ts.idstack.emplace_back(*ts.pstate)
2016-08-18 00:06:39 +02:00
);
ts.callstack->usedargs[id->get_index()] = true;
2016-08-17 04:57:53 +02:00
}
arg.set_ident(id);
continue;
2016-08-12 18:38:43 +02:00
}
2021-03-23 23:29:32 +01:00
case BC_INST_LOOKUP_U | BC_RET_STRING: {
ident *id = nullptr;
any_value &arg = args.back();
switch (get_lookupu_type(ts, arg, id, op)) {
case ID_ALIAS:
arg = static_cast<alias_impl *>(id)->p_astack->val_s;
arg.force_str();
2016-08-17 04:57:53 +02:00
continue;
case ID_SVAR:
2021-03-23 23:29:32 +01:00
arg.set_str(static_cast<string_var *>(id)->get_value());
2016-08-17 04:57:53 +02:00
continue;
case ID_IVAR:
2021-03-23 23:29:32 +01:00
arg.set_int(static_cast<integer_var *>(id)->get_value());
arg.force_str();
2016-08-17 04:57:53 +02:00
continue;
case ID_FVAR:
2021-03-23 23:29:32 +01:00
arg.set_float(static_cast<float_var *>(id)->get_value());
arg.force_str();
2016-08-17 04:57:53 +02:00
continue;
case ID_UNKNOWN:
2016-08-17 04:57:53 +02:00
arg.set_str("");
continue;
default:
continue;
}
}
case BC_INST_LOOKUP | BC_RET_STRING: {
2021-03-28 00:19:51 +01:00
alias *a = get_lookup_id(ts, op);
2016-08-18 00:18:36 +02:00
if (!a) {
args.emplace_back(cs).set_str("");
2016-08-17 04:57:53 +02:00
} else {
auto &v = args.emplace_back(cs);
v = static_cast<alias_impl *>(a)->p_astack->val_s;
v.force_str();
2016-08-17 04:57:53 +02:00
}
continue;
}
2021-03-23 23:29:32 +01:00
case BC_INST_LOOKUP_U | BC_RET_INT: {
ident *id = nullptr;
any_value &arg = args.back();
switch (get_lookupu_type(ts, arg, id, op)) {
case ID_ALIAS:
arg.set_int(static_cast<alias_impl *>(
id
)->p_astack->val_s.get_int());
2016-08-17 04:57:53 +02:00
continue;
case ID_SVAR:
2021-03-23 01:45:35 +01:00
arg.set_int(parse_int(
2021-03-23 23:29:32 +01:00
static_cast<string_var *>(id)->get_value()
));
2016-08-17 04:57:53 +02:00
continue;
case ID_IVAR:
2021-03-23 23:29:32 +01:00
arg.set_int(static_cast<integer_var *>(id)->get_value());
2016-08-17 04:57:53 +02:00
continue;
case ID_FVAR:
2016-08-18 04:14:55 +02:00
arg.set_int(
2021-03-23 23:29:32 +01:00
integer_type(static_cast<float_var *>(id)->get_value())
2016-08-18 04:14:55 +02:00
);
2016-08-17 04:57:53 +02:00
continue;
case ID_UNKNOWN:
2016-08-17 04:57:53 +02:00
arg.set_int(0);
continue;
default:
continue;
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
}
2021-03-28 00:19:51 +01:00
case BC_INST_LOOKUP | BC_RET_INT: {
alias *a = get_lookup_id(ts, op);
2016-08-18 00:18:36 +02:00
if (!a) {
args.emplace_back(cs).set_int(0);
2016-08-17 04:57:53 +02:00
} else {
args.emplace_back(cs).set_int(
static_cast<alias_impl *>(a)->p_astack->val_s.get_int()
);
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
continue;
}
2021-03-23 23:29:32 +01:00
case BC_INST_LOOKUP_U | BC_RET_FLOAT: {
ident *id = nullptr;
any_value &arg = args.back();
switch (get_lookupu_type(ts, arg, id, op)) {
case ID_ALIAS:
arg.set_float(static_cast<alias_impl *>(
id
)->p_astack->val_s.get_float());
2016-08-17 04:57:53 +02:00
continue;
case ID_SVAR:
2021-03-23 01:45:35 +01:00
arg.set_float(parse_float(
2021-03-23 23:29:32 +01:00
static_cast<string_var *>(id)->get_value()
));
2016-08-17 04:57:53 +02:00
continue;
case ID_IVAR:
2021-03-23 23:29:32 +01:00
arg.set_float(float_type(
static_cast<integer_var *>(id)->get_value()
));
2016-08-17 04:57:53 +02:00
continue;
case ID_FVAR:
2016-08-18 04:14:55 +02:00
arg.set_float(
2021-03-23 23:29:32 +01:00
static_cast<float_var *>(id)->get_value()
2016-08-18 04:14:55 +02:00
);
2016-08-17 04:57:53 +02:00
continue;
case ID_UNKNOWN:
2021-03-23 23:29:32 +01:00
arg.set_float(float_type(0));
2016-08-17 04:57:53 +02:00
continue;
default:
continue;
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
}
2021-03-28 00:19:51 +01:00
case BC_INST_LOOKUP | BC_RET_FLOAT: {
alias *a = get_lookup_id(ts, op);
2016-08-18 00:18:36 +02:00
if (!a) {
args.emplace_back(cs).set_float(float_type(0));
2016-08-17 04:57:53 +02:00
} else {
args.emplace_back(cs).set_float(static_cast<alias_impl *>(
a
)->p_astack->val_s.get_float());
2016-08-17 04:57:53 +02:00
}
continue;
}
2021-03-23 23:29:32 +01:00
case BC_INST_LOOKUP_U | BC_RET_NULL: {
ident *id = nullptr;
any_value &arg = args.back();
switch (get_lookupu_type(ts, arg, id, op)) {
case ID_ALIAS:
static_cast<alias_impl *>(
id
)->p_astack->val_s.get_val(arg);
2016-08-17 04:57:53 +02:00
continue;
case ID_SVAR:
2021-03-23 23:29:32 +01:00
arg.set_str(static_cast<string_var *>(id)->get_value());
2016-08-17 04:57:53 +02:00
continue;
case ID_IVAR:
2021-03-23 23:29:32 +01:00
arg.set_int(static_cast<integer_var *>(id)->get_value());
2016-08-17 04:57:53 +02:00
continue;
case ID_FVAR:
2016-08-18 04:14:55 +02:00
arg.set_float(
2021-03-23 23:29:32 +01:00
static_cast<float_var *>(id)->get_value()
2016-08-18 04:14:55 +02:00
);
2016-08-17 04:57:53 +02:00
continue;
case ID_UNKNOWN:
2021-03-18 20:55:14 +01:00
arg.set_none();
2016-08-17 04:57:53 +02:00
continue;
default:
continue;
}
}
2021-03-28 00:19:51 +01:00
case BC_INST_LOOKUP | BC_RET_NULL: {
alias *a = get_lookup_id(ts, op);
2016-08-18 00:18:36 +02:00
if (!a) {
args.emplace_back(cs).set_none();
2016-08-17 04:57:53 +02:00
} else {
static_cast<alias_impl *>(a)->p_astack->val_s.get_val(
args.emplace_back(cs)
);
2016-08-17 04:57:53 +02:00
}
continue;
2016-08-12 18:38:43 +02:00
}
2021-03-28 17:11:35 +02:00
case BC_INST_CONC | BC_RET_NULL:
case BC_INST_CONC | BC_RET_STRING:
case BC_INST_CONC | BC_RET_FLOAT:
case BC_INST_CONC | BC_RET_INT:
case BC_INST_CONC_W | BC_RET_NULL:
case BC_INST_CONC_W | BC_RET_STRING:
case BC_INST_CONC_W | BC_RET_FLOAT:
case BC_INST_CONC_W | BC_RET_INT: {
std::size_t numconc = op >> 8;
auto buf = concat_values(
cs, std::span{&args[args.size() - numconc], numconc},
((op & BC_INST_OP_MASK) == BC_INST_CONC) ? " " : ""
);
args.resize(args.size() - numconc, any_value{cs});
2021-03-28 22:49:46 +02:00
args.emplace_back(cs).set_str(buf);
force_arg(args.back(), op & BC_INST_RET_MASK);
2021-03-28 17:11:35 +02:00
continue;
}
2021-03-23 23:29:32 +01:00
case BC_INST_SVAR | BC_RET_STRING:
case BC_INST_SVAR | BC_RET_NULL:
args.emplace_back(cs).set_str(static_cast<string_var *>(
ts.istate->identmap[op >> 8]
)->get_value());
2016-08-17 04:57:53 +02:00
continue;
2021-03-23 23:29:32 +01:00
case BC_INST_SVAR | BC_RET_INT:
args.emplace_back(cs).set_int(parse_int(
static_cast<string_var *>(
ts.istate->identmap[op >> 8]
)->get_value()
));
2016-08-17 04:57:53 +02:00
continue;
2021-03-23 23:29:32 +01:00
case BC_INST_SVAR | BC_RET_FLOAT:
args.emplace_back(cs).set_float(parse_float(
static_cast<string_var *>(
ts.istate->identmap[op >> 8]
)->get_value()
));
2016-08-17 04:57:53 +02:00
continue;
case BC_INST_SVAR1: {
auto v = std::move(args.back());
args.pop_back();
2016-08-17 23:29:31 +02:00
cs.set_var_str_checked(
static_cast<string_var *>(ts.istate->identmap[op >> 8]),
v.get_str()
2016-08-17 23:29:31 +02:00
);
2016-08-17 04:57:53 +02:00
continue;
}
2016-08-12 18:38:43 +02:00
2021-03-23 23:29:32 +01:00
case BC_INST_IVAR | BC_RET_INT:
case BC_INST_IVAR | BC_RET_NULL:
args.emplace_back(cs).set_int(static_cast<integer_var *>(
ts.istate->identmap[op >> 8]
)->get_value());
2016-08-17 04:57:53 +02:00
continue;
case BC_INST_IVAR | BC_RET_STRING: {
auto &v = args.emplace_back(cs);
v.set_int(static_cast<integer_var *>(
ts.istate->identmap[op >> 8]
)->get_value());
v.force_str();
2016-08-17 04:57:53 +02:00
continue;
}
2021-03-23 23:29:32 +01:00
case BC_INST_IVAR | BC_RET_FLOAT:
args.emplace_back(cs).set_float(float_type(
static_cast<integer_var *>(
ts.istate->identmap[op >> 8]
)->get_value()
));
2016-08-17 04:57:53 +02:00
continue;
case BC_INST_IVAR1: {
auto v = std::move(args.back());
args.pop_back();
2016-08-17 23:29:31 +02:00
cs.set_var_int_checked(
static_cast<integer_var *>(ts.istate->identmap[op >> 8]),
v.get_int()
2016-08-17 23:29:31 +02:00
);
2016-08-17 04:57:53 +02:00
continue;
}
case BC_INST_IVAR2: {
auto v1 = std::move(args.back()); args.pop_back();
auto v2 = std::move(args.back()); args.pop_back();
2016-08-17 04:57:53 +02:00
cs.set_var_int_checked(
static_cast<integer_var *>(ts.istate->identmap[op >> 8]),
(v2.get_int() << 16) | (v1.get_int() << 8)
2016-08-30 22:55:35 +02:00
);
2016-08-17 04:57:53 +02:00
continue;
}
case BC_INST_IVAR3: {
auto v1 = std::move(args.back()); args.pop_back();
auto v2 = std::move(args.back()); args.pop_back();
auto v3 = std::move(args.back()); args.pop_back();
2016-08-17 04:57:53 +02:00
cs.set_var_int_checked(
static_cast<integer_var *>(ts.istate->identmap[op >> 8]),
(v3.get_int() << 16) | (v2.get_int() << 8) | (v1.get_int())
);
2016-08-17 04:57:53 +02:00
continue;
}
2016-08-12 18:38:43 +02:00
2021-03-23 23:29:32 +01:00
case BC_INST_FVAR | BC_RET_FLOAT:
case BC_INST_FVAR | BC_RET_NULL:
args.emplace_back(cs).set_float(static_cast<float_var *>(
ts.istate->identmap[op >> 8]
)->get_value());
2016-08-17 04:57:53 +02:00
continue;
case BC_INST_FVAR | BC_RET_STRING: {
auto &v = args.emplace_back(cs);
2021-03-31 02:21:32 +02:00
v.set_int(integer_type(std::floor(static_cast<float_var *>(
ts.istate->identmap[op >> 8]
2021-03-31 02:21:32 +02:00
)->get_value())));
v.force_str();
2016-08-17 04:57:53 +02:00
continue;
}
2021-03-23 23:29:32 +01:00
case BC_INST_FVAR | BC_RET_INT:
args.emplace_back(cs).set_int(int(static_cast<float_var *>(
ts.istate->identmap[op >> 8]
)->get_value()));
2016-08-17 04:57:53 +02:00
continue;
case BC_INST_FVAR1: {
auto &v = args.back();
2016-08-17 23:29:31 +02:00
cs.set_var_float_checked(
static_cast<float_var *>(ts.istate->identmap[op >> 8]),
v.get_float()
2016-08-17 23:29:31 +02:00
);
args.pop_back();
2016-08-17 04:57:53 +02:00
continue;
}
2016-08-17 04:57:53 +02:00
2021-03-28 00:19:51 +01:00
case BC_INST_ALIAS: {
auto *imp = static_cast<alias_impl *>(
ts.istate->identmap[op >> 8]
2021-03-28 00:19:51 +01:00
);
if (imp->get_flags() & IDENT_FLAG_ARG) {
imp->set_arg(ts, args.back());
} else {
imp->set_alias(ts, args.back());
}
args.pop_back();
2016-08-17 04:57:53 +02:00
continue;
2021-03-28 00:19:51 +01:00
}
case BC_INST_ALIAS_U: {
auto v = std::move(args.back());
args.pop_back();
cs.set_alias(args.back().get_str(), std::move(v));
args.pop_back();
2016-08-17 04:57:53 +02:00
continue;
}
2016-08-17 04:57:53 +02:00
2021-03-23 23:29:32 +01:00
case BC_INST_CALL | BC_RET_NULL:
case BC_INST_CALL | BC_RET_STRING:
case BC_INST_CALL | BC_RET_FLOAT:
case BC_INST_CALL | BC_RET_INT: {
2021-03-18 20:55:14 +01:00
result.force_none();
ident *id = ts.istate->identmap[op >> 8];
std::size_t callargs = *code++;
std::size_t nnargs = args.size();
std::size_t offset = nnargs - callargs;
2021-03-28 00:19:51 +01:00
auto flags = id->get_flags();
if (flags & IDENT_FLAG_ARG) {
if (!ident_is_used_arg(id, ts)) {
args.resize(offset, any_value{cs});
force_arg(result, op & BC_INST_RET_MASK);
continue;
}
} else if (flags & IDENT_FLAG_UNKNOWN) {
2021-03-23 23:29:32 +01:00
force_arg(result, op & BC_INST_RET_MASK);
throw error{
2021-03-20 08:22:15 +01:00
cs, "unknown command: %s", id->get_name().data()
};
2016-08-17 04:57:53 +02:00
}
exec_alias(
ts, static_cast<alias *>(id), &args[0], result, callargs,
nnargs, offset, 0, op
2016-08-17 04:57:53 +02:00
);
args.resize(nnargs, any_value{cs});
2016-08-12 18:38:43 +02:00
continue;
}
2016-08-17 04:57:53 +02:00
2021-03-23 23:29:32 +01:00
case BC_INST_CALL_U | BC_RET_NULL:
case BC_INST_CALL_U | BC_RET_STRING:
case BC_INST_CALL_U | BC_RET_FLOAT:
case BC_INST_CALL_U | BC_RET_INT: {
std::size_t callargs = op >> 8;
std::size_t nnargs = args.size();
std::size_t offset = nnargs - callargs;
2021-03-23 23:29:32 +01:00
any_value &idarg = args[offset - 1];
if (idarg.get_type() != value_type::STRING) {
2016-08-17 04:57:53 +02:00
litval:
2017-01-25 01:57:33 +01:00
result = std::move(idarg);
2021-03-23 23:29:32 +01:00
force_arg(result, op & BC_INST_RET_MASK);
args.resize(offset - 1, any_value{cs});
2016-08-17 04:57:53 +02:00
continue;
}
2021-03-17 21:57:47 +01:00
auto idn = idarg.get_str();
2021-03-23 23:29:32 +01:00
ident *id = cs.get_ident(idn);
2016-08-17 04:57:53 +02:00
if (!id) {
noid:
if (!is_valid_name(idn)) {
2016-08-17 04:57:53 +02:00
goto litval;
}
2021-03-18 20:55:14 +01:00
result.force_none();
2021-03-23 23:29:32 +01:00
force_arg(result, op & BC_INST_RET_MASK);
2021-03-20 08:22:15 +01:00
std::string_view ids{idn};
throw error{
2021-03-20 08:22:15 +01:00
cs, "unknown command: %s", ids.data()
};
2016-08-17 04:57:53 +02:00
}
2021-03-18 20:55:14 +01:00
result.force_none();
2021-03-21 02:41:04 +01:00
switch (id->get_raw_type()) {
2016-08-17 04:57:53 +02:00
default:
if (!ident_is_callable(id)) {
args.resize(offset - 1, any_value{cs});
2021-03-23 23:29:32 +01:00
force_arg(result, op & BC_INST_RET_MASK);
2016-08-17 04:57:53 +02:00
continue;
}
/* fallthrough */
case ID_COMMAND:
exec_command(
ts, static_cast<command_impl *>(id),
2021-03-21 02:41:04 +01:00
&args[offset], result, callargs
2016-08-17 23:04:43 +02:00
);
2021-03-23 23:29:32 +01:00
force_arg(result, op & BC_INST_RET_MASK);
args.resize(offset - 1, any_value{cs});
2016-08-17 04:57:53 +02:00
continue;
case ID_LOCAL: {
std::size_t idstsz = ts.idstack.size();
2017-01-25 02:09:50 +01:00
for (size_t j = 0; j < size_t(callargs); ++j) {
push_alias(
args[offset + j].force_ident(cs),
ts.idstack.emplace_back(*ts.pstate)
);
2016-08-17 04:57:53 +02:00
}
2021-03-30 23:49:50 +02:00
auto cleanup = [&]() {
2017-01-25 02:09:50 +01:00
for (size_t j = 0; j < size_t(callargs); ++j) {
2021-03-23 23:29:32 +01:00
pop_alias(args[offset + j].get_ident());
}
ts.idstack.resize(idstsz, ident_stack{*ts.pstate});
2021-03-30 23:49:50 +02:00
};
try {
code = vm_exec(ts, code, result);
} catch (...) {
cleanup();
throw;
}
cleanup();
2016-09-23 21:06:44 +02:00
return code;
2016-08-17 04:57:53 +02:00
}
case ID_IVAR:
2016-08-17 04:57:53 +02:00
if (callargs <= 0) {
2021-03-23 23:29:32 +01:00
cs.print_var(*static_cast<global_var *>(id));
2016-08-17 04:57:53 +02:00
} else {
cs.set_var_int_checked(
2021-03-23 23:29:32 +01:00
static_cast<integer_var *>(id),
2021-03-20 05:41:25 +01:00
std::span{&args[offset], std::size_t(callargs)}
2016-08-17 04:57:53 +02:00
);
}
args.resize(offset - 1, any_value{cs});
2021-03-23 23:29:32 +01:00
force_arg(result, op & BC_INST_RET_MASK);
2016-08-17 04:57:53 +02:00
continue;
case ID_FVAR:
2016-08-17 04:57:53 +02:00
if (callargs <= 0) {
2021-03-23 23:29:32 +01:00
cs.print_var(*static_cast<global_var *>(id));
2016-08-17 04:57:53 +02:00
} else {
cs.set_var_float_checked(
2021-03-23 23:29:32 +01:00
static_cast<float_var *>(id),
2016-08-17 23:29:31 +02:00
args[offset].force_float()
2016-08-17 04:57:53 +02:00
);
}
args.resize(offset - 1, any_value{cs});
2021-03-23 23:29:32 +01:00
force_arg(result, op & BC_INST_RET_MASK);
2016-08-17 04:57:53 +02:00
continue;
case ID_SVAR:
2016-08-17 04:57:53 +02:00
if (callargs <= 0) {
2021-03-23 23:29:32 +01:00
cs.print_var(*static_cast<global_var *>(id));
2016-08-17 04:57:53 +02:00
} else {
2016-08-17 23:29:31 +02:00
cs.set_var_str_checked(
2021-03-23 23:29:32 +01:00
static_cast<string_var *>(id),
2016-08-17 23:29:31 +02:00
args[offset].force_str()
);
2016-08-17 04:57:53 +02:00
}
args.resize(offset - 1, any_value{cs});
2021-03-23 23:29:32 +01:00
force_arg(result, op & BC_INST_RET_MASK);
2016-08-17 04:57:53 +02:00
continue;
case ID_ALIAS: {
2021-03-23 23:29:32 +01:00
alias *a = static_cast<alias *>(id);
2016-08-17 04:57:53 +02:00
if (
(a->get_flags() & IDENT_FLAG_ARG) &&
2021-03-26 02:29:54 +01:00
!ident_is_used_arg(a, ts)
2016-08-17 04:57:53 +02:00
) {
args.resize(offset - 1, any_value{cs});
2021-03-23 23:29:32 +01:00
force_arg(result, op & BC_INST_RET_MASK);
2016-08-17 04:57:53 +02:00
continue;
}
if (static_cast<alias_impl *>(
a
)->p_astack->val_s.get_type() == value_type::NONE) {
2016-08-17 04:57:53 +02:00
goto noid;
}
exec_alias(
ts, a, &args[0], result, callargs, nnargs,
2016-08-17 04:57:53 +02:00
offset, 1, op
);
args.resize(nnargs, any_value{cs});
2016-08-17 04:57:53 +02:00
continue;
2016-08-18 00:06:39 +02:00
}
2016-08-17 04:57:53 +02:00
}
}
2021-03-28 17:11:35 +02:00
case BC_INST_COM | BC_RET_NULL:
case BC_INST_COM | BC_RET_STRING:
case BC_INST_COM | BC_RET_FLOAT:
case BC_INST_COM | BC_RET_INT: {
command_impl *id = static_cast<command_impl *>(
ts.istate->identmap[op >> 8]
);
std::size_t offset = args.size() - id->get_num_args();
result.force_none();
id->call(cs, std::span<any_value>{
&args[offset], std::size_t(id->get_num_args())
}, result);
force_arg(result, op & BC_INST_RET_MASK);
args.resize(offset, any_value{cs});
continue;
}
case BC_INST_COM_V | BC_RET_NULL:
case BC_INST_COM_V | BC_RET_STRING:
case BC_INST_COM_V | BC_RET_FLOAT:
case BC_INST_COM_V | BC_RET_INT: {
command_impl *id = static_cast<command_impl *>(
ts.istate->identmap[op >> 8]
2021-03-28 17:11:35 +02:00
);
std::size_t callargs = *code++;
2021-03-28 17:11:35 +02:00
std::size_t offset = args.size() - callargs;
result.force_none();
id->call(cs, std::span{&args[offset], callargs}, result);
force_arg(result, op & BC_INST_RET_MASK);
args.resize(offset, any_value{cs});
continue;
}
case BC_INST_COM_C | BC_RET_NULL:
case BC_INST_COM_C | BC_RET_STRING:
case BC_INST_COM_C | BC_RET_FLOAT:
case BC_INST_COM_C | BC_RET_INT: {
command_impl *id = static_cast<command_impl *>(
ts.istate->identmap[op >> 8]
2021-03-28 17:11:35 +02:00
);
std::size_t callargs = *code++;
std::size_t offset = args.size() - callargs;
2021-03-28 17:11:35 +02:00
result.force_none();
{
any_value tv{cs};
tv.set_str(concat_values(cs, std::span{
&args[offset], callargs
}, " "));
id->call(cs, std::span<any_value>{&tv, 1}, result);
}
force_arg(result, op & BC_INST_RET_MASK);
args.resize(offset, any_value{cs});
continue;
}
2016-08-12 18:38:43 +02:00
}
}
return code;
}
2021-03-23 23:32:25 +01:00
} /* namespace cubescript */