2017-06-20 19:21:39 +00:00
|
|
|
#include <cubescript/cubescript.hh>
|
2016-08-12 16:38:43 +00:00
|
|
|
#include "cs_vm.hh"
|
2021-03-23 00:45:35 +00:00
|
|
|
#include "cs_std.hh"
|
2021-03-23 21:17:25 +00:00
|
|
|
#include "cs_parser.hh"
|
2021-05-08 15:20:56 +00:00
|
|
|
#include "cs_error.hh"
|
2016-08-12 16:38:43 +00:00
|
|
|
|
2021-03-20 05:52:10 +00:00
|
|
|
#include <cstdio>
|
2021-03-31 00:21:32 +00:00
|
|
|
#include <cmath>
|
2017-02-09 19:59:14 +00:00
|
|
|
#include <limits>
|
2016-08-12 23:26:16 +00:00
|
|
|
|
2021-03-23 22:32:25 +00:00
|
|
|
namespace cubescript {
|
2016-08-12 16:38:43 +00:00
|
|
|
|
2021-04-24 21:33:19 +00:00
|
|
|
static inline void push_alias(thread_state &ts, ident &id, ident_stack &st) {
|
2021-05-05 01:24:41 +00:00
|
|
|
if (id.type() != ident_type::ALIAS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!static_cast<alias &>(id).is_arg()) {
|
2021-04-24 21:33:19 +00:00
|
|
|
auto *aimp = static_cast<alias_impl *>(&id);
|
2021-04-03 23:08:30 +00:00
|
|
|
auto ast = ts.get_astack(aimp);
|
|
|
|
ast.push(st);
|
|
|
|
ast.flags &= ~IDENT_FLAG_UNKNOWN;
|
2016-08-17 22:06:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-24 21:33:19 +00:00
|
|
|
static inline void pop_alias(thread_state &ts, ident &id) {
|
2021-05-05 01:24:41 +00:00
|
|
|
if (id.type() != ident_type::ALIAS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!static_cast<alias &>(id).is_arg()) {
|
2021-04-24 21:33:19 +00:00
|
|
|
ts.get_astack(static_cast<alias *>(&id)).pop();
|
2016-08-17 22:06:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-26 23:26:59 +00:00
|
|
|
void exec_command(
|
2021-04-03 01:14:52 +00:00
|
|
|
thread_state &ts, command_impl *id, ident *self, any_value *args,
|
|
|
|
any_value &res, std::size_t nargs, bool lookup
|
2016-08-17 02:57:53 +00:00
|
|
|
) {
|
2021-03-24 21:37:53 +00:00
|
|
|
int i = -1, fakeargs = 0, numargs = int(nargs);
|
2016-08-12 16:38:43 +00:00
|
|
|
bool rep = false;
|
2021-05-05 01:16:32 +00:00
|
|
|
auto fmt = id->args();
|
2021-05-13 02:48:55 +00:00
|
|
|
auto set_fake = [](
|
|
|
|
int &idx, int &fargs, bool r, int argn, any_value *argp
|
|
|
|
) {
|
|
|
|
if (++idx >= argn) {
|
|
|
|
if (r) {
|
2021-04-28 23:24:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
2021-05-13 02:48:55 +00:00
|
|
|
argp[idx].set_none();
|
|
|
|
++fargs;
|
2021-04-28 23:24:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
2021-03-20 01:26:37 +00:00
|
|
|
for (auto it = fmt.begin(); it != fmt.end(); ++it) {
|
|
|
|
switch (*it) {
|
2016-08-17 02:57:53 +00:00
|
|
|
case 'i':
|
2021-05-13 02:48:55 +00:00
|
|
|
if (set_fake(i, fakeargs, rep, numargs, args)) {
|
2021-04-05 22:54:46 +00:00
|
|
|
args[i].force_integer();
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'f':
|
2021-05-13 02:48:55 +00:00
|
|
|
if (set_fake(i, fakeargs, rep, numargs, args)) {
|
2016-08-17 02:57:53 +00:00
|
|
|
args[i].force_float();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 's':
|
2021-05-13 02:48:55 +00:00
|
|
|
if (set_fake(i, fakeargs, rep, numargs, args)) {
|
2021-04-11 01:32:14 +00:00
|
|
|
args[i].force_string(*ts.pstate);
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
|
|
|
break;
|
2021-04-28 23:24:05 +00:00
|
|
|
case 'a':
|
2021-05-13 02:48:55 +00:00
|
|
|
set_fake(i, fakeargs, rep, numargs, args);
|
2016-08-17 02:57:53 +00:00
|
|
|
break;
|
2021-04-28 23:24:05 +00:00
|
|
|
case 'c':
|
2021-05-13 02:48:55 +00:00
|
|
|
if (set_fake(i, fakeargs, rep, numargs, args)) {
|
2021-05-05 01:16:32 +00:00
|
|
|
if (args[i].type() == value_type::STRING) {
|
2021-04-28 23:24:05 +00:00
|
|
|
auto str = args[i].get_string(*ts.pstate);
|
|
|
|
if (str.empty()) {
|
|
|
|
args[i].set_integer(0);
|
|
|
|
} else {
|
|
|
|
args[i].force_code(*ts.pstate);
|
|
|
|
}
|
2021-03-24 20:01:01 +00:00
|
|
|
}
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
|
|
|
break;
|
2021-04-28 23:24:05 +00:00
|
|
|
case 'b':
|
2021-05-13 02:48:55 +00:00
|
|
|
if (set_fake(i, fakeargs, rep, numargs, args)) {
|
2021-03-25 00:37:13 +00:00
|
|
|
args[i].force_code(*ts.pstate);
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
|
|
|
break;
|
2021-04-29 18:02:04 +00:00
|
|
|
case 'v':
|
2021-05-13 02:48:55 +00:00
|
|
|
if (set_fake(i, fakeargs, rep, numargs, args)) {
|
2021-03-25 00:37:13 +00:00
|
|
|
args[i].force_ident(*ts.pstate);
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '$':
|
2016-09-06 18:48:24 +00:00
|
|
|
i += 1;
|
2021-04-24 21:50:06 +00:00
|
|
|
args[i].set_ident(*self);
|
2016-08-17 02:57:53 +00:00
|
|
|
break;
|
2021-04-29 02:15:16 +00:00
|
|
|
case '#':
|
2016-09-06 18:48:24 +00:00
|
|
|
i += 1;
|
2021-04-05 22:54:46 +00:00
|
|
|
args[i].set_integer(integer_type(lookup ? -1 : i - fakeargs));
|
2016-08-17 02:57:53 +00:00
|
|
|
break;
|
2021-04-29 17:56:48 +00:00
|
|
|
case '.':
|
2017-02-18 16:49:01 +00:00
|
|
|
i = std::max(i + 1, numargs);
|
2021-05-02 20:44:38 +00:00
|
|
|
id->call(ts, span_type<any_value>{args, std::size_t(i)}, res);
|
2016-09-06 21:54:28 +00:00
|
|
|
return;
|
2016-08-17 02:57:53 +00:00
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
if (i + 1 < numargs) {
|
2021-03-20 01:26:37 +00:00
|
|
|
it -= *it - '0' + 1;
|
2016-08-17 02:57:53 +00:00
|
|
|
rep = true;
|
|
|
|
}
|
|
|
|
break;
|
2016-08-12 16:38:43 +00:00
|
|
|
}
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
2016-08-12 16:38:43 +00:00
|
|
|
++i;
|
2021-05-02 20:44:38 +00:00
|
|
|
id->call(ts, span_type<any_value>{args, std::size_t(i)}, res);
|
2021-04-05 22:54:46 +00:00
|
|
|
res.force_plain();
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
|
|
|
|
2021-05-14 21:31:27 +00:00
|
|
|
any_value exec_alias(
|
|
|
|
thread_state &ts, alias *a, any_value *args,
|
|
|
|
std::size_t callargs, alias_stack &astack
|
2016-08-17 02:57:53 +00:00
|
|
|
) {
|
2021-03-30 00:08:25 +00:00
|
|
|
/* excess arguments get ignored (make error maybe?) */
|
2021-05-14 21:31:27 +00:00
|
|
|
any_value ret;
|
2021-03-30 00:08:25 +00:00
|
|
|
callargs = std::min(callargs, MAX_ARGUMENTS);
|
2021-05-06 21:13:48 +00:00
|
|
|
builtin_var *anargs = ts.istate->ivar_numargs;
|
2021-03-28 21:46:08 +00:00
|
|
|
argset uargs{};
|
2021-03-29 22:28:06 +00:00
|
|
|
std::size_t noff = ts.idstack.size();
|
2021-03-24 21:37:53 +00:00
|
|
|
for(std::size_t i = 0; i < callargs; i++) {
|
2021-04-02 03:47:49 +00:00
|
|
|
auto &ast = ts.get_astack(
|
2022-04-20 02:31:24 +00:00
|
|
|
static_cast<alias *>(ts.istate->lookup_ident(i))
|
2021-04-02 03:47:49 +00:00
|
|
|
);
|
2021-04-11 01:32:14 +00:00
|
|
|
auto &st = ts.idstack.emplace_back();
|
2021-04-02 21:50:35 +00:00
|
|
|
ast.push(st);
|
2021-05-14 21:31:27 +00:00
|
|
|
st.val_s = std::move(args[i]);
|
2021-03-28 21:46:08 +00:00
|
|
|
uargs[i] = true;
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
2021-05-06 02:01:29 +00:00
|
|
|
auto oldargs = anargs->value();
|
2021-04-03 23:08:30 +00:00
|
|
|
auto oldflags = ts.ident_flags;
|
2021-05-14 20:42:19 +00:00
|
|
|
ts.ident_flags = astack.flags;
|
2021-05-06 02:01:29 +00:00
|
|
|
any_value cv;
|
2021-05-09 23:16:27 +00:00
|
|
|
cv.set_integer(integer_type(callargs));
|
2021-05-06 02:01:29 +00:00
|
|
|
anargs->set_raw_value(*ts.pstate, std::move(cv));
|
2021-05-14 21:31:27 +00:00
|
|
|
auto &lev = ts.callstack.emplace_back(*a);
|
|
|
|
lev.usedargs = std::move(uargs);
|
2021-05-14 20:42:19 +00:00
|
|
|
if (!astack.node->code) {
|
2021-05-14 21:14:48 +00:00
|
|
|
try {
|
|
|
|
gen_state gs{ts};
|
|
|
|
gs.gen_main(astack.node->val_s.get_string(*ts.pstate));
|
|
|
|
astack.node->code = gs.steal_ref();
|
|
|
|
} catch (...) {
|
|
|
|
ts.callstack.pop_back();
|
|
|
|
throw;
|
|
|
|
}
|
2021-04-02 03:47:49 +00:00
|
|
|
}
|
2021-05-14 20:42:19 +00:00
|
|
|
bcode_ref coderef = astack.node->code;
|
2021-05-13 02:48:55 +00:00
|
|
|
auto cleanup = [](
|
2021-05-14 21:14:48 +00:00
|
|
|
auto &tss, std::size_t cargs, std::size_t nids, auto oflags
|
2021-05-13 02:48:55 +00:00
|
|
|
) {
|
2021-05-14 21:14:48 +00:00
|
|
|
auto amask = tss.callstack.back().usedargs;
|
|
|
|
tss.callstack.pop_back();
|
2021-05-13 02:48:55 +00:00
|
|
|
tss.ident_flags = oflags;
|
|
|
|
for (std::size_t i = 0; i < cargs; i++) {
|
|
|
|
tss.get_astack(
|
2022-04-20 02:31:24 +00:00
|
|
|
static_cast<alias *>(tss.istate->lookup_ident(i))
|
2021-04-02 21:50:35 +00:00
|
|
|
).pop();
|
2021-03-28 21:46:08 +00:00
|
|
|
amask[i] = false;
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
2021-05-13 02:48:55 +00:00
|
|
|
for (; amask.any(); ++cargs) {
|
|
|
|
if (amask[cargs]) {
|
|
|
|
tss.get_astack(
|
2022-04-20 02:31:24 +00:00
|
|
|
static_cast<alias *>(tss.istate->lookup_ident(cargs))
|
2021-04-02 21:50:35 +00:00
|
|
|
).pop();
|
2021-05-13 02:48:55 +00:00
|
|
|
amask[cargs] = false;
|
2016-09-08 21:42:14 +00:00
|
|
|
}
|
|
|
|
}
|
2021-05-13 02:48:55 +00:00
|
|
|
tss.idstack.resize(nids);
|
2021-03-30 21:49:50 +00:00
|
|
|
};
|
|
|
|
try {
|
2021-05-14 21:31:27 +00:00
|
|
|
vm_exec(ts, bcode_p{coderef}.get()->raw(), ret);
|
2021-03-30 21:49:50 +00:00
|
|
|
} catch (...) {
|
2021-05-14 21:14:48 +00:00
|
|
|
cleanup(ts, callargs, noff, oldflags);
|
2021-05-13 02:48:55 +00:00
|
|
|
anargs->set_raw_value(*ts.pstate, std::move(oldargs));
|
2021-03-30 21:49:50 +00:00
|
|
|
throw;
|
|
|
|
}
|
2021-05-14 21:14:48 +00:00
|
|
|
cleanup(ts, callargs, noff, oldflags);
|
2021-05-13 02:48:55 +00:00
|
|
|
anargs->set_raw_value(*ts.pstate, std::move(oldargs));
|
2021-05-14 21:31:27 +00:00
|
|
|
return ret;
|
2016-08-12 16:38:43 +00:00
|
|
|
}
|
|
|
|
|
2021-05-14 00:54:29 +00:00
|
|
|
any_value exec_code_with_args(thread_state &ts, bcode_ref const &body) {
|
2021-05-14 21:14:48 +00:00
|
|
|
if (ts.callstack.empty()) {
|
2021-05-14 00:54:29 +00:00
|
|
|
return body.call(*ts.pstate);
|
|
|
|
}
|
2021-05-14 21:14:48 +00:00
|
|
|
auto mask = ts.callstack.back().usedargs;
|
2021-05-14 00:54:29 +00:00
|
|
|
std::size_t noff = ts.idstack.size();
|
|
|
|
for (std::size_t i = 0; mask.any(); ++i) {
|
|
|
|
if (mask[0]) {
|
|
|
|
auto &ast = ts.get_astack(
|
2022-04-20 02:31:24 +00:00
|
|
|
static_cast<alias *>(ts.istate->lookup_ident(i))
|
2021-05-14 00:54:29 +00:00
|
|
|
);
|
|
|
|
auto &st = ts.idstack.emplace_back();
|
|
|
|
st.next = ast.node;
|
|
|
|
ast.node = ast.node->next;
|
|
|
|
}
|
|
|
|
mask >>= 1;
|
|
|
|
}
|
2021-05-14 21:14:48 +00:00
|
|
|
ident_level *prevstack = nullptr;
|
|
|
|
if (ts.callstack.size() >= 2) {
|
|
|
|
prevstack = &ts.callstack[ts.callstack.size() - 2];
|
|
|
|
}
|
|
|
|
auto &lev = ts.callstack.emplace_back(ts.callstack.back().id);
|
2021-05-14 00:54:29 +00:00
|
|
|
if (!prevstack) {
|
2021-05-14 21:14:48 +00:00
|
|
|
lev.usedargs.set();
|
|
|
|
} else {
|
|
|
|
lev.usedargs = prevstack->usedargs;
|
2021-05-14 00:54:29 +00:00
|
|
|
}
|
2021-05-14 21:14:48 +00:00
|
|
|
auto cleanup = [](auto &tss, ident_level *pstack, std::size_t offn) {
|
|
|
|
auto mask2 = tss.callstack.back().usedargs;
|
2021-05-14 00:54:29 +00:00
|
|
|
if (pstack) {
|
2021-05-14 21:14:48 +00:00
|
|
|
pstack->usedargs = mask2;
|
2021-05-14 00:54:29 +00:00
|
|
|
}
|
2021-05-14 21:14:48 +00:00
|
|
|
tss.callstack.pop_back();
|
2021-05-14 00:54:29 +00:00
|
|
|
for (std::size_t i = 0, nredo = 0; mask2.any(); ++i) {
|
|
|
|
if (mask2[0]) {
|
|
|
|
tss.get_astack(
|
2022-04-20 02:31:24 +00:00
|
|
|
static_cast<alias *>(tss.istate->lookup_ident(i))
|
2021-05-14 00:54:29 +00:00
|
|
|
).node = tss.idstack[offn + nredo++].next;
|
|
|
|
}
|
|
|
|
mask2 >>= 1;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
any_value ret;
|
|
|
|
try {
|
|
|
|
ret = body.call(*ts.pstate);
|
|
|
|
} catch (...) {
|
2021-05-14 21:14:48 +00:00
|
|
|
cleanup(ts, prevstack, noff);
|
2021-05-14 00:54:29 +00:00
|
|
|
ts.idstack.resize(noff);
|
|
|
|
throw;
|
|
|
|
}
|
2021-05-14 21:14:48 +00:00
|
|
|
cleanup(ts, prevstack, noff);
|
2021-05-14 00:54:29 +00:00
|
|
|
ts.idstack.resize(noff);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-05-14 00:36:16 +00:00
|
|
|
struct vm_guard {
|
|
|
|
vm_guard(thread_state &s): ts{s}, oldtop{s.vmstack.size()} {
|
|
|
|
if (s.max_call_depth && (s.call_depth >= s.max_call_depth)) {
|
|
|
|
throw error{*s.pstate, "exceeded recursion limit"};
|
|
|
|
}
|
|
|
|
++s.call_depth;
|
|
|
|
}
|
|
|
|
|
|
|
|
~vm_guard() {
|
|
|
|
--ts.call_depth;
|
|
|
|
ts.vmstack.resize(oldtop);
|
|
|
|
}
|
|
|
|
|
|
|
|
thread_state &ts;
|
|
|
|
std::size_t oldtop;
|
|
|
|
};
|
|
|
|
|
2021-03-26 23:26:59 +00:00
|
|
|
std::uint32_t *vm_exec(
|
2021-03-25 00:37:13 +00:00
|
|
|
thread_state &ts, std::uint32_t *code, any_value &result
|
2021-03-24 21:37:53 +00:00
|
|
|
) {
|
2021-03-18 19:55:14 +00:00
|
|
|
result.set_none();
|
2021-03-25 00:37:13 +00:00
|
|
|
auto &cs = *ts.pstate;
|
2021-05-14 00:36:16 +00:00
|
|
|
vm_guard scope{ts}; /* keep track of recursion depth + manage stack */
|
2021-03-25 00:37:13 +00:00
|
|
|
auto &args = ts.vmstack;
|
2021-05-05 01:16:32 +00:00
|
|
|
auto &chook = cs.call_hook();
|
2016-09-05 19:34:48 +00:00
|
|
|
if (chook) {
|
2016-09-11 21:13:39 +00:00
|
|
|
chook(cs);
|
2016-09-05 19:34:48 +00:00
|
|
|
}
|
2021-05-14 17:18:11 +00:00
|
|
|
auto force_val = [](state &s, any_value &v, int opn) {
|
|
|
|
switch (opn & BC_INST_RET_MASK) {
|
|
|
|
case BC_RET_STRING:
|
|
|
|
v.force_string(s);
|
|
|
|
break;
|
|
|
|
case BC_RET_INT:
|
|
|
|
v.force_integer();
|
|
|
|
break;
|
|
|
|
case BC_RET_FLOAT:
|
|
|
|
v.force_float();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
2016-08-12 16:38:43 +00:00
|
|
|
for (;;) {
|
2021-03-24 21:37:53 +00:00
|
|
|
std::uint32_t op = *code++;
|
2021-05-12 22:43:44 +00:00
|
|
|
switch (op & BC_INST_OP_MASK) {
|
2021-03-23 22:29:32 +00:00
|
|
|
case BC_INST_START:
|
|
|
|
case BC_INST_OFFSET:
|
2016-08-17 02:57:53 +00:00
|
|
|
continue;
|
2016-08-12 16:38:43 +00:00
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_NULL:
|
2021-05-12 02:08:47 +00:00
|
|
|
result.set_none();
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2016-08-12 16:38:43 +00:00
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_FALSE:
|
2021-05-12 02:08:47 +00:00
|
|
|
result.set_integer(0);
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2016-08-12 16:38:43 +00:00
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_TRUE:
|
2021-05-12 02:08:47 +00:00
|
|
|
result.set_integer(1);
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2016-08-12 16:38:43 +00:00
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_NOT:
|
2021-05-12 02:08:47 +00:00
|
|
|
result.set_integer(!args.back().get_bool());
|
2021-03-24 21:37:53 +00:00
|
|
|
args.pop_back();
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2016-08-12 16:38:43 +00:00
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
case BC_INST_POP:
|
2021-03-24 21:37:53 +00:00
|
|
|
args.pop_back();
|
2016-08-17 02:57:53 +00:00
|
|
|
continue;
|
2021-05-14 17:18:11 +00:00
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
case BC_INST_ENTER:
|
2021-04-11 01:32:14 +00:00
|
|
|
code = vm_exec(ts, code, args.emplace_back());
|
2016-08-17 02:57:53 +00:00
|
|
|
continue;
|
2021-05-14 17:18:11 +00:00
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
case BC_INST_ENTER_RESULT:
|
2021-03-26 23:26:59 +00:00
|
|
|
code = vm_exec(ts, code, result);
|
2016-08-17 02:57:53 +00:00
|
|
|
continue;
|
2021-05-12 02:08:47 +00:00
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_EXIT:
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_exit;
|
2021-03-28 15:07:04 +00:00
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_RESULT:
|
2021-03-28 15:07:04 +00:00
|
|
|
result = std::move(args.back());
|
|
|
|
args.pop_back();
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2021-03-28 15:07:04 +00:00
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_RESULT_ARG:
|
2021-03-24 21:37:53 +00:00
|
|
|
args.emplace_back(std::move(result));
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_top;
|
2021-03-28 15:07:04 +00:00
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_FORCE:
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_top;
|
2021-03-28 15:07:04 +00:00
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_DUP: {
|
2021-03-28 15:07:04 +00:00
|
|
|
auto &v = args.back();
|
2021-05-13 02:48:55 +00:00
|
|
|
args.emplace_back() = v;
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_top;
|
2021-03-28 15:07:04 +00:00
|
|
|
}
|
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_VAL:
|
|
|
|
switch (op & BC_INST_RET_MASK) {
|
|
|
|
case BC_RET_STRING: {
|
2021-05-13 02:48:55 +00:00
|
|
|
auto len = op >> 8;
|
2021-05-14 20:10:16 +00:00
|
|
|
char const *str;
|
|
|
|
std::memcpy(&str, &code, sizeof(str));
|
|
|
|
std::string_view sv{str, len};
|
|
|
|
args.emplace_back().set_string(sv, cs);
|
2021-05-12 22:43:44 +00:00
|
|
|
code += len / sizeof(std::uint32_t) + 1;
|
|
|
|
continue;
|
|
|
|
}
|
2021-05-14 20:10:16 +00:00
|
|
|
case BC_RET_INT: {
|
|
|
|
integer_type i;
|
|
|
|
std::memcpy(&i, code, sizeof(i));
|
|
|
|
args.emplace_back().set_integer(i);
|
2021-05-12 22:43:44 +00:00
|
|
|
code += bc_store_size<integer_type>;
|
|
|
|
continue;
|
2021-05-14 20:10:16 +00:00
|
|
|
}
|
|
|
|
case BC_RET_FLOAT: {
|
|
|
|
float_type f;
|
|
|
|
std::memcpy(&f, code, sizeof(f));
|
|
|
|
args.emplace_back().set_float(f);
|
2021-05-12 22:43:44 +00:00
|
|
|
code += bc_store_size<float_type>;
|
|
|
|
continue;
|
2021-05-14 20:10:16 +00:00
|
|
|
}
|
2021-05-12 22:43:44 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2021-04-11 01:32:14 +00:00
|
|
|
args.emplace_back().set_none();
|
2021-03-28 15:07:04 +00:00
|
|
|
continue;
|
2021-05-12 22:43:44 +00:00
|
|
|
|
|
|
|
case BC_INST_VAL_INT:
|
|
|
|
switch (op & BC_INST_RET_MASK) {
|
|
|
|
case 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 */
|
2021-05-13 02:48:55 +00:00
|
|
|
args.emplace_back().set_string(s, cs);
|
2021-05-12 22:43:44 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
case BC_RET_INT:
|
|
|
|
args.emplace_back().set_integer(integer_type(op) >> 8);
|
|
|
|
continue;
|
|
|
|
case BC_RET_FLOAT:
|
|
|
|
args.emplace_back().set_float(
|
|
|
|
float_type(integer_type(op) >> 8)
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
args.emplace_back().set_none();
|
2021-03-28 15:07:04 +00:00
|
|
|
continue;
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
case BC_INST_LOCAL: {
|
2021-03-24 21:37:53 +00:00
|
|
|
std::size_t numlocals = op >> 8;
|
|
|
|
std::size_t offset = args.size() - numlocals;
|
2021-03-29 22:28:06 +00:00
|
|
|
std::size_t idstsz = ts.idstack.size();
|
2021-03-24 21:37:53 +00:00
|
|
|
for (std::size_t i = 0; i < numlocals; ++i) {
|
2021-03-29 22:28:06 +00:00
|
|
|
push_alias(
|
2021-04-24 21:33:19 +00:00
|
|
|
ts, args[offset + i].get_ident(cs),
|
2021-04-11 01:32:14 +00:00
|
|
|
ts.idstack.emplace_back()
|
2021-03-29 22:28:06 +00:00
|
|
|
);
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
2021-05-13 02:48:55 +00:00
|
|
|
auto cleanup = [](
|
|
|
|
auto &css, std::size_t off, std::size_t isz, auto &av
|
|
|
|
) {
|
|
|
|
for (std::size_t i = off; i < av.size(); ++i) {
|
|
|
|
pop_alias(state_p{css}.ts(), av[i].get_ident(css));
|
2016-09-08 21:42:14 +00:00
|
|
|
}
|
2021-05-13 02:48:55 +00:00
|
|
|
state_p{css}.ts().idstack.resize(isz);
|
2021-03-30 21:49:50 +00:00
|
|
|
};
|
|
|
|
try {
|
|
|
|
code = vm_exec(ts, code, result);
|
|
|
|
} catch (...) {
|
2021-05-13 02:48:55 +00:00
|
|
|
cleanup(cs, offset, idstsz, args);
|
2021-03-30 21:49:50 +00:00
|
|
|
throw;
|
|
|
|
}
|
2021-05-13 02:48:55 +00:00
|
|
|
cleanup(cs, offset, idstsz, args);
|
2016-09-23 19:06:44 +00:00
|
|
|
return code;
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
2016-08-12 16:38:43 +00:00
|
|
|
|
2021-05-14 00:54:29 +00:00
|
|
|
case BC_INST_DO_ARGS: {
|
|
|
|
auto v = std::move(args.back());
|
|
|
|
args.pop_back();
|
|
|
|
result = exec_code_with_args(ts, v.get_code());
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2021-05-14 00:54:29 +00:00
|
|
|
}
|
2021-05-12 22:43:44 +00:00
|
|
|
|
|
|
|
case BC_INST_DO: {
|
2021-03-24 21:37:53 +00:00
|
|
|
auto v = std::move(args.back());
|
|
|
|
args.pop_back();
|
2021-05-02 20:44:38 +00:00
|
|
|
result = v.get_code().call(cs);
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2021-03-24 21:37:53 +00:00
|
|
|
}
|
2016-08-12 16:38:43 +00:00
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
case BC_INST_JUMP: {
|
2021-03-24 21:37:53 +00:00
|
|
|
std::uint32_t len = op >> 8;
|
2016-08-17 02:57:53 +00:00
|
|
|
code += len;
|
2016-08-12 16:38:43 +00:00
|
|
|
continue;
|
|
|
|
}
|
2021-05-12 22:43:44 +00:00
|
|
|
|
|
|
|
case BC_INST_JUMP_B: {
|
2021-03-24 21:37:53 +00:00
|
|
|
std::uint32_t len = op >> 8;
|
2021-05-12 22:43:44 +00:00
|
|
|
/* BC_INST_FLAG_TRUE/FALSE */
|
|
|
|
if (args.back().get_bool() == !!(op & BC_INST_RET_MASK)) {
|
2016-08-17 02:57:53 +00:00
|
|
|
code += len;
|
|
|
|
}
|
2021-03-24 21:37:53 +00:00
|
|
|
args.pop_back();
|
2016-08-17 02:57:53 +00:00
|
|
|
continue;
|
|
|
|
}
|
2021-05-12 22:43:44 +00:00
|
|
|
|
|
|
|
case BC_INST_JUMP_RESULT: {
|
2021-03-24 21:37:53 +00:00
|
|
|
std::uint32_t len = op >> 8;
|
|
|
|
auto v = std::move(args.back());
|
|
|
|
args.pop_back();
|
2021-05-05 01:16:32 +00:00
|
|
|
if (v.type() == value_type::CODE) {
|
2021-05-02 20:44:38 +00:00
|
|
|
result = v.get_code().call(cs);
|
2016-08-17 02:57:53 +00:00
|
|
|
} else {
|
2021-03-24 21:37:53 +00:00
|
|
|
result = std::move(v);
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
2021-05-12 22:43:44 +00:00
|
|
|
/* BC_INST_FLAG_TRUE/FALSE */
|
|
|
|
if (result.get_bool() == !!(op & BC_INST_RET_MASK)) {
|
2016-08-17 02:57:53 +00:00
|
|
|
code += len;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2021-05-12 22:43:44 +00:00
|
|
|
|
|
|
|
case BC_INST_BREAK:
|
2021-04-04 17:43:28 +00:00
|
|
|
if (ts.loop_level) {
|
2021-05-12 22:43:44 +00:00
|
|
|
if (op & BC_INST_RET_MASK) {
|
|
|
|
throw continue_exception{};
|
|
|
|
} else {
|
|
|
|
throw break_exception{};
|
|
|
|
}
|
2016-09-15 00:12:22 +00:00
|
|
|
} else {
|
2021-05-12 22:43:44 +00:00
|
|
|
if (op & BC_INST_RET_MASK) {
|
|
|
|
throw error{cs, "no loop to continue"};
|
|
|
|
} else {
|
|
|
|
throw error{cs, "no loop to break"};
|
|
|
|
}
|
2016-09-15 00:12:22 +00:00
|
|
|
}
|
|
|
|
break;
|
2016-08-12 16:38:43 +00:00
|
|
|
|
2021-03-28 15:11:35 +00:00
|
|
|
case BC_INST_BLOCK: {
|
|
|
|
std::uint32_t len = op >> 8;
|
2021-05-14 20:10:16 +00:00
|
|
|
bcode *b;
|
|
|
|
code += 1;
|
|
|
|
std::memcpy(&b, &code, sizeof(b));
|
|
|
|
args.emplace_back().set_code(bcode_p::make_ref(b));
|
|
|
|
code += len - 1;
|
2021-03-28 15:11:35 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_EMPTY:
|
2021-04-11 01:32:14 +00:00
|
|
|
args.emplace_back().set_code(bcode_p::make_ref(
|
2021-05-12 01:55:20 +00:00
|
|
|
bcode_get_empty(ts.istate->empty, op & BC_INST_RET_MASK)
|
2021-04-10 01:37:59 +00:00
|
|
|
));
|
2016-08-12 16:38:43 +00:00
|
|
|
break;
|
2021-03-28 15:11:35 +00:00
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
case BC_INST_COMPILE: {
|
2021-03-24 21:37:53 +00:00
|
|
|
any_value &arg = args.back();
|
2021-04-08 22:41:55 +00:00
|
|
|
gen_state gs{ts};
|
2021-05-05 01:16:32 +00:00
|
|
|
switch (arg.type()) {
|
2021-04-05 22:54:46 +00:00
|
|
|
case value_type::INTEGER:
|
2021-04-08 22:50:13 +00:00
|
|
|
gs.gen_main_integer(arg.get_integer());
|
2016-08-17 02:57:53 +00:00
|
|
|
break;
|
2021-03-23 22:29:32 +00:00
|
|
|
case value_type::FLOAT:
|
2021-04-08 22:50:13 +00:00
|
|
|
gs.gen_main_float(arg.get_float());
|
2016-08-17 02:57:53 +00:00
|
|
|
break;
|
2021-04-08 23:03:29 +00:00
|
|
|
case value_type::STRING:
|
2021-04-11 01:32:14 +00:00
|
|
|
gs.gen_main(arg.get_string(cs));
|
2016-08-17 02:57:53 +00:00
|
|
|
break;
|
|
|
|
default:
|
2021-04-08 22:50:13 +00:00
|
|
|
gs.gen_main_null();
|
2016-08-17 02:57:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2021-04-08 23:12:52 +00:00
|
|
|
arg.set_code(gs.steal_ref());
|
2016-08-17 02:57:53 +00:00
|
|
|
continue;
|
|
|
|
}
|
2021-03-28 15:11:35 +00:00
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
case BC_INST_COND: {
|
2021-03-24 21:37:53 +00:00
|
|
|
any_value &arg = args.back();
|
2021-05-05 01:16:32 +00:00
|
|
|
switch (arg.type()) {
|
2021-03-23 22:29:32 +00:00
|
|
|
case value_type::STRING: {
|
2021-04-11 01:32:14 +00:00
|
|
|
std::string_view s = arg.get_string(cs);
|
2016-08-30 20:55:35 +00:00
|
|
|
if (!s.empty()) {
|
2021-04-08 22:41:55 +00:00
|
|
|
gen_state gs{ts};
|
2021-04-09 22:54:28 +00:00
|
|
|
gs.gen_main(s);
|
2021-04-08 23:12:52 +00:00
|
|
|
arg.set_code(gs.steal_ref());
|
2016-08-17 02:57:53 +00:00
|
|
|
} else {
|
2021-03-18 19:55:14 +00:00
|
|
|
arg.force_none();
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
|
|
|
break;
|
2016-08-30 20:55:35 +00:00
|
|
|
}
|
2016-08-30 21:30:40 +00:00
|
|
|
default:
|
|
|
|
break;
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
|
|
|
continue;
|
2016-08-12 16:38:43 +00:00
|
|
|
}
|
|
|
|
|
2021-03-27 23:19:51 +00:00
|
|
|
case BC_INST_IDENT: {
|
2021-03-23 22:29:32 +00:00
|
|
|
alias *a = static_cast<alias *>(
|
2022-04-20 02:31:24 +00:00
|
|
|
ts.istate->lookup_ident(op >> 8)
|
2016-09-12 18:04:59 +00:00
|
|
|
);
|
2021-04-03 03:39:19 +00:00
|
|
|
if (a->is_arg() && !ident_is_used_arg(a, ts)) {
|
2021-04-11 01:32:14 +00:00
|
|
|
ts.get_astack(a).push(ts.idstack.emplace_back());
|
2021-05-14 21:14:48 +00:00
|
|
|
ts.callstack.back().usedargs[a->index()] = true;
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
2021-04-24 21:50:06 +00:00
|
|
|
args.emplace_back().set_ident(*a);
|
2016-08-17 02:57:53 +00:00
|
|
|
continue;
|
2016-08-12 16:38:43 +00:00
|
|
|
}
|
2021-03-23 22:29:32 +00:00
|
|
|
case BC_INST_IDENT_U: {
|
2021-03-24 21:37:53 +00:00
|
|
|
any_value &arg = args.back();
|
2021-04-04 04:52:02 +00:00
|
|
|
ident *id = ts.istate->id_dummy;
|
2021-05-05 01:16:32 +00:00
|
|
|
if (arg.type() == value_type::STRING) {
|
2021-04-05 17:52:13 +00:00
|
|
|
id = &ts.istate->new_ident(
|
2021-04-11 01:32:14 +00:00
|
|
|
cs, arg.get_string(cs), IDENT_FLAG_UNKNOWN
|
2021-04-03 04:16:43 +00:00
|
|
|
);
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
2021-04-03 03:39:19 +00:00
|
|
|
alias *a = static_cast<alias *>(id);
|
|
|
|
if (a->is_arg() && !ident_is_used_arg(id, ts)) {
|
2021-04-11 01:32:14 +00:00
|
|
|
ts.get_astack(a).push(ts.idstack.emplace_back());
|
2021-05-14 21:14:48 +00:00
|
|
|
ts.callstack.back().usedargs[id->index()] = true;
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
2021-04-24 21:50:06 +00:00
|
|
|
arg.set_ident(*id);
|
2016-08-17 02:57:53 +00:00
|
|
|
continue;
|
2016-08-12 16:38:43 +00:00
|
|
|
}
|
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_LOOKUP_U:
|
2021-04-28 01:20:36 +00:00
|
|
|
args.back() = cs.lookup_value(args.back().get_string(cs));
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_top;
|
2021-03-28 15:07:04 +00:00
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_LOOKUP: {
|
2022-04-20 02:31:24 +00:00
|
|
|
ident *id = ts.istate->lookup_ident(op >> 8);
|
2021-05-14 17:18:11 +00:00
|
|
|
if (static_cast<alias *>(id)->is_arg()) {
|
|
|
|
auto &v = args.emplace_back();
|
|
|
|
if (ident_is_used_arg(id, ts)) {
|
|
|
|
v = ts.get_astack(static_cast<alias *>(id)).node->val_s;
|
|
|
|
}
|
|
|
|
goto use_top;
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
2021-05-14 17:18:11 +00:00
|
|
|
auto &ast = ts.get_astack(static_cast<alias *>(id));
|
|
|
|
if (ast.flags & IDENT_FLAG_UNKNOWN) {
|
|
|
|
throw error_p::make(
|
|
|
|
*ts.pstate, "unknown alias lookup: %s",
|
|
|
|
id->name().data()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
args.emplace_back() = ast.node->val_s;
|
|
|
|
goto use_top;
|
2016-08-12 16:38:43 +00:00
|
|
|
}
|
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_CONC:
|
|
|
|
case BC_INST_CONC_W: {
|
2021-03-28 15:11:35 +00:00
|
|
|
std::size_t numconc = op >> 8;
|
|
|
|
auto buf = concat_values(
|
2021-04-15 18:26:49 +00:00
|
|
|
cs, span_type<any_value>{
|
|
|
|
&args[args.size() - numconc], numconc
|
|
|
|
}, ((op & BC_INST_OP_MASK) == BC_INST_CONC) ? " " : ""
|
2021-03-28 15:11:35 +00:00
|
|
|
);
|
2021-04-11 01:32:14 +00:00
|
|
|
args.resize(args.size() - numconc);
|
|
|
|
args.emplace_back().set_string(buf);
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_top;
|
2021-03-28 15:11:35 +00:00
|
|
|
}
|
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_VAR:
|
2021-05-06 01:47:38 +00:00
|
|
|
args.emplace_back() = static_cast<builtin_var *>(
|
2022-04-20 02:31:24 +00:00
|
|
|
ts.istate->lookup_ident(op >> 8)
|
2021-05-06 01:34:25 +00:00
|
|
|
)->value();
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_top;
|
2016-08-17 02:57:53 +00:00
|
|
|
|
2021-03-27 23:19:51 +00:00
|
|
|
case BC_INST_ALIAS: {
|
2021-04-02 03:47:49 +00:00
|
|
|
auto *a = static_cast<alias *>(
|
2022-04-20 02:31:24 +00:00
|
|
|
ts.istate->lookup_ident(op >> 8)
|
2021-03-27 23:19:51 +00:00
|
|
|
);
|
2021-04-02 03:47:49 +00:00
|
|
|
auto &ast = ts.get_astack(a);
|
2021-04-03 03:39:19 +00:00
|
|
|
if (a->is_arg()) {
|
2021-04-02 03:47:49 +00:00
|
|
|
ast.set_arg(a, ts, args.back());
|
2021-03-27 23:19:51 +00:00
|
|
|
} else {
|
2021-04-02 03:47:49 +00:00
|
|
|
ast.set_alias(a, ts, args.back());
|
2021-03-27 23:19:51 +00:00
|
|
|
}
|
2021-03-24 21:37:53 +00:00
|
|
|
args.pop_back();
|
2016-08-17 02:57:53 +00:00
|
|
|
continue;
|
2021-03-27 23:19:51 +00:00
|
|
|
}
|
2021-05-14 17:18:11 +00:00
|
|
|
|
2021-03-24 21:37:53 +00:00
|
|
|
case BC_INST_ALIAS_U: {
|
|
|
|
auto v = std::move(args.back());
|
|
|
|
args.pop_back();
|
2021-04-28 01:20:36 +00:00
|
|
|
cs.assign_value(args.back().get_string(cs), std::move(v));
|
2021-03-24 21:37:53 +00:00
|
|
|
args.pop_back();
|
2016-08-17 02:57:53 +00:00
|
|
|
continue;
|
2021-03-24 21:37:53 +00:00
|
|
|
}
|
2016-08-17 02:57:53 +00:00
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_CALL: {
|
2021-03-18 19:55:14 +00:00
|
|
|
result.force_none();
|
2022-04-20 02:31:24 +00:00
|
|
|
ident *id = ts.istate->lookup_ident(op >> 8);
|
2021-03-30 00:08:25 +00:00
|
|
|
std::size_t callargs = *code++;
|
2021-05-14 21:31:27 +00:00
|
|
|
std::size_t offset = args.size() - callargs;
|
2021-04-03 03:39:19 +00:00
|
|
|
auto *imp = static_cast<alias_impl *>(id);
|
|
|
|
if (imp->is_arg()) {
|
2021-03-27 23:19:51 +00:00
|
|
|
if (!ident_is_used_arg(id, ts)) {
|
2021-04-11 01:32:14 +00:00
|
|
|
args.resize(offset);
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2021-03-27 23:19:51 +00:00
|
|
|
}
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
2021-05-14 20:42:19 +00:00
|
|
|
auto &ast = ts.get_astack(imp);
|
|
|
|
if (ast.flags & IDENT_FLAG_UNKNOWN) {
|
|
|
|
throw error_p::make(
|
|
|
|
cs, "unknown command: %s", id->name().data()
|
|
|
|
);
|
|
|
|
}
|
2021-05-14 21:31:27 +00:00
|
|
|
result = exec_alias(ts, imp, &args[offset], callargs, ast);
|
|
|
|
args.resize(offset);
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2016-08-12 16:38:43 +00:00
|
|
|
}
|
2016-08-17 02:57:53 +00:00
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_CALL_U: {
|
2021-03-24 21:37:53 +00:00
|
|
|
std::size_t callargs = op >> 8;
|
2021-05-14 21:31:27 +00:00
|
|
|
std::size_t offset = args.size() - callargs;
|
2021-03-23 22:29:32 +00:00
|
|
|
any_value &idarg = args[offset - 1];
|
2021-05-05 01:16:32 +00:00
|
|
|
if (idarg.type() != value_type::STRING) {
|
2016-08-17 02:57:53 +00:00
|
|
|
litval:
|
2017-01-25 00:57:33 +00:00
|
|
|
result = std::move(idarg);
|
2021-04-11 01:32:14 +00:00
|
|
|
args.resize(offset - 1);
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
2021-04-11 01:32:14 +00:00
|
|
|
auto idn = idarg.get_string(cs);
|
2021-04-26 00:42:08 +00:00
|
|
|
auto id = cs.get_ident(idn);
|
2016-08-17 02:57:53 +00:00
|
|
|
if (!id) {
|
|
|
|
noid:
|
2021-03-23 21:17:25 +00:00
|
|
|
if (!is_valid_name(idn)) {
|
2016-08-17 02:57:53 +00:00
|
|
|
goto litval;
|
|
|
|
}
|
2021-03-20 07:22:15 +00:00
|
|
|
std::string_view ids{idn};
|
2021-05-08 15:20:56 +00:00
|
|
|
throw error_p::make(
|
2021-03-20 07:22:15 +00:00
|
|
|
cs, "unknown command: %s", ids.data()
|
2021-05-08 15:20:56 +00:00
|
|
|
);
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
2021-03-18 19:55:14 +00:00
|
|
|
result.force_none();
|
2021-04-26 00:42:08 +00:00
|
|
|
switch (ident_p{id->get()}.impl().p_type) {
|
2016-08-17 02:57:53 +00:00
|
|
|
default:
|
2021-04-26 00:42:08 +00:00
|
|
|
if (!ident_is_callable(&id->get())) {
|
2021-04-11 01:32:14 +00:00
|
|
|
args.resize(offset - 1);
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
|
|
|
/* fallthrough */
|
2021-04-03 01:14:52 +00:00
|
|
|
case ID_COMMAND: {
|
2021-04-26 00:42:08 +00:00
|
|
|
auto *cimp = static_cast<command_impl *>(&id->get());
|
2021-04-03 01:14:52 +00:00
|
|
|
args.resize(offset + std::max(
|
2021-05-05 01:16:32 +00:00
|
|
|
std::size_t(cimp->arg_count()), callargs
|
2021-04-11 01:32:14 +00:00
|
|
|
));
|
2021-03-26 23:26:59 +00:00
|
|
|
exec_command(
|
2021-04-03 01:14:52 +00:00
|
|
|
ts, cimp, cimp, &args[offset], result, callargs
|
2016-08-17 21:04:43 +00:00
|
|
|
);
|
2021-04-11 01:32:14 +00:00
|
|
|
args.resize(offset - 1);
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2021-04-03 01:14:52 +00:00
|
|
|
}
|
2021-03-22 21:33:01 +00:00
|
|
|
case ID_LOCAL: {
|
2021-03-29 22:28:06 +00:00
|
|
|
std::size_t idstsz = ts.idstack.size();
|
2021-05-13 02:48:55 +00:00
|
|
|
for (std::size_t j = 0; j < callargs; ++j) {
|
2021-03-24 20:01:01 +00:00
|
|
|
push_alias(
|
2021-04-24 21:33:19 +00:00
|
|
|
ts, args[offset + j].force_ident(cs),
|
2021-04-11 01:32:14 +00:00
|
|
|
ts.idstack.emplace_back()
|
2021-03-24 20:01:01 +00:00
|
|
|
);
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
2021-03-30 21:49:50 +00:00
|
|
|
try {
|
|
|
|
code = vm_exec(ts, code, result);
|
|
|
|
} catch (...) {
|
2021-05-13 02:48:55 +00:00
|
|
|
for (std::size_t j = 0; j < callargs; ++j) {
|
|
|
|
pop_alias(ts, args[offset + j].get_ident(cs));
|
|
|
|
}
|
|
|
|
ts.idstack.resize(idstsz);
|
2021-03-30 21:49:50 +00:00
|
|
|
throw;
|
|
|
|
}
|
2021-05-13 02:48:55 +00:00
|
|
|
for (std::size_t j = 0; j < callargs; ++j) {
|
|
|
|
pop_alias(ts, args[offset + j].get_ident(cs));
|
|
|
|
}
|
|
|
|
ts.idstack.resize(idstsz);
|
2016-09-23 19:06:44 +00:00
|
|
|
return code;
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
2021-05-06 22:07:13 +00:00
|
|
|
case ID_VAR: {
|
|
|
|
auto *hid = static_cast<var_impl &>(
|
|
|
|
id->get()
|
|
|
|
).get_setter(ts);
|
2021-04-03 01:14:52 +00:00
|
|
|
auto *cimp = static_cast<command_impl *>(hid);
|
|
|
|
/* the $ argument */
|
2021-04-11 01:32:14 +00:00
|
|
|
args.insert(offset, any_value{});
|
2021-04-03 01:14:52 +00:00
|
|
|
args.resize(offset + std::max(
|
2021-05-05 01:16:32 +00:00
|
|
|
std::size_t(cimp->arg_count()), callargs
|
2021-04-11 01:32:14 +00:00
|
|
|
));
|
2021-04-03 01:14:52 +00:00
|
|
|
exec_command(
|
2021-04-26 00:42:08 +00:00
|
|
|
ts, cimp, &id->get(), &args[offset],
|
|
|
|
result, callargs
|
2021-04-03 01:14:52 +00:00
|
|
|
);
|
2021-04-11 01:32:14 +00:00
|
|
|
args.resize(offset - 1);
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2021-04-03 01:14:52 +00:00
|
|
|
}
|
2021-03-22 21:33:01 +00:00
|
|
|
case ID_ALIAS: {
|
2021-04-26 00:42:08 +00:00
|
|
|
alias *a = static_cast<alias *>(&id->get());
|
2021-04-03 03:39:19 +00:00
|
|
|
if (a->is_arg() && !ident_is_used_arg(a, ts)) {
|
2021-04-11 01:32:14 +00:00
|
|
|
args.resize(offset - 1);
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
2021-05-14 20:42:19 +00:00
|
|
|
auto &ast = ts.get_astack(a);
|
|
|
|
if (ast.node->val_s.type() == value_type::NONE) {
|
2016-08-17 02:57:53 +00:00
|
|
|
goto noid;
|
|
|
|
}
|
2021-05-14 21:31:27 +00:00
|
|
|
result = exec_alias(
|
|
|
|
ts, a, &args[offset], callargs, ast
|
2021-05-14 20:42:19 +00:00
|
|
|
);
|
2021-05-14 21:31:27 +00:00
|
|
|
args.resize(offset - 1);
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2016-08-17 22:06:39 +00:00
|
|
|
}
|
2016-08-17 02:57:53 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-28 15:11:35 +00:00
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_COM: {
|
2021-03-28 15:11:35 +00:00
|
|
|
command_impl *id = static_cast<command_impl *>(
|
2022-04-20 02:31:24 +00:00
|
|
|
ts.istate->lookup_ident(op >> 8)
|
2021-03-28 15:11:35 +00:00
|
|
|
);
|
2021-05-05 01:16:32 +00:00
|
|
|
std::size_t offset = args.size() - id->arg_count();
|
2021-03-28 15:11:35 +00:00
|
|
|
result.force_none();
|
2021-04-15 18:26:49 +00:00
|
|
|
id->call(ts, span_type<any_value>{
|
2021-05-05 01:16:32 +00:00
|
|
|
&args[offset], std::size_t(id->arg_count())
|
2021-03-28 15:11:35 +00:00
|
|
|
}, result);
|
2021-04-11 01:32:14 +00:00
|
|
|
args.resize(offset);
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2021-03-28 15:11:35 +00:00
|
|
|
}
|
|
|
|
|
2021-05-12 22:43:44 +00:00
|
|
|
case BC_INST_COM_V: {
|
2021-03-28 15:11:35 +00:00
|
|
|
command_impl *id = static_cast<command_impl *>(
|
2022-04-20 02:31:24 +00:00
|
|
|
ts.istate->lookup_ident(op >> 8)
|
2021-03-28 15:11:35 +00:00
|
|
|
);
|
2021-03-30 00:08:25 +00:00
|
|
|
std::size_t callargs = *code++;
|
2021-03-28 15:11:35 +00:00
|
|
|
std::size_t offset = args.size() - callargs;
|
|
|
|
result.force_none();
|
2021-04-15 18:26:49 +00:00
|
|
|
id->call(
|
|
|
|
ts, span_type<any_value>{&args[offset], callargs}, result
|
|
|
|
);
|
2021-04-11 01:32:14 +00:00
|
|
|
args.resize(offset);
|
2021-05-14 17:18:11 +00:00
|
|
|
goto use_result;
|
2021-03-28 15:11:35 +00:00
|
|
|
}
|
2016-08-12 16:38:43 +00:00
|
|
|
}
|
2021-05-14 17:18:11 +00:00
|
|
|
continue;
|
|
|
|
use_result:
|
|
|
|
force_val(cs, result, op);
|
|
|
|
continue;
|
|
|
|
use_top:
|
|
|
|
force_val(cs, args.back(), op);
|
|
|
|
continue;
|
|
|
|
use_exit:
|
|
|
|
force_val(cs, result, op);
|
|
|
|
break;
|
2016-08-12 16:38:43 +00:00
|
|
|
}
|
|
|
|
return code;
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:32:25 +00:00
|
|
|
} /* namespace cubescript */
|