libcubescript/src/cs_vm.hh

448 lines
12 KiB
C++
Raw Permalink 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>
2016-08-12 18:38:43 +02:00
#include "cs_util.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
};
2017-02-13 18:10:40 +01:00
struct cs_identLink {
cs_ident *id;
cs_identLink *next;
2016-09-10 20:03:58 +02:00
int usedargs;
2017-02-13 18:10:40 +01:00
cs_ident_stack *argstack;
2016-09-10 20:03:58 +02:00
};
enum {
2016-09-07 20:20:36 +02:00
CsValNull = 0, CsValInt, CsValFloat, CsValString,
CsValAny, CsValCode, CsValMacro, CsValIdent, CsValCstring,
CsValCany, CsValWord, CsValPop, CsValCond
};
static const int cs_valtypet[] = {
2016-09-07 20:20:36 +02:00
CsValNull, CsValInt, CsValFloat, CsValString,
CsValCstring, CsValCode, CsValMacro, CsValIdent
};
2017-02-13 18:10:40 +01:00
static inline int cs_vtype_to_int(cs_value_type v) {
return cs_valtypet[int(v)];
}
/* instruction: uint32 [length 24][retflag 2][opcode 6] */
2016-08-12 18:38:43 +02:00
enum {
2016-09-07 20:20:36 +02:00
CsCodeStart = 0,
CsCodeOffset,
CsCodeNull, CsCodeTrue, CsCodeFalse, CsCodeNot,
CsCodePop,
CsCodeEnter, CsCodeEnterResult,
CsCodeExit, CsCodeResultArg,
CsCodeVal, CsCodeValInt,
CsCodeDup,
CsCodeMacro,
CsCodeBool,
CsCodeBlock, CsCodeEmpty,
CsCodeCompile, CsCodeCond,
CsCodeForce,
CsCodeResult,
CsCodeIdent, CsCodeIdentU, CsCodeIdentArg,
CsCodeCom, CsCodeComC, CsCodeComV,
CsCodeConc, CsCodeConcW, CsCodeConcM,
CsCodeSvar, CsCodeSvarM, CsCodeSvar1,
CsCodeIvar, CsCodeIvar1, CsCodeIvar2, CsCodeIvar3,
CsCodeFvar, CsCodeFvar1,
CsCodeLookup, CsCodeLookupU, CsCodeLookupArg,
CsCodeLookupM, CsCodeLookupMu, CsCodeLookupMarg,
CsCodeAlias, CsCodeAliasU, CsCodeAliasArg,
CsCodeCall, CsCodeCallU, CsCodeCallArg,
CsCodePrint,
CsCodeLocal,
CsCodeDo, CsCodeDoArgs,
CsCodeJump, CsCodeJumpB, CsCodeJumpResult,
2016-09-15 02:12:22 +02:00
CsCodeBreak,
2016-09-07 20:20:36 +02:00
CsCodeOpMask = 0x3F,
CsCodeRet = 6,
CsCodeRetMask = 0xC0,
2016-08-12 18:38:43 +02:00
/* return type flags */
2016-09-07 20:20:36 +02:00
CsRetNull = CsValNull << CsCodeRet,
CsRetString = CsValString << CsCodeRet,
CsRetInt = CsValInt << CsCodeRet,
CsRetFloat = CsValFloat << CsCodeRet,
/* CsCodeJumpB, CsCodeJumpResult */
CsCodeFlagTrue = 1 << CsCodeRet,
CsCodeFlagFalse = 0 << CsCodeRet
2016-08-12 18:38:43 +02:00
};
2017-02-13 18:10:40 +01:00
struct cs_shared_state {
2018-04-27 23:53:55 +02:00
cs_map<ostd::string_range, cs_ident *> idents;
cs_vector<cs_ident *> identmap;
2017-02-13 18:10:40 +01:00
cs_alloc_cb allocf;
2016-10-02 13:56:55 +02:00
void *aptr;
2017-01-25 02:09:50 +01:00
void *alloc(void *ptr, size_t os, size_t ns) {
return allocf(aptr, ptr, os, ns);
}
template<typename T, typename ...A>
T *create(A &&...args) {
T *ret = static_cast<T *>(alloc(nullptr, 0, sizeof(T)));
2017-01-25 01:57:33 +01:00
new (ret) T(std::forward<A>(args)...);
return ret;
}
template<typename T>
2017-01-25 02:09:50 +01:00
T *create_array(size_t len) {
T *ret = static_cast<T *>(alloc(nullptr, 0, len * sizeof(T)));
2017-01-25 02:09:50 +01:00
for (size_t i = 0; i < len; ++i) {
new (&ret[i]) T();
}
return ret;
}
template<typename T>
void destroy(T *v) noexcept {
v->~T();
alloc(v, sizeof(T), 0);
}
template<typename T>
2017-01-25 02:09:50 +01:00
void destroy_array(T *v, size_t len) noexcept {
v->~T();
alloc(v, len * sizeof(T), 0);
}
};
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;
2018-04-27 23:53:55 +02:00
cs_vector<uint32_t> code;
2017-02-16 19:07:22 +01:00
ostd::string_range source;
2017-01-25 02:09:50 +01:00
size_t current_line;
2017-02-16 19:07:22 +01:00
ostd::string_range 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(),
source(nullptr), 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
2017-02-16 19:07:22 +01:00
ostd::string_range get_str();
2017-02-13 18:10:40 +01:00
cs_string get_str_dup(bool unescape = true);
2016-09-20 22:11:40 +02:00
2017-02-16 19:07:22 +01:00
ostd::string_range get_word();
2016-09-20 22:11:40 +02:00
2017-02-16 19:07:22 +01:00
void gen_str(ostd::string_range word, bool macro = false) {
2016-08-12 18:38:43 +02:00
if (word.size() <= 3 && !macro) {
2017-01-25 02:10:17 +01:00
uint32_t op = CsCodeValInt | CsRetString;
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;
}
2017-01-25 01:18:29 +01:00
code.push_back(
2016-09-07 20:20:36 +02:00
(macro ? CsCodeMacro : (CsCodeVal | CsRetString)) | (word.size() << 8)
2016-08-17 05:02:53 +02:00
);
2017-01-25 02:10:17 +01:00
auto it = reinterpret_cast<uint32_t const *>(word.data());
2017-01-25 01:18:29 +01:00
code.insert(
2017-01-25 02:10:17 +01:00
code.end(), it, it + (word.size() / sizeof(uint32_t))
2016-08-17 05:02:53 +02:00
);
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() {
2017-01-25 01:18:29 +01:00
code.push_back(CsCodeValInt | CsRetString);
2016-08-12 18:38:43 +02:00
}
void gen_null() {
2017-01-25 01:18:29 +01:00
code.push_back(CsCodeValInt | CsRetNull);
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) {
2017-01-25 01:18:29 +01:00
code.push_back(CsCodeValInt | CsRetInt | (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;
2017-01-25 01:18:29 +01:00
code.push_back(CsCodeVal | CsRetInt);
2017-02-13 18:10:40 +01:00
code.insert(code.end(), c.u, c.u + CsTypeStorageSize<cs_int>);
2016-08-12 18:38:43 +02:00
}
}
2017-02-16 19:07:22 +01:00
void gen_int(ostd::string_range 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) {
code.push_back(CsCodeValInt | CsRetFloat | (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;
2017-01-25 01:18:29 +01:00
code.push_back(CsCodeVal | CsRetFloat);
2017-02-13 18:10:40 +01:00
code.insert(code.end(), c.u, c.u + CsTypeStorageSize<cs_float>);
2016-08-12 18:38:43 +02:00
}
}
2017-02-16 19:07:22 +01:00
void gen_float(ostd::string_range 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)
2016-09-07 20:20:36 +02:00
? CsCodeIdentArg
: CsCodeIdent
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
}
2017-02-16 19:07:22 +01:00
void gen_ident(ostd::string_range 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(
2017-02-16 19:07:22 +01:00
int wordtype, ostd::string_range word = ostd::string_range(),
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
2017-02-16 19:07:22 +01:00
void gen_main(ostd::string_range s, int ret_type = CsValAny);
2016-08-12 18:38:43 +02:00
2016-09-22 01:19:29 +02:00
void next_char() {
if (source.empty()) {
return;
}
2016-09-22 01:44:35 +02:00
if (*source == '\n') {
++current_line;
}
2016-09-22 01:19:29 +02:00
source.pop_front();
2016-08-12 18:38:43 +02:00
}
2017-01-25 02:09:50 +01:00
char current(size_t ahead = 0) {
2016-09-22 01:15:51 +02:00
if (source.size() <= ahead) {
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
2017-02-16 19:07:22 +01:00
ostd::string_range read_macro_name();
2016-09-22 00:20:23 +02:00
2017-02-16 19:07:22 +01:00
char skip_until(ostd::string_range 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
};
2017-02-13 18:10:40 +01:00
cs_string intstr(cs_int v);
cs_string floatstr(cs_float v);
2016-08-12 18:38:43 +02:00
2017-02-16 19:07:22 +01:00
bool cs_check_num(ostd::string_range s);
2016-08-12 18:38:43 +02:00
2017-01-25 02:10:17 +01:00
static inline void bcode_incr(uint32_t *bc) {
2016-08-13 01:26:16 +02:00
*bc += 0x100;
}
2017-01-25 02:10:17 +01:00
static inline void bcode_decr(uint32_t *bc) {
2016-08-13 01:26:16 +02:00
*bc -= 0x100;
2017-01-30 19:38:11 +01:00
if (std::int32_t(*bc) < 0x100) {
2016-08-13 01:26:16 +02:00
delete[] bc;
}
}
2017-02-13 18:10:40 +01:00
static inline bool cs_is_arg_used(cs_state &cs, cs_ident *id) {
2016-09-10 19:54:55 +02:00
if (!cs.p_callstack) {
return true;
}
return cs.p_callstack->usedargs & (1 << id->get_index());
}
2018-04-27 23:53:55 +02:00
struct cs_alias_internal {
static void push_arg(
2017-02-13 18:10:40 +01:00
cs_alias *a, cs_value &v, cs_ident_stack &st, bool um = true
) {
if (a->p_astack == &st) {
/* prevent cycles and unnecessary code elsewhere */
2017-01-25 01:57:33 +01:00
a->p_val = std::move(v);
clean_code(a);
return;
}
2017-01-25 01:57:33 +01:00
st.val_s = std::move(a->p_val);
st.next = a->p_astack;
a->p_astack = &st;
2017-01-25 01:57:33 +01:00
a->p_val = std::move(v);
clean_code(a);
if (um) {
2017-02-13 18:10:40 +01:00
a->p_flags &= ~CS_IDF_UNKNOWN;
}
}
2017-02-13 18:10:40 +01:00
static void pop_arg(cs_alias *a) {
if (!a->p_astack) {
return;
}
2017-02-13 18:10:40 +01:00
cs_ident_stack *st = a->p_astack;
2017-01-25 01:57:33 +01:00
a->p_val = std::move(a->p_astack->val_s);
clean_code(a);
a->p_astack = st->next;
}
2017-02-13 18:10:40 +01:00
static void undo_arg(cs_alias *a, cs_ident_stack &st) {
cs_ident_stack *prev = a->p_astack;
2017-01-25 01:57:33 +01:00
st.val_s = std::move(a->p_val);
st.next = prev;
a->p_astack = prev->next;
2017-01-25 01:57:33 +01:00
a->p_val = std::move(prev->val_s);
clean_code(a);
}
2017-02-13 18:10:40 +01:00
static void redo_arg(cs_alias *a, cs_ident_stack &st) {
cs_ident_stack *prev = st.next;
2017-01-25 01:57:33 +01:00
prev->val_s = std::move(a->p_val);
a->p_astack = prev;
2017-01-25 01:57:33 +01:00
a->p_val = std::move(st.val_s);
clean_code(a);
}
2017-02-13 18:10:40 +01:00
static void set_arg(cs_alias *a, cs_state &cs, cs_value &v) {
2016-09-10 19:54:55 +02:00
if (cs_is_arg_used(cs, a)) {
2017-01-25 01:57:33 +01:00
a->p_val = std::move(v);
clean_code(a);
} else {
push_arg(a, v, cs.p_callstack->argstack[a->get_index()], false);
cs.p_callstack->usedargs |= 1 << a->get_index();
}
}
2017-02-13 18:10:40 +01:00
static void set_alias(cs_alias *a, cs_state &cs, cs_value &v) {
2017-01-25 01:57:33 +01:00
a->p_val = std::move(v);
clean_code(a);
a->p_flags = (a->p_flags & cs.identflags) | cs.identflags;
}
2017-02-13 18:10:40 +01:00
static void clean_code(cs_alias *a) {
2017-01-25 02:10:17 +01:00
uint32_t *bcode = reinterpret_cast<uint32_t *>(a->p_acode);
if (bcode) {
bcode_decr(bcode);
a->p_acode = nullptr;
}
}
2017-02-13 18:10:40 +01:00
static cs_bcode *compile_code(cs_alias *a, cs_state &cs) {
if (!a->p_acode) {
2017-02-13 18:10:40 +01:00
cs_gen_state gs(cs);
gs.code.reserve(64);
gs.gen_main(a->get_value().get_str());
2017-01-25 01:18:29 +01:00
/* i wish i could steal the memory somehow */
2017-01-25 02:10:17 +01:00
uint32_t *code = new uint32_t[gs.code.size()];
2017-01-25 01:18:29 +01:00
memcpy(code, gs.code.data(), gs.code.size() * sizeof(uint32_t));
bcode_incr(code);
2017-02-13 18:10:40 +01:00
a->p_acode = reinterpret_cast<cs_bcode *>(code);
}
return a->p_acode;
}
};
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;
}
2017-02-13 18:10:40 +01:00
cs_ident_stack argstack[MaxArguments];
int argmask1 = cs.p_callstack->usedargs;
for (int i = 0; argmask1; argmask1 >>= 1, ++i) {
if (argmask1 & 1) {
2018-04-27 23:53:55 +02:00
cs_alias_internal::undo_arg(
2017-02-13 18:10:40 +01:00
static_cast<cs_alias *>(cs.p_state->identmap[i]), argstack[i]
);
}
}
2017-02-13 18:10:40 +01:00
cs_identLink *prevstack = cs.p_callstack->next;
cs_identLink 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) {
2018-04-27 23:53:55 +02:00
cs_alias_internal::redo_arg(
2017-02-13 18:10:40 +01:00
static_cast<cs_alias *>(cs.p_state->identmap[i]), argstack[i]
);
}
}
});
}
2017-02-13 18:10:40 +01:00
cs_bcode *cs_copy_code(cs_bcode *c);
2016-09-06 20:06:49 +02:00
2016-08-12 18:38:43 +02:00
} /* namespace cscript */
#endif /* LIBCUBESCRIPT_CS_VM_HH */