libcubescript/src/cs_vm.hh

417 lines
11 KiB
C++
Raw Normal View History

2016-08-12 18:38:43 +02:00
#ifndef LIBCUBESCRIPT_CS_VM_HH
#define LIBCUBESCRIPT_CS_VM_HH
2016-09-07 22:57:28 +02:00
#include "cubescript/cubescript.hh"
2016-08-12 18:38:43 +02:00
2017-02-14 18:33:45 +01:00
#include <cstdlib>
#include <array>
2017-04-23 15:34:45 +02:00
#include <vector>
#include <type_traits>
2016-08-12 18:38:43 +02:00
#include "cs_util.hh"
#include "cs_bcode.hh"
2016-08-12 18:38:43 +02:00
namespace cscript {
static constexpr int MaxArguments = 25;
static constexpr int MaxResults = 7;
static constexpr int DummyIdx = MaxArguments;
static constexpr int NumargsIdx = MaxArguments + 1;
static constexpr int DbgaliasIdx = MaxArguments + 2;
2016-08-12 18:38:43 +02:00
enum {
2016-09-07 20:20:36 +02:00
CsIdUnknown = -1, CsIdIvar, CsIdFvar, CsIdSvar, CsIdCommand, CsIdAlias,
2016-09-15 02:12:22 +02:00
CsIdLocal, CsIdDo, CsIdDoArgs, CsIdIf, CsIdBreak, CsIdContinue, CsIdResult,
CsIdNot, CsIdAnd, CsIdOr
2016-08-12 18:38:43 +02:00
};
2021-03-21 02:41:04 +01:00
struct cs_ident_impl {
cs_ident_impl() = delete;
cs_ident_impl(cs_ident_impl const &) = delete;
cs_ident_impl(cs_ident_impl &&) = delete;
/* trigger destructors for all inherited members properly */
virtual ~cs_ident_impl() {};
cs_ident_impl &operator=(cs_ident_impl const &) = delete;
cs_ident_impl &operator=(cs_ident_impl &&) = delete;
cs_ident_impl(cs_ident_type tp, cs_strref name, int flags = 0);
cs_strref p_name;
/* represents the cs_ident_type above, but internally it has a wider variety
* of values, so it's an int here (maps to an internal enum)
*/
int p_type, p_flags;
int p_index = -1;
};
struct cs_var_impl: cs_ident_impl {
cs_var_impl(cs_ident_type tp, cs_strref name, cs_var_cb func, int flags = 0);
cs_var_cb cb_var;
void changed(cs_state &cs);
};
struct cs_ivar_impl: cs_var_impl, cs_ivar {
cs_ivar_impl(
cs_strref n, cs_int m, cs_int x, cs_int v, cs_var_cb f, int flags
);
cs_int p_storage, p_minval, p_maxval, p_overrideval;
};
struct cs_fvar_impl: cs_var_impl, cs_fvar {
cs_fvar_impl(
cs_strref n, cs_float m, cs_float x, cs_float v,
cs_var_cb f, int flags
);
cs_float p_storage, p_minval, p_maxval, p_overrideval;
};
struct cs_svar_impl: cs_var_impl, cs_svar {
cs_svar_impl(cs_strref n, cs_strref v, cs_strref ov, cs_var_cb f, int flags);
cs_strref p_storage, p_overrideval;
};
struct cs_ident_link {
cs_ident *id;
cs_ident_link *next;
int usedargs;
cs_ident_stack *argstack;
};
static inline bool cs_is_arg_used(cs_state &cs, cs_ident *id) {
if (!cs.p_callstack) {
return true;
}
return cs.p_callstack->usedargs & (1 << id->get_index());
}
2021-03-21 02:41:04 +01:00
struct cs_alias_impl: cs_ident_impl, cs_alias {
cs_alias_impl(cs_state &cs, cs_strref n, cs_strref a, int flags);
cs_alias_impl(cs_state &cs, cs_strref n, std::string_view a, int flags);
cs_alias_impl(cs_state &cs, cs_strref n, cs_int a, int flags);
cs_alias_impl(cs_state &cs, cs_strref n, cs_float a, int flags);
cs_alias_impl(cs_state &cs, cs_strref n, int flags);
cs_alias_impl(cs_state &cs, cs_strref n, cs_value v, int flags);
void push_arg(cs_value &v, cs_ident_stack &st, bool um = true) {
if (p_astack == &st) {
/* prevent cycles and unnecessary code elsewhere */
p_val = std::move(v);
clean_code();
return;
}
st.val_s = std::move(p_val);
st.next = p_astack;
p_astack = &st;
p_val = std::move(v);
clean_code();
if (um) {
p_flags &= ~CS_IDF_UNKNOWN;
}
}
void pop_arg() {
if (!p_astack) {
return;
}
cs_ident_stack *st = p_astack;
p_val = std::move(p_astack->val_s);
clean_code();
p_astack = st->next;
}
void undo_arg(cs_ident_stack &st) {
cs_ident_stack *prev = p_astack;
st.val_s = std::move(p_val);
st.next = prev;
p_astack = prev->next;
p_val = std::move(prev->val_s);
clean_code();
}
void redo_arg(cs_ident_stack &st) {
cs_ident_stack *prev = st.next;
prev->val_s = std::move(p_val);
p_astack = prev;
p_val = std::move(st.val_s);
clean_code();
}
void set_arg(cs_state &cs, cs_value &v) {
if (cs_is_arg_used(cs, this)) {
p_val = std::move(v);
clean_code();
} else {
push_arg(v, cs.p_callstack->argstack[get_index()], false);
cs.p_callstack->usedargs |= 1 << get_index();
}
}
void set_alias(cs_state &cs, cs_value &v) {
p_val = std::move(v);
clean_code();
p_flags = (p_flags & cs.identflags) | cs.identflags;
}
void clean_code();
cs_bcode *compile_code(cs_state &cs);
2021-03-21 02:41:04 +01:00
cs_bcode *p_acode;
cs_ident_stack *p_astack;
cs_value p_val;
};
struct cs_command_impl: cs_ident_impl, cs_command {
cs_command_impl(cs_strref name, cs_strref args, int numargs, cs_command_cb func);
2021-03-21 03:07:01 +01:00
void call(cs_state &cs, std::span<cs_value> args, cs_value &ret) {
p_cb_cftv(cs, args, ret);
}
2021-03-21 02:41:04 +01:00
cs_strref p_cargs;
cs_command_cb p_cb_cftv;
int p_numargs;
};
template<typename T, std::size_t N>
struct cs_valarray {
cs_valarray(cs_state &cs) {
for (std::size_t i = 0; i < N; ++i) {
new (&stor[i]) T{cs};
}
}
~cs_valarray() {
for (std::size_t i = 0; i < N; ++i) {
reinterpret_cast<T *>(&stor[i])->~T();
}
}
T &operator[](std::size_t i) {
return *reinterpret_cast<T *>(&stor[i]);
}
std::aligned_storage_t<sizeof(T), alignof(T)> stor[N];
};
static const int cs_valtypet[] = {
2021-03-18 20:55:14 +01:00
CS_VAL_NULL, CS_VAL_INT, CS_VAL_FLOAT, CS_VAL_STRING,
CS_VAL_CODE, CS_VAL_IDENT
};
2017-02-13 18:10:40 +01:00
static inline int cs_vtype_to_int(cs_value_type v) {
return cs_valtypet[int(v)];
}
2016-09-14 23:24:13 +02:00
struct CsBreakException {
};
struct CsContinueException {
};
template<typename T>
2017-01-25 02:09:50 +01:00
constexpr size_t CsTypeStorageSize =
2017-01-25 02:10:17 +01:00
(sizeof(T) - 1) / sizeof(uint32_t) + 1;
2017-02-13 18:10:40 +01:00
struct cs_gen_state {
cs_state &cs;
cs_gen_state *prevps;
bool parsing = true;
2021-03-19 22:49:29 +01:00
cs_valbuf<uint32_t> code;
char const *source, *send;
2017-01-25 02:09:50 +01:00
size_t current_line;
std::string_view src_name;
2016-08-12 18:38:43 +02:00
2017-02-13 18:10:40 +01:00
cs_gen_state() = delete;
cs_gen_state(cs_state &csr):
cs{csr}, prevps{csr.p_pstate}, code{cs},
source{}, send{}, current_line{1}, src_name{}
{
csr.p_pstate = this;
}
2017-02-13 18:10:40 +01:00
~cs_gen_state() {
done();
}
void done() {
if (!parsing) {
return;
}
cs.p_pstate = prevps;
parsing = false;
}
2016-08-12 18:38:43 +02:00
std::string_view get_str();
2021-03-19 22:25:38 +01:00
cs_charbuf get_str_dup();
2016-09-20 22:11:40 +02:00
std::string_view get_word();
2016-09-20 22:11:40 +02:00
void gen_str(std::string_view word) {
if (word.size() <= 3) {
2021-03-18 20:55:14 +01:00
uint32_t op = CS_CODE_VAL_INT | CS_RET_STRING;
2017-01-25 02:09:50 +01:00
for (size_t i = 0; i < word.size(); ++i) {
2017-04-04 00:28:56 +02:00
op |= uint32_t(
static_cast<unsigned char>(word[i])
) << ((i + 1) * 8);
2016-08-17 05:02:53 +02:00
}
2017-01-25 01:18:29 +01:00
code.push_back(op);
2016-08-12 18:38:43 +02:00
return;
}
2021-03-18 20:55:14 +01:00
code.push_back(CS_CODE_VAL | CS_RET_STRING | (word.size() << 8));
2017-01-25 02:10:17 +01:00
auto it = reinterpret_cast<uint32_t const *>(word.data());
2021-03-19 22:49:29 +01:00
code.append(it, it + (word.size() / sizeof(uint32_t)));
2017-01-25 02:10:17 +01:00
size_t esz = word.size() % sizeof(uint32_t);
2016-08-12 18:38:43 +02:00
union {
2017-01-25 02:10:17 +01:00
char c[sizeof(uint32_t)];
uint32_t u;
2016-08-12 18:38:43 +02:00
} end;
end.u = 0;
memcpy(end.c, word.data() + word.size() - esz, esz);
2017-01-25 01:18:29 +01:00
code.push_back(end.u);
2016-08-12 18:38:43 +02:00
}
void gen_str() {
2021-03-18 20:55:14 +01:00
code.push_back(CS_CODE_VAL_INT | CS_RET_STRING);
2016-08-12 18:38:43 +02:00
}
void gen_null() {
2021-03-18 20:55:14 +01:00
code.push_back(CS_CODE_VAL_INT | CS_RET_NULL);
2016-08-12 18:38:43 +02:00
}
2017-02-13 18:10:40 +01:00
void gen_int(cs_int i = 0) {
2016-08-17 05:02:53 +02:00
if (i >= -0x800000 && i <= 0x7FFFFF) {
2021-03-18 20:55:14 +01:00
code.push_back(CS_CODE_VAL_INT | CS_RET_INT | (i << 8));
2016-08-17 05:02:53 +02:00
} else {
union {
2017-02-13 18:10:40 +01:00
cs_int i;
uint32_t u[CsTypeStorageSize<cs_int>];
} c;
c.i = i;
2021-03-18 20:55:14 +01:00
code.push_back(CS_CODE_VAL | CS_RET_INT);
2021-03-19 22:49:29 +01:00
code.append(c.u, c.u + CsTypeStorageSize<cs_int>);
2016-08-12 18:38:43 +02:00
}
}
void gen_int(std::string_view word);
2016-08-12 18:38:43 +02:00
2017-02-13 18:10:40 +01:00
void gen_float(cs_float f = 0.0f) {
if (cs_int(f) == f && f >= -0x800000 && f <= 0x7FFFFF) {
2021-03-18 20:55:14 +01:00
code.push_back(CS_CODE_VAL_INT | CS_RET_FLOAT | (cs_int(f) << 8));
2016-08-17 05:02:53 +02:00
} else {
2016-08-12 18:38:43 +02:00
union {
2017-02-13 18:10:40 +01:00
cs_float f;
uint32_t u[CsTypeStorageSize<cs_float>];
2016-08-12 18:38:43 +02:00
} c;
c.f = f;
2021-03-18 20:55:14 +01:00
code.push_back(CS_CODE_VAL | CS_RET_FLOAT);
2021-03-19 22:49:29 +01:00
code.append(c.u, c.u + CsTypeStorageSize<cs_float>);
2016-08-12 18:38:43 +02:00
}
}
void gen_float(std::string_view word);
2016-08-12 18:38:43 +02:00
2017-02-13 18:10:40 +01:00
void gen_ident(cs_ident *id) {
2017-01-25 01:18:29 +01:00
code.push_back(
2016-08-18 03:53:51 +02:00
((id->get_index() < MaxArguments)
2021-03-18 20:55:14 +01:00
? CS_CODE_IDENT_ARG
: CS_CODE_IDENT
2016-08-18 03:53:51 +02:00
) | (id->get_index() << 8)
2016-08-17 05:02:53 +02:00
);
2016-08-12 18:38:43 +02:00
}
void gen_ident() {
gen_ident(cs.p_state->identmap[DummyIdx]);
2016-08-12 18:38:43 +02:00
}
void gen_ident(std::string_view word) {
2016-08-12 18:38:43 +02:00
gen_ident(cs.new_ident(word));
}
2016-08-17 05:02:53 +02:00
void gen_value(
int wordtype, std::string_view word = std::string_view(),
2016-09-22 01:44:35 +02:00
int line = 0
2016-08-17 05:02:53 +02:00
);
2016-08-12 18:38:43 +02:00
void gen_main(std::string_view s, int ret_type = CS_VAL_ANY);
2016-08-12 18:38:43 +02:00
2016-09-22 01:19:29 +02:00
void next_char() {
if (source == send) {
2016-09-22 01:19:29 +02:00
return;
}
2016-09-22 01:44:35 +02:00
if (*source == '\n') {
++current_line;
}
++source;
2016-08-12 18:38:43 +02:00
}
2017-01-25 02:09:50 +01:00
char current(size_t ahead = 0) {
if (std::size_t(send - source) <= ahead) {
2016-09-22 01:15:51 +02:00
return '\0';
}
2016-09-22 00:20:23 +02:00
return source[ahead];
2016-08-12 18:38:43 +02:00
}
2016-09-22 00:20:23 +02:00
std::string_view read_macro_name();
2016-09-22 00:20:23 +02:00
char skip_until(std::string_view chars);
2016-09-22 00:20:23 +02:00
char skip_until(char cf);
void skip_comments();
2016-08-12 18:38:43 +02:00
};
bool cs_check_num(std::string_view s);
2016-08-12 18:38:43 +02:00
void bcode_ref(uint32_t *code);
void bcode_unref(uint32_t *code);
template<typename F>
2017-02-13 18:10:40 +01:00
static void cs_do_args(cs_state &cs, F body) {
2016-09-10 19:54:55 +02:00
if (!cs.p_callstack) {
body();
return;
}
cs_valarray<cs_ident_stack, MaxArguments> argstack{cs};
int argmask1 = cs.p_callstack->usedargs;
for (int i = 0; argmask1; argmask1 >>= 1, ++i) {
if (argmask1 & 1) {
static_cast<cs_alias_impl *>(cs.p_state->identmap[i])->undo_arg(
argstack[i]
);
}
}
2021-03-18 20:55:14 +01:00
cs_ident_link *prevstack = cs.p_callstack->next;
cs_ident_link aliaslink = {
2016-09-15 04:30:37 +02:00
cs.p_callstack->id, cs.p_callstack,
prevstack ? prevstack->usedargs : ((1 << MaxArguments) - 1),
prevstack ? prevstack->argstack : nullptr
};
cs.p_callstack = &aliaslink;
2017-01-25 01:57:33 +01:00
cs_do_and_cleanup(std::move(body), [&]() {
2016-09-15 04:30:37 +02:00
if (prevstack) {
prevstack->usedargs = aliaslink.usedargs;
}
cs.p_callstack = aliaslink.next;
int argmask2 = cs.p_callstack->usedargs;
for (int i = 0; argmask2; argmask2 >>= 1, ++i) {
if (argmask2 & 1) {
static_cast<cs_alias_impl *>(cs.p_state->identmap[i])->redo_arg(
argstack[i]
);
}
}
});
}
2016-08-12 18:38:43 +02:00
} /* namespace cscript */
#endif /* LIBCUBESCRIPT_CS_VM_HH */