2015-08-08 16:13:19 +00:00
|
|
|
#include "cubescript.hh"
|
2016-08-12 16:38:43 +00:00
|
|
|
#include "cs_vm.hh"
|
2016-08-15 01:19:59 +00:00
|
|
|
#include "cs_util.hh"
|
2015-08-08 16:13:19 +00:00
|
|
|
|
2015-08-08 15:13:46 +00:00
|
|
|
namespace cscript {
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
ostd::String intstr(CsInt v) {
|
2016-07-13 18:24:26 +00:00
|
|
|
char buf[256];
|
2016-08-14 16:35:38 +00:00
|
|
|
snprintf(buf, sizeof(buf), IntFormat, v);
|
2016-07-13 18:24:26 +00:00
|
|
|
return buf;
|
2015-08-11 21:01:56 +00:00
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
ostd::String floatstr(CsFloat v) {
|
2016-07-13 18:24:26 +00:00
|
|
|
char buf[256];
|
2016-08-14 16:35:38 +00:00
|
|
|
snprintf(buf, sizeof(buf), v == CsInt(v) ? RoundFloatFormat : FloatFormat, v);
|
2016-07-13 18:24:26 +00:00
|
|
|
return buf;
|
2015-08-11 21:01:56 +00:00
|
|
|
}
|
|
|
|
|
2016-08-02 00:21:36 +00:00
|
|
|
char *cs_dup_ostr(ostd::ConstCharRange s) {
|
2015-08-11 21:16:20 +00:00
|
|
|
char *r = new char[s.size() + 1];
|
|
|
|
memcpy(r, s.data(), s.size());
|
|
|
|
r[s.size()] = 0;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2016-08-12 16:38:43 +00:00
|
|
|
bool cs_check_num(ostd::ConstCharRange s) {
|
2015-08-06 22:16:02 +00:00
|
|
|
if (isdigit(s[0]))
|
|
|
|
return true;
|
|
|
|
switch (s[0]) {
|
|
|
|
case '+':
|
|
|
|
case '-':
|
|
|
|
return isdigit(s[1]) || (s[1] == '.' && isdigit(s[2]));
|
|
|
|
case '.':
|
|
|
|
return isdigit(s[1]) != 0;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-10 17:33:43 +00:00
|
|
|
Ident::Ident(): type(ID_UNKNOWN) {}
|
|
|
|
|
2016-08-14 15:15:56 +00:00
|
|
|
/* ID_IVAR */
|
2016-08-14 16:35:38 +00:00
|
|
|
Ident::Ident(ostd::ConstCharRange n, CsInt m, CsInt x, CsInt *s,
|
2016-08-01 00:10:21 +00:00
|
|
|
VarCb f, int flagsv)
|
2016-08-14 15:15:56 +00:00
|
|
|
: type(ID_IVAR), flags(flagsv | (m > x ? IDF_READONLY : 0)), name(n),
|
2016-08-01 18:17:13 +00:00
|
|
|
minval(m), maxval(x), cb_var(ostd::move(f)) {
|
2015-08-13 20:08:57 +00:00
|
|
|
storage.ip = s;
|
2015-08-11 21:16:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ID_FVAR */
|
2016-08-14 16:35:38 +00:00
|
|
|
Ident::Ident(ostd::ConstCharRange n, CsFloat m, CsFloat x, CsFloat *s,
|
2016-08-01 00:10:21 +00:00
|
|
|
VarCb f, int flagsv)
|
2016-08-10 17:33:43 +00:00
|
|
|
: type(ID_FVAR), flags(flagsv | (m > x ? IDF_READONLY : 0)), name(n),
|
2016-08-01 18:17:13 +00:00
|
|
|
minvalf(m), maxvalf(x), cb_var(ostd::move(f)) {
|
2015-08-13 20:08:57 +00:00
|
|
|
storage.fp = s;
|
2015-08-11 21:16:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ID_SVAR */
|
2016-08-10 17:33:43 +00:00
|
|
|
Ident::Ident(ostd::ConstCharRange n, char **s, VarCb f, int flagsv)
|
|
|
|
: type(ID_SVAR), flags(flagsv), name(n), cb_var(ostd::move(f)) {
|
2015-08-13 20:08:57 +00:00
|
|
|
storage.sp = s;
|
2015-08-11 21:16:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ID_ALIAS */
|
2016-08-10 17:33:43 +00:00
|
|
|
Ident::Ident(ostd::ConstCharRange n, char *a, int flagsv)
|
|
|
|
: type(ID_ALIAS), valtype(VAL_STR), flags(flagsv), name(n), code(nullptr),
|
2015-08-11 21:16:20 +00:00
|
|
|
stack(nullptr) {
|
|
|
|
val.s = a;
|
2016-08-01 20:46:50 +00:00
|
|
|
val.len = strlen(a);
|
2015-08-11 21:16:20 +00:00
|
|
|
}
|
2016-08-14 16:35:38 +00:00
|
|
|
Ident::Ident(ostd::ConstCharRange n, CsInt a, int flagsv)
|
2016-08-10 17:33:43 +00:00
|
|
|
: type(ID_ALIAS), valtype(VAL_INT), flags(flagsv), name(n), code(nullptr),
|
2015-08-11 21:16:20 +00:00
|
|
|
stack(nullptr) {
|
|
|
|
val.i = a;
|
|
|
|
}
|
2016-08-14 16:35:38 +00:00
|
|
|
Ident::Ident(ostd::ConstCharRange n, CsFloat a, int flagsv)
|
2016-08-10 17:33:43 +00:00
|
|
|
: type(ID_ALIAS), valtype(VAL_FLOAT), flags(flagsv), name(n), code(nullptr),
|
2015-08-11 21:16:20 +00:00
|
|
|
stack(nullptr) {
|
|
|
|
val.f = a;
|
|
|
|
}
|
2016-08-10 17:33:43 +00:00
|
|
|
Ident::Ident(ostd::ConstCharRange n, int flagsv)
|
|
|
|
: type(ID_ALIAS), valtype(VAL_NULL), flags(flagsv), name(n), code(nullptr),
|
2015-08-11 21:16:20 +00:00
|
|
|
stack(nullptr) {
|
|
|
|
}
|
2016-08-10 17:33:43 +00:00
|
|
|
Ident::Ident(ostd::ConstCharRange n, TaggedValue const &v, int flagsv)
|
|
|
|
: type(ID_ALIAS), valtype(v.p_type), flags(flagsv), name(n), code(nullptr),
|
2015-08-11 21:16:20 +00:00
|
|
|
stack(nullptr) {
|
|
|
|
val = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ID_COMMAND */
|
|
|
|
Ident::Ident(int t, ostd::ConstCharRange n, ostd::ConstCharRange args,
|
2016-08-10 17:33:43 +00:00
|
|
|
ostd::Uint32 argmask, int numargs, CmdFunc f)
|
|
|
|
: type(t), numargs(numargs), flags(0), name(n),
|
2016-08-09 23:54:51 +00:00
|
|
|
cargs(!args.empty() ? cs_dup_ostr(args) : nullptr),
|
2016-08-01 18:17:13 +00:00
|
|
|
argmask(argmask), cb_cftv(ostd::move(f)) {
|
2015-08-11 21:16:20 +00:00
|
|
|
}
|
|
|
|
|
2016-08-06 15:34:10 +00:00
|
|
|
void cs_init_lib_base(CsState &cs);
|
|
|
|
|
2016-08-11 17:21:18 +00:00
|
|
|
CsState::CsState() {
|
2016-07-27 17:52:01 +00:00
|
|
|
noalias.id = nullptr;
|
|
|
|
noalias.next = nullptr;
|
|
|
|
noalias.usedargs = (1 << MaxArguments) - 1;
|
|
|
|
noalias.argstack = nullptr;
|
2016-02-06 23:17:28 +00:00
|
|
|
for (int i = 0; i < MaxArguments; ++i) {
|
2015-08-05 21:58:45 +00:00
|
|
|
char buf[32];
|
|
|
|
snprintf(buf, sizeof(buf), "arg%d", i + 1);
|
2016-07-17 17:50:40 +00:00
|
|
|
new_ident(static_cast<char const *>(buf), IDF_ARG);
|
2015-08-05 21:58:45 +00:00
|
|
|
}
|
2015-08-13 18:51:15 +00:00
|
|
|
dummy = new_ident("//dummy");
|
2016-08-10 17:33:43 +00:00
|
|
|
add_ident("numargs", MaxArguments, 0, &numargs);
|
|
|
|
add_ident("dbgalias", 0, 1000, &dbgalias);
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_init_lib_base(*this);
|
2015-08-05 21:58:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CsState::~CsState() {
|
|
|
|
for (Ident &i: idents.iter()) {
|
|
|
|
if (i.type == ID_ALIAS) {
|
2015-08-11 20:41:12 +00:00
|
|
|
i.force_null();
|
2016-08-06 18:12:38 +00:00
|
|
|
delete[] reinterpret_cast<ostd::Uint32 *>(i.code);
|
2015-08-05 21:58:45 +00:00
|
|
|
i.code = nullptr;
|
|
|
|
} else if (i.type == ID_COMMAND || i.type >= ID_LOCAL) {
|
2016-08-09 23:54:51 +00:00
|
|
|
delete[] i.cargs;
|
2015-08-05 21:58:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CsState::clear_override(Ident &id) {
|
|
|
|
if (!(id.flags & IDF_OVERRIDDEN)) return;
|
|
|
|
switch (id.type) {
|
|
|
|
case ID_ALIAS:
|
2015-08-13 21:23:46 +00:00
|
|
|
if (id.get_valtype() == VAL_STR) {
|
2015-08-05 21:58:45 +00:00
|
|
|
if (!id.val.s[0]) break;
|
|
|
|
delete[] id.val.s;
|
|
|
|
}
|
|
|
|
id.clean_code();
|
|
|
|
id.valtype = VAL_STR;
|
2015-08-11 21:16:20 +00:00
|
|
|
id.val.s = cs_dup_ostr("");
|
2016-08-01 20:46:50 +00:00
|
|
|
id.val.len = 0;
|
2015-08-05 21:58:45 +00:00
|
|
|
break;
|
2016-08-14 15:15:56 +00:00
|
|
|
case ID_IVAR:
|
2015-08-13 20:08:57 +00:00
|
|
|
*id.storage.ip = id.overrideval.i;
|
2016-08-01 18:33:40 +00:00
|
|
|
id.changed();
|
2015-08-05 21:58:45 +00:00
|
|
|
break;
|
|
|
|
case ID_FVAR:
|
2015-08-13 20:08:57 +00:00
|
|
|
*id.storage.fp = id.overrideval.f;
|
2016-08-01 18:33:40 +00:00
|
|
|
id.changed();
|
2015-08-05 21:58:45 +00:00
|
|
|
break;
|
|
|
|
case ID_SVAR:
|
2015-08-13 20:08:57 +00:00
|
|
|
delete[] *id.storage.sp;
|
|
|
|
*id.storage.sp = id.overrideval.s;
|
2016-08-01 18:33:40 +00:00
|
|
|
id.changed();
|
2015-08-05 21:58:45 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
id.flags &= ~IDF_OVERRIDDEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CsState::clear_overrides() {
|
|
|
|
for (Ident &id: idents.iter())
|
|
|
|
clear_override(id);
|
|
|
|
}
|
|
|
|
|
2015-08-06 22:16:02 +00:00
|
|
|
Ident *CsState::new_ident(ostd::ConstCharRange name, int flags) {
|
|
|
|
Ident *id = idents.at(name);
|
|
|
|
if (!id) {
|
2015-08-11 20:41:12 +00:00
|
|
|
if (cs_check_num(name)) {
|
2015-08-12 17:50:02 +00:00
|
|
|
cs_debug_code(*this, "number %s is not a valid identifier name",
|
|
|
|
name);
|
2015-08-06 22:16:02 +00:00
|
|
|
return dummy;
|
|
|
|
}
|
2016-08-10 17:33:43 +00:00
|
|
|
id = add_ident(name, flags);
|
2015-08-06 22:16:02 +00:00
|
|
|
}
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ident *CsState::force_ident(TaggedValue &v) {
|
2015-08-13 20:48:03 +00:00
|
|
|
switch (v.get_type()) {
|
2015-08-06 22:16:02 +00:00
|
|
|
case VAL_IDENT:
|
|
|
|
return v.id;
|
|
|
|
case VAL_MACRO:
|
|
|
|
case VAL_CSTR: {
|
2015-08-13 18:51:15 +00:00
|
|
|
Ident *id = new_ident(v.s);
|
2015-08-06 22:16:02 +00:00
|
|
|
v.set_ident(id);
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
case VAL_STR: {
|
2015-08-13 18:51:15 +00:00
|
|
|
Ident *id = new_ident(v.s);
|
2015-08-06 22:16:02 +00:00
|
|
|
delete[] v.s;
|
|
|
|
v.set_ident(id);
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
v.cleanup();
|
|
|
|
v.set_ident(dummy);
|
|
|
|
return dummy;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CsState::reset_var(ostd::ConstCharRange name) {
|
|
|
|
Ident *id = idents.at(name);
|
|
|
|
if (!id) return false;
|
|
|
|
if (id->flags & IDF_READONLY) {
|
2015-08-12 17:50:02 +00:00
|
|
|
cs_debug_code(*this, "variable %s is read only", id->name);
|
2015-08-06 22:16:02 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
clear_override(*id);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CsState::touch_var(ostd::ConstCharRange name) {
|
|
|
|
Ident *id = idents.at(name);
|
|
|
|
if (id) switch (id->type) {
|
2016-08-14 15:15:56 +00:00
|
|
|
case ID_IVAR:
|
2015-08-06 22:16:02 +00:00
|
|
|
case ID_FVAR:
|
|
|
|
case ID_SVAR:
|
2016-08-01 18:33:40 +00:00
|
|
|
id->changed();
|
2015-08-06 22:16:02 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-06 22:38:22 +00:00
|
|
|
void CsState::set_alias(ostd::ConstCharRange name, TaggedValue &v) {
|
2015-08-06 23:09:20 +00:00
|
|
|
Ident *id = idents.at(name);
|
2015-08-06 22:38:22 +00:00
|
|
|
if (id) {
|
|
|
|
switch (id->type) {
|
|
|
|
case ID_ALIAS:
|
2016-02-06 23:17:28 +00:00
|
|
|
if (id->index < MaxArguments)
|
2015-08-11 21:16:20 +00:00
|
|
|
id->set_arg(*this, v);
|
|
|
|
else
|
|
|
|
id->set_alias(*this, v);
|
2015-08-06 22:38:22 +00:00
|
|
|
return;
|
2016-08-14 15:15:56 +00:00
|
|
|
case ID_IVAR:
|
2015-08-07 01:44:51 +00:00
|
|
|
set_var_int_checked(id, v.get_int());
|
2015-08-06 22:38:22 +00:00
|
|
|
break;
|
|
|
|
case ID_FVAR:
|
2015-08-07 01:44:51 +00:00
|
|
|
set_var_float_checked(id, v.get_float());
|
2015-08-06 22:38:22 +00:00
|
|
|
break;
|
|
|
|
case ID_SVAR:
|
2015-08-07 01:44:51 +00:00
|
|
|
set_var_str_checked(id, v.get_str());
|
2015-08-06 22:38:22 +00:00
|
|
|
break;
|
|
|
|
default:
|
2015-08-12 17:50:02 +00:00
|
|
|
cs_debug_code(*this, "cannot redefine builtin %s with an alias",
|
|
|
|
id->name);
|
2015-08-06 22:38:22 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
v.cleanup();
|
2015-08-11 20:41:12 +00:00
|
|
|
} else if (cs_check_num(name)) {
|
2015-08-12 17:50:02 +00:00
|
|
|
cs_debug_code(*this, "cannot alias number %s", name);
|
2015-08-06 22:38:22 +00:00
|
|
|
v.cleanup();
|
|
|
|
} else {
|
2016-08-10 17:33:43 +00:00
|
|
|
add_ident(name, v, identflags);
|
2015-08-06 22:38:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
void CsState::print_var_int(Ident *id, CsInt i) {
|
2015-08-07 20:38:57 +00:00
|
|
|
if (i < 0) {
|
|
|
|
writefln("%s = %d", id->name, i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (id->flags & IDF_HEX) {
|
|
|
|
if (id->maxval == 0xFFFFFF)
|
|
|
|
writefln("%s = 0x%.6X (%d, %d, %d)", id->name,
|
|
|
|
i, (i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF);
|
|
|
|
else
|
|
|
|
writefln("%s = 0x%X", id->name, i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
writefln("%s = %d", id->name, i);
|
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
void CsState::print_var_float(Ident *id, CsFloat f) {
|
2015-08-07 20:38:57 +00:00
|
|
|
writefln("%s = %s", id->name, floatstr(f));
|
|
|
|
}
|
|
|
|
|
|
|
|
void CsState::print_var_str(Ident *id, ostd::ConstCharRange s) {
|
|
|
|
if (ostd::find(s, '"').empty())
|
|
|
|
writefln("%s = \"%s\"", id->name, s);
|
|
|
|
else
|
|
|
|
writefln("%s = [%s]", id->name, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CsState::print_var(Ident *id) {
|
|
|
|
switch (id->type) {
|
2016-08-14 15:15:56 +00:00
|
|
|
case ID_IVAR:
|
2015-08-13 20:08:57 +00:00
|
|
|
print_var_int(id, *id->storage.ip);
|
2015-08-07 20:38:57 +00:00
|
|
|
break;
|
|
|
|
case ID_FVAR:
|
2015-08-13 20:08:57 +00:00
|
|
|
print_var_float(id, *id->storage.fp);
|
2015-08-07 20:38:57 +00:00
|
|
|
break;
|
|
|
|
case ID_SVAR:
|
2015-08-13 20:08:57 +00:00
|
|
|
print_var_str(id, *id->storage.sp);
|
2015-08-07 20:38:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-14 01:02:38 +00:00
|
|
|
void TaggedValue::cleanup() {
|
2015-08-13 20:48:03 +00:00
|
|
|
switch (get_type()) {
|
2015-08-05 21:58:45 +00:00
|
|
|
case VAL_STR:
|
|
|
|
delete[] s;
|
|
|
|
break;
|
|
|
|
case VAL_CODE:
|
2016-08-06 18:12:38 +00:00
|
|
|
ostd::Uint32 *bcode = const_cast<ostd::Uint32 *>(
|
|
|
|
reinterpret_cast<ostd::Uint32 const *>(code)
|
|
|
|
);
|
|
|
|
if (bcode[-1] == CODE_START) {
|
|
|
|
delete[] bcode;
|
2016-07-17 17:50:40 +00:00
|
|
|
}
|
2015-08-05 21:58:45 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-14 01:02:38 +00:00
|
|
|
void TaggedValue::force_null() {
|
2015-08-13 20:48:03 +00:00
|
|
|
if (get_type() == VAL_NULL) return;
|
2015-08-05 21:58:45 +00:00
|
|
|
cleanup();
|
|
|
|
set_null();
|
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
CsFloat TaggedValue::force_float() {
|
|
|
|
CsFloat rf = 0.0f;
|
2015-08-13 20:48:03 +00:00
|
|
|
switch (get_type()) {
|
2015-08-05 21:58:45 +00:00
|
|
|
case VAL_INT:
|
|
|
|
rf = i;
|
|
|
|
break;
|
|
|
|
case VAL_STR:
|
|
|
|
case VAL_MACRO:
|
|
|
|
case VAL_CSTR:
|
2016-08-15 17:55:22 +00:00
|
|
|
rf = cs_parse_float(s);
|
2015-08-05 21:58:45 +00:00
|
|
|
break;
|
|
|
|
case VAL_FLOAT:
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
cleanup();
|
|
|
|
set_float(rf);
|
|
|
|
return rf;
|
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
CsInt TaggedValue::force_int() {
|
|
|
|
CsInt ri = 0;
|
2015-08-13 20:48:03 +00:00
|
|
|
switch (get_type()) {
|
2015-08-05 21:58:45 +00:00
|
|
|
case VAL_FLOAT:
|
|
|
|
ri = f;
|
|
|
|
break;
|
|
|
|
case VAL_STR:
|
|
|
|
case VAL_MACRO:
|
|
|
|
case VAL_CSTR:
|
2016-08-15 17:55:22 +00:00
|
|
|
ri = cs_parse_int(s);
|
2015-08-05 21:58:45 +00:00
|
|
|
break;
|
|
|
|
case VAL_INT:
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
cleanup();
|
|
|
|
set_int(ri);
|
|
|
|
return ri;
|
|
|
|
}
|
|
|
|
|
2015-10-14 01:02:38 +00:00
|
|
|
ostd::ConstCharRange TaggedValue::force_str() {
|
2016-07-13 18:24:26 +00:00
|
|
|
ostd::String rs;
|
2015-08-13 20:48:03 +00:00
|
|
|
switch (get_type()) {
|
2015-08-05 21:58:45 +00:00
|
|
|
case VAL_FLOAT:
|
2016-07-13 18:24:26 +00:00
|
|
|
rs = ostd::move(floatstr(f));
|
2015-08-05 21:58:45 +00:00
|
|
|
break;
|
|
|
|
case VAL_INT:
|
2016-07-13 18:24:26 +00:00
|
|
|
rs = ostd::move(intstr(i));
|
2015-08-05 21:58:45 +00:00
|
|
|
break;
|
|
|
|
case VAL_MACRO:
|
|
|
|
case VAL_CSTR:
|
2016-08-01 20:46:50 +00:00
|
|
|
rs = ostd::ConstCharRange(s, len);
|
2015-08-05 21:58:45 +00:00
|
|
|
break;
|
|
|
|
case VAL_STR:
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
cleanup();
|
2016-07-13 18:24:26 +00:00
|
|
|
set_str(ostd::move(rs));
|
2015-08-11 21:47:25 +00:00
|
|
|
return s;
|
2015-08-05 21:58:45 +00:00
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
static inline CsInt cs_get_int(IdentValue const &v, int type) {
|
2015-08-11 20:41:12 +00:00
|
|
|
switch (type) {
|
|
|
|
case VAL_FLOAT:
|
2016-08-14 16:35:38 +00:00
|
|
|
return CsInt(v.f);
|
2015-08-11 20:41:12 +00:00
|
|
|
case VAL_INT:
|
|
|
|
return v.i;
|
|
|
|
case VAL_STR:
|
|
|
|
case VAL_MACRO:
|
|
|
|
case VAL_CSTR:
|
2016-08-15 17:55:22 +00:00
|
|
|
return cs_parse_int(v.s);
|
2015-08-11 20:41:12 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
CsInt TaggedValue::get_int() const {
|
2015-08-13 20:48:03 +00:00
|
|
|
return cs_get_int(*this, get_type());
|
2015-08-11 20:41:12 +00:00
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
CsInt Ident::get_int() const {
|
2015-08-13 21:23:46 +00:00
|
|
|
return cs_get_int(val, get_valtype());
|
2015-08-11 20:41:12 +00:00
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
static inline CsFloat cs_get_float(IdentValue const &v, int type) {
|
2015-08-11 20:41:12 +00:00
|
|
|
switch (type) {
|
|
|
|
case VAL_FLOAT:
|
|
|
|
return v.f;
|
|
|
|
case VAL_INT:
|
2016-08-14 16:35:38 +00:00
|
|
|
return CsFloat(v.i);
|
2015-08-11 20:41:12 +00:00
|
|
|
case VAL_STR:
|
|
|
|
case VAL_MACRO:
|
|
|
|
case VAL_CSTR:
|
2016-08-15 17:55:22 +00:00
|
|
|
return cs_parse_float(v.s);
|
2015-08-11 20:41:12 +00:00
|
|
|
}
|
|
|
|
return 0.0f;
|
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
CsFloat TaggedValue::get_float() const {
|
2015-08-13 20:48:03 +00:00
|
|
|
return cs_get_float(*this, get_type());
|
2015-08-11 20:41:12 +00:00
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
CsFloat Ident::get_float() const {
|
2015-08-13 21:23:46 +00:00
|
|
|
return cs_get_float(val, get_valtype());
|
2015-08-11 20:41:12 +00:00
|
|
|
}
|
|
|
|
|
2016-08-06 18:12:38 +00:00
|
|
|
Bytecode *TaggedValue::get_code() const {
|
2016-07-30 20:42:49 +00:00
|
|
|
if (get_type() != VAL_CODE)
|
|
|
|
return nullptr;
|
2016-08-06 18:12:38 +00:00
|
|
|
return const_cast<Bytecode *>(code);
|
2016-07-30 20:42:49 +00:00
|
|
|
}
|
|
|
|
|
2016-08-01 20:35:42 +00:00
|
|
|
Ident *TaggedValue::get_ident() const {
|
|
|
|
if (get_type() != VAL_IDENT)
|
|
|
|
return nullptr;
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2016-08-01 20:46:50 +00:00
|
|
|
static inline ostd::String cs_get_str(IdentValue const &v, int type) {
|
2015-08-11 21:01:56 +00:00
|
|
|
switch (type) {
|
|
|
|
case VAL_STR:
|
|
|
|
case VAL_MACRO:
|
|
|
|
case VAL_CSTR:
|
2016-08-01 20:46:50 +00:00
|
|
|
return ostd::ConstCharRange(v.s, v.len);
|
2015-08-11 21:01:56 +00:00
|
|
|
case VAL_INT:
|
|
|
|
return intstr(v.i);
|
|
|
|
case VAL_FLOAT:
|
|
|
|
return floatstr(v.f);
|
|
|
|
}
|
2016-07-13 18:24:26 +00:00
|
|
|
return ostd::String("");
|
2015-08-11 21:01:56 +00:00
|
|
|
}
|
|
|
|
|
2016-07-13 18:24:26 +00:00
|
|
|
ostd::String TaggedValue::get_str() const {
|
2016-08-01 20:46:50 +00:00
|
|
|
return cs_get_str(*this, get_type());
|
2015-08-11 21:01:56 +00:00
|
|
|
}
|
|
|
|
|
2016-07-13 18:24:26 +00:00
|
|
|
ostd::String Ident::get_str() const {
|
2016-08-01 20:46:50 +00:00
|
|
|
return cs_get_str(val, get_valtype());
|
2015-08-11 21:01:56 +00:00
|
|
|
}
|
|
|
|
|
2016-08-01 20:46:50 +00:00
|
|
|
static inline ostd::ConstCharRange cs_get_strr(IdentValue const &v, int type) {
|
2016-07-30 23:49:32 +00:00
|
|
|
switch (type) {
|
|
|
|
case VAL_STR:
|
|
|
|
case VAL_MACRO:
|
|
|
|
case VAL_CSTR:
|
2016-08-01 20:46:50 +00:00
|
|
|
return ostd::ConstCharRange(v.s, v.len);
|
2016-07-30 23:49:32 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ostd::ConstCharRange();
|
|
|
|
}
|
|
|
|
|
|
|
|
ostd::ConstCharRange TaggedValue::get_strr() const {
|
2016-08-01 20:46:50 +00:00
|
|
|
return cs_get_strr(*this, get_type());
|
2016-07-30 23:49:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ostd::ConstCharRange Ident::get_strr() const {
|
2016-08-01 20:46:50 +00:00
|
|
|
return cs_get_strr(val, get_valtype());
|
2016-07-30 23:49:32 +00:00
|
|
|
}
|
|
|
|
|
2016-08-01 20:46:50 +00:00
|
|
|
static inline void cs_get_val(IdentValue const &v, int type, TaggedValue &r) {
|
2015-08-11 20:41:12 +00:00
|
|
|
switch (type) {
|
|
|
|
case VAL_STR:
|
|
|
|
case VAL_MACRO:
|
2015-08-13 21:46:03 +00:00
|
|
|
case VAL_CSTR: {
|
2016-08-01 20:46:50 +00:00
|
|
|
r.set_str(ostd::ConstCharRange(v.s, v.len));
|
2015-08-11 20:41:12 +00:00
|
|
|
break;
|
2015-08-13 21:46:03 +00:00
|
|
|
}
|
2015-08-11 20:41:12 +00:00
|
|
|
case VAL_INT:
|
|
|
|
r.set_int(v.i);
|
|
|
|
break;
|
|
|
|
case VAL_FLOAT:
|
|
|
|
r.set_float(v.f);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
r.set_null();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-14 01:02:38 +00:00
|
|
|
void TaggedValue::get_val(TaggedValue &r) const {
|
2016-08-01 20:46:50 +00:00
|
|
|
cs_get_val(*this, get_type(), r);
|
2015-08-11 20:41:12 +00:00
|
|
|
}
|
|
|
|
|
2015-10-14 01:02:38 +00:00
|
|
|
void Ident::get_val(TaggedValue &r) const {
|
2016-08-01 20:46:50 +00:00
|
|
|
cs_get_val(val, get_valtype(), r);
|
2015-08-11 20:41:12 +00:00
|
|
|
}
|
|
|
|
|
2016-08-14 15:05:55 +00:00
|
|
|
OSTD_EXPORT bool code_is_empty(Bytecode const *code) {
|
|
|
|
if (!code) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return (*reinterpret_cast<
|
|
|
|
ostd::Uint32 const *
|
|
|
|
>(code) & CODE_OP_MASK) == CODE_EXIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TaggedValue::code_is_empty() const {
|
|
|
|
if (get_type() != VAL_CODE) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return cscript::code_is_empty(code);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool cs_get_bool(ostd::ConstCharRange s) {
|
2016-08-15 01:19:59 +00:00
|
|
|
if (s.empty()) {
|
2016-08-14 15:05:55 +00:00
|
|
|
return false;
|
|
|
|
}
|
2016-08-15 01:19:59 +00:00
|
|
|
ostd::ConstCharRange end = s;
|
2016-08-15 17:55:22 +00:00
|
|
|
CsInt ival = cs_parse_int(end, &end);
|
2016-08-15 01:19:59 +00:00
|
|
|
if (end.empty()) {
|
|
|
|
return !!ival;
|
|
|
|
}
|
|
|
|
end = s;
|
2016-08-15 17:55:22 +00:00
|
|
|
CsFloat fval = cs_parse_float(end, &end);
|
2016-08-15 01:19:59 +00:00
|
|
|
if (end.empty()) {
|
|
|
|
return !!fval;
|
2016-08-14 15:05:55 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TaggedValue::get_bool() const {
|
|
|
|
switch (get_type()) {
|
|
|
|
case VAL_FLOAT:
|
|
|
|
return f != 0;
|
|
|
|
case VAL_INT:
|
|
|
|
return i != 0;
|
|
|
|
case VAL_STR:
|
|
|
|
case VAL_MACRO:
|
|
|
|
case VAL_CSTR:
|
|
|
|
return cs_get_bool(ostd::ConstCharRange(s, len));
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-14 01:02:38 +00:00
|
|
|
void Ident::get_cstr(TaggedValue &v) const {
|
2015-08-13 21:23:46 +00:00
|
|
|
switch (get_valtype()) {
|
2015-08-11 20:41:12 +00:00
|
|
|
case VAL_MACRO:
|
2016-08-12 17:14:07 +00:00
|
|
|
v.set_macro(val.code, val.len);
|
2015-08-11 20:41:12 +00:00
|
|
|
break;
|
|
|
|
case VAL_STR:
|
|
|
|
case VAL_CSTR:
|
2016-08-01 20:46:50 +00:00
|
|
|
v.set_cstr(ostd::ConstCharRange(val.s, val.len));
|
2015-08-11 20:41:12 +00:00
|
|
|
break;
|
|
|
|
case VAL_INT:
|
2016-07-13 18:24:26 +00:00
|
|
|
v.set_str(ostd::move(intstr(val.i)));
|
2015-08-11 20:41:12 +00:00
|
|
|
break;
|
|
|
|
case VAL_FLOAT:
|
2016-07-13 18:24:26 +00:00
|
|
|
v.set_str(ostd::move(floatstr(val.f)));
|
2015-08-11 20:41:12 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
v.set_cstr("");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-14 01:02:38 +00:00
|
|
|
void Ident::get_cval(TaggedValue &v) const {
|
2015-08-13 21:23:46 +00:00
|
|
|
switch (get_valtype()) {
|
2015-08-11 20:41:12 +00:00
|
|
|
case VAL_MACRO:
|
2016-08-12 17:14:07 +00:00
|
|
|
v.set_macro(val.code, val.len);
|
2015-08-11 20:41:12 +00:00
|
|
|
break;
|
|
|
|
case VAL_STR:
|
|
|
|
case VAL_CSTR:
|
2016-08-01 20:46:50 +00:00
|
|
|
v.set_cstr(ostd::ConstCharRange(val.s, val.len));
|
2015-08-11 20:41:12 +00:00
|
|
|
break;
|
|
|
|
case VAL_INT:
|
|
|
|
v.set_int(val.i);
|
|
|
|
break;
|
|
|
|
case VAL_FLOAT:
|
|
|
|
v.set_float(val.f);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
v.set_null();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-05 21:58:45 +00:00
|
|
|
void Ident::clean_code() {
|
2016-08-06 18:12:38 +00:00
|
|
|
ostd::Uint32 *bcode = reinterpret_cast<ostd::Uint32 *>(code);
|
|
|
|
if (bcode) {
|
2016-08-12 23:26:16 +00:00
|
|
|
bcode_decr(bcode);
|
2015-08-05 21:58:45 +00:00
|
|
|
code = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-17 17:50:40 +00:00
|
|
|
void Ident::push_arg(TaggedValue const &v, IdentStack &st, bool um) {
|
2015-08-06 22:02:56 +00:00
|
|
|
st.val = val;
|
|
|
|
st.valtype = valtype;
|
|
|
|
st.next = stack;
|
|
|
|
stack = &st;
|
2015-08-11 20:41:12 +00:00
|
|
|
set_value(v);
|
2015-08-06 22:02:56 +00:00
|
|
|
clean_code();
|
2015-08-13 18:11:54 +00:00
|
|
|
if (um)
|
|
|
|
flags &= ~IDF_UNKNOWN;
|
2015-08-06 22:02:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Ident::pop_arg() {
|
|
|
|
if (!stack) return;
|
|
|
|
IdentStack *st = stack;
|
2015-08-13 21:23:46 +00:00
|
|
|
if (get_valtype() == VAL_STR) delete[] val.s;
|
2015-08-11 20:41:12 +00:00
|
|
|
set_value(*stack);
|
2015-08-06 22:02:56 +00:00
|
|
|
clean_code();
|
|
|
|
stack = st->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Ident::undo_arg(IdentStack &st) {
|
|
|
|
IdentStack *prev = stack;
|
|
|
|
st.val = val;
|
|
|
|
st.valtype = valtype;
|
|
|
|
st.next = prev;
|
|
|
|
stack = prev->next;
|
2015-08-11 20:41:12 +00:00
|
|
|
set_value(*prev);
|
2015-08-06 22:02:56 +00:00
|
|
|
clean_code();
|
|
|
|
}
|
|
|
|
|
2016-07-17 17:50:40 +00:00
|
|
|
void Ident::redo_arg(IdentStack const &st) {
|
2015-08-06 22:02:56 +00:00
|
|
|
IdentStack *prev = st.next;
|
|
|
|
prev->val = val;
|
|
|
|
prev->valtype = valtype;
|
|
|
|
stack = prev;
|
2015-08-11 20:41:12 +00:00
|
|
|
set_value(st);
|
2015-08-06 22:02:56 +00:00
|
|
|
clean_code();
|
|
|
|
}
|
|
|
|
|
2015-08-06 22:16:02 +00:00
|
|
|
void Ident::push_alias(IdentStack &stack) {
|
2016-02-06 23:17:28 +00:00
|
|
|
if (type == ID_ALIAS && index >= MaxArguments)
|
2015-08-06 22:16:02 +00:00
|
|
|
push_arg(null_value, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Ident::pop_alias() {
|
2016-02-06 23:17:28 +00:00
|
|
|
if (type == ID_ALIAS && index >= MaxArguments) pop_arg();
|
2015-08-06 22:16:02 +00:00
|
|
|
}
|
|
|
|
|
2015-08-06 22:38:22 +00:00
|
|
|
void Ident::set_arg(CsState &cs, TaggedValue &v) {
|
|
|
|
if (cs.stack->usedargs & (1 << index)) {
|
2015-08-13 21:23:46 +00:00
|
|
|
if (get_valtype() == VAL_STR) delete[] val.s;
|
2015-08-11 20:41:12 +00:00
|
|
|
set_value(v);
|
2015-08-06 22:38:22 +00:00
|
|
|
clean_code();
|
|
|
|
} else {
|
2015-08-13 18:11:54 +00:00
|
|
|
push_arg(v, cs.stack->argstack[index], false);
|
2015-08-06 22:38:22 +00:00
|
|
|
cs.stack->usedargs |= 1 << index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Ident::set_alias(CsState &cs, TaggedValue &v) {
|
2015-08-13 21:23:46 +00:00
|
|
|
if (get_valtype() == VAL_STR) delete[] val.s;
|
2015-08-11 20:41:12 +00:00
|
|
|
set_value(v);
|
2015-08-06 22:38:22 +00:00
|
|
|
clean_code();
|
|
|
|
flags = (flags & cs.identflags) | cs.identflags;
|
|
|
|
}
|
|
|
|
|
2016-08-10 17:33:43 +00:00
|
|
|
IdentType Ident::get_type() const {
|
|
|
|
if (type > ID_ALIAS) {
|
|
|
|
return IdentType::unknown;
|
|
|
|
}
|
|
|
|
return IdentType(type);
|
|
|
|
}
|
|
|
|
|
2015-08-07 01:11:53 +00:00
|
|
|
template<typename SF, typename RF, typename CF>
|
|
|
|
bool cs_override_var(CsState &cs, Ident *id, SF sf, RF rf, CF cf) {
|
|
|
|
if ((cs.identflags & IDF_OVERRIDDEN) || (id->flags & IDF_OVERRIDE)) {
|
|
|
|
if (id->flags & IDF_PERSIST) {
|
2015-08-12 17:50:02 +00:00
|
|
|
cs_debug_code(cs, "cannot override persistent variable '%s'",
|
2015-08-07 01:11:53 +00:00
|
|
|
id->name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!(id->flags & IDF_OVERRIDDEN)) {
|
|
|
|
sf();
|
|
|
|
id->flags |= IDF_OVERRIDDEN;
|
|
|
|
} else cf();
|
|
|
|
} else {
|
|
|
|
if (id->flags & IDF_OVERRIDDEN) {
|
|
|
|
rf();
|
|
|
|
id->flags &= ~IDF_OVERRIDDEN;
|
|
|
|
}
|
|
|
|
cf();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
void CsState::set_var_int(ostd::ConstCharRange name, CsInt v,
|
2015-08-07 01:11:53 +00:00
|
|
|
bool dofunc, bool doclamp) {
|
|
|
|
Ident *id = idents.at(name);
|
2016-08-14 15:15:56 +00:00
|
|
|
if (!id || id->type != ID_IVAR)
|
2015-08-07 01:11:53 +00:00
|
|
|
return;
|
|
|
|
bool success = cs_override_var(*this, id,
|
2015-08-13 20:08:57 +00:00
|
|
|
[&id]() { id->overrideval.i = *id->storage.ip; },
|
2015-08-07 01:11:53 +00:00
|
|
|
[]() {}, []() {});
|
|
|
|
if (!success)
|
|
|
|
return;
|
|
|
|
if (doclamp)
|
2015-08-13 20:08:57 +00:00
|
|
|
*id->storage.ip = ostd::clamp(v, id->minval, id->maxval);
|
2015-08-07 01:11:53 +00:00
|
|
|
else
|
2015-08-13 20:08:57 +00:00
|
|
|
*id->storage.ip = v;
|
2015-08-07 01:11:53 +00:00
|
|
|
if (dofunc)
|
2016-08-01 18:33:40 +00:00
|
|
|
id->changed();
|
2015-08-07 01:11:53 +00:00
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
void CsState::set_var_float(ostd::ConstCharRange name, CsFloat v,
|
2015-08-07 01:11:53 +00:00
|
|
|
bool dofunc, bool doclamp) {
|
|
|
|
Ident *id = idents.at(name);
|
|
|
|
if (!id || id->type != ID_FVAR)
|
|
|
|
return;
|
|
|
|
bool success = cs_override_var(*this, id,
|
2015-08-13 20:08:57 +00:00
|
|
|
[&id]() { id->overrideval.f = *id->storage.fp; },
|
2015-08-07 01:11:53 +00:00
|
|
|
[]() {}, []() {});
|
|
|
|
if (!success)
|
|
|
|
return;
|
|
|
|
if (doclamp)
|
2015-08-13 20:08:57 +00:00
|
|
|
*id->storage.fp = ostd::clamp(v, id->minvalf, id->maxvalf);
|
2015-08-07 01:11:53 +00:00
|
|
|
else
|
2015-08-13 20:08:57 +00:00
|
|
|
*id->storage.fp = v;
|
2015-08-07 01:11:53 +00:00
|
|
|
if (dofunc)
|
2016-08-01 18:33:40 +00:00
|
|
|
id->changed();
|
2015-08-07 01:11:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CsState::set_var_str(ostd::ConstCharRange name, ostd::ConstCharRange v,
|
|
|
|
bool dofunc) {
|
|
|
|
Ident *id = idents.at(name);
|
|
|
|
if (!id || id->type != ID_SVAR)
|
|
|
|
return;
|
|
|
|
bool success = cs_override_var(*this, id,
|
2015-08-13 20:08:57 +00:00
|
|
|
[&id]() { id->overrideval.s = *id->storage.sp; },
|
2015-08-07 01:11:53 +00:00
|
|
|
[&id]() { delete[] id->overrideval.s; },
|
2015-08-13 20:08:57 +00:00
|
|
|
[&id]() { delete[] *id->storage.sp; });
|
2015-08-07 01:11:53 +00:00
|
|
|
if (!success)
|
|
|
|
return;
|
2015-08-13 20:08:57 +00:00
|
|
|
*id->storage.sp = cs_dup_ostr(v);
|
2015-08-07 01:11:53 +00:00
|
|
|
if (dofunc)
|
2016-08-01 18:33:40 +00:00
|
|
|
id->changed();
|
2015-08-07 01:11:53 +00:00
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
ostd::Maybe<CsInt> CsState::get_var_int(ostd::ConstCharRange name) {
|
2015-08-07 01:11:53 +00:00
|
|
|
Ident *id = idents.at(name);
|
2016-08-14 15:15:56 +00:00
|
|
|
if (!id || id->type != ID_IVAR)
|
2015-08-07 01:11:53 +00:00
|
|
|
return ostd::nothing;
|
2015-08-13 20:08:57 +00:00
|
|
|
return *id->storage.ip;
|
2015-08-07 01:11:53 +00:00
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
ostd::Maybe<CsFloat> CsState::get_var_float(ostd::ConstCharRange name) {
|
2015-08-07 01:11:53 +00:00
|
|
|
Ident *id = idents.at(name);
|
|
|
|
if (!id || id->type != ID_FVAR)
|
|
|
|
return ostd::nothing;
|
2015-08-13 20:08:57 +00:00
|
|
|
return *id->storage.fp;
|
2015-08-07 01:11:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ostd::Maybe<ostd::String> CsState::get_var_str(ostd::ConstCharRange name) {
|
|
|
|
Ident *id = idents.at(name);
|
|
|
|
if (!id || id->type != ID_SVAR)
|
|
|
|
return ostd::nothing;
|
2015-08-13 20:08:57 +00:00
|
|
|
return ostd::String(*id->storage.sp);
|
2015-08-07 01:11:53 +00:00
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
ostd::Maybe<CsInt> CsState::get_var_min_int(ostd::ConstCharRange name) {
|
2015-08-07 01:11:53 +00:00
|
|
|
Ident *id = idents.at(name);
|
2016-08-14 15:15:56 +00:00
|
|
|
if (!id || id->type != ID_IVAR)
|
2015-08-07 01:11:53 +00:00
|
|
|
return ostd::nothing;
|
|
|
|
return id->minval;
|
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
ostd::Maybe<CsInt> CsState::get_var_max_int(ostd::ConstCharRange name) {
|
2015-08-07 01:11:53 +00:00
|
|
|
Ident *id = idents.at(name);
|
2016-08-14 15:15:56 +00:00
|
|
|
if (!id || id->type != ID_IVAR)
|
2015-08-07 01:11:53 +00:00
|
|
|
return ostd::nothing;
|
|
|
|
return id->maxval;
|
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
ostd::Maybe<CsFloat> CsState::get_var_min_float(ostd::ConstCharRange name) {
|
2015-08-07 01:11:53 +00:00
|
|
|
Ident *id = idents.at(name);
|
|
|
|
if (!id || id->type != ID_FVAR)
|
|
|
|
return ostd::nothing;
|
|
|
|
return id->minvalf;
|
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
ostd::Maybe<CsFloat> CsState::get_var_max_float(ostd::ConstCharRange name) {
|
2015-08-07 01:11:53 +00:00
|
|
|
Ident *id = idents.at(name);
|
|
|
|
if (!id || id->type != ID_FVAR)
|
|
|
|
return ostd::nothing;
|
|
|
|
return id->maxvalf;
|
|
|
|
}
|
|
|
|
|
2016-07-13 18:24:26 +00:00
|
|
|
ostd::Maybe<ostd::String>
|
2015-08-07 01:11:53 +00:00
|
|
|
CsState::get_alias(ostd::ConstCharRange name) {
|
|
|
|
Ident *id = idents.at(name);
|
|
|
|
if (!id || id->type != ID_ALIAS)
|
|
|
|
return ostd::nothing;
|
2016-02-06 23:17:28 +00:00
|
|
|
if ((id->index < MaxArguments) && !(stack->usedargs & (1 << id->index)))
|
2015-08-07 01:11:53 +00:00
|
|
|
return ostd::nothing;
|
2016-07-13 18:24:26 +00:00
|
|
|
return ostd::move(id->get_str());
|
2015-08-07 01:11:53 +00:00
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
CsInt cs_clamp_var(CsState &cs, Ident *id, CsInt v) {
|
2015-08-07 01:44:51 +00:00
|
|
|
if (v < id->minval)
|
|
|
|
v = id->minval;
|
|
|
|
else if (v > id->maxval)
|
|
|
|
v = id->maxval;
|
|
|
|
else
|
|
|
|
return v;
|
2015-08-12 17:50:02 +00:00
|
|
|
cs_debug_code(cs, (id->flags & IDF_HEX)
|
|
|
|
? ((id->minval <= 255)
|
|
|
|
? "valid range for '%s' is %d..0x%X"
|
|
|
|
: "valid range for '%s' is 0x%X..0x%X")
|
|
|
|
: "valid range for '%s' is %d..%d",
|
2015-08-07 01:44:51 +00:00
|
|
|
id->name, id->minval, id->maxval);
|
|
|
|
return v;
|
2015-08-05 21:58:45 +00:00
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
void CsState::set_var_int_checked(Ident *id, CsInt v) {
|
2015-08-07 01:44:51 +00:00
|
|
|
if (id->flags & IDF_READONLY) {
|
2015-08-12 17:50:02 +00:00
|
|
|
cs_debug_code(*this, "variable '%s' is read only", id->name);
|
2015-08-07 01:44:51 +00:00
|
|
|
return;
|
2015-08-05 21:58:45 +00:00
|
|
|
}
|
2015-08-07 01:44:51 +00:00
|
|
|
bool success = cs_override_var(*this, id,
|
2015-08-13 20:08:57 +00:00
|
|
|
[&id]() { id->overrideval.i = *id->storage.ip; },
|
2015-08-07 01:44:51 +00:00
|
|
|
[]() {}, []() {});
|
|
|
|
if (!success)
|
|
|
|
return;
|
|
|
|
if (v < id->minval || v > id->maxval)
|
|
|
|
v = cs_clamp_var(*this, id, v);
|
2015-08-13 20:08:57 +00:00
|
|
|
*id->storage.ip = v;
|
2016-08-01 18:33:40 +00:00
|
|
|
id->changed();
|
2015-08-05 21:58:45 +00:00
|
|
|
}
|
|
|
|
|
2015-08-27 08:16:22 +00:00
|
|
|
void CsState::set_var_int_checked(Ident *id, TvalRange args) {
|
2016-08-14 16:35:38 +00:00
|
|
|
CsInt v = args[0].force_int();
|
2015-08-07 01:44:51 +00:00
|
|
|
if ((id->flags & IDF_HEX) && (args.size() > 1)) {
|
|
|
|
v = (v << 16) | (args[1].force_int() << 8);
|
|
|
|
if (args.size() > 2)
|
|
|
|
v |= args[2].force_int();
|
2015-08-05 21:58:45 +00:00
|
|
|
}
|
2015-08-07 01:44:51 +00:00
|
|
|
set_var_int_checked(id, v);
|
2015-08-05 21:58:45 +00:00
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
CsFloat cs_clamp_fvar(CsState &cs, Ident *id, CsFloat v) {
|
2015-08-07 01:44:51 +00:00
|
|
|
if (v < id->minvalf)
|
|
|
|
v = id->minvalf;
|
|
|
|
else if (v > id->maxvalf)
|
|
|
|
v = id->maxvalf;
|
|
|
|
else
|
|
|
|
return v;
|
2015-08-12 17:50:02 +00:00
|
|
|
cs_debug_code(cs, "valid range for '%s' is %s..%s", floatstr(id->minvalf),
|
2015-08-07 01:44:51 +00:00
|
|
|
floatstr(id->maxvalf));
|
|
|
|
return v;
|
2015-08-05 21:58:45 +00:00
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
void CsState::set_var_float_checked(Ident *id, CsFloat v) {
|
2015-08-07 01:44:51 +00:00
|
|
|
if (id->flags & IDF_READONLY) {
|
2015-08-12 17:50:02 +00:00
|
|
|
cs_debug_code(*this, "variable '%s' is read only", id->name);
|
2015-08-07 01:44:51 +00:00
|
|
|
return;
|
2015-08-05 21:58:45 +00:00
|
|
|
}
|
2015-08-07 01:44:51 +00:00
|
|
|
bool success = cs_override_var(*this, id,
|
2015-08-13 20:08:57 +00:00
|
|
|
[&id]() { id->overrideval.f = *id->storage.fp; },
|
2015-08-07 01:44:51 +00:00
|
|
|
[]() {}, []() {});
|
|
|
|
if (!success)
|
|
|
|
return;
|
|
|
|
if (v < id->minvalf || v > id->maxvalf)
|
|
|
|
v = cs_clamp_fvar(*this, id, v);
|
2015-08-13 20:08:57 +00:00
|
|
|
*id->storage.fp = v;
|
2016-08-01 18:33:40 +00:00
|
|
|
id->changed();
|
2015-08-05 21:58:45 +00:00
|
|
|
}
|
|
|
|
|
2015-08-07 01:44:51 +00:00
|
|
|
void CsState::set_var_str_checked(Ident *id, ostd::ConstCharRange v) {
|
|
|
|
if (id->flags & IDF_READONLY) {
|
2015-08-12 17:50:02 +00:00
|
|
|
cs_debug_code(*this, "variable '%s' is read only", id->name);
|
2015-08-07 01:44:51 +00:00
|
|
|
return;
|
2015-08-05 21:58:45 +00:00
|
|
|
}
|
2015-08-07 01:44:51 +00:00
|
|
|
bool success = cs_override_var(*this, id,
|
2015-08-13 20:08:57 +00:00
|
|
|
[&id]() { id->overrideval.s = *id->storage.sp; },
|
2015-08-07 01:44:51 +00:00
|
|
|
[&id]() { delete[] id->overrideval.s; },
|
2015-08-13 20:08:57 +00:00
|
|
|
[&id]() { delete[] *id->storage.sp; });
|
2015-08-07 01:44:51 +00:00
|
|
|
if (!success) return;
|
2015-08-13 20:08:57 +00:00
|
|
|
*id->storage.sp = cs_dup_ostr(v);
|
2016-08-01 18:33:40 +00:00
|
|
|
id->changed();
|
2015-08-05 21:58:45 +00:00
|
|
|
}
|
|
|
|
|
2016-08-10 17:33:43 +00:00
|
|
|
static bool cs_add_command(
|
|
|
|
CsState &cs, ostd::ConstCharRange name, ostd::ConstCharRange args,
|
|
|
|
CmdFunc func, int type = ID_COMMAND
|
|
|
|
) {
|
2015-08-07 22:37:54 +00:00
|
|
|
ostd::Uint32 argmask = 0;
|
2015-08-05 21:58:45 +00:00
|
|
|
int nargs = 0;
|
|
|
|
ostd::ConstCharRange fmt(args);
|
|
|
|
for (; !fmt.empty(); fmt.pop_front()) {
|
|
|
|
switch (fmt.front()) {
|
|
|
|
case 'i':
|
|
|
|
case 'b':
|
|
|
|
case 'f':
|
|
|
|
case 'F':
|
|
|
|
case 't':
|
|
|
|
case 'T':
|
|
|
|
case 'E':
|
|
|
|
case 'N':
|
|
|
|
case 'D':
|
2016-02-06 23:17:28 +00:00
|
|
|
if (nargs < MaxArguments) nargs++;
|
2015-08-05 21:58:45 +00:00
|
|
|
break;
|
|
|
|
case 'S':
|
|
|
|
case 's':
|
|
|
|
case 'e':
|
|
|
|
case 'r':
|
|
|
|
case '$':
|
2016-02-06 23:17:28 +00:00
|
|
|
if (nargs < MaxArguments) {
|
2015-08-05 21:58:45 +00:00
|
|
|
argmask |= 1 << nargs;
|
|
|
|
nargs++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
2016-02-06 23:17:28 +00:00
|
|
|
if (nargs < MaxArguments)
|
2015-08-05 21:58:45 +00:00
|
|
|
fmt.push_front_n(fmt.front() - '0' + 1);
|
|
|
|
break;
|
|
|
|
case 'C':
|
|
|
|
case 'V':
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ostd::err.writefln("builtin %s declared with illegal type: %c",
|
|
|
|
name, fmt.front());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2016-08-10 17:33:43 +00:00
|
|
|
cs.add_ident(type, name, args, argmask, nargs, ostd::move(func));
|
2015-08-05 21:58:45 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-10 17:33:43 +00:00
|
|
|
bool CsState::add_command(
|
|
|
|
ostd::ConstCharRange name, ostd::ConstCharRange args, CmdFunc func
|
|
|
|
) {
|
|
|
|
return cs_add_command(*this, name, args, ostd::move(func));
|
|
|
|
}
|
|
|
|
|
2016-08-06 15:34:10 +00:00
|
|
|
void cs_init_lib_io(CsState &cs) {
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "exec", "sb", [&cs](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
auto file = args[0].get_strr();
|
|
|
|
bool ret = cs.run_file(file);
|
|
|
|
if (!ret) {
|
|
|
|
if (args[1].get_int())
|
|
|
|
ostd::err.writefln("could not run file \"%s\"", file);
|
2016-08-11 17:14:18 +00:00
|
|
|
res.set_int(0);
|
2016-08-06 15:34:10 +00:00
|
|
|
} else
|
2016-08-11 17:14:18 +00:00
|
|
|
res.set_int(1);
|
2016-08-06 15:34:10 +00:00
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "echo", "C", [](TvalRange args, TaggedValue &) {
|
2016-08-06 15:34:10 +00:00
|
|
|
ostd::writeln(args[0].get_strr());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
static inline void cs_set_iter(Ident &id, CsInt i, IdentStack &stack) {
|
2016-08-06 15:34:10 +00:00
|
|
|
if (id.stack == &stack) {
|
|
|
|
if (id.get_valtype() != VAL_INT) {
|
|
|
|
if (id.get_valtype() == VAL_STR) {
|
|
|
|
delete[] id.val.s;
|
|
|
|
id.val.s = nullptr;
|
|
|
|
id.val.len = 0;
|
|
|
|
}
|
|
|
|
id.clean_code();
|
|
|
|
id.valtype = VAL_INT;
|
|
|
|
}
|
|
|
|
id.val.i = i;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
TaggedValue v;
|
|
|
|
v.set_int(i);
|
|
|
|
id.push_arg(v, stack);
|
|
|
|
}
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
static inline void cs_do_loop(CsState &cs, Ident &id, CsInt offset, CsInt n,
|
|
|
|
CsInt step, Bytecode *cond, Bytecode *body) {
|
2016-08-06 15:34:10 +00:00
|
|
|
if (n <= 0 || (id.type != ID_ALIAS))
|
|
|
|
return;
|
|
|
|
IdentStack stack;
|
2016-08-14 16:35:38 +00:00
|
|
|
for (CsInt i = 0; i < n; ++i) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_set_iter(id, offset + i * step, stack);
|
|
|
|
if (cond && !cs.run_bool(cond)) break;
|
|
|
|
cs.run_int(body);
|
|
|
|
}
|
|
|
|
id.pop_arg();
|
|
|
|
}
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
static inline void cs_loop_conc(
|
2016-08-14 16:35:38 +00:00
|
|
|
CsState &cs, TaggedValue &res, Ident &id, CsInt offset, CsInt n,
|
|
|
|
CsInt step, Bytecode *body, bool space
|
2016-08-11 17:14:18 +00:00
|
|
|
) {
|
2016-08-06 15:34:10 +00:00
|
|
|
if (n <= 0 || id.type != ID_ALIAS)
|
|
|
|
return;
|
|
|
|
IdentStack stack;
|
|
|
|
ostd::Vector<char> s;
|
2016-08-14 16:35:38 +00:00
|
|
|
for (CsInt i = 0; i < n; ++i) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_set_iter(id, offset + i * step, stack);
|
|
|
|
TaggedValue v;
|
|
|
|
cs.run_ret(body, v);
|
|
|
|
ostd::String vstr = ostd::move(v.get_str());
|
|
|
|
if (space && i) s.push(' ');
|
|
|
|
s.push_n(vstr.data(), vstr.size());
|
|
|
|
v.cleanup();
|
|
|
|
}
|
|
|
|
if (n > 0) id.pop_arg();
|
|
|
|
s.push('\0');
|
|
|
|
ostd::Size len = s.size() - 1;
|
2016-08-11 17:14:18 +00:00
|
|
|
res.set_mstr(ostd::CharRange(s.disown(), len));
|
2016-08-06 15:34:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void cs_init_lib_base(CsState &cs) {
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "do", "e", [&cs](TvalRange args, TaggedValue &res) {
|
|
|
|
cs.run_ret(args[0].get_code(), res);
|
2016-08-06 15:34:10 +00:00
|
|
|
}, ID_DO);
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "doargs", "e", [&cs](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
if (cs.stack != &cs.noalias)
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_do_args(cs, [&]() { cs.run_ret(args[0].get_code(), res); });
|
2016-08-06 15:34:10 +00:00
|
|
|
else
|
2016-08-11 17:14:18 +00:00
|
|
|
cs.run_ret(args[0].get_code(), res);
|
2016-08-06 15:34:10 +00:00
|
|
|
}, ID_DOARGS);
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "if", "tee", [&cs](TvalRange args, TaggedValue &res) {
|
|
|
|
cs.run_ret((args[0].get_bool() ? args[1] : args[2]).get_code(), res);
|
2016-08-06 15:34:10 +00:00
|
|
|
}, ID_IF);
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "result", "T", [](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
TaggedValue &v = args[0];
|
2016-08-11 17:14:18 +00:00
|
|
|
res = v;
|
2016-08-06 15:34:10 +00:00
|
|
|
v.set_null();
|
|
|
|
}, ID_RESULT);
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "!", "t", [](TvalRange args, TaggedValue &res) {
|
|
|
|
res.set_int(!args[0].get_bool());
|
2016-08-06 15:34:10 +00:00
|
|
|
}, ID_NOT);
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "&&", "E1V", [&cs](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
if (args.empty())
|
2016-08-11 17:14:18 +00:00
|
|
|
res.set_int(1);
|
2016-08-06 15:34:10 +00:00
|
|
|
else for (ostd::Size i = 0; i < args.size(); ++i) {
|
2016-08-11 17:14:18 +00:00
|
|
|
if (i) res.cleanup();
|
2016-08-06 15:34:10 +00:00
|
|
|
if (args[i].get_type() == VAL_CODE)
|
2016-08-11 17:14:18 +00:00
|
|
|
cs.run_ret(args[i].code, res);
|
2016-08-06 15:34:10 +00:00
|
|
|
else
|
2016-08-11 17:14:18 +00:00
|
|
|
res = args[i];
|
|
|
|
if (!res.get_bool()) break;
|
2016-08-06 15:34:10 +00:00
|
|
|
}
|
|
|
|
}, ID_AND);
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "||", "E1V", [&cs](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
if (args.empty())
|
2016-08-11 17:14:18 +00:00
|
|
|
res.set_int(0);
|
2016-08-06 15:34:10 +00:00
|
|
|
else for (ostd::Size i = 0; i < args.size(); ++i) {
|
2016-08-11 17:14:18 +00:00
|
|
|
if (i) res.cleanup();
|
2016-08-06 15:34:10 +00:00
|
|
|
if (args[i].get_type() == VAL_CODE)
|
2016-08-11 17:14:18 +00:00
|
|
|
cs.run_ret(args[i].code, res);
|
2016-08-06 15:34:10 +00:00
|
|
|
else
|
2016-08-11 17:14:18 +00:00
|
|
|
res = args[i];
|
|
|
|
if (res.get_bool()) break;
|
2016-08-06 15:34:10 +00:00
|
|
|
}
|
|
|
|
}, ID_OR);
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "?", "tTT", [](TvalRange args, TaggedValue &res) {
|
|
|
|
res.set(args[0].get_bool() ? args[1] : args[2]);
|
2016-08-06 15:34:10 +00:00
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "cond", "ee2V", [&cs](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
for (ostd::Size i = 0; i < args.size(); i += 2) {
|
|
|
|
if ((i + 1) < args.size()) {
|
|
|
|
if (cs.run_bool(args[i].code)) {
|
2016-08-11 17:14:18 +00:00
|
|
|
cs.run_ret(args[i + 1].code, res);
|
2016-08-06 15:34:10 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2016-08-11 17:14:18 +00:00
|
|
|
cs.run_ret(args[i].code, res);
|
2016-08-06 15:34:10 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
#define CS_CMD_CASE(name, fmt, type, acc, compare) \
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, name, fmt "te2V", [&cs](TvalRange args, TaggedValue &res) { \
|
2016-08-06 15:34:10 +00:00
|
|
|
type val = ostd::move(acc); \
|
|
|
|
ostd::Size i; \
|
|
|
|
for (i = 1; (i + 1) < args.size(); i += 2) { \
|
|
|
|
if (compare) { \
|
2016-08-11 17:14:18 +00:00
|
|
|
cs.run_ret(args[i + 1].code, res); \
|
2016-08-06 15:34:10 +00:00
|
|
|
return; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
});
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
CS_CMD_CASE("case", "i", CsInt, args[0].get_int(),
|
2016-08-06 15:34:10 +00:00
|
|
|
((args[i].get_type() == VAL_NULL) ||
|
|
|
|
(args[i].get_int() == val)));
|
|
|
|
|
2016-08-14 16:35:38 +00:00
|
|
|
CS_CMD_CASE("casef", "f", CsFloat, args[0].get_float(),
|
2016-08-06 15:34:10 +00:00
|
|
|
((args[i].get_type() == VAL_NULL) ||
|
|
|
|
(args[i].get_float() == val)));
|
|
|
|
|
|
|
|
CS_CMD_CASE("cases", "s", ostd::String, args[0].get_str(),
|
|
|
|
((args[i].get_type() == VAL_NULL) ||
|
|
|
|
(args[i].get_str() == val)));
|
|
|
|
|
|
|
|
#undef CS_CMD_CASE
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "pushif", "rTe", [&cs](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
Ident *id = args[0].get_ident();
|
|
|
|
TaggedValue &v = args[1];
|
2016-08-06 18:12:38 +00:00
|
|
|
Bytecode *code = args[2].get_code();
|
2016-08-06 15:34:10 +00:00
|
|
|
if ((id->type != ID_ALIAS) || (id->index < MaxArguments))
|
|
|
|
return;
|
|
|
|
if (v.get_bool()) {
|
|
|
|
IdentStack stack;
|
|
|
|
id->push_arg(v, stack);
|
|
|
|
v.set_null();
|
2016-08-11 17:14:18 +00:00
|
|
|
cs.run_ret(code, res);
|
2016-08-06 15:34:10 +00:00
|
|
|
id->pop_arg();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "loop", "rie", [&cs](TvalRange args, TaggedValue &) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_do_loop(
|
|
|
|
cs, *args[0].get_ident(), 0, args[1].get_int(), 1, nullptr,
|
|
|
|
args[2].get_code()
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "loop+", "riie", [&cs](TvalRange args, TaggedValue &) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_do_loop(
|
|
|
|
cs, *args[0].get_ident(), args[1].get_int(), args[2].get_int(), 1,
|
|
|
|
nullptr, args[3].get_code()
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "loop*", "riie", [&cs](TvalRange args, TaggedValue &) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_do_loop(
|
|
|
|
cs, *args[0].get_ident(), 0, args[1].get_int(), args[2].get_int(),
|
|
|
|
nullptr, args[3].get_code()
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "loop+*", "riiie", [&cs](TvalRange args, TaggedValue &) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_do_loop(
|
|
|
|
cs, *args[0].get_ident(), args[1].get_int(), args[3].get_int(),
|
|
|
|
args[2].get_int(), nullptr, args[4].get_code()
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "loopwhile", "riee", [&cs](TvalRange args, TaggedValue &) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_do_loop(
|
|
|
|
cs, *args[0].get_ident(), 0, args[1].get_int(), 1,
|
|
|
|
args[2].get_code(), args[3].get_code()
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "loopwhile+", "riiee", [&cs](TvalRange args, TaggedValue &) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_do_loop(
|
|
|
|
cs, *args[0].get_ident(), args[1].get_int(), args[2].get_int(), 1,
|
|
|
|
args[3].get_code(), args[4].get_code()
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "loopwhile*", "riiee", [&cs](TvalRange args, TaggedValue &) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_do_loop(
|
|
|
|
cs, *args[0].get_ident(), 0, args[2].get_int(), args[1].get_int(),
|
|
|
|
args[3].get_code(), args[4].get_code()
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "loopwhile+*", "riiiee", [&cs](TvalRange args, TaggedValue &) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_do_loop(
|
|
|
|
cs, *args[0].get_ident(), args[1].get_int(), args[3].get_int(),
|
|
|
|
args[2].get_int(), args[4].get_code(), args[5].get_code()
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "while", "ee", [&cs](TvalRange args, TaggedValue &) {
|
2016-08-06 18:12:38 +00:00
|
|
|
Bytecode *cond = args[0].get_code(), *body = args[1].get_code();
|
2016-08-06 15:34:10 +00:00
|
|
|
while (cs.run_bool(cond)) {
|
|
|
|
cs.run_int(body);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "loopconcat", "rie", [&cs](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_loop_conc(
|
2016-08-11 17:14:18 +00:00
|
|
|
cs, res, *args[0].get_ident(), 0, args[1].get_int(), 1,
|
2016-08-06 15:34:10 +00:00
|
|
|
args[2].get_code(), true
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "loopconcat+", "riie", [&cs](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_loop_conc(
|
2016-08-11 17:14:18 +00:00
|
|
|
cs, res, *args[0].get_ident(), args[1].get_int(), args[2].get_int(), 1,
|
2016-08-06 15:34:10 +00:00
|
|
|
args[3].get_code(), true
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "loopconcat*", "riie", [&cs](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_loop_conc(
|
2016-08-11 17:14:18 +00:00
|
|
|
cs, res, *args[0].get_ident(), 0, args[2].get_int(), args[1].get_int(),
|
2016-08-06 15:34:10 +00:00
|
|
|
args[3].get_code(), true
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "loopconcat+*", "riiie", [&cs](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_loop_conc(
|
2016-08-11 17:14:18 +00:00
|
|
|
cs, res, *args[0].get_ident(), args[1].get_int(), args[3].get_int(),
|
2016-08-06 15:34:10 +00:00
|
|
|
args[2].get_int(), args[4].get_code(), true
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "loopconcatword", "rie", [&cs](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_loop_conc(
|
2016-08-11 17:14:18 +00:00
|
|
|
cs, res, *args[0].get_ident(), 0, args[1].get_int(), 1,
|
2016-08-06 15:34:10 +00:00
|
|
|
args[2].get_code(), false
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "loopconcatword+", "riie", [&cs](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_loop_conc(
|
2016-08-11 17:14:18 +00:00
|
|
|
cs, res, *args[0].get_ident(), args[1].get_int(), args[2].get_int(), 1,
|
2016-08-06 15:34:10 +00:00
|
|
|
args[3].get_code(), false
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "loopconcatword*", "riie", [&cs](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_loop_conc(
|
2016-08-11 17:14:18 +00:00
|
|
|
cs, res, *args[0].get_ident(), 0, args[2].get_int(), args[1].get_int(),
|
2016-08-06 15:34:10 +00:00
|
|
|
args[3].get_code(), false
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "loopconcatword+*", "riiie", [&cs](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
cs_loop_conc(
|
2016-08-11 17:14:18 +00:00
|
|
|
cs, res, *args[0].get_ident(), args[1].get_int(), args[3].get_int(),
|
2016-08-06 15:34:10 +00:00
|
|
|
args[2].get_int(), args[4].get_code(), false
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "nodebug", "e", [&cs](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
++cs.nodebug;
|
2016-08-11 17:14:18 +00:00
|
|
|
cs.run_ret(args[0].get_code(), res);
|
2016-08-06 15:34:10 +00:00
|
|
|
--cs.nodebug;
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "push", "rTe", [&cs](TvalRange args, TaggedValue &res) {
|
2016-08-06 15:34:10 +00:00
|
|
|
Ident *id = args[0].get_ident();
|
|
|
|
if (id->type != ID_ALIAS || id->index < MaxArguments) return;
|
|
|
|
IdentStack stack;
|
|
|
|
TaggedValue &v = args[1];
|
|
|
|
id->push_arg(v, stack);
|
|
|
|
v.set_null();
|
2016-08-11 17:14:18 +00:00
|
|
|
cs.run_ret(args[2].get_code(), res);
|
2016-08-06 15:34:10 +00:00
|
|
|
id->pop_arg();
|
|
|
|
});
|
|
|
|
|
2016-08-10 17:33:43 +00:00
|
|
|
cs_add_command(cs, "local", nullptr, nullptr, ID_LOCAL);
|
2016-08-06 15:34:10 +00:00
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "resetvar", "s", [&cs](TvalRange args, TaggedValue &res) {
|
|
|
|
res.set_int(cs.reset_var(args[0].get_strr()));
|
2016-08-06 15:34:10 +00:00
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "alias", "sT", [&cs](TvalRange args, TaggedValue &) {
|
2016-08-06 15:34:10 +00:00
|
|
|
TaggedValue &v = args[1];
|
|
|
|
cs.set_alias(args[0].get_strr(), v);
|
|
|
|
v.set_null();
|
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "getvarmin", "s", [&cs](TvalRange args, TaggedValue &res) {
|
|
|
|
res.set_int(cs.get_var_min_int(args[0].get_strr()).value_or(0));
|
2016-08-06 15:34:10 +00:00
|
|
|
});
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "getvarmax", "s", [&cs](TvalRange args, TaggedValue &res) {
|
|
|
|
res.set_int(cs.get_var_max_int(args[0].get_strr()).value_or(0));
|
2016-08-06 15:34:10 +00:00
|
|
|
});
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "getfvarmin", "s", [&cs](TvalRange args, TaggedValue &res) {
|
|
|
|
res.set_float(cs.get_var_min_float(args[0].get_strr()).value_or(0.0f));
|
2016-08-06 15:34:10 +00:00
|
|
|
});
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "getfvarmax", "s", [&cs](TvalRange args, TaggedValue &res) {
|
|
|
|
res.set_float(cs.get_var_max_float(args[0].get_strr()).value_or(0.0f));
|
2016-08-06 15:34:10 +00:00
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "identexists", "s", [&cs](TvalRange args, TaggedValue &res) {
|
|
|
|
res.set_int(cs.have_ident(args[0].get_strr()));
|
2016-08-06 15:34:10 +00:00
|
|
|
});
|
|
|
|
|
2016-08-11 17:14:18 +00:00
|
|
|
cs_add_command(cs, "getalias", "s", [&cs](TvalRange args, TaggedValue &res) {
|
|
|
|
res.set_str(ostd::move(cs.get_alias(args[0].get_strr()).value_or("")));
|
2016-08-06 15:34:10 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-08-02 00:21:36 +00:00
|
|
|
void cs_init_lib_math(CsState &cs);
|
|
|
|
void cs_init_lib_string(CsState &cs);
|
|
|
|
void cs_init_lib_list(CsState &cs);
|
2015-08-08 00:40:29 +00:00
|
|
|
|
2016-03-17 21:21:45 +00:00
|
|
|
OSTD_EXPORT void init_libs(CsState &cs, int libs) {
|
2016-02-28 22:21:28 +00:00
|
|
|
if (libs & CS_LIB_IO ) cs_init_lib_io(cs);
|
|
|
|
if (libs & CS_LIB_MATH ) cs_init_lib_math(cs);
|
|
|
|
if (libs & CS_LIB_STRING) cs_init_lib_string(cs);
|
|
|
|
if (libs & CS_LIB_LIST ) cs_init_lib_list(cs);
|
|
|
|
}
|
|
|
|
|
2016-02-07 21:22:39 +00:00
|
|
|
} /* namespace cscript */
|