libcubescript/cs_vm.cc

1933 lines
64 KiB
C++
Raw Normal View History

2016-08-12 18:38:43 +02:00
#include "cubescript.hh"
#include "cs_vm.hh"
#include "cs_util.hh"
2016-08-12 18:38:43 +02:00
2016-08-13 01:26:16 +02:00
#include <ostd/memory.hh>
2016-08-12 18:38:43 +02:00
namespace cscript {
2016-08-31 20:54:08 +02:00
void CsAlias::push_arg(CsValue const &v, CsIdentStack &st, bool um) {
if (p_astack == &st) {
/* prevent cycles and unnecessary code elsewhere */
p_val.cleanup();
p_val = v;
clean_code();
return;
}
st.val_s = p_val;
st.next = p_astack;
p_astack = &st;
p_val = v;
clean_code();
if (um) {
p_flags &= ~IDF_UNKNOWN;
}
}
void CsAlias::pop_arg() {
if (!p_astack) {
return;
}
CsIdentStack *st = p_astack;
p_val.cleanup();
p_val = p_astack->val_s;
clean_code();
p_astack = st->next;
}
void CsAlias::undo_arg(CsIdentStack &st) {
CsIdentStack *prev = p_astack;
st.val_s = p_val;
st.next = prev;
p_astack = prev->next;
p_val = prev->val_s;
clean_code();
}
void CsAlias::redo_arg(CsIdentStack const &st) {
CsIdentStack *prev = st.next;
prev->val_s = p_val;
p_astack = prev;
p_val = st.val_s;
clean_code();
}
void CsAlias::set_arg(CsState &cs, CsValue &v) {
if (cs.p_stack->usedargs & (1 << get_index())) {
p_val.cleanup();
p_val = v;
clean_code();
} else {
push_arg(v, cs.p_stack->argstack[get_index()], false);
cs.p_stack->usedargs |= 1 << get_index();
}
}
void CsAlias::set_alias(CsState &cs, CsValue &v) {
p_val.cleanup();
p_val = v;
clean_code();
p_flags = (p_flags & cs.identflags) | cs.identflags;
}
2016-08-29 19:17:11 +02:00
static inline bool cs_has_cmd_cb(CsIdent *id) {
2016-08-18 03:53:51 +02:00
if (!id->is_command() && !id->is_special()) {
2016-08-17 23:04:43 +02:00
return false;
}
Command *cb = static_cast<Command *>(id);
return !!cb->cb_cftv;
}
2016-08-29 19:17:11 +02:00
static inline void cs_push_alias(CsIdent *id, CsIdentStack &st) {
2016-08-18 03:53:51 +02:00
if (id->is_alias() && (id->get_index() >= MaxArguments)) {
2016-08-29 19:17:11 +02:00
static_cast<CsAlias *>(id)->push_arg(null_value, st);
2016-08-18 00:06:39 +02:00
}
}
2016-08-29 19:17:11 +02:00
static inline void cs_pop_alias(CsIdent *id) {
2016-08-18 03:53:51 +02:00
if (id->is_alias() && (id->get_index() >= MaxArguments)) {
2016-08-29 19:17:11 +02:00
static_cast<CsAlias *>(id)->pop_arg();
2016-08-18 00:06:39 +02:00
}
}
/* TODO: make thread_local later */
static ostd::ConstCharRange cs_src_file, cs_src_str;
2016-08-17 04:57:53 +02:00
ostd::ConstCharRange cs_debug_line(
ostd::ConstCharRange p, ostd::ConstCharRange fmt, ostd::CharRange buf
2016-08-17 04:57:53 +02:00
) {
if (cs_src_str.empty()) {
2016-08-17 04:57:53 +02:00
return fmt;
}
2016-08-14 17:02:46 +02:00
ostd::Size num = 1;
ostd::ConstCharRange line(cs_src_str);
2016-08-14 17:02:46 +02:00
for (;;) {
ostd::ConstCharRange end = ostd::find(line, '\n');
2016-08-17 04:57:53 +02:00
if (!end.empty()) {
2016-08-14 17:02:46 +02:00
line = ostd::slice_until(line, end);
2016-08-17 04:57:53 +02:00
}
2016-08-14 17:02:46 +02:00
if (&p[0] >= &line[0] && &p[0] <= &line[line.size()]) {
ostd::CharRange r(buf);
if (!cs_src_file.empty()) {
ostd::format(r, "%s:%d: %s", cs_src_file, num, fmt);
2016-08-17 04:57:53 +02:00
} else {
2016-08-14 17:02:46 +02:00
ostd::format(r, "%d: %s", num, fmt);
2016-08-17 04:57:53 +02:00
}
2016-08-14 17:02:46 +02:00
r.put('\0');
2016-08-31 19:49:24 +02:00
return buf.data(); /* trigger strlen */
2016-08-14 17:02:46 +02:00
}
2016-08-17 04:57:53 +02:00
if (end.empty()) {
break;
}
2016-08-14 17:02:46 +02:00
line = end;
line.pop_front();
++num;
}
return fmt;
}
void cs_debug_alias(CsState &cs) {
2016-08-29 19:17:11 +02:00
CsIvar *dalias = static_cast<CsIvar *>(cs.identmap[DbgaliasIdx]);
if (!dalias->get_value()) {
2016-08-17 04:57:53 +02:00
return;
}
2016-08-14 17:02:46 +02:00
int total = 0, depth = 0;
2016-08-29 19:17:11 +02:00
for (CsIdentLink *l = cs.p_stack; l != &cs.noalias; l = l->next) {
2016-08-17 04:57:53 +02:00
total++;
}
2016-08-29 19:17:11 +02:00
for (CsIdentLink *l = cs.p_stack; l != &cs.noalias; l = l->next) {
CsIdent *id = l->id;
2016-08-14 17:02:46 +02:00
++depth;
if (depth < dalias->get_value()) {
2016-08-18 03:53:51 +02:00
ostd::err.writefln(" %d) %s", total - depth + 1, id->get_name());
2016-08-17 04:57:53 +02:00
} else if (l->next == &cs.noalias) {
ostd::err.writefln(
depth == dalias->get_value() ? " %d) %s" : " ..%d) %s",
2016-08-18 03:53:51 +02:00
total - depth + 1, id->get_name()
2016-08-17 04:57:53 +02:00
);
}
2016-08-14 17:02:46 +02:00
}
}
2016-08-14 17:05:55 +02:00
static void bcode_ref(ostd::Uint32 *code) {
2016-08-17 04:57:53 +02:00
if (!code) {
return;
}
if ((*code & CODE_OP_MASK) == CODE_START) {
2016-08-14 17:05:55 +02:00
bcode_incr(code);
return;
}
switch (code[-1]&CODE_OP_MASK) {
2016-08-17 04:57:53 +02:00
case CODE_START:
bcode_incr(&code[-1]);
break;
case CODE_OFFSET:
code -= ostd::Ptrdiff(code[-1] >> 8);
bcode_incr(code);
break;
2016-08-14 17:05:55 +02:00
}
}
static void bcode_unref(ostd::Uint32 *code) {
2016-08-17 04:57:53 +02:00
if (!code) {
return;
}
if ((*code & CODE_OP_MASK) == CODE_START) {
2016-08-14 17:05:55 +02:00
bcode_decr(code);
return;
}
switch (code[-1]&CODE_OP_MASK) {
2016-08-17 04:57:53 +02:00
case CODE_START:
bcode_decr(&code[-1]);
break;
case CODE_OFFSET:
code -= ostd::Ptrdiff(code[-1] >> 8);
bcode_decr(code);
break;
2016-08-14 17:05:55 +02:00
}
}
2016-08-28 19:40:18 +02:00
CsBytecodeRef::CsBytecodeRef(CsBytecode *v): p_code(v) {
2016-08-14 17:05:55 +02:00
bcode_ref(reinterpret_cast<ostd::Uint32 *>(p_code));
}
2016-08-28 19:40:18 +02:00
CsBytecodeRef::CsBytecodeRef(CsBytecodeRef const &v): p_code(v.p_code) {
2016-08-14 17:05:55 +02:00
bcode_ref(reinterpret_cast<ostd::Uint32 *>(p_code));
}
2016-08-28 19:40:18 +02:00
CsBytecodeRef::~CsBytecodeRef() {
2016-08-14 17:05:55 +02:00
bcode_unref(reinterpret_cast<ostd::Uint32 *>(p_code));
}
2016-08-28 19:40:18 +02:00
CsBytecodeRef &CsBytecodeRef::operator=(CsBytecodeRef const &v) {
2016-08-14 17:05:55 +02:00
bcode_unref(reinterpret_cast<ostd::Uint32 *>(p_code));
p_code = v.p_code;
bcode_ref(reinterpret_cast<ostd::Uint32 *>(p_code));
return *this;
}
2016-08-28 19:40:18 +02:00
CsBytecodeRef &CsBytecodeRef::operator=(CsBytecodeRef &&v) {
2016-08-14 17:05:55 +02:00
bcode_unref(reinterpret_cast<ostd::Uint32 *>(p_code));
p_code = v.p_code;
v.p_code = nullptr;
return *this;
}
2016-08-30 22:29:09 +02:00
static inline ostd::Uint32 *forcecode(CsState &cs, CsValue &v) {
ostd::Uint32 *code = reinterpret_cast<ostd::Uint32 *>(v.get_code());
if (!code) {
2016-08-12 19:31:34 +02:00
GenState gs(cs);
gs.code.reserve(64);
gs.gen_main(v.get_str());
v.cleanup();
2016-08-28 19:40:18 +02:00
v.set_code(reinterpret_cast<CsBytecode *>(gs.code.disown() + 1));
2016-08-30 22:29:09 +02:00
code = reinterpret_cast<ostd::Uint32 *>(v.get_code());
2016-08-12 19:31:34 +02:00
}
2016-08-30 22:29:09 +02:00
return code;
2016-08-12 19:31:34 +02:00
}
2016-08-18 20:38:30 +02:00
static inline void forcecond(CsState &cs, CsValue &v) {
2016-08-12 19:31:34 +02:00
switch (v.get_type()) {
case CsValueType::string:
case CsValueType::macro:
case CsValueType::cstring:
2016-08-30 22:55:35 +02:00
if (!v.get_strr().empty()) {
2016-08-17 04:57:53 +02:00
forcecode(cs, v);
} else {
v.set_int(0);
}
break;
default:
break;
2016-08-12 19:31:34 +02:00
}
}
2016-08-12 18:38:43 +02:00
static ostd::Uint32 emptyblock[VAL_ANY][2] = {
{ CODE_START + 0x100, CODE_EXIT | RET_NULL },
{ CODE_START + 0x100, CODE_EXIT | RET_INT },
{ CODE_START + 0x100, CODE_EXIT | RET_FLOAT },
{ CODE_START + 0x100, CODE_EXIT | RET_STR }
};
2016-08-18 20:38:30 +02:00
static inline void force_arg(CsValue &v, int type) {
2016-08-12 18:38:43 +02:00
switch (type) {
2016-08-17 04:57:53 +02:00
case RET_STR:
if (v.get_type() != CsValueType::string) {
2016-08-17 04:57:53 +02:00
v.force_str();
}
break;
case RET_INT:
if (v.get_type() != CsValueType::integer) {
2016-08-17 04:57:53 +02:00
v.force_int();
}
break;
case RET_FLOAT:
if (v.get_type() != CsValueType::number) {
2016-08-17 04:57:53 +02:00
v.force_float();
}
break;
2016-08-12 18:38:43 +02:00
}
}
2016-08-18 20:38:30 +02:00
static inline void free_args(CsValue *args, int &oldnum, int newnum) {
2016-08-17 04:57:53 +02:00
for (int i = newnum; i < oldnum; i++) {
args[i].cleanup();
}
2016-08-12 18:38:43 +02:00
oldnum = newnum;
}
2016-08-30 22:29:09 +02:00
static ostd::Uint32 *skipcode(
ostd::Uint32 *code, CsValue *result = nullptr
2016-08-17 04:57:53 +02:00
) {
2016-08-12 18:38:43 +02:00
int depth = 0;
for (;;) {
ostd::Uint32 op = *code++;
switch (op & 0xFF) {
2016-08-17 04:57:53 +02:00
case CODE_MACRO:
case CODE_VAL | RET_STR: {
ostd::Uint32 len = op >> 8;
code += len / sizeof(ostd::Uint32) + 1;
continue;
}
case CODE_BLOCK:
case CODE_JUMP:
case CODE_JUMP_TRUE:
case CODE_JUMP_FALSE:
case CODE_JUMP_RESULT_TRUE:
case CODE_JUMP_RESULT_FALSE: {
ostd::Uint32 len = op >> 8;
code += len;
continue;
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
case CODE_ENTER:
case CODE_ENTER_RESULT:
++depth;
continue;
case CODE_EXIT | RET_NULL:
case CODE_EXIT | RET_STR:
case CODE_EXIT | RET_INT:
case CODE_EXIT | RET_FLOAT:
if (depth <= 0) {
if (result) {
force_arg(*result, op & CODE_RET_MASK);
}
return code;
}
--depth;
continue;
2016-08-12 18:38:43 +02:00
}
}
}
2016-08-18 20:38:30 +02:00
void CsValue::copy_arg(CsValue &r) const {
2016-08-12 18:38:43 +02:00
r.cleanup();
switch (get_type()) {
case CsValueType::integer:
case CsValueType::number:
case CsValueType::ident:
2016-08-12 18:38:43 +02:00
r = *this;
break;
case CsValueType::string:
case CsValueType::cstring:
case CsValueType::macro:
2016-08-30 22:55:35 +02:00
r.set_str(ostd::ConstCharRange(p_s, p_len));
2016-08-12 18:38:43 +02:00
break;
case CsValueType::code: {
2016-08-30 22:29:09 +02:00
ostd::Uint32 *bcode = reinterpret_cast<ostd::Uint32 *>(r.get_code());
ostd::Uint32 *end = skipcode(bcode);
2016-08-12 18:38:43 +02:00
ostd::Uint32 *dst = new ostd::Uint32[end - bcode + 1];
*dst++ = CODE_START;
memcpy(dst, bcode, (end - bcode) * sizeof(ostd::Uint32));
2016-08-30 22:29:09 +02:00
r.set_code(reinterpret_cast<CsBytecode *>(dst));
2016-08-12 18:38:43 +02:00
break;
}
default:
r.set_null();
break;
}
}
2016-08-17 04:57:53 +02:00
static inline void callcommand(
2016-08-18 20:38:30 +02:00
CsState &cs, Command *id, CsValue *args, CsValue &res, int numargs,
2016-08-17 04:57:53 +02:00
bool lookup = false
) {
2016-08-12 18:38:43 +02:00
int i = -1, fakeargs = 0;
bool rep = false;
2016-08-17 04:57:53 +02:00
for (char const *fmt = id->cargs; *fmt; fmt++) {
switch (*fmt) {
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;
}
args[i].set_int(CsIntMin);
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("");
fakeargs++;
} else {
args[i].force_str();
}
break;
case 's':
if (++i >= numargs) {
if (rep) {
break;
}
args[i].set_cstr("");
fakeargs++;
} else {
args[i].force_str();
}
break;
case 'T':
case 't':
if (++i >= numargs) {
if (rep) {
break;
}
args[i].set_null();
fakeargs++;
}
break;
case 'E':
if (++i >= numargs) {
if (rep) {
break;
}
args[i].set_null();
fakeargs++;
} else {
forcecond(cs, args[i]);
}
break;
case 'e':
if (++i >= numargs) {
if (rep) {
break;
}
args[i].set_code(
2016-08-28 19:40:18 +02:00
reinterpret_cast<CsBytecode *>(emptyblock[VAL_NULL] + 1)
2016-08-17 04:57:53 +02:00
);
fakeargs++;
} else {
forcecode(cs, args[i]);
}
break;
case 'r':
if (++i >= numargs) {
if (rep) {
break;
}
args[i].set_ident(cs.identmap[DummyIdx]);
2016-08-17 04:57:53 +02:00
fakeargs++;
} else {
cs.force_ident(args[i]);
}
break;
case '$':
if (++i < numargs) {
args[i].cleanup();
}
args[i].set_ident(id);
break;
case 'N':
if (++i < numargs) {
args[i].cleanup();
}
args[i].set_int(CsInt(lookup ? -1 : i - fakeargs));
break;
case 'C': {
i = ostd::max(i + 1, numargs);
2016-08-21 02:34:03 +02:00
auto buf = ostd::appender<CsString>();
2016-08-17 04:57:53 +02:00
cscript::util::tvals_concat(buf, ostd::iter(args, i), " ");
2016-08-18 20:38:30 +02:00
CsValue tv;
2016-08-17 04:57:53 +02:00
tv.set_mstr(buf.get().iter());
2016-08-18 20:38:30 +02:00
id->cb_cftv(CsValueRange(&tv, 1), res);
2016-08-17 04:57:53 +02:00
goto cleanup;
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
case 'V':
i = ostd::max(i + 1, numargs);
id->cb_cftv(ostd::iter(args, i), res);
goto cleanup;
case '1':
case '2':
case '3':
case '4':
if (i + 1 < numargs) {
fmt -= *fmt - '0' + 1;
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;
2016-08-18 20:38:30 +02:00
id->cb_cftv(CsValueRange(args, i), res);
2016-08-12 18:38:43 +02:00
cleanup:
2016-08-17 04:57:53 +02:00
for (ostd::Size k = 0; k < ostd::Size(i); ++k) {
args[k].cleanup();
}
for (; i < numargs; i++) {
args[i].cleanup();
}
}
2016-08-30 22:29:09 +02:00
static ostd::Uint32 *runcode(CsState &cs, ostd::Uint32 *code, CsValue &result);
2016-08-17 04:57:53 +02:00
static inline void cs_call_alias(
2016-08-29 19:17:11 +02:00
CsState &cs, CsAlias *a, CsValue *args, CsValue &result,
2016-08-17 04:57:53 +02:00
int callargs, int &nargs, int offset, int skip, ostd::Uint32 op
) {
2016-08-29 19:17:11 +02:00
CsIvar *anargs = static_cast<CsIvar *>(cs.identmap[NumargsIdx]);
CsIdentStack argstack[MaxArguments];
2016-08-17 04:57:53 +02:00
for(int i = 0; i < callargs; i++) {
2016-08-29 19:17:11 +02:00
static_cast<CsAlias *>(cs.identmap[i])->push_arg(
2016-08-18 00:06:39 +02:00
args[offset + i], argstack[i], false
);
2016-08-17 04:57:53 +02:00
}
int oldargs = anargs->get_value();
anargs->set_value(callargs);
2016-08-17 04:57:53 +02:00
int oldflags = cs.identflags;
2016-08-18 03:53:51 +02:00
cs.identflags |= a->get_flags()&IDF_OVERRIDDEN;
2016-08-29 19:17:11 +02:00
CsIdentLink aliaslink = {
2016-08-20 17:40:00 +02:00
a, cs.p_stack, (1<<callargs)-1, argstack
2016-08-17 04:57:53 +02:00
};
2016-08-20 17:40:00 +02:00
cs.p_stack = &aliaslink;
2016-08-21 01:51:45 +02:00
ostd::Uint32 *codep = reinterpret_cast<ostd::Uint32 *>(a->compile_code(cs));
2016-08-17 04:57:53 +02:00
bcode_incr(codep);
runcode(cs, codep+1, (result));
bcode_decr(codep);
2016-08-20 17:40:00 +02:00
cs.p_stack = aliaslink.next;
2016-08-17 04:57:53 +02:00
cs.identflags = oldflags;
for (int i = 0; i < callargs; i++) {
2016-08-29 19:17:11 +02:00
static_cast<CsAlias *>(cs.identmap[i])->pop_arg();
2016-08-17 04:57:53 +02:00
}
int argmask = aliaslink.usedargs & (~0 << callargs);
for (; argmask; ++callargs) {
if (argmask & (1 << callargs)) {
2016-08-29 19:17:11 +02:00
static_cast<CsAlias *>(cs.identmap[callargs])->pop_arg();
2016-08-17 04:57:53 +02:00
argmask &= ~(1 << callargs);
}
}
force_arg(result, op & CODE_RET_MASK);
anargs->set_value(oldargs);
2016-08-17 04:57:53 +02:00
nargs = offset - skip;
2016-08-12 18:38:43 +02:00
}
static constexpr int MaxRunDepth = 255;
static thread_local int rundepth = 0;
2016-08-29 19:17:11 +02:00
static inline CsAlias *cs_get_lookup_id(CsState &cs, ostd::Uint32 op) {
CsIdent *id = cs.identmap[op >> 8];
2016-08-18 03:53:51 +02:00
if (id->get_flags() & IDF_UNKNOWN) {
cs_debug_code(cs, "unknown alias lookup: %s", id->get_name());
2016-08-17 04:57:53 +02:00
}
2016-08-29 19:17:11 +02:00
return static_cast<CsAlias *>(id);
2016-08-17 04:57:53 +02:00
}
2016-08-29 19:17:11 +02:00
static inline CsAlias *cs_get_lookuparg_id(CsState &cs, ostd::Uint32 op) {
CsIdent *id = cs.identmap[op >> 8];
2016-08-20 17:40:00 +02:00
if (!(cs.p_stack->usedargs & (1 << id->get_index()))) {
2016-08-17 04:57:53 +02:00
return nullptr;
}
2016-08-29 19:17:11 +02:00
return static_cast<CsAlias *>(id);
2016-08-17 04:57:53 +02:00
}
static inline int cs_get_lookupu_type(
2016-08-29 19:17:11 +02:00
CsState &cs, CsValue &arg, CsIdent *&id, ostd::Uint32 op
2016-08-17 04:57:53 +02:00
) {
if (
arg.get_type() != CsValueType::string &&
arg.get_type() != CsValueType::macro &&
arg.get_type() != CsValueType::cstring
2016-08-17 04:57:53 +02:00
) {
return -2; /* default case */
}
2016-08-30 22:55:35 +02:00
id = cs.get_ident(arg.get_strr());
2016-08-17 04:57:53 +02:00
if (id) {
2016-08-18 03:53:51 +02:00
switch(id->get_type()) {
2016-08-29 19:17:11 +02:00
case CsIdentType::alias:
2016-08-18 03:53:51 +02:00
if (id->get_flags() & IDF_UNKNOWN) {
2016-08-17 04:57:53 +02:00
break;
}
arg.cleanup();
if (
2016-08-18 03:53:51 +02:00
(id->get_index() < MaxArguments) &&
2016-08-20 17:40:00 +02:00
!(cs.p_stack->usedargs & (1 << id->get_index()))
2016-08-17 04:57:53 +02:00
) {
return ID_UNKNOWN;
}
return ID_ALIAS;
2016-08-29 19:17:11 +02:00
case CsIdentType::svar:
2016-08-17 04:57:53 +02:00
arg.cleanup();
return ID_SVAR;
2016-08-29 19:17:11 +02:00
case CsIdentType::ivar:
2016-08-17 04:57:53 +02:00
arg.cleanup();
return ID_IVAR;
2016-08-29 19:17:11 +02:00
case CsIdentType::fvar:
2016-08-17 04:57:53 +02:00
arg.cleanup();
return ID_FVAR;
2016-08-29 19:17:11 +02:00
case CsIdentType::command: {
2016-08-17 04:57:53 +02:00
arg.cleanup();
arg.set_null();
2016-08-18 20:38:30 +02:00
CsValue buf[MaxArguments];
2016-08-17 23:04:43 +02:00
callcommand(cs, static_cast<Command *>(id), buf, arg, 0, true);
2016-08-17 04:57:53 +02:00
force_arg(arg, op & CODE_RET_MASK);
return -2; /* ignore */
}
default:
arg.cleanup();
return ID_UNKNOWN;
}
}
2016-08-30 22:55:35 +02:00
cs_debug_code(cs, "unknown alias lookup: %s", arg.get_strr());
2016-08-17 04:57:53 +02:00
arg.cleanup();
return ID_UNKNOWN;
}
2016-08-30 22:29:09 +02:00
static ostd::Uint32 *runcode(CsState &cs, ostd::Uint32 *code, CsValue &result) {
2016-08-12 18:38:43 +02:00
result.set_null();
if (rundepth >= MaxRunDepth) {
cs_debug_code(cs, "exceeded recursion limit");
2016-08-12 19:20:33 +02:00
return skipcode(code, &result);
2016-08-12 18:38:43 +02:00
}
++rundepth;
int numargs = 0;
2016-08-18 20:38:30 +02:00
CsValue args[MaxArguments + MaxResults];
2016-08-12 18:38:43 +02:00
for (;;) {
ostd::Uint32 op = *code++;
switch (op & 0xFF) {
2016-08-17 04:57:53 +02:00
case CODE_START:
case CODE_OFFSET:
continue;
2016-08-12 18:38:43 +02:00
2016-08-17 04:57:53 +02:00
case CODE_NULL | RET_NULL:
result.cleanup();
result.set_null();
continue;
case CODE_NULL | RET_STR:
result.cleanup();
result.set_str("");
continue;
case CODE_NULL | RET_INT:
result.cleanup();
result.set_int(0);
continue;
case CODE_NULL | RET_FLOAT:
result.cleanup();
result.set_float(0.0f);
continue;
2016-08-12 18:38:43 +02:00
2016-08-17 04:57:53 +02:00
case CODE_FALSE | RET_STR:
result.cleanup();
result.set_str("0");
continue;
case CODE_FALSE | RET_NULL:
case CODE_FALSE | RET_INT:
result.cleanup();
result.set_int(0);
continue;
case CODE_FALSE | RET_FLOAT:
result.cleanup();
result.set_float(0.0f);
continue;
2016-08-12 18:38:43 +02:00
2016-08-17 04:57:53 +02:00
case CODE_TRUE | RET_STR:
result.cleanup();
result.set_str("1");
continue;
case CODE_TRUE | RET_NULL:
case CODE_TRUE | RET_INT:
result.cleanup();
result.set_int(1);
continue;
case CODE_TRUE | RET_FLOAT:
result.cleanup();
result.set_float(1.0f);
continue;
2016-08-12 18:38:43 +02:00
2016-08-17 04:57:53 +02:00
case CODE_NOT | RET_STR:
result.cleanup();
--numargs;
result.set_str(args[numargs].get_bool() ? "0" : "1");
args[numargs].cleanup();
continue;
case CODE_NOT | RET_NULL:
case CODE_NOT | RET_INT:
result.cleanup();
--numargs;
result.set_int(!args[numargs].get_bool());
args[numargs].cleanup();
continue;
case CODE_NOT | RET_FLOAT:
result.cleanup();
--numargs;
result.set_float(CsFloat(!args[numargs].get_bool()));
args[numargs].cleanup();
continue;
2016-08-12 18:38:43 +02:00
2016-08-17 04:57:53 +02:00
case CODE_POP:
args[--numargs].cleanup();
continue;
case CODE_ENTER:
code = runcode(cs, code, args[numargs++]);
continue;
case CODE_ENTER_RESULT:
result.cleanup();
code = runcode(cs, code, result);
continue;
case CODE_EXIT | RET_STR:
case CODE_EXIT | RET_INT:
case CODE_EXIT | RET_FLOAT:
force_arg(result, op & CODE_RET_MASK);
/* fallthrough */
case CODE_EXIT | RET_NULL:
goto exit;
case CODE_RESULT_ARG | RET_STR:
case CODE_RESULT_ARG | RET_INT:
case CODE_RESULT_ARG | RET_FLOAT:
force_arg(result, op & CODE_RET_MASK);
/* fallthrough */
case CODE_RESULT_ARG | RET_NULL:
args[numargs++] = result;
result.set_null();
continue;
case CODE_PRINT:
2016-08-29 19:17:11 +02:00
cs.print_var(static_cast<CsVar *>(cs.identmap[op >> 8]));
2016-08-17 04:57:53 +02:00
continue;
2016-08-12 18:38:43 +02:00
2016-08-17 04:57:53 +02:00
case CODE_LOCAL: {
result.cleanup();
int numlocals = op >> 8, offset = numargs - numlocals;
2016-08-29 19:17:11 +02:00
CsIdentStack locals[MaxArguments];
2016-08-17 04:57:53 +02:00
for (int i = 0; i < numlocals; ++i) {
2016-08-30 22:29:09 +02:00
cs_push_alias(args[offset + i].get_ident(), locals[i]);
2016-08-17 04:57:53 +02:00
}
code = runcode(cs, code, result);
for (int i = offset; i < numargs; i++) {
2016-08-30 22:29:09 +02:00
cs_pop_alias(args[i].get_ident());
2016-08-17 04:57:53 +02:00
}
goto exit;
}
2016-08-12 18:38:43 +02:00
2016-08-17 04:57:53 +02:00
case CODE_DOARGS | RET_NULL:
case CODE_DOARGS | RET_STR:
case CODE_DOARGS | RET_INT:
case CODE_DOARGS | RET_FLOAT:
2016-08-20 17:40:00 +02:00
if (cs.p_stack != &cs.noalias) {
2016-08-17 04:57:53 +02:00
cs_do_args(cs, [&]() {
result.cleanup();
2016-08-30 22:29:09 +02:00
cs.run_ret(args[--numargs].get_code(), result);
2016-08-17 04:57:53 +02:00
args[numargs].cleanup();
force_arg(result, op & CODE_RET_MASK);
});
continue;
}
/* fallthrough */
case CODE_DO | RET_NULL:
case CODE_DO | RET_STR:
case CODE_DO | RET_INT:
case CODE_DO | RET_FLOAT:
result.cleanup();
2016-08-30 22:29:09 +02:00
cs.run_ret(args[--numargs].get_code(), result);
2016-08-17 04:57:53 +02:00
args[numargs].cleanup();
force_arg(result, op & CODE_RET_MASK);
continue;
2016-08-12 18:38:43 +02:00
2016-08-17 04:57:53 +02:00
case CODE_JUMP: {
ostd::Uint32 len = op >> 8;
code += len;
2016-08-12 18:38:43 +02:00
continue;
}
2016-08-17 04:57:53 +02:00
case CODE_JUMP_TRUE: {
ostd::Uint32 len = op >> 8;
if (args[--numargs].get_bool()) {
code += len;
}
2016-08-12 18:38:43 +02:00
args[numargs].cleanup();
2016-08-17 04:57:53 +02:00
continue;
}
case CODE_JUMP_FALSE: {
ostd::Uint32 len = op >> 8;
if (!args[--numargs].get_bool()) {
code += len;
}
2016-08-12 18:38:43 +02:00
args[numargs].cleanup();
2016-08-17 04:57:53 +02:00
continue;
}
case CODE_JUMP_RESULT_TRUE: {
ostd::Uint32 len = op >> 8;
result.cleanup();
--numargs;
if (args[numargs].get_type() == CsValueType::code) {
2016-08-30 22:29:09 +02:00
cs.run_ret(args[numargs].get_code(), result);
2016-08-17 04:57:53 +02:00
args[numargs].cleanup();
} else {
result = args[numargs];
}
if (result.get_bool()) {
code += len;
}
continue;
}
case CODE_JUMP_RESULT_FALSE: {
ostd::Uint32 len = op >> 8;
result.cleanup();
--numargs;
if (args[numargs].get_type() == CsValueType::code) {
2016-08-30 22:29:09 +02:00
cs.run_ret(args[numargs].get_code(), result);
2016-08-17 04:57:53 +02:00
args[numargs].cleanup();
} else {
result = args[numargs];
}
if (!result.get_bool()) {
code += len;
}
continue;
}
2016-08-12 18:38:43 +02:00
2016-08-17 04:57:53 +02:00
case CODE_MACRO: {
ostd::Uint32 len = op >> 8;
2016-08-30 22:29:09 +02:00
args[numargs++].set_macro(ostd::ConstCharRange(
reinterpret_cast<char const *>(code), len
));
2016-08-17 04:57:53 +02:00
code += len / sizeof(ostd::Uint32) + 1;
continue;
}
2016-08-12 18:38:43 +02:00
2016-08-17 04:57:53 +02:00
case CODE_VAL | RET_STR: {
ostd::Uint32 len = op >> 8;
args[numargs++].set_str(ostd::ConstCharRange(
reinterpret_cast<char const *>(code), len
));
code += len / sizeof(ostd::Uint32) + 1;
continue;
}
case CODE_VALI | RET_STR: {
char s[4] = {
char((op >> 8) & 0xFF),
char((op >> 16) & 0xFF),
char((op >> 24) & 0xFF), '\0'
};
args[numargs++].set_str(s);
continue;
}
case CODE_VAL | RET_NULL:
case CODE_VALI | RET_NULL:
args[numargs++].set_null();
continue;
case CODE_VAL | RET_INT:
args[numargs++].set_int(CsInt(*code++));
continue;
case CODE_VALI | RET_INT:
args[numargs++].set_int(CsInt(op) >> 8);
continue;
case CODE_VAL | RET_FLOAT:
args[numargs++].set_float(
*reinterpret_cast<CsFloat const *>(code++)
);
continue;
case CODE_VALI | RET_FLOAT:
args[numargs++].set_float(CsFloat(CsInt(op) >> 8));
continue;
case CODE_DUP | RET_NULL:
args[numargs - 1].get_val(args[numargs]);
numargs++;
continue;
case CODE_DUP | RET_INT:
args[numargs].set_int(args[numargs - 1].get_int());
numargs++;
continue;
case CODE_DUP | RET_FLOAT:
args[numargs].set_float(args[numargs - 1].get_float());
numargs++;
continue;
case CODE_DUP | RET_STR:
args[numargs].set_str(ostd::move(args[numargs - 1].get_str()));
numargs++;
continue;
case CODE_FORCE | RET_STR:
args[numargs - 1].force_str();
continue;
case CODE_FORCE | RET_INT:
args[numargs - 1].force_int();
continue;
case CODE_FORCE | RET_FLOAT:
args[numargs - 1].force_float();
continue;
case CODE_RESULT | RET_NULL:
result.cleanup();
result = args[--numargs];
continue;
case CODE_RESULT | RET_STR:
case CODE_RESULT | RET_INT:
case CODE_RESULT | RET_FLOAT:
result.cleanup();
result = args[--numargs];
force_arg(result, op & CODE_RET_MASK);
continue;
case CODE_EMPTY | RET_NULL:
args[numargs++].set_code(
2016-08-28 19:40:18 +02:00
reinterpret_cast<CsBytecode *>(emptyblock[VAL_NULL] + 1)
2016-08-17 04:57:53 +02:00
);
2016-08-12 18:38:43 +02:00
break;
2016-08-17 04:57:53 +02:00
case CODE_EMPTY | RET_STR:
args[numargs++].set_code(
2016-08-28 19:40:18 +02:00
reinterpret_cast<CsBytecode *>(emptyblock[VAL_STR] + 1)
2016-08-17 04:57:53 +02:00
);
2016-08-12 18:38:43 +02:00
break;
2016-08-17 04:57:53 +02:00
case CODE_EMPTY | RET_INT:
args[numargs++].set_code(
2016-08-28 19:40:18 +02:00
reinterpret_cast<CsBytecode *>(emptyblock[VAL_INT] + 1)
2016-08-17 04:57:53 +02:00
);
2016-08-12 18:38:43 +02:00
break;
2016-08-17 04:57:53 +02:00
case CODE_EMPTY | RET_FLOAT:
args[numargs++].set_code(
2016-08-28 19:40:18 +02:00
reinterpret_cast<CsBytecode *>(emptyblock[VAL_FLOAT] + 1)
2016-08-17 04:57:53 +02:00
);
2016-08-12 18:38:43 +02:00
break;
2016-08-17 04:57:53 +02:00
case CODE_BLOCK: {
ostd::Uint32 len = op >> 8;
args[numargs++].set_code(
2016-08-30 22:29:09 +02:00
reinterpret_cast<CsBytecode *>(code + 1)
2016-08-17 04:57:53 +02:00
);
code += len;
continue;
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
case CODE_COMPILE: {
2016-08-18 20:38:30 +02:00
CsValue &arg = args[numargs - 1];
2016-08-17 04:57:53 +02:00
GenState gs(cs);
switch (arg.get_type()) {
case CsValueType::integer:
2016-08-17 04:57:53 +02:00
gs.code.reserve(8);
gs.code.push(CODE_START);
2016-08-30 22:55:35 +02:00
gs.gen_int(arg.get_int());
2016-08-17 04:57:53 +02:00
gs.code.push(CODE_RESULT);
gs.code.push(CODE_EXIT);
break;
case CsValueType::number:
2016-08-17 04:57:53 +02:00
gs.code.reserve(8);
gs.code.push(CODE_START);
2016-08-30 22:55:35 +02:00
gs.gen_float(arg.get_float());
2016-08-17 04:57:53 +02:00
gs.code.push(CODE_RESULT);
gs.code.push(CODE_EXIT);
break;
case CsValueType::string:
case CsValueType::macro:
case CsValueType::cstring:
2016-08-17 04:57:53 +02:00
gs.code.reserve(64);
2016-08-30 22:55:35 +02:00
gs.gen_main(arg.get_strr());
2016-08-17 04:57:53 +02:00
arg.cleanup();
break;
default:
gs.code.reserve(8);
gs.code.push(CODE_START);
gs.gen_null();
gs.code.push(CODE_RESULT);
gs.code.push(CODE_EXIT);
break;
}
arg.set_code(
2016-08-30 22:29:09 +02:00
reinterpret_cast<CsBytecode *>(gs.code.disown() + 1)
2016-08-17 04:57:53 +02:00
);
continue;
}
case CODE_COND: {
2016-08-18 20:38:30 +02:00
CsValue &arg = args[numargs - 1];
2016-08-17 04:57:53 +02:00
switch (arg.get_type()) {
case CsValueType::string:
case CsValueType::macro:
case CsValueType::cstring: {
2016-08-30 22:55:35 +02:00
ostd::ConstCharRange s = arg.get_strr();
if (!s.empty()) {
2016-08-17 04:57:53 +02:00
GenState gs(cs);
gs.code.reserve(64);
2016-08-30 22:55:35 +02:00
gs.gen_main(s);
2016-08-17 04:57:53 +02:00
arg.cleanup();
2016-08-30 22:29:09 +02:00
arg.set_code(reinterpret_cast<CsBytecode *>(
2016-08-17 04:57:53 +02:00
gs.code.disown() + 1
));
} else {
arg.force_null();
}
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
}
2016-08-17 04:57:53 +02:00
case CODE_IDENT:
args[numargs++].set_ident(cs.identmap[op >> 8]);
continue;
case CODE_IDENTARG: {
2016-08-29 19:17:11 +02:00
CsAlias *a = static_cast<CsAlias *>(cs.identmap[op >> 8]);
2016-08-20 17:40:00 +02:00
if (!(cs.p_stack->usedargs & (1 << a->get_index()))) {
2016-08-18 03:53:51 +02:00
a->push_arg(
2016-08-20 17:40:00 +02:00
null_value, cs.p_stack->argstack[a->get_index()], false
2016-08-18 03:53:51 +02:00
);
2016-08-20 17:40:00 +02:00
cs.p_stack->usedargs |= 1 << a->get_index();
2016-08-17 04:57:53 +02:00
}
2016-08-18 00:06:39 +02:00
args[numargs++].set_ident(a);
2016-08-17 04:57:53 +02:00
continue;
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
case CODE_IDENTU: {
2016-08-18 20:38:30 +02:00
CsValue &arg = args[numargs - 1];
2016-08-29 19:17:11 +02:00
CsIdent *id = cs.identmap[DummyIdx];
2016-08-17 04:57:53 +02:00
if (
arg.get_type() == CsValueType::string ||
arg.get_type() == CsValueType::macro ||
arg.get_type() == CsValueType::cstring
2016-08-17 04:57:53 +02:00
) {
2016-08-30 22:55:35 +02:00
id = cs.new_ident(arg.get_strr());
2016-08-17 04:57:53 +02:00
}
2016-08-18 03:53:51 +02:00
if (
id->get_index() < MaxArguments &&
2016-08-20 17:40:00 +02:00
!(cs.p_stack->usedargs & (1 << id->get_index()))
2016-08-18 03:53:51 +02:00
) {
2016-08-29 19:17:11 +02:00
static_cast<CsAlias *>(id)->push_arg(
2016-08-20 17:40:00 +02:00
null_value, cs.p_stack->argstack[id->get_index()], false
2016-08-18 00:06:39 +02:00
);
2016-08-20 17:40:00 +02:00
cs.p_stack->usedargs |= 1 << id->get_index();
2016-08-17 04:57:53 +02:00
}
arg.cleanup();
arg.set_ident(id);
continue;
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
case CODE_LOOKUPU | RET_STR: {
2016-08-29 19:17:11 +02:00
CsIdent *id = nullptr;
2016-08-18 20:38:30 +02:00
CsValue &arg = args[numargs - 1];
2016-08-17 04:57:53 +02:00
switch (cs_get_lookupu_type(cs, arg, id, op)) {
case ID_ALIAS:
2016-08-18 00:18:36 +02:00
arg.set_str(ostd::move(
2016-08-31 20:18:53 +02:00
static_cast<CsAlias *>(id)->get_value().get_str()
2016-08-18 00:18:36 +02:00
));
2016-08-17 04:57:53 +02:00
continue;
case ID_SVAR:
2016-08-29 19:17:11 +02:00
arg.set_str(static_cast<CsSvar *>(id)->get_value());
2016-08-17 04:57:53 +02:00
continue;
case ID_IVAR:
arg.set_str(ostd::move(
2016-08-29 19:17:11 +02:00
intstr(static_cast<CsIvar *>(id)->get_value())
));
2016-08-17 04:57:53 +02:00
continue;
case ID_FVAR:
arg.set_str(ostd::move(
2016-08-29 19:17:11 +02:00
floatstr(static_cast<CsFvar *>(id)->get_value())
));
2016-08-17 04:57:53 +02:00
continue;
case ID_UNKNOWN:
arg.set_str("");
continue;
default:
continue;
}
}
case CODE_LOOKUP | RET_STR:
args[numargs++].set_str(
2016-08-31 20:18:53 +02:00
ostd::move(cs_get_lookup_id(cs, op)->get_value().get_str())
2016-08-17 04:57:53 +02:00
);
continue;
case CODE_LOOKUPARG | RET_STR: {
2016-08-29 19:17:11 +02:00
CsAlias *a = cs_get_lookuparg_id(cs, op);
2016-08-18 00:18:36 +02:00
if (!a) {
2016-08-17 04:57:53 +02:00
args[numargs++].set_str("");
} else {
2016-08-31 20:18:53 +02:00
args[numargs++].set_str(
ostd::move(a->get_value().get_str())
);
2016-08-17 04:57:53 +02:00
}
continue;
}
case CODE_LOOKUPU | RET_INT: {
2016-08-29 19:17:11 +02:00
CsIdent *id = nullptr;
2016-08-18 20:38:30 +02:00
CsValue &arg = args[numargs - 1];
2016-08-17 04:57:53 +02:00
switch (cs_get_lookupu_type(cs, arg, id, op)) {
case ID_ALIAS:
2016-08-31 20:18:53 +02:00
arg.set_int(
static_cast<CsAlias *>(id)->get_value().get_int()
);
2016-08-17 04:57:53 +02:00
continue;
case ID_SVAR:
arg.set_int(cs_parse_int(
2016-08-29 19:17:11 +02:00
static_cast<CsSvar *>(id)->get_value()
));
2016-08-17 04:57:53 +02:00
continue;
case ID_IVAR:
2016-08-29 19:17:11 +02:00
arg.set_int(static_cast<CsIvar *>(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(
2016-08-29 19:17:11 +02:00
CsInt(static_cast<CsFvar *>(id)->get_value())
2016-08-18 04:14:55 +02:00
);
2016-08-17 04:57:53 +02:00
continue;
case ID_UNKNOWN:
arg.set_int(0);
continue;
default:
continue;
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
}
case CODE_LOOKUP | RET_INT:
args[numargs++].set_int(
2016-08-31 20:18:53 +02:00
cs_get_lookup_id(cs, op)->get_value().get_int()
2016-08-17 04:57:53 +02:00
);
continue;
case CODE_LOOKUPARG | RET_INT: {
2016-08-29 19:17:11 +02:00
CsAlias *a = cs_get_lookuparg_id(cs, op);
2016-08-18 00:18:36 +02:00
if (!a) {
2016-08-17 04:57:53 +02:00
args[numargs++].set_int(0);
} else {
2016-08-31 20:18:53 +02:00
args[numargs++].set_int(a->get_value().get_int());
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
continue;
}
case CODE_LOOKUPU | RET_FLOAT: {
2016-08-29 19:17:11 +02:00
CsIdent *id = nullptr;
2016-08-18 20:38:30 +02:00
CsValue &arg = args[numargs - 1];
2016-08-17 04:57:53 +02:00
switch (cs_get_lookupu_type(cs, arg, id, op)) {
case ID_ALIAS:
arg.set_float(
2016-08-31 20:18:53 +02:00
static_cast<CsAlias *>(id)->get_value().get_float()
);
2016-08-17 04:57:53 +02:00
continue;
case ID_SVAR:
arg.set_float(cs_parse_float(
2016-08-29 19:17:11 +02:00
static_cast<CsSvar *>(id)->get_value()
));
2016-08-17 04:57:53 +02:00
continue;
case ID_IVAR:
arg.set_float(CsFloat(
2016-08-29 19:17:11 +02:00
static_cast<CsIvar *>(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(
2016-08-29 19:17:11 +02:00
static_cast<CsFvar *>(id)->get_value()
2016-08-18 04:14:55 +02:00
);
2016-08-17 04:57:53 +02:00
continue;
case ID_UNKNOWN:
arg.set_float(CsFloat(0));
continue;
default:
continue;
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
}
case CODE_LOOKUP | RET_FLOAT:
args[numargs++].set_float(
2016-08-31 20:18:53 +02:00
cs_get_lookup_id(cs, op)->get_value().get_float()
2016-08-17 04:57:53 +02:00
);
continue;
case CODE_LOOKUPARG | RET_FLOAT: {
2016-08-29 19:17:11 +02:00
CsAlias *a = cs_get_lookuparg_id(cs, op);
2016-08-18 00:18:36 +02:00
if (!a) {
2016-08-17 04:57:53 +02:00
args[numargs++].set_float(CsFloat(0));
} else {
2016-08-31 20:18:53 +02:00
args[numargs++].set_float(a->get_value().get_float());
2016-08-17 04:57:53 +02:00
}
continue;
}
case CODE_LOOKUPU | RET_NULL: {
2016-08-29 19:17:11 +02:00
CsIdent *id = nullptr;
2016-08-18 20:38:30 +02:00
CsValue &arg = args[numargs - 1];
2016-08-17 04:57:53 +02:00
switch (cs_get_lookupu_type(cs, arg, id, op)) {
case ID_ALIAS:
2016-08-31 20:18:53 +02:00
static_cast<CsAlias *>(id)->get_value().get_val(arg);
2016-08-17 04:57:53 +02:00
continue;
case ID_SVAR:
2016-08-29 19:17:11 +02:00
arg.set_str(static_cast<CsSvar *>(id)->get_value());
2016-08-17 04:57:53 +02:00
continue;
case ID_IVAR:
2016-08-29 19:17:11 +02:00
arg.set_int(static_cast<CsIvar *>(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(
2016-08-29 19:17:11 +02:00
static_cast<CsFvar *>(id)->get_value()
2016-08-18 04:14:55 +02:00
);
2016-08-17 04:57:53 +02:00
continue;
case ID_UNKNOWN:
arg.set_null();
continue;
default:
continue;
}
}
case CODE_LOOKUP | RET_NULL:
2016-08-31 20:18:53 +02:00
cs_get_lookup_id(cs, op)->get_value().get_val(args[numargs++]);
2016-08-17 04:57:53 +02:00
continue;
case CODE_LOOKUPARG | RET_NULL: {
2016-08-29 19:17:11 +02:00
CsAlias *a = cs_get_lookuparg_id(cs, op);
2016-08-18 00:18:36 +02:00
if (!a) {
2016-08-17 04:57:53 +02:00
args[numargs++].set_null();
} else {
2016-08-31 20:18:53 +02:00
a->get_value().get_val(args[numargs++]);
2016-08-17 04:57:53 +02:00
}
continue;
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
case CODE_LOOKUPMU | RET_STR: {
2016-08-29 19:17:11 +02:00
CsIdent *id = nullptr;
2016-08-18 20:38:30 +02:00
CsValue &arg = args[numargs - 1];
2016-08-17 04:57:53 +02:00
switch (cs_get_lookupu_type(cs, arg, id, op)) {
case ID_ALIAS:
2016-08-29 19:17:11 +02:00
static_cast<CsAlias *>(id)->get_cstr(arg);
2016-08-17 04:57:53 +02:00
continue;
case ID_SVAR:
2016-08-29 19:17:11 +02:00
arg.set_cstr(static_cast<CsSvar *>(id)->get_value());
2016-08-17 04:57:53 +02:00
continue;
case ID_IVAR:
arg.set_str(ostd::move(
2016-08-29 19:17:11 +02:00
intstr(static_cast<CsIvar *>(id)->get_value())
));
2016-08-17 04:57:53 +02:00
continue;
case ID_FVAR:
arg.set_str(ostd::move(
2016-08-29 19:17:11 +02:00
floatstr(static_cast<CsFvar *>(id)->get_value())
));
2016-08-17 04:57:53 +02:00
continue;
case ID_UNKNOWN:
arg.set_cstr("");
continue;
default:
continue;
}
}
case CODE_LOOKUPM | RET_STR:
cs_get_lookup_id(cs, op)->get_cstr(args[numargs++]);
continue;
case CODE_LOOKUPMARG | RET_STR: {
2016-08-29 19:17:11 +02:00
CsAlias *a = cs_get_lookuparg_id(cs, op);
2016-08-18 00:18:36 +02:00
if (!a) {
2016-08-17 04:57:53 +02:00
args[numargs++].set_cstr("");
} else {
2016-08-18 00:18:36 +02:00
a->get_cstr(args[numargs++]);
2016-08-17 04:57:53 +02:00
}
continue;
}
case CODE_LOOKUPMU | RET_NULL: {
2016-08-29 19:17:11 +02:00
CsIdent *id = nullptr;
2016-08-18 20:38:30 +02:00
CsValue &arg = args[numargs - 1];
2016-08-17 04:57:53 +02:00
switch (cs_get_lookupu_type(cs, arg, id, op)) {
case ID_ALIAS:
2016-08-29 19:17:11 +02:00
static_cast<CsAlias *>(id)->get_cval(arg);
2016-08-17 04:57:53 +02:00
continue;
case ID_SVAR:
2016-08-29 19:17:11 +02:00
arg.set_cstr(static_cast<CsSvar *>(id)->get_value());
2016-08-17 04:57:53 +02:00
continue;
case ID_IVAR:
2016-08-29 19:17:11 +02:00
arg.set_int(static_cast<CsIvar *>(id)->get_value());
2016-08-17 04:57:53 +02:00
continue;
case ID_FVAR:
2016-08-29 19:17:11 +02:00
arg.set_float(static_cast<CsFvar *>(id)->get_value());
2016-08-17 04:57:53 +02:00
continue;
case ID_UNKNOWN:
arg.set_null();
continue;
default:
continue;
}
}
case CODE_LOOKUPM | RET_NULL:
cs_get_lookup_id(cs, op)->get_cval(args[numargs++]);
continue;
case CODE_LOOKUPMARG | RET_NULL: {
2016-08-29 19:17:11 +02:00
CsAlias *a = cs_get_lookuparg_id(cs, op);
2016-08-18 00:18:36 +02:00
if (!a) {
2016-08-17 04:57:53 +02:00
args[numargs++].set_null();
} else {
2016-08-18 00:18:36 +02:00
a->get_cval(args[numargs++]);
2016-08-17 04:57:53 +02:00
}
continue;
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
case CODE_SVAR | RET_STR:
case CODE_SVAR | RET_NULL:
args[numargs++].set_str(
2016-08-29 19:17:11 +02:00
static_cast<CsSvar *>(cs.identmap[op >> 8])->get_value()
);
2016-08-17 04:57:53 +02:00
continue;
case CODE_SVAR | RET_INT:
args[numargs++].set_int(cs_parse_int(
2016-08-29 19:17:11 +02:00
static_cast<CsSvar *>(cs.identmap[op >> 8])->get_value()
));
2016-08-17 04:57:53 +02:00
continue;
case CODE_SVAR | RET_FLOAT:
args[numargs++].set_float(cs_parse_float(
2016-08-29 19:17:11 +02:00
static_cast<CsSvar *>(cs.identmap[op >> 8])->get_value()
));
2016-08-17 04:57:53 +02:00
continue;
case CODE_SVARM:
args[numargs++].set_cstr(
2016-08-29 19:17:11 +02:00
static_cast<CsSvar *>(cs.identmap[op >> 8])->get_value()
);
2016-08-17 04:57:53 +02:00
continue;
case CODE_SVAR1:
2016-08-17 23:29:31 +02:00
cs.set_var_str_checked(
2016-08-30 22:55:35 +02:00
static_cast<CsSvar *>(cs.identmap[op >> 8]),
args[--numargs].get_strr()
2016-08-17 23:29:31 +02:00
);
2016-08-17 04:57:53 +02:00
args[numargs].cleanup();
continue;
2016-08-12 18:38:43 +02:00
2016-08-17 04:57:53 +02:00
case CODE_IVAR | RET_INT:
case CODE_IVAR | RET_NULL:
args[numargs++].set_int(
2016-08-29 19:17:11 +02:00
static_cast<CsIvar *>(cs.identmap[op >> 8])->get_value()
);
2016-08-17 04:57:53 +02:00
continue;
case CODE_IVAR | RET_STR:
args[numargs++].set_str(ostd::move(intstr(
2016-08-29 19:17:11 +02:00
static_cast<CsIvar *>(cs.identmap[op >> 8])->get_value()
)));
2016-08-17 04:57:53 +02:00
continue;
case CODE_IVAR | RET_FLOAT:
args[numargs++].set_float(CsFloat(
2016-08-29 19:17:11 +02:00
static_cast<CsIvar *>(cs.identmap[op >> 8])->get_value()
));
2016-08-17 04:57:53 +02:00
continue;
case CODE_IVAR1:
2016-08-17 23:29:31 +02:00
cs.set_var_int_checked(
2016-08-30 22:55:35 +02:00
static_cast<CsIvar *>(cs.identmap[op >> 8]),
args[--numargs].get_int()
2016-08-17 23:29:31 +02:00
);
2016-08-17 04:57:53 +02:00
continue;
case CODE_IVAR2:
numargs -= 2;
cs.set_var_int_checked(
2016-08-29 19:17:11 +02:00
static_cast<CsIvar *>(cs.identmap[op >> 8]),
2016-08-30 22:55:35 +02:00
(args[numargs].get_int() << 16)
| (args[numargs + 1].get_int() << 8)
);
2016-08-17 04:57:53 +02:00
continue;
case CODE_IVAR3:
numargs -= 3;
cs.set_var_int_checked(
2016-08-29 19:17:11 +02:00
static_cast<CsIvar *>(cs.identmap[op >> 8]),
2016-08-30 22:55:35 +02:00
(args[numargs].get_int() << 16)
| (args[numargs + 1].get_int() << 8)
| (args[numargs + 2].get_int()));
2016-08-17 04:57:53 +02:00
continue;
2016-08-12 18:38:43 +02:00
2016-08-17 04:57:53 +02:00
case CODE_FVAR | RET_FLOAT:
case CODE_FVAR | RET_NULL:
args[numargs++].set_float(
2016-08-29 19:17:11 +02:00
static_cast<CsFvar *>(cs.identmap[op >> 8])->get_value()
);
2016-08-17 04:57:53 +02:00
continue;
case CODE_FVAR | RET_STR:
args[numargs++].set_str(ostd::move(floatstr(
2016-08-29 19:17:11 +02:00
static_cast<CsFvar *>(cs.identmap[op >> 8])->get_value()
)));
2016-08-17 04:57:53 +02:00
continue;
case CODE_FVAR | RET_INT:
args[numargs++].set_int(int(
2016-08-29 19:17:11 +02:00
static_cast<CsFvar *>(cs.identmap[op >> 8])->get_value()
));
2016-08-17 04:57:53 +02:00
continue;
case CODE_FVAR1:
2016-08-17 23:29:31 +02:00
cs.set_var_float_checked(
2016-08-30 22:55:35 +02:00
static_cast<CsFvar *>(cs.identmap[op >> 8]),
args[--numargs].get_float()
2016-08-17 23:29:31 +02:00
);
2016-08-17 04:57:53 +02:00
continue;
case CODE_COM | RET_NULL:
case CODE_COM | RET_STR:
case CODE_COM | RET_FLOAT:
case CODE_COM | RET_INT: {
2016-08-17 23:04:43 +02:00
Command *id = static_cast<Command *>(cs.identmap[op >> 8]);
2016-08-17 04:57:53 +02:00
int offset = numargs - id->numargs;
result.force_null();
2016-08-18 20:38:30 +02:00
id->cb_cftv(CsValueRange(args + offset, id->numargs), result);
2016-08-17 04:57:53 +02:00
force_arg(result, op & CODE_RET_MASK);
free_args(args, numargs, offset);
continue;
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
case CODE_COMV | RET_NULL:
case CODE_COMV | RET_STR:
case CODE_COMV | RET_FLOAT:
case CODE_COMV | RET_INT: {
2016-08-17 23:04:43 +02:00
Command *id = static_cast<Command *>(cs.identmap[op >> 13]);
2016-08-17 04:57:53 +02:00
int callargs = (op >> 8) & 0x1F, offset = numargs - callargs;
result.force_null();
id->cb_cftv(ostd::iter(&args[offset], callargs), result);
2016-08-12 18:38:43 +02:00
force_arg(result, op & CODE_RET_MASK);
2016-08-17 04:57:53 +02:00
free_args(args, numargs, offset);
2016-08-12 18:38:43 +02:00
continue;
}
2016-08-17 04:57:53 +02:00
case CODE_COMC | RET_NULL:
case CODE_COMC | RET_STR:
case CODE_COMC | RET_FLOAT:
case CODE_COMC | RET_INT: {
2016-08-17 23:04:43 +02:00
Command *id = static_cast<Command *>(cs.identmap[op >> 13]);
2016-08-17 04:57:53 +02:00
int callargs = (op >> 8) & 0x1F, offset = numargs - callargs;
2016-08-12 18:38:43 +02:00
result.force_null();
2016-08-17 04:57:53 +02:00
{
2016-08-21 02:34:03 +02:00
auto buf = ostd::appender<CsString>();
2016-08-17 04:57:53 +02:00
cscript::util::tvals_concat(
buf, ostd::iter(&args[offset], callargs), " "
);
2016-08-18 20:38:30 +02:00
CsValue tv;
2016-08-17 04:57:53 +02:00
tv.set_mstr(buf.get().iter());
2016-08-18 20:38:30 +02:00
id->cb_cftv(CsValueRange(&tv, 1), result);
2016-08-17 04:57:53 +02:00
}
force_arg(result, op & CODE_RET_MASK);
free_args(args, numargs, offset);
continue;
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
case CODE_CONC | RET_NULL:
case CODE_CONC | RET_STR:
case CODE_CONC | RET_FLOAT:
case CODE_CONC | RET_INT:
case CODE_CONCW | RET_NULL:
case CODE_CONCW | RET_STR:
case CODE_CONCW | RET_FLOAT:
case CODE_CONCW | RET_INT: {
int numconc = op >> 8;
2016-08-21 02:34:03 +02:00
auto buf = ostd::appender<CsString>();
2016-08-17 04:57:53 +02:00
cscript::util::tvals_concat(
buf, ostd::iter(&args[numargs - numconc], numconc),
((op & CODE_OP_MASK) == CODE_CONC) ? " " : ""
);
free_args(args, numargs, numargs - numconc);
args[numargs].set_mstr(buf.get().iter());
buf.get().disown();
force_arg(args[numargs], op & CODE_RET_MASK);
numargs++;
continue;
}
case CODE_CONCM | RET_NULL:
case CODE_CONCM | RET_STR:
case CODE_CONCM | RET_FLOAT:
case CODE_CONCM | RET_INT: {
int numconc = op >> 8;
2016-08-21 02:34:03 +02:00
auto buf = ostd::appender<CsString>();
2016-08-17 04:57:53 +02:00
cscript::util::tvals_concat(
buf, ostd::iter(&args[numargs - numconc], numconc)
);
free_args(args, numargs, numargs - numconc);
result.set_mstr(buf.get().iter());
buf.get().disown();
2016-08-12 18:38:43 +02:00
force_arg(result, op & CODE_RET_MASK);
continue;
}
2016-08-17 04:57:53 +02:00
case CODE_ALIAS:
2016-08-29 19:17:11 +02:00
static_cast<CsAlias *>(cs.identmap[op >> 8])->set_alias(
2016-08-18 00:06:39 +02:00
cs, args[--numargs]
);
2016-08-17 04:57:53 +02:00
continue;
case CODE_ALIASARG:
2016-08-29 19:17:11 +02:00
static_cast<CsAlias *>(cs.identmap[op >> 8])->set_arg(
2016-08-18 00:06:39 +02:00
cs, args[--numargs]
);
2016-08-17 04:57:53 +02:00
continue;
case CODE_ALIASU:
numargs -= 2;
cs.set_alias(args[numargs].get_str(), args[numargs + 1]);
args[numargs].cleanup();
continue;
case CODE_CALL | RET_NULL:
case CODE_CALL | RET_STR:
case CODE_CALL | RET_FLOAT:
case CODE_CALL | RET_INT: {
result.force_null();
2016-08-29 19:17:11 +02:00
CsIdent *id = cs.identmap[op >> 13];
2016-08-17 04:57:53 +02:00
int callargs = (op >> 8) & 0x1F, offset = numargs - callargs;
2016-08-18 03:53:51 +02:00
if (id->get_flags() & IDF_UNKNOWN) {
cs_debug_code(cs, "unknown command: %s", id->get_name());
2016-08-17 04:57:53 +02:00
free_args(args, numargs, offset);
force_arg(result, op & CODE_RET_MASK);
continue;
}
cs_call_alias(
2016-08-29 19:17:11 +02:00
cs, static_cast<CsAlias *>(id), args, result, callargs,
2016-08-18 00:06:39 +02:00
numargs, offset, 0, op
2016-08-17 04:57:53 +02:00
);
2016-08-12 18:38:43 +02:00
continue;
}
2016-08-17 04:57:53 +02:00
case CODE_CALLARG | RET_NULL:
case CODE_CALLARG | RET_STR:
case CODE_CALLARG | RET_FLOAT:
case CODE_CALLARG | RET_INT: {
result.force_null();
2016-08-29 19:17:11 +02:00
CsIdent *id = cs.identmap[op >> 13];
2016-08-17 04:57:53 +02:00
int callargs = (op >> 8) & 0x1F, offset = numargs - callargs;
2016-08-20 17:40:00 +02:00
if (!(cs.p_stack->usedargs & (1 << id->get_index()))) {
2016-08-17 04:57:53 +02:00
free_args(args, numargs, offset);
force_arg(result, op & CODE_RET_MASK);
continue;
}
cs_call_alias(
2016-08-29 19:17:11 +02:00
cs, static_cast<CsAlias *>(id), args, result, callargs,
2016-08-18 00:06:39 +02:00
numargs, offset, 0, op
2016-08-17 04:57:53 +02:00
);
continue;
}
case CODE_CALLU | RET_NULL:
case CODE_CALLU | RET_STR:
case CODE_CALLU | RET_FLOAT:
case CODE_CALLU | RET_INT: {
int callargs = op >> 8, offset = numargs - callargs;
2016-08-18 20:38:30 +02:00
CsValue &idarg = args[offset - 1];
2016-08-17 04:57:53 +02:00
if (
idarg.get_type() != CsValueType::string &&
idarg.get_type() != CsValueType::macro &&
idarg.get_type() != CsValueType::cstring
2016-08-17 04:57:53 +02:00
) {
litval:
result.cleanup();
result = idarg;
force_arg(result, op & CODE_RET_MASK);
while (--numargs >= offset) {
args[numargs].cleanup();
}
continue;
}
2016-08-30 22:55:35 +02:00
CsIdent *id = cs.get_ident(idarg.get_strr());
2016-08-17 04:57:53 +02:00
if (!id) {
noid:
2016-08-30 22:55:35 +02:00
if (cs_check_num(idarg.get_strr())) {
2016-08-17 04:57:53 +02:00
goto litval;
}
2016-08-30 22:55:35 +02:00
cs_debug_code(cs, "unknown command: %s", idarg.get_strr());
2016-08-17 04:57:53 +02:00
result.force_null();
free_args(args, numargs, offset - 1);
force_arg(result, op & CODE_RET_MASK);
continue;
}
result.force_null();
2016-08-18 03:53:51 +02:00
switch (id->get_type_raw()) {
2016-08-17 04:57:53 +02:00
default:
2016-08-17 23:04:43 +02:00
if (!cs_has_cmd_cb(id)) {
2016-08-17 04:57:53 +02:00
free_args(args, numargs, offset - 1);
force_arg(result, op & CODE_RET_MASK);
continue;
}
/* fallthrough */
case ID_COMMAND:
idarg.cleanup();
2016-08-17 23:04:43 +02:00
callcommand(
cs, static_cast<Command *>(id), &args[offset],
result, callargs
);
2016-08-17 04:57:53 +02:00
force_arg(result, op & CODE_RET_MASK);
numargs = offset - 1;
continue;
case ID_LOCAL: {
2016-08-29 19:17:11 +02:00
CsIdentStack locals[MaxArguments];
2016-08-17 04:57:53 +02:00
idarg.cleanup();
for (ostd::Size j = 0; j < ostd::Size(callargs); ++j) {
2016-08-18 00:06:39 +02:00
cs_push_alias(cs.force_ident(
2016-08-17 04:57:53 +02:00
args[offset + j]
2016-08-18 00:06:39 +02:00
), locals[j]);
2016-08-17 04:57:53 +02:00
}
code = runcode(cs, code, result);
for (ostd::Size j = 0; j < ostd::Size(callargs); ++j) {
2016-08-30 22:29:09 +02:00
cs_pop_alias(args[offset + j].get_ident());
2016-08-17 04:57:53 +02:00
}
goto exit;
}
case ID_IVAR:
if (callargs <= 0) {
2016-08-29 19:17:11 +02:00
cs.print_var(static_cast<CsIvar *>(id));
2016-08-17 04:57:53 +02:00
} else {
cs.set_var_int_checked(
2016-08-29 19:17:11 +02:00
static_cast<CsIvar *>(id),
2016-08-17 23:29:31 +02:00
ostd::iter(&args[offset], callargs)
2016-08-17 04:57:53 +02:00
);
}
free_args(args, numargs, offset - 1);
force_arg(result, op & CODE_RET_MASK);
continue;
case ID_FVAR:
if (callargs <= 0) {
2016-08-29 19:17:11 +02:00
cs.print_var(static_cast<CsFvar *>(id));
2016-08-17 04:57:53 +02:00
} else {
cs.set_var_float_checked(
2016-08-29 19:17:11 +02:00
static_cast<CsFvar *>(id),
2016-08-17 23:29:31 +02:00
args[offset].force_float()
2016-08-17 04:57:53 +02:00
);
}
free_args(args, numargs, offset - 1);
force_arg(result, op & CODE_RET_MASK);
continue;
case ID_SVAR:
if (callargs <= 0) {
2016-08-29 19:17:11 +02:00
cs.print_var(static_cast<CsSvar *>(id));
2016-08-17 04:57:53 +02:00
} else {
2016-08-17 23:29:31 +02:00
cs.set_var_str_checked(
2016-08-29 19:17:11 +02:00
static_cast<CsSvar *>(id),
2016-08-17 23:29:31 +02:00
args[offset].force_str()
);
2016-08-17 04:57:53 +02:00
}
free_args(args, numargs, offset - 1);
force_arg(result, op & CODE_RET_MASK);
continue;
2016-08-18 00:06:39 +02:00
case ID_ALIAS: {
2016-08-29 19:17:11 +02:00
CsAlias *a = static_cast<CsAlias *>(id);
2016-08-17 04:57:53 +02:00
if (
2016-08-18 03:53:51 +02:00
a->get_index() < MaxArguments &&
2016-08-20 17:40:00 +02:00
!(cs.p_stack->usedargs & (1 << a->get_index()))
2016-08-17 04:57:53 +02:00
) {
free_args(args, numargs, offset - 1);
force_arg(result, op & CODE_RET_MASK);
continue;
}
2016-08-31 20:18:53 +02:00
if (a->get_value().get_type() == CsValueType::null) {
2016-08-17 04:57:53 +02:00
goto noid;
}
idarg.cleanup();
cs_call_alias(
2016-08-18 00:06:39 +02:00
cs, a, args, result, callargs, numargs,
2016-08-17 04:57:53 +02:00
offset, 1, op
);
continue;
2016-08-18 00:06:39 +02:00
}
2016-08-17 04:57:53 +02:00
}
}
2016-08-12 18:38:43 +02:00
}
}
exit:
--rundepth;
return code;
}
2016-08-30 22:29:09 +02:00
void CsState::run_ret(CsBytecode *code, CsValue &ret) {
runcode(*this, reinterpret_cast<ostd::Uint32 *>(code), ret);
2016-08-12 18:38:43 +02:00
}
void CsState::run_ret(ostd::ConstCharRange code, CsValue &ret) {
GenState gs(*this);
2016-08-12 18:38:43 +02:00
gs.code.reserve(64);
/* FIXME range */
gs.gen_main(code.data(), VAL_ANY);
runcode(*this, gs.code.data() + 1, ret);
2016-08-17 04:57:53 +02:00
if (int(gs.code[0]) >= 0x100) {
2016-08-12 18:38:43 +02:00
gs.code.disown();
2016-08-17 04:57:53 +02:00
}
2016-08-12 18:38:43 +02:00
}
2016-08-29 19:17:11 +02:00
void CsState::run_ret(CsIdent *id, CsValueRange args, CsValue &ret) {
2016-08-12 18:38:43 +02:00
int nargs = int(args.size());
ret.set_null();
++rundepth;
2016-08-17 04:57:53 +02:00
if (rundepth > MaxRunDepth) {
cs_debug_code(*this, "exceeded recursion limit");
} else if (id) {
2016-08-18 03:53:51 +02:00
switch (id->get_type()) {
2016-08-17 04:57:53 +02:00
default:
2016-08-17 23:04:43 +02:00
if (!cs_has_cmd_cb(id)) {
2016-08-17 04:57:53 +02:00
break;
}
/* fallthrough */
2016-08-29 19:17:11 +02:00
case CsIdentType::command:
2016-08-17 23:04:43 +02:00
if (nargs < static_cast<Command *>(id)->numargs) {
2016-08-18 20:38:30 +02:00
CsValue buf[MaxArguments];
memcpy(buf, args.data(), args.size() * sizeof(CsValue));
2016-08-17 23:04:43 +02:00
callcommand(
*this, static_cast<Command *>(id), buf, ret,
nargs, false
);
2016-08-17 04:57:53 +02:00
} else {
2016-08-17 23:04:43 +02:00
callcommand(
*this, static_cast<Command *>(id), args.data(),
ret, nargs, false
);
2016-08-17 04:57:53 +02:00
}
nargs = 0;
break;
2016-08-29 19:17:11 +02:00
case CsIdentType::ivar:
2016-08-17 04:57:53 +02:00
if (args.empty()) {
2016-08-29 19:17:11 +02:00
print_var(static_cast<CsIvar *>(id));
2016-08-17 04:57:53 +02:00
} else {
2016-08-29 19:17:11 +02:00
set_var_int_checked(static_cast<CsIvar *>(id), args);
2016-08-17 04:57:53 +02:00
}
break;
2016-08-29 19:17:11 +02:00
case CsIdentType::fvar:
2016-08-17 04:57:53 +02:00
if (args.empty()) {
2016-08-29 19:17:11 +02:00
print_var(static_cast<CsFvar *>(id));
2016-08-17 04:57:53 +02:00
} else {
2016-08-17 23:29:31 +02:00
set_var_float_checked(
2016-08-29 19:17:11 +02:00
static_cast<CsFvar *>(id), args[0].force_float()
2016-08-17 23:29:31 +02:00
);
2016-08-17 04:57:53 +02:00
}
break;
2016-08-29 19:17:11 +02:00
case CsIdentType::svar:
2016-08-17 04:57:53 +02:00
if (args.empty()) {
2016-08-29 19:17:11 +02:00
print_var(static_cast<CsSvar *>(id));
2016-08-17 04:57:53 +02:00
} else {
2016-08-17 23:29:31 +02:00
set_var_str_checked(
2016-08-29 19:17:11 +02:00
static_cast<CsSvar *>(id), args[0].force_str()
2016-08-17 23:29:31 +02:00
);
2016-08-17 04:57:53 +02:00
}
break;
2016-08-29 19:17:11 +02:00
case CsIdentType::alias: {
CsAlias *a = static_cast<CsAlias *>(id);
2016-08-18 03:53:51 +02:00
if (a->get_index() < MaxArguments) {
2016-08-20 17:40:00 +02:00
if (!(p_stack->usedargs & (1 << a->get_index()))) {
2016-08-17 04:57:53 +02:00
break;
}
}
2016-08-31 20:18:53 +02:00
if (a->get_value().get_type() == CsValueType::null) {
2016-08-17 04:57:53 +02:00
break;
}
cs_call_alias(
2016-08-18 00:06:39 +02:00
*this, a, args.data(), ret, nargs, nargs, 0, 0, RET_NULL
2016-08-17 04:57:53 +02:00
);
break;
2016-08-18 00:06:39 +02:00
}
2016-08-12 18:38:43 +02:00
}
2016-08-17 04:57:53 +02:00
}
2016-08-12 18:38:43 +02:00
free_args(args.data(), nargs, 0);
--rundepth;
}
2016-08-30 22:29:09 +02:00
CsString CsState::run_str(CsBytecode *code) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-12 18:38:43 +02:00
run_ret(code, ret);
2016-08-21 02:34:03 +02:00
CsString s = ret.get_str();
2016-08-12 18:38:43 +02:00
ret.cleanup();
return s;
}
2016-08-21 02:34:03 +02:00
CsString CsState::run_str(ostd::ConstCharRange code) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-12 18:38:43 +02:00
run_ret(code, ret);
2016-08-21 02:34:03 +02:00
CsString s = ret.get_str();
2016-08-12 18:38:43 +02:00
ret.cleanup();
return s;
}
2016-08-29 19:17:11 +02:00
CsString CsState::run_str(CsIdent *id, CsValueRange args) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-12 18:38:43 +02:00
run_ret(id, args, ret);
2016-08-21 02:34:03 +02:00
CsString s = ret.get_str();
2016-08-12 18:38:43 +02:00
ret.cleanup();
return s;
}
2016-08-30 22:29:09 +02:00
CsInt CsState::run_int(CsBytecode *code) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-12 18:38:43 +02:00
run_ret(code, ret);
2016-08-14 18:35:38 +02:00
CsInt i = ret.get_int();
2016-08-12 18:38:43 +02:00
ret.cleanup();
return i;
}
2016-08-14 18:35:38 +02:00
CsInt CsState::run_int(ostd::ConstCharRange code) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-12 18:38:43 +02:00
run_ret(code, ret);
2016-08-14 18:35:38 +02:00
CsInt i = ret.get_int();
2016-08-12 18:38:43 +02:00
ret.cleanup();
return i;
}
2016-08-29 19:17:11 +02:00
CsInt CsState::run_int(CsIdent *id, CsValueRange args) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-12 18:38:43 +02:00
run_ret(id, args, ret);
2016-08-14 18:35:38 +02:00
CsInt i = ret.get_int();
2016-08-12 18:38:43 +02:00
ret.cleanup();
return i;
}
2016-08-30 22:29:09 +02:00
CsFloat CsState::run_float(CsBytecode *code) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-12 18:38:43 +02:00
run_ret(code, ret);
2016-08-14 18:35:38 +02:00
CsFloat f = ret.get_float();
2016-08-12 18:38:43 +02:00
ret.cleanup();
return f;
}
2016-08-14 18:35:38 +02:00
CsFloat CsState::run_float(ostd::ConstCharRange code) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-12 18:38:43 +02:00
run_ret(code, ret);
2016-08-14 18:35:38 +02:00
CsFloat f = ret.get_float();
2016-08-12 18:38:43 +02:00
ret.cleanup();
return f;
}
2016-08-29 19:17:11 +02:00
CsFloat CsState::run_float(CsIdent *id, CsValueRange args) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-12 18:38:43 +02:00
run_ret(id, args, ret);
2016-08-14 18:35:38 +02:00
CsFloat f = ret.get_float();
2016-08-12 18:38:43 +02:00
ret.cleanup();
return f;
}
2016-08-30 22:29:09 +02:00
bool CsState::run_bool(CsBytecode *code) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-12 18:38:43 +02:00
run_ret(code, ret);
bool b = ret.get_bool();
ret.cleanup();
return b;
}
bool CsState::run_bool(ostd::ConstCharRange code) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-12 18:38:43 +02:00
run_ret(code, ret);
bool b = ret.get_bool();
ret.cleanup();
return b;
}
2016-08-29 19:17:11 +02:00
bool CsState::run_bool(CsIdent *id, CsValueRange args) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-12 18:38:43 +02:00
run_ret(id, args, ret);
bool b = ret.get_bool();
ret.cleanup();
return b;
}
2016-08-30 22:29:09 +02:00
void CsState::run(CsBytecode *code) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-18 20:34:24 +02:00
run_ret(code, ret);
ret.cleanup();
}
void CsState::run(ostd::ConstCharRange code) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-18 20:34:24 +02:00
run_ret(code, ret);
ret.cleanup();
}
2016-08-29 19:17:11 +02:00
void CsState::run(CsIdent *id, CsValueRange args) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-18 20:34:24 +02:00
run_ret(id, args, ret);
ret.cleanup();
}
static bool cs_run_file(
2016-08-18 20:38:30 +02:00
CsState &cs, ostd::ConstCharRange fname, CsValue &ret
2016-08-18 20:34:24 +02:00
) {
ostd::ConstCharRange old_src_file = cs_src_file, old_src_str = cs_src_str;
2016-08-13 01:26:16 +02:00
ostd::Box<char[]> buf;
2016-08-12 18:38:43 +02:00
ostd::Size len;
ostd::FileStream f(fname, ostd::StreamMode::read);
2016-08-17 04:57:53 +02:00
if (!f.is_open()) {
2016-08-12 18:38:43 +02:00
return false;
2016-08-17 04:57:53 +02:00
}
2016-08-12 18:38:43 +02:00
len = f.size();
2016-08-13 01:26:16 +02:00
buf = ostd::make_box<char[]>(len + 1);
if (!buf || f.get(buf.get(), len) != len) {
2016-08-12 18:38:43 +02:00
return false;
}
buf[len] = '\0';
ostd::ConstCharRange src_str = ostd::ConstCharRange(buf.get(), len);
cs_src_file = fname;
cs_src_str = src_str;
cs.run_ret(src_str, ret);
cs_src_file = old_src_file;
cs_src_str = old_src_str;
2016-08-18 20:34:24 +02:00
return true;
}
2016-08-21 02:34:03 +02:00
ostd::Maybe<CsString> CsState::run_file_str(ostd::ConstCharRange fname) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-18 20:34:24 +02:00
if (!cs_run_file(*this, fname, ret)) {
return ostd::nothing;
}
2016-08-21 02:34:03 +02:00
CsString s = ret.get_str();
2016-08-18 20:34:24 +02:00
ret.cleanup();
return ostd::move(s);
}
ostd::Maybe<CsInt> CsState::run_file_int(ostd::ConstCharRange fname) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-18 20:34:24 +02:00
if (!cs_run_file(*this, fname, ret)) {
return ostd::nothing;
}
CsInt i = ret.get_int();
ret.cleanup();
return i;
}
ostd::Maybe<CsFloat> CsState::run_file_float(ostd::ConstCharRange fname) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-18 20:34:24 +02:00
if (!cs_run_file(*this, fname, ret)) {
return ostd::nothing;
}
CsFloat f = ret.get_float();
ret.cleanup();
return f;
}
ostd::Maybe<bool> CsState::run_file_bool(ostd::ConstCharRange fname) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-18 20:34:24 +02:00
if (!cs_run_file(*this, fname, ret)) {
return ostd::nothing;
}
bool i = ret.get_bool();
ret.cleanup();
return i;
}
2016-08-18 20:38:30 +02:00
bool CsState::run_file_ret(ostd::ConstCharRange fname, CsValue &ret) {
2016-08-18 20:34:24 +02:00
return cs_run_file(*this, fname, ret);
}
bool CsState::run_file(ostd::ConstCharRange fname) {
2016-08-18 20:38:30 +02:00
CsValue ret;
2016-08-18 20:34:24 +02:00
if (!cs_run_file(*this, fname, ret)) {
return false;
}
ret.cleanup();
2016-08-12 18:38:43 +02:00
return true;
}
} /* namespace cscript */