libcubescript/src/cubescript.cc

292 lines
8.3 KiB
C++
Raw Normal View History

2017-06-20 21:21:39 +02:00
#include <cubescript/cubescript.hh>
2016-08-12 18:38:43 +02:00
#include "cs_vm.hh"
2015-08-08 18:13:19 +02:00
#include <iterator>
2015-08-08 17:13:46 +02:00
namespace cscript {
bool cs_check_num(std::string_view s) {
2016-08-17 18:53:38 +02:00
if (isdigit(s[0])) {
2015-08-07 00:16:02 +02:00
return true;
2016-08-17 18:53:38 +02:00
}
2015-08-07 00:16:02 +02:00
switch (s[0]) {
2016-08-17 18:53:38 +02:00
case '+':
case '-':
return isdigit(s[1]) || ((s[1] == '.') && isdigit(s[2]));
case '.':
return isdigit(s[1]) != 0;
default:
return false;
2015-08-07 00:16:02 +02:00
}
}
LIBCUBESCRIPT_EXPORT void cs_state::clear_override(cs_ident &id) {
2017-02-13 18:10:40 +01:00
if (!(id.get_flags() & CS_IDF_OVERRIDDEN)) {
2016-08-17 18:53:38 +02:00
return;
}
2016-08-18 03:53:51 +02:00
switch (id.get_type()) {
2021-03-18 20:55:14 +01:00
case cs_ident_type::ALIAS: {
2021-03-21 02:41:04 +01:00
cs_alias_impl &a = static_cast<cs_alias_impl &>(id);
a.clean_code();
2016-08-31 20:18:53 +02:00
a.get_value().set_str("");
2016-08-17 18:53:38 +02:00
break;
2016-08-17 23:29:31 +02:00
}
2021-03-18 20:55:14 +01:00
case cs_ident_type::IVAR: {
2021-03-21 02:41:04 +01:00
cs_ivar_impl &iv = static_cast<cs_ivar_impl &>(id);
2016-08-22 19:43:58 +02:00
iv.set_value(iv.p_overrideval);
iv.changed(*this);
2016-08-17 18:53:38 +02:00
break;
2016-08-17 23:29:31 +02:00
}
2021-03-18 20:55:14 +01:00
case cs_ident_type::FVAR: {
2021-03-21 02:41:04 +01:00
cs_fvar_impl &fv = static_cast<cs_fvar_impl &>(id);
2016-08-22 19:43:58 +02:00
fv.set_value(fv.p_overrideval);
fv.changed(*this);
2016-08-17 18:53:38 +02:00
break;
2016-08-17 23:29:31 +02:00
}
2021-03-18 20:55:14 +01:00
case cs_ident_type::SVAR: {
2021-03-21 02:41:04 +01:00
cs_svar_impl &sv = static_cast<cs_svar_impl &>(id);
2016-08-22 19:43:58 +02:00
sv.set_value(sv.p_overrideval);
sv.changed(*this);
2016-08-17 18:53:38 +02:00
break;
2016-08-17 23:29:31 +02:00
}
2016-08-18 03:53:51 +02:00
default:
break;
}
2021-03-21 02:41:04 +01:00
id.p_impl->p_flags &= ~CS_IDF_OVERRIDDEN;
}
LIBCUBESCRIPT_EXPORT void cs_state::clear_overrides() {
2017-01-31 19:28:34 +01:00
for (auto &p: p_state->idents) {
2016-08-17 22:21:16 +02:00
clear_override(*(p.second));
2016-08-17 18:53:38 +02:00
}
}
2021-03-21 02:41:04 +01:00
LIBCUBESCRIPT_EXPORT cs_ident *cs_state::add_ident(
cs_ident *id, cs_ident_impl *impl
) {
2016-08-18 03:53:51 +02:00
if (!id) {
return nullptr;
}
2021-03-21 02:41:04 +01:00
id->p_impl = impl;
p_state->idents[id->get_name()] = id;
2021-03-21 02:41:04 +01:00
static_cast<cs_ident_impl *>(impl)->p_index = p_state->identmap.size();
2017-01-25 01:18:29 +01:00
p_state->identmap.push_back(id);
return p_state->identmap.back();
2016-08-18 03:53:51 +02:00
}
LIBCUBESCRIPT_EXPORT cs_ident *cs_state::new_ident(std::string_view name, int flags) {
2017-02-13 18:10:40 +01:00
cs_ident *id = get_ident(name);
2015-08-07 00:16:02 +02:00
if (!id) {
2015-08-11 22:41:12 +02:00
if (cs_check_num(name)) {
2017-02-13 18:10:40 +01:00
throw cs_error(
2021-03-20 08:22:15 +01:00
*this, "number %s is not a valid identifier name", name.data()
2016-08-17 18:53:38 +02:00
);
2015-08-07 00:16:02 +02:00
}
2021-03-21 02:41:04 +01:00
auto *inst = p_state->create<cs_alias_impl>(
2021-03-23 01:11:21 +01:00
*this, cs_strref{p_state, name}, flags
2021-03-21 02:41:04 +01:00
);
id = add_ident(inst, inst);
2015-08-07 00:16:02 +02:00
}
return id;
}
LIBCUBESCRIPT_EXPORT cs_ident *cs_state::force_ident(cs_value &v) {
2015-08-13 22:48:03 +02:00
switch (v.get_type()) {
2021-03-18 20:55:14 +01:00
case cs_value_type::IDENT:
2016-08-30 22:29:09 +02:00
return v.get_ident();
2021-03-18 20:55:14 +01:00
case cs_value_type::STRING: {
2021-03-17 21:57:47 +01:00
cs_ident *id = new_ident(v.get_str());
2016-08-17 18:53:38 +02:00
v.set_ident(id);
return id;
}
default:
break;
2015-08-07 00:16:02 +02:00
}
v.set_ident(p_state->identmap[DummyIdx]);
return p_state->identmap[DummyIdx];
}
LIBCUBESCRIPT_EXPORT cs_ident *cs_state::get_ident(std::string_view name) {
2017-01-31 19:28:34 +01:00
auto id = p_state->idents.find(name);
if (id != p_state->idents.end()) {
return id->second;
}
2017-01-31 19:28:34 +01:00
return nullptr;
}
LIBCUBESCRIPT_EXPORT cs_alias *cs_state::get_alias(std::string_view name) {
2017-01-31 19:28:34 +01:00
auto id = get_ident(name);
if (!id || !id->is_alias()) {
return nullptr;
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_alias *>(id);
}
LIBCUBESCRIPT_EXPORT bool cs_state::have_ident(std::string_view name) {
2017-01-31 19:28:34 +01:00
return p_state->idents.find(name) != p_state->idents.end();
}
LIBCUBESCRIPT_EXPORT std::span<cs_ident *> cs_state::get_idents() {
2021-03-20 05:41:25 +01:00
return std::span<cs_ident *>{
2017-02-09 22:54:09 +01:00
p_state->identmap.data(),
2021-03-20 05:41:25 +01:00
p_state->identmap.size()
};
}
LIBCUBESCRIPT_EXPORT std::span<cs_ident const *> cs_state::get_idents() const {
2017-02-13 18:10:40 +01:00
auto ptr = const_cast<cs_ident const **>(p_state->identmap.data());
2021-03-20 05:41:25 +01:00
return std::span<cs_ident const *>{ptr, p_state->identmap.size()};
2015-08-07 00:16:02 +02:00
}
LIBCUBESCRIPT_EXPORT cs_ivar *cs_state::new_ivar(
std::string_view n, cs_int m, cs_int x, cs_int v, cs_var_cb f, int flags
2016-09-02 19:01:25 +02:00
) {
2021-03-21 02:41:04 +01:00
auto *iv = p_state->create<cs_ivar_impl>(
2021-03-23 01:11:21 +01:00
cs_strref{p_state, n}, m, x, v, std::move(f), flags
2021-03-21 02:41:04 +01:00
);
add_ident(iv, iv);
return iv;
2016-09-02 19:01:25 +02:00
}
LIBCUBESCRIPT_EXPORT cs_fvar *cs_state::new_fvar(
std::string_view n, cs_float m, cs_float x, cs_float v, cs_var_cb f, int flags
2016-09-02 19:01:25 +02:00
) {
2021-03-21 02:41:04 +01:00
auto *fv = p_state->create<cs_fvar_impl>(
2021-03-23 01:11:21 +01:00
cs_strref{p_state, n}, m, x, v, std::move(f), flags
2021-03-21 02:41:04 +01:00
);
add_ident(fv, fv);
return fv;
2016-09-02 19:01:25 +02:00
}
LIBCUBESCRIPT_EXPORT cs_svar *cs_state::new_svar(
std::string_view n, std::string_view v, cs_var_cb f, int flags
2016-09-02 19:01:25 +02:00
) {
2021-03-21 02:41:04 +01:00
auto *sv = p_state->create<cs_svar_impl>(
2021-03-23 01:11:21 +01:00
cs_strref{p_state, n}, cs_strref{p_state, v},
cs_strref{p_state, ""}, std::move(f), flags
2021-03-21 02:41:04 +01:00
);
add_ident(sv, sv);
return sv;
2016-09-02 19:01:25 +02:00
}
LIBCUBESCRIPT_EXPORT void cs_state::reset_var(std::string_view name) {
2017-02-13 18:10:40 +01:00
cs_ident *id = get_ident(name);
2016-08-17 18:53:38 +02:00
if (!id) {
2021-03-20 08:22:15 +01:00
throw cs_error(*this, "variable %s does not exist", name.data());
2016-08-17 18:53:38 +02:00
}
2017-02-13 18:10:40 +01:00
if (id->get_flags() & CS_IDF_READONLY) {
2021-03-20 08:22:15 +01:00
throw cs_error(*this, "variable %s is read only", name.data());
2015-08-07 00:16:02 +02:00
}
clear_override(*id);
}
LIBCUBESCRIPT_EXPORT void cs_state::touch_var(std::string_view name) {
2017-02-13 18:10:40 +01:00
cs_ident *id = get_ident(name);
2016-08-17 18:53:38 +02:00
if (id && id->is_var()) {
2021-03-21 02:41:04 +01:00
static_cast<cs_var_impl *>(id->p_impl)->changed(*this);
2015-08-07 00:16:02 +02:00
}
}
LIBCUBESCRIPT_EXPORT void cs_state::set_alias(std::string_view name, cs_value v) {
2017-02-13 18:10:40 +01:00
cs_ident *id = get_ident(name);
2015-08-07 00:38:22 +02:00
if (id) {
2016-08-18 03:53:51 +02:00
switch (id->get_type()) {
2021-03-18 20:55:14 +01:00
case cs_ident_type::ALIAS: {
2021-03-21 02:41:04 +01:00
cs_alias_impl *a = static_cast<cs_alias_impl *>(id);
2016-08-18 03:53:51 +02:00
if (a->get_index() < MaxArguments) {
a->set_arg(*this, v);
2016-08-17 18:53:38 +02:00
} else {
a->set_alias(*this, v);
2016-08-17 18:53:38 +02:00
}
return;
2016-08-17 23:29:31 +02:00
}
2021-03-18 20:55:14 +01:00
case cs_ident_type::IVAR:
2017-02-13 18:10:40 +01:00
set_var_int_checked(static_cast<cs_ivar *>(id), v.get_int());
2016-08-17 18:53:38 +02:00
break;
2021-03-18 20:55:14 +01:00
case cs_ident_type::FVAR:
2017-02-13 18:10:40 +01:00
set_var_float_checked(static_cast<cs_fvar *>(id), v.get_float());
2016-08-17 18:53:38 +02:00
break;
2021-03-18 20:55:14 +01:00
case cs_ident_type::SVAR:
2017-02-13 18:10:40 +01:00
set_var_str_checked(static_cast<cs_svar *>(id), v.get_str());
2016-08-17 18:53:38 +02:00
break;
default:
2017-02-13 18:10:40 +01:00
throw cs_error(
2016-08-18 03:53:51 +02:00
*this, "cannot redefine builtin %s with an alias",
2021-03-20 08:22:15 +01:00
id->get_name().data()
2016-08-17 18:53:38 +02:00
);
2015-08-07 00:38:22 +02:00
}
2015-08-11 22:41:12 +02:00
} else if (cs_check_num(name)) {
2021-03-20 08:22:15 +01:00
throw cs_error(*this, "cannot alias number %s", name.data());
2015-08-07 00:38:22 +02:00
} else {
2021-03-21 02:41:04 +01:00
auto *a = p_state->create<cs_alias_impl>(
2021-03-23 01:11:21 +01:00
*this, cs_strref{p_state, name}, std::move(v), identflags
2021-03-21 02:41:04 +01:00
);
add_ident(a, a);
2015-08-07 00:38:22 +02:00
}
}
LIBCUBESCRIPT_EXPORT void cs_state::print_var(cs_var const &v) const {
if (p_state->varprintf) {
p_state->varprintf(*this, v);
}
2015-08-07 22:38:57 +02:00
}
LIBCUBESCRIPT_EXPORT cs_command *cs_state::new_command(
std::string_view name, std::string_view args, cs_command_cb func
2016-08-10 19:33:43 +02:00
) {
int nargs = 0;
for (auto fmt = args.begin(); fmt != args.end(); ++fmt) {
2016-08-17 18:53:38 +02:00
switch (*fmt) {
case 'i':
case 'b':
case 'f':
case 'F':
case 't':
case 'T':
case 'E':
case 'N':
case 's':
case 'e':
case 'r':
case '$':
if (nargs < MaxArguments) {
++nargs;
2016-08-17 18:53:38 +02:00
}
break;
case '1':
case '2':
case '3':
case '4':
if (nargs < (*fmt - '0')) {
return nullptr;
}
if ((args.end() - fmt) != 2) {
return nullptr;
}
if ((fmt[1] != 'C') && (fmt[1] != 'V')) {
return nullptr;
}
2016-08-17 18:53:38 +02:00
if (nargs < MaxArguments) {
fmt -= *fmt - '0' + 1;
2016-08-17 18:53:38 +02:00
}
break;
case 'C':
case 'V':
if ((fmt + 1) != args.end()) {
return nullptr;
}
2016-08-17 18:53:38 +02:00
break;
default:
2016-09-02 19:01:25 +02:00
return nullptr;
}
}
2021-03-21 02:41:04 +01:00
auto *cmd = p_state->create<cs_command_impl>(
2021-03-23 01:11:21 +01:00
cs_strref{p_state, name}, cs_strref{p_state, args}, nargs,
2021-03-21 02:41:04 +01:00
std::move(func)
);
add_ident(cmd, cmd);
return cmd;
2016-08-10 19:33:43 +02:00
}
2016-02-07 22:22:39 +01:00
} /* namespace cscript */