libcubescript/src/cubescript.cc

1321 lines
37 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
}
}
2021-03-17 23:32:38 +01:00
cs_ident::cs_ident(cs_ident_type tp, cs_strref nm, int fl):
2016-08-18 03:53:51 +02:00
p_name(nm), p_type(int(tp)), p_flags(fl)
{}
2016-08-10 19:33:43 +02:00
2021-03-17 23:32:38 +01:00
cs_var::cs_var(cs_ident_type tp, cs_strref name, cs_var_cb f, int fl):
2017-02-13 18:10:40 +01:00
cs_ident(tp, name, fl), cb_var(std::move(f))
{}
2016-08-17 23:29:31 +02:00
2017-02-13 18:10:40 +01:00
cs_ivar::cs_ivar(
2021-03-17 23:32:38 +01:00
cs_strref name, cs_int m, cs_int x, cs_int v, cs_var_cb f, int fl
):
2021-03-18 20:55:14 +01:00
cs_var(cs_ident_type::IVAR, name, std::move(f), fl | ((m > x) ? CS_IDF_READONLY : 0)),
2016-08-22 19:43:58 +02:00
p_storage(v), p_minval(m), p_maxval(x), p_overrideval(0)
{}
2015-08-11 23:16:20 +02:00
2017-02-13 18:10:40 +01:00
cs_fvar::cs_fvar(
2021-03-17 23:32:38 +01:00
cs_strref name, cs_float m, cs_float x, cs_float v, cs_var_cb f, int fl
):
2021-03-18 20:55:14 +01:00
cs_var(cs_ident_type::FVAR, name, std::move(f), fl | ((m > x) ? CS_IDF_READONLY : 0)),
2016-08-22 19:43:58 +02:00
p_storage(v), p_minval(m), p_maxval(x), p_overrideval(0)
{}
2015-08-11 23:16:20 +02:00
2021-03-17 23:32:38 +01:00
cs_svar::cs_svar(cs_strref name, cs_strref v, cs_strref ov, cs_var_cb f, int fl):
2021-03-18 20:55:14 +01:00
cs_var(cs_ident_type::SVAR, name, std::move(f), fl),
2021-03-17 23:32:38 +01:00
p_storage{v}, p_overrideval{ov}
{}
2015-08-11 23:16:20 +02:00
2021-03-17 23:32:38 +01:00
cs_alias::cs_alias(cs_state &cs, cs_strref name, cs_strref a, int fl):
2021-03-18 20:55:14 +01:00
cs_ident(cs_ident_type::ALIAS, name, fl),
p_acode(nullptr), p_astack(nullptr), p_val{cs}
2016-08-18 00:18:36 +02:00
{
p_val.set_str(a);
}
cs_alias::cs_alias(cs_state &cs, cs_strref name, std::string_view a, int fl):
2021-03-18 20:55:14 +01:00
cs_ident(cs_ident_type::ALIAS, name, fl),
p_acode(nullptr), p_astack(nullptr), p_val{cs}
{
p_val.set_str(a);
2015-08-11 23:16:20 +02:00
}
2021-03-17 23:32:38 +01:00
cs_alias::cs_alias(cs_state &cs, cs_strref name, cs_int a, int fl):
2021-03-18 20:55:14 +01:00
cs_ident(cs_ident_type::ALIAS, name, fl),
p_acode(nullptr), p_astack(nullptr), p_val{cs}
2016-08-18 00:18:36 +02:00
{
2016-08-31 20:18:53 +02:00
p_val.set_int(a);
2015-08-11 23:16:20 +02:00
}
2021-03-17 23:32:38 +01:00
cs_alias::cs_alias(cs_state &cs, cs_strref name, cs_float a, int fl):
2021-03-18 20:55:14 +01:00
cs_ident(cs_ident_type::ALIAS, name, fl),
p_acode(nullptr), p_astack(nullptr), p_val{cs}
2016-08-18 00:18:36 +02:00
{
2016-08-31 20:18:53 +02:00
p_val.set_float(a);
2015-08-11 23:16:20 +02:00
}
2021-03-17 23:32:38 +01:00
cs_alias::cs_alias(cs_state &cs, cs_strref name, int fl):
2021-03-18 20:55:14 +01:00
cs_ident(cs_ident_type::ALIAS, name, fl),
p_acode(nullptr), p_astack(nullptr), p_val{cs}
2016-08-18 00:18:36 +02:00
{
2021-03-18 20:55:14 +01:00
p_val.set_none();
2016-08-17 23:04:43 +02:00
}
/* FIXME: use cs rather than val's cs */
2021-03-17 23:32:38 +01:00
cs_alias::cs_alias(cs_state &, cs_strref name, cs_value v, int fl):
2021-03-18 20:55:14 +01:00
cs_ident(cs_ident_type::ALIAS, name, fl),
2021-03-17 23:32:38 +01:00
p_acode(nullptr), p_astack(nullptr), p_val(v)
2016-09-06 22:57:10 +02:00
{}
2015-08-11 23:16:20 +02:00
2017-02-13 18:10:40 +01:00
cs_command::cs_command(
2021-03-17 23:32:38 +01:00
cs_strref name, cs_strref args, int nargs, cs_command_cb f
2016-08-17 18:53:38 +02:00
):
2021-03-18 20:55:14 +01:00
cs_ident(cs_ident_type::COMMAND, name, 0),
2017-01-25 01:57:33 +01:00
p_cargs(args), p_cb_cftv(std::move(f)), p_numargs(nargs)
2016-09-02 19:01:25 +02:00
{}
2015-08-11 23:16:20 +02:00
2017-02-13 18:10:40 +01:00
bool cs_ident::is_alias() const {
2021-03-18 20:55:14 +01:00
return get_type() == cs_ident_type::ALIAS;
2016-08-18 00:54:57 +02:00
}
2017-02-13 18:10:40 +01:00
cs_alias *cs_ident::get_alias() {
2016-08-18 00:54:57 +02:00
if (!is_alias()) {
return nullptr;
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_alias *>(this);
2016-08-18 00:54:57 +02:00
}
2017-02-13 18:10:40 +01:00
cs_alias const *cs_ident::get_alias() const {
2016-08-18 00:54:57 +02:00
if (!is_alias()) {
return nullptr;
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_alias const *>(this);
2016-08-18 00:54:57 +02:00
}
2017-02-13 18:10:40 +01:00
bool cs_ident::is_command() const {
2021-03-18 20:55:14 +01:00
return get_type() == cs_ident_type::COMMAND;
2016-08-18 00:54:57 +02:00
}
2017-02-13 18:10:40 +01:00
cs_command *cs_ident::get_command() {
if (!is_command()) {
return nullptr;
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_command *>(this);
}
2017-02-13 18:10:40 +01:00
cs_command const *cs_ident::get_command() const {
if (!is_command()) {
return nullptr;
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_command const *>(this);
}
2017-02-13 18:10:40 +01:00
bool cs_ident::is_special() const {
2021-03-18 20:55:14 +01:00
return get_type() == cs_ident_type::SPECIAL;
2016-08-18 03:53:51 +02:00
}
2017-02-13 18:10:40 +01:00
bool cs_ident::is_var() const {
cs_ident_type tp = get_type();
2021-03-18 20:55:14 +01:00
return (tp >= cs_ident_type::IVAR) && (tp <= cs_ident_type::SVAR);
2016-08-18 00:54:57 +02:00
}
2017-02-13 18:10:40 +01:00
cs_var *cs_ident::get_var() {
2016-08-18 00:54:57 +02:00
if (!is_var()) {
return nullptr;
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_var *>(this);
2016-08-18 00:54:57 +02:00
}
2017-02-13 18:10:40 +01:00
cs_var const *cs_ident::get_var() const {
2016-08-18 00:54:57 +02:00
if (!is_var()) {
return nullptr;
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_var const *>(this);
2016-08-18 00:54:57 +02:00
}
2017-02-13 18:10:40 +01:00
bool cs_ident::is_ivar() const {
2021-03-18 20:55:14 +01:00
return get_type() == cs_ident_type::IVAR;
2016-08-18 00:54:57 +02:00
}
2017-02-13 18:10:40 +01:00
cs_ivar *cs_ident::get_ivar() {
2016-08-18 00:54:57 +02:00
if (!is_ivar()) {
return nullptr;
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_ivar *>(this);
2016-08-18 00:54:57 +02:00
}
2017-02-13 18:10:40 +01:00
cs_ivar const *cs_ident::get_ivar() const {
2016-08-18 00:54:57 +02:00
if (!is_ivar()) {
return nullptr;
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_ivar const *>(this);
2016-08-18 00:54:57 +02:00
}
2017-02-13 18:10:40 +01:00
bool cs_ident::is_fvar() const {
2021-03-18 20:55:14 +01:00
return get_type() == cs_ident_type::FVAR;
2016-08-18 00:54:57 +02:00
}
2017-02-13 18:10:40 +01:00
cs_fvar *cs_ident::get_fvar() {
2016-08-18 00:54:57 +02:00
if (!is_fvar()) {
return nullptr;
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_fvar *>(this);
2016-08-18 00:54:57 +02:00
}
2017-02-13 18:10:40 +01:00
cs_fvar const *cs_ident::get_fvar() const {
2016-08-18 00:54:57 +02:00
if (!is_fvar()) {
return nullptr;
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_fvar const *>(this);
2016-08-18 00:54:57 +02:00
}
2017-02-13 18:10:40 +01:00
bool cs_ident::is_svar() const {
2021-03-18 20:55:14 +01:00
return get_type() == cs_ident_type::SVAR;
2016-08-18 00:54:57 +02:00
}
2017-02-13 18:10:40 +01:00
cs_svar *cs_ident::get_svar() {
2016-08-18 00:54:57 +02:00
if (!is_svar()) {
return nullptr;
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_svar *>(this);
2016-08-18 00:54:57 +02:00
}
2017-02-13 18:10:40 +01:00
cs_svar const *cs_ident::get_svar() const {
2016-08-18 00:54:57 +02:00
if (!is_svar()) {
return nullptr;
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_svar const *>(this);
2016-08-18 00:54:57 +02:00
}
2017-02-13 18:10:40 +01:00
cs_int cs_ivar::get_val_min() const {
2016-08-18 04:14:55 +02:00
return p_minval;
}
2017-02-13 18:10:40 +01:00
cs_int cs_ivar::get_val_max() const {
2016-08-18 04:14:55 +02:00
return p_maxval;
}
2017-02-13 18:10:40 +01:00
cs_int cs_ivar::get_value() const {
2016-08-22 19:43:58 +02:00
return p_storage;
}
2017-02-13 18:10:40 +01:00
void cs_ivar::set_value(cs_int val) {
2016-08-22 19:43:58 +02:00
p_storage = val;
2016-08-18 04:14:55 +02:00
}
2017-02-13 18:10:40 +01:00
cs_float cs_fvar::get_val_min() const {
2016-08-18 04:14:55 +02:00
return p_minval;
}
2017-02-13 18:10:40 +01:00
cs_float cs_fvar::get_val_max() const {
2016-08-18 04:14:55 +02:00
return p_maxval;
}
2017-02-13 18:10:40 +01:00
cs_float cs_fvar::get_value() const {
2016-08-22 19:43:58 +02:00
return p_storage;
}
2017-02-13 18:10:40 +01:00
void cs_fvar::set_value(cs_float val) {
2016-08-22 19:43:58 +02:00
p_storage = val;
2016-08-18 04:14:55 +02:00
}
2021-03-17 23:32:38 +01:00
cs_strref cs_svar::get_value() const {
return p_storage;
2016-08-22 19:43:58 +02:00
}
2021-03-17 23:32:38 +01:00
void cs_svar::set_value(cs_strref val) {
p_storage = val;
2016-08-18 04:14:55 +02:00
}
std::string_view cs_command::get_args() const {
2016-09-02 22:49:05 +02:00
return p_cargs;
}
2017-02-13 18:10:40 +01:00
int cs_command::get_num_args() const {
2016-09-02 22:49:05 +02:00
return p_numargs;
}
2017-02-13 18:10:40 +01:00
void cs_init_lib_base(cs_state &cs);
2017-02-13 18:10:40 +01:00
cs_state::cs_state(cs_alloc_cb func, void *data):
2016-10-02 13:56:55 +02:00
p_state(nullptr), p_callhook()
{
2016-10-02 13:56:55 +02:00
if (!func) {
func = cs_default_alloc;
}
/* allocator is not set up yet, use func directly */
2017-02-13 18:10:40 +01:00
p_state = static_cast<cs_shared_state *>(
func(data, nullptr, 0, sizeof(cs_shared_state))
2016-10-02 13:56:55 +02:00
);
/* allocator will be set up in the constructor */
new (p_state) cs_shared_state{func, data};
2018-04-26 19:23:11 +02:00
p_owner = true;
2016-10-02 13:56:55 +02:00
2016-02-07 00:17:28 +01:00
for (int i = 0; i < MaxArguments; ++i) {
char buf[32];
snprintf(buf, sizeof(buf), "arg%d", i + 1);
2017-02-13 18:10:40 +01:00
new_ident(static_cast<char const *>(buf), CS_IDF_ARG);
}
2017-02-13 18:10:40 +01:00
cs_ident *id = new_ident("//dummy");
if (id->get_index() != DummyIdx) {
throw cs_internal_error{"invalid dummy index"};
}
2016-09-02 19:01:25 +02:00
id = new_ivar("numargs", MaxArguments, 0, 0);
if (id->get_index() != NumargsIdx) {
throw cs_internal_error{"invalid numargs index"};
}
2016-09-02 19:01:25 +02:00
id = new_ivar("dbgalias", 0, 1000, 4);
if (id->get_index() != DbgaliasIdx) {
throw cs_internal_error{"invalid dbgalias index"};
}
new_command("do", "e", [](auto &cs, auto args, auto &res) {
cs.run(args[0].get_code(), res);
2016-09-07 20:20:36 +02:00
})->p_type = CsIdDo;
2016-09-02 19:01:25 +02:00
new_command("doargs", "e", [](auto &cs, auto args, auto &res) {
cs_do_args(cs, [&cs, &res, &args]() {
cs.run(args[0].get_code(), res);
});
2016-09-07 20:20:36 +02:00
})->p_type = CsIdDoArgs;
2016-09-02 19:01:25 +02:00
new_command("if", "tee", [](auto &cs, auto args, auto &res) {
cs.run((args[0].get_bool() ? args[1] : args[2]).get_code(), res);
2016-09-07 20:20:36 +02:00
})->p_type = CsIdIf;
2016-09-02 19:01:25 +02:00
new_command("result", "t", [](auto &, auto args, auto &res) {
2017-01-25 01:57:33 +01:00
res = std::move(args[0]);
2016-09-07 20:20:36 +02:00
})->p_type = CsIdResult;
2016-09-02 19:01:25 +02:00
new_command("!", "t", [](auto &, auto args, auto &res) {
2016-09-02 19:01:25 +02:00
res.set_int(!args[0].get_bool());
2016-09-07 20:20:36 +02:00
})->p_type = CsIdNot;
2016-09-02 19:01:25 +02:00
new_command("&&", "E1V", [](auto &cs, auto args, auto &res) {
2016-09-02 19:01:25 +02:00
if (args.empty()) {
res.set_int(1);
} else {
2017-01-25 02:09:50 +01:00
for (size_t i = 0; i < args.size(); ++i) {
2017-02-13 18:10:40 +01:00
cs_bcode *code = args[i].get_code();
2016-09-02 19:01:25 +02:00
if (code) {
cs.run(code, res);
2016-09-02 19:01:25 +02:00
} else {
2017-01-25 01:57:33 +01:00
res = std::move(args[i]);
2016-09-02 19:01:25 +02:00
}
if (!res.get_bool()) {
break;
}
}
}
2016-09-07 20:20:36 +02:00
})->p_type = CsIdAnd;
2016-09-02 19:01:25 +02:00
new_command("||", "E1V", [](auto &cs, auto args, auto &res) {
2016-09-02 19:01:25 +02:00
if (args.empty()) {
res.set_int(0);
} else {
2017-01-25 02:09:50 +01:00
for (size_t i = 0; i < args.size(); ++i) {
2017-02-13 18:10:40 +01:00
cs_bcode *code = args[i].get_code();
2016-09-02 19:01:25 +02:00
if (code) {
cs.run(code, res);
2016-09-02 19:01:25 +02:00
} else {
2017-01-25 01:57:33 +01:00
res = std::move(args[i]);
2016-09-02 19:01:25 +02:00
}
if (res.get_bool()) {
break;
}
}
}
2016-09-07 20:20:36 +02:00
})->p_type = CsIdOr;
2016-09-02 19:01:25 +02:00
new_command("local", "", nullptr)->p_type = CsIdLocal;
2016-09-02 19:01:25 +02:00
2016-09-15 02:12:22 +02:00
new_command("break", "", [](auto &cs, auto, auto &) {
if (cs.is_in_loop()) {
throw CsBreakException();
} else {
2017-02-13 18:10:40 +01:00
throw cs_error(cs, "no loop to break");
2016-09-15 02:12:22 +02:00
}
})->p_type = CsIdBreak;
new_command("continue", "", [](auto &cs, auto, auto &) {
if (cs.is_in_loop()) {
throw CsContinueException();
} else {
2017-02-13 18:10:40 +01:00
throw cs_error(cs, "no loop to continue");
2016-09-15 02:12:22 +02:00
}
})->p_type = CsIdContinue;
cs_init_lib_base(*this);
}
LIBCUBESCRIPT_EXPORT cs_state::~cs_state() {
2018-04-26 19:23:11 +02:00
destroy();
}
LIBCUBESCRIPT_EXPORT void cs_state::destroy() {
2018-04-26 19:23:11 +02:00
if (!p_state || !p_owner) {
return;
}
2017-01-31 19:28:34 +01:00
for (auto &p: p_state->idents) {
2017-02-13 18:10:40 +01:00
cs_ident *i = p.second;
cs_alias *a = i->get_alias();
2016-08-18 03:53:51 +02:00
if (a) {
2021-03-18 20:55:14 +01:00
a->get_value().force_none();
2018-04-27 23:53:55 +02:00
cs_alias_internal::clean_code(a);
}
p_state->destroy(i);
}
p_state->destroy(p_state->strman);
p_state->destroy(p_state);
}
2018-04-26 19:23:11 +02:00
cs_state::cs_state(cs_shared_state *s):
p_state(s), p_owner(false)
{}
LIBCUBESCRIPT_EXPORT cs_state cs_state::new_thread() {
2018-04-26 19:23:11 +02:00
return cs_state{p_state};
}
LIBCUBESCRIPT_EXPORT cs_hook_cb cs_state::set_call_hook(cs_hook_cb func) {
2017-01-25 01:57:33 +01:00
auto hk = std::move(p_callhook);
p_callhook = std::move(func);
return hk;
}
LIBCUBESCRIPT_EXPORT cs_hook_cb const &cs_state::get_call_hook() const {
return p_callhook;
}
LIBCUBESCRIPT_EXPORT cs_hook_cb &cs_state::get_call_hook() {
return p_callhook;
}
LIBCUBESCRIPT_EXPORT cs_vprint_cb cs_state::set_var_printer(cs_vprint_cb func) {
2021-03-18 00:03:30 +01:00
auto fn = std::move(p_state->varprintf);
p_state->varprintf = std::move(func);
return fn;
}
LIBCUBESCRIPT_EXPORT cs_vprint_cb const &cs_state::get_var_printer() const {
2021-03-18 00:03:30 +01:00
return p_state->varprintf;
}
2017-02-13 18:10:40 +01:00
void *cs_state::alloc(void *ptr, size_t os, size_t ns) {
return p_state->alloc(ptr, os, ns);
}
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: {
2017-02-13 18:10:40 +01:00
cs_alias &a = static_cast<cs_alias &>(id);
2018-04-27 23:53:55 +02:00
cs_alias_internal::clean_code(&a);
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: {
2017-02-13 18:10:40 +01:00
cs_ivar &iv = static_cast<cs_ivar &>(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: {
2017-02-13 18:10:40 +01:00
cs_fvar &fv = static_cast<cs_fvar &>(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: {
2017-02-13 18:10:40 +01:00
cs_svar &sv = static_cast<cs_svar &>(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;
}
2017-02-13 18:10:40 +01:00
id.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
}
}
LIBCUBESCRIPT_EXPORT cs_ident *cs_state::add_ident(cs_ident *id) {
2016-08-18 03:53:51 +02:00
if (!id) {
return nullptr;
}
p_state->idents[id->get_name()] = id;
id->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-17 23:32:38 +01:00
id = add_ident(p_state->create<cs_alias>(
*this, cs_strref{*p_state, name}, flags
));
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-17 23:32:38 +01:00
return add_ident(p_state->create<cs_ivar>(
cs_strref{*p_state, n}, m, x, v, std::move(f), flags
))->get_ivar();
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-17 23:32:38 +01:00
return add_ident(p_state->create<cs_fvar>(
cs_strref{*p_state, n}, m, x, v, std::move(f), flags
))->get_fvar();
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-17 23:32:38 +01:00
return add_ident(p_state->create<cs_svar>(
cs_strref{*p_state, n}, cs_strref{*p_state, v},
cs_strref{*p_state, ""}, std::move(f), flags
))->get_svar();
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()) {
2017-02-13 18:10:40 +01:00
static_cast<cs_var *>(id)->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: {
2017-02-13 18:10:40 +01:00
cs_alias *a = static_cast<cs_alias *>(id);
2016-08-18 03:53:51 +02:00
if (a->get_index() < MaxArguments) {
2018-04-27 23:53:55 +02:00
cs_alias_internal::set_arg(a, *this, v);
2016-08-17 18:53:38 +02:00
} else {
2018-04-27 23:53:55 +02:00
cs_alias_internal::set_alias(a, *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 {
add_ident(p_state->create<cs_alias>(
2021-03-17 23:32:38 +01:00
*this, cs_strref{*p_state, name}, std::move(v), identflags
));
2015-08-07 00:38:22 +02:00
}
}
LIBCUBESCRIPT_EXPORT void cs_state::print_var(cs_var const &v) const {
2021-03-18 00:03:30 +01:00
p_state->varprintf(*this, v);
2015-08-07 22:38:57 +02:00
}
2017-02-13 18:10:40 +01:00
void cs_alias::get_cval(cs_value &v) const {
2016-08-31 20:18:53 +02:00
switch (p_val.get_type()) {
2021-03-18 20:55:14 +01:00
case cs_value_type::STRING:
v = p_val;
2016-08-17 18:53:38 +02:00
break;
2021-03-18 20:55:14 +01:00
case cs_value_type::INT:
2016-08-31 20:18:53 +02:00
v.set_int(p_val.get_int());
2016-08-17 18:53:38 +02:00
break;
2021-03-18 20:55:14 +01:00
case cs_value_type::FLOAT:
2016-08-31 20:18:53 +02:00
v.set_float(p_val.get_float());
2016-08-17 18:53:38 +02:00
break;
default:
2021-03-18 20:55:14 +01:00
v.set_none();
2016-08-17 18:53:38 +02:00
break;
2015-08-11 22:41:12 +02:00
}
}
2017-02-13 18:10:40 +01:00
cs_ident_type cs_ident::get_type() const {
2016-09-07 20:20:36 +02:00
if (p_type > CsIdAlias) {
2021-03-18 20:55:14 +01:00
return cs_ident_type::SPECIAL;
2016-08-10 19:33:43 +02:00
}
2017-02-13 18:10:40 +01:00
return cs_ident_type(p_type);
2016-08-18 03:53:51 +02:00
}
std::string_view cs_ident::get_name() const {
2016-08-18 03:53:51 +02:00
return p_name;
}
2017-02-13 18:10:40 +01:00
int cs_ident::get_flags() const {
2016-08-18 03:53:51 +02:00
return p_flags;
}
2017-02-13 18:10:40 +01:00
int cs_ident::get_index() const {
2016-08-18 03:53:51 +02:00
return p_index;
2016-08-10 19:33:43 +02:00
}
2016-08-22 19:43:58 +02:00
template<typename SF>
2017-02-13 18:10:40 +01:00
static inline void cs_override_var(cs_state &cs, cs_var *v, int &vflags, SF sf) {
if ((cs.identflags & CS_IDF_OVERRIDDEN) || (vflags & CS_IDF_OVERRIDE)) {
if (vflags & CS_IDF_PERSIST) {
throw cs_error(
2021-03-20 08:22:15 +01:00
cs, "cannot override persistent variable '%s'",
v->get_name().data()
2016-08-17 23:29:31 +02:00
);
2015-08-07 03:11:53 +02:00
}
2017-02-13 18:10:40 +01:00
if (!(vflags & CS_IDF_OVERRIDDEN)) {
2015-08-07 03:11:53 +02:00
sf();
2017-02-13 18:10:40 +01:00
vflags |= CS_IDF_OVERRIDDEN;
2016-08-17 18:53:38 +02:00
}
2015-08-07 03:11:53 +02:00
} else {
2017-02-13 18:10:40 +01:00
if (vflags & CS_IDF_OVERRIDDEN) {
vflags &= ~CS_IDF_OVERRIDDEN;
2015-08-07 03:11:53 +02:00
}
}
}
LIBCUBESCRIPT_EXPORT void cs_state::set_var_int(
std::string_view name, cs_int v, bool dofunc, bool doclamp
2016-08-17 18:53:38 +02:00
) {
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_ivar()) {
2015-08-07 03:11:53 +02:00
return;
2016-08-17 18:53:38 +02:00
}
2017-02-13 18:10:40 +01:00
cs_ivar *iv = static_cast<cs_ivar *>(id);
cs_override_var(
2016-08-18 03:53:51 +02:00
*this, iv, iv->p_flags,
2016-08-22 19:43:58 +02:00
[&iv]() { iv->p_overrideval = iv->get_value(); }
2016-08-17 18:53:38 +02:00
);
if (doclamp) {
2017-02-18 17:49:01 +01:00
iv->set_value(std::clamp(v, iv->get_val_min(), iv->get_val_max()));
2016-08-17 18:53:38 +02:00
} else {
2016-08-22 19:43:58 +02:00
iv->set_value(v);
2016-08-17 18:53:38 +02:00
}
if (dofunc) {
iv->changed(*this);
2016-08-17 18:53:38 +02:00
}
2015-08-07 03:11:53 +02:00
}
LIBCUBESCRIPT_EXPORT void cs_state::set_var_float(
std::string_view name, cs_float v, bool dofunc, bool doclamp
2016-08-17 18:53:38 +02:00
) {
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_fvar()) {
2015-08-07 03:11:53 +02:00
return;
2016-08-17 18:53:38 +02:00
}
2017-02-13 18:10:40 +01:00
cs_fvar *fv = static_cast<cs_fvar *>(id);
cs_override_var(
2016-08-18 03:53:51 +02:00
*this, fv, fv->p_flags,
2016-08-22 19:43:58 +02:00
[&fv]() { fv->p_overrideval = fv->get_value(); }
2016-08-17 18:53:38 +02:00
);
if (doclamp) {
2017-02-18 17:49:01 +01:00
fv->set_value(std::clamp(v, fv->get_val_min(), fv->get_val_max()));
2016-08-17 18:53:38 +02:00
} else {
2016-08-22 19:43:58 +02:00
fv->set_value(v);
2016-08-17 18:53:38 +02:00
}
if (dofunc) {
fv->changed(*this);
2016-08-17 18:53:38 +02:00
}
2015-08-07 03:11:53 +02:00
}
LIBCUBESCRIPT_EXPORT void cs_state::set_var_str(
std::string_view name, std::string_view v, bool dofunc
2016-08-17 18:53:38 +02:00
) {
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_svar()) {
2015-08-07 03:11:53 +02:00
return;
2016-08-17 18:53:38 +02:00
}
2017-02-13 18:10:40 +01:00
cs_svar *sv = static_cast<cs_svar *>(id);
cs_override_var(
2016-08-18 03:53:51 +02:00
*this, sv, sv->p_flags,
2016-08-22 19:43:58 +02:00
[&sv]() { sv->p_overrideval = sv->get_value(); }
2016-08-17 18:53:38 +02:00
);
2021-03-17 23:32:38 +01:00
sv->set_value(cs_strref{*p_state, v});
2016-08-17 18:53:38 +02:00
if (dofunc) {
sv->changed(*this);
2016-08-17 18:53:38 +02:00
}
2015-08-07 03:11:53 +02:00
}
LIBCUBESCRIPT_EXPORT std::optional<cs_int>
cs_state::get_var_int(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_ivar()) {
2017-01-30 19:38:11 +01:00
return std::nullopt;
2016-08-17 18:53:38 +02:00
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_ivar *>(id)->get_value();
2015-08-07 03:11:53 +02:00
}
LIBCUBESCRIPT_EXPORT std::optional<cs_float>
cs_state::get_var_float(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_fvar()) {
2017-01-30 19:38:11 +01:00
return std::nullopt;
2016-08-17 18:53:38 +02:00
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_fvar *>(id)->get_value();
2015-08-07 03:11:53 +02:00
}
LIBCUBESCRIPT_EXPORT std::optional<cs_strref>
cs_state::get_var_str(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_svar()) {
2017-01-30 19:38:11 +01:00
return std::nullopt;
2016-08-17 18:53:38 +02:00
}
return cs_strref{*p_state, static_cast<cs_svar *>(id)->get_value()};
2015-08-07 03:11:53 +02:00
}
LIBCUBESCRIPT_EXPORT std::optional<cs_int>
cs_state::get_var_min_int(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_ivar()) {
2017-01-30 19:38:11 +01:00
return std::nullopt;
2016-08-17 18:53:38 +02:00
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_ivar *>(id)->get_val_min();
2015-08-07 03:11:53 +02:00
}
LIBCUBESCRIPT_EXPORT std::optional<cs_int>
cs_state::get_var_max_int(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_ivar()) {
2017-01-30 19:38:11 +01:00
return std::nullopt;
2016-08-17 18:53:38 +02:00
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_ivar *>(id)->get_val_max();
2015-08-07 03:11:53 +02:00
}
LIBCUBESCRIPT_EXPORT std::optional<cs_float>
cs_state::get_var_min_float(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_fvar()) {
2017-01-30 19:38:11 +01:00
return std::nullopt;
2016-08-17 18:53:38 +02:00
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_fvar *>(id)->get_val_min();
2015-08-07 03:11:53 +02:00
}
LIBCUBESCRIPT_EXPORT std::optional<cs_float>
cs_state::get_var_max_float(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_fvar()) {
2017-01-30 19:38:11 +01:00
return std::nullopt;
2016-08-17 18:53:38 +02:00
}
2017-02-13 18:10:40 +01:00
return static_cast<cs_fvar *>(id)->get_val_max();
2015-08-07 03:11:53 +02:00
}
LIBCUBESCRIPT_EXPORT std::optional<cs_strref>
cs_state::get_alias_val(std::string_view name) {
2017-02-13 18:10:40 +01:00
cs_alias *a = get_alias(name);
2016-08-17 23:29:31 +02:00
if (!a) {
2017-01-30 19:38:11 +01:00
return std::nullopt;
2016-08-17 18:53:38 +02:00
}
2016-09-10 19:54:55 +02:00
if ((a->get_index() < MaxArguments) && !cs_is_arg_used(*this, a)) {
2017-01-30 19:38:11 +01:00
return std::nullopt;
2016-08-17 18:53:38 +02:00
}
2017-01-30 01:18:55 +01:00
return a->get_value().get_str();
2015-08-07 03:11:53 +02:00
}
2017-02-13 18:10:40 +01:00
cs_int cs_clamp_var(cs_state &cs, cs_ivar *iv, cs_int v) {
2016-08-18 04:14:55 +02:00
if (v < iv->get_val_min()) {
v = iv->get_val_min();
} else if (v > iv->get_val_max()) {
v = iv->get_val_max();
2016-08-17 18:53:38 +02:00
} else {
2015-08-07 03:44:51 +02:00
return v;
2016-08-17 18:53:38 +02:00
}
2017-02-13 18:10:40 +01:00
throw cs_error(
2016-08-17 18:53:38 +02:00
cs,
2017-02-13 18:10:40 +01:00
(iv->get_flags() & CS_IDF_HEX)
2016-08-17 18:53:38 +02:00
? (
2016-08-18 04:14:55 +02:00
(iv->get_val_min() <= 255)
2016-08-17 18:53:38 +02:00
? "valid range for '%s' is %d..0x%X"
: "valid range for '%s' is 0x%X..0x%X"
)
: "valid range for '%s' is %d..%d",
2021-03-20 08:22:15 +01:00
iv->get_name().data(), iv->get_val_min(), iv->get_val_max()
2016-08-17 18:53:38 +02:00
);
}
LIBCUBESCRIPT_EXPORT void cs_state::set_var_int_checked(cs_ivar *iv, cs_int v) {
2017-02-13 18:10:40 +01:00
if (iv->get_flags() & CS_IDF_READONLY) {
throw cs_error(
2021-03-20 08:22:15 +01:00
*this, "variable '%s' is read only", iv->get_name().data()
);
}
cs_override_var(
2016-08-18 03:53:51 +02:00
*this, iv, iv->p_flags,
2016-08-22 19:43:58 +02:00
[&iv]() { iv->p_overrideval = iv->get_value(); }
2016-08-17 18:53:38 +02:00
);
2016-08-18 04:14:55 +02:00
if ((v < iv->get_val_min()) || (v > iv->get_val_max())) {
2016-08-17 23:29:31 +02:00
v = cs_clamp_var(*this, iv, v);
2016-08-17 18:53:38 +02:00
}
2016-08-22 19:43:58 +02:00
iv->set_value(v);
iv->changed(*this);
}
LIBCUBESCRIPT_EXPORT void cs_state::set_var_int_checked(
2021-03-20 05:41:25 +01:00
cs_ivar *iv, std::span<cs_value> args
) {
2017-02-13 18:10:40 +01:00
cs_int v = args[0].force_int();
if ((iv->get_flags() & CS_IDF_HEX) && (args.size() > 1)) {
2015-08-07 03:44:51 +02:00
v = (v << 16) | (args[1].force_int() << 8);
2016-08-17 18:53:38 +02:00
if (args.size() > 2) {
2015-08-07 03:44:51 +02:00
v |= args[2].force_int();
2016-08-17 18:53:38 +02:00
}
}
2016-08-17 23:29:31 +02:00
set_var_int_checked(iv, v);
}
2017-02-13 18:10:40 +01:00
cs_float cs_clamp_fvar(cs_state &cs, cs_fvar *fv, cs_float v) {
2016-08-18 04:14:55 +02:00
if (v < fv->get_val_min()) {
v = fv->get_val_min();
} else if (v > fv->get_val_max()) {
v = fv->get_val_max();
2016-08-17 18:53:38 +02:00
} else {
2015-08-07 03:44:51 +02:00
return v;
2016-08-17 18:53:38 +02:00
}
cs_value vmin{cs}, vmax{cs};
vmin.set_float(fv->get_val_min());
vmax.set_float(fv->get_val_max());
2017-02-13 18:10:40 +01:00
throw cs_error(
2021-03-20 08:22:15 +01:00
cs, "valid range for '%s' is %s..%s", fv->get_name().data(),
vmin.force_str(), vmax.force_str()
2016-08-17 18:53:38 +02:00
);
2015-08-07 03:44:51 +02:00
return v;
}
LIBCUBESCRIPT_EXPORT void cs_state::set_var_float_checked(cs_fvar *fv, cs_float v) {
2017-02-13 18:10:40 +01:00
if (fv->get_flags() & CS_IDF_READONLY) {
throw cs_error(
2021-03-20 08:22:15 +01:00
*this, "variable '%s' is read only", fv->get_name().data()
);
}
cs_override_var(
2016-08-18 03:53:51 +02:00
*this, fv, fv->p_flags,
2016-08-22 19:43:58 +02:00
[&fv]() { fv->p_overrideval = fv->get_value(); }
2016-08-17 18:53:38 +02:00
);
2016-08-18 04:14:55 +02:00
if ((v < fv->get_val_min()) || (v > fv->get_val_max())) {
2016-08-17 23:29:31 +02:00
v = cs_clamp_fvar(*this, fv, v);
2016-08-17 18:53:38 +02:00
}
2016-08-22 19:43:58 +02:00
fv->set_value(v);
fv->changed(*this);
}
LIBCUBESCRIPT_EXPORT void cs_state::set_var_str_checked(
cs_svar *sv, std::string_view v
2018-04-26 19:23:11 +02:00
) {
2017-02-13 18:10:40 +01:00
if (sv->get_flags() & CS_IDF_READONLY) {
throw cs_error(
2021-03-20 08:22:15 +01:00
*this, "variable '%s' is read only", sv->get_name().data()
);
}
cs_override_var(
2016-08-18 03:53:51 +02:00
*this, sv, sv->p_flags,
2016-08-22 19:43:58 +02:00
[&sv]() { sv->p_overrideval = sv->get_value(); }
2016-08-17 18:53:38 +02:00
);
2021-03-17 23:32:38 +01:00
sv->set_value(cs_strref{*p_state, v});
sv->changed(*this);
}
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-17 23:32:38 +01:00
return static_cast<cs_command *>(add_ident(p_state->create<cs_command>(
cs_strref{*p_state, name}, cs_strref{*p_state, args}, nargs,
std::move(func))
));
2016-08-10 19:33:43 +02:00
}
2016-08-17 18:53:38 +02:00
static inline void cs_do_loop(
2017-02-13 18:10:40 +01:00
cs_state &cs, cs_ident &id, cs_int offset, cs_int n, cs_int step,
cs_bcode *cond, cs_bcode *body
2016-08-17 18:53:38 +02:00
) {
cs_stacked_value idv{cs, &id};
2016-08-31 19:49:24 +02:00
if (n <= 0 || !idv.has_alias()) {
return;
2016-08-17 18:53:38 +02:00
}
2017-02-13 18:10:40 +01:00
for (cs_int i = 0; i < n; ++i) {
2016-08-31 19:49:24 +02:00
idv.set_int(offset + i * step);
idv.push();
if (cond && !cs.run(cond).get_bool()) {
2016-08-17 18:53:38 +02:00
break;
}
2016-09-14 23:24:13 +02:00
switch (cs.run_loop(body)) {
2021-03-18 20:55:14 +01:00
case cs_loop_state::BREAK:
2016-09-14 23:24:13 +02:00
goto end;
default: /* continue and normal */
break;
}
}
2016-09-14 23:24:13 +02:00
end:
return;
}
static inline void cs_loop_conc(
2017-02-13 18:10:40 +01:00
cs_state &cs, cs_value &res, cs_ident &id, cs_int offset, cs_int n,
cs_int step, cs_bcode *body, bool space
) {
cs_stacked_value idv{cs, &id};
2016-08-31 19:49:24 +02:00
if (n <= 0 || !idv.has_alias()) {
return;
2016-08-17 18:53:38 +02:00
}
2021-03-19 22:25:38 +01:00
cs_charbuf s{cs};
2017-02-13 18:10:40 +01:00
for (cs_int i = 0; i < n; ++i) {
2016-08-31 19:49:24 +02:00
idv.set_int(offset + i * step);
idv.push();
cs_value v{cs};
2016-09-14 23:24:13 +02:00
switch (cs.run_loop(body, v)) {
2021-03-18 20:55:14 +01:00
case cs_loop_state::BREAK:
2016-09-14 23:24:13 +02:00
goto end;
2021-03-18 20:55:14 +01:00
case cs_loop_state::CONTINUE:
2016-09-14 23:24:13 +02:00
continue;
default:
break;
}
2016-08-17 18:53:38 +02:00
if (space && i) {
2021-03-19 22:25:38 +01:00
s.push_back(' ');
2016-08-17 18:53:38 +02:00
}
2021-03-19 22:25:38 +01:00
s.append(v.get_str());
}
2016-09-14 23:24:13 +02:00
end:
2021-03-19 22:25:38 +01:00
res.set_str(s.str());
}
2017-02-13 18:10:40 +01:00
void cs_init_lib_base(cs_state &gcs) {
gcs.new_command("error", "s", [](auto &cs, auto args, auto &) {
2021-03-17 21:57:47 +01:00
throw cs_error(cs, args[0].get_str());
});
gcs.new_command("pcall", "err", [](auto &cs, auto args, auto &ret) {
2017-02-13 18:10:40 +01:00
cs_alias *cret = args[1].get_ident()->get_alias(),
2016-09-10 20:43:58 +02:00
*css = args[2].get_ident()->get_alias();
if (!cret || !css) {
ret.set_int(0);
return;
}
cs_value result{cs}, tback{cs};
bool rc = true;
try {
cs.run(args[0].get_code(), result);
2017-02-13 18:10:40 +01:00
} catch (cs_error const &e) {
result.set_str(e.what());
if (e.get_stack().get()) {
cs_charbuf buf{cs};
util::print_stack(std::back_inserter(buf), e.get_stack());
tback.set_str(buf.str());
2016-09-10 20:43:58 +02:00
}
rc = false;
2016-09-10 20:43:58 +02:00
}
ret.set_int(rc);
2018-04-27 23:53:55 +02:00
cs_alias_internal::set_alias(cret, cs, result);
cs_alias_internal::set_alias(css, cs, tback);
});
gcs.new_command("?", "ttt", [](auto &, auto args, auto &res) {
if (args[0].get_bool()) {
res = args[1];
} else {
res = args[2];
}
});
gcs.new_command("cond", "ee2V", [](auto &cs, auto args, auto &res) {
2017-01-25 02:09:50 +01:00
for (size_t i = 0; i < args.size(); i += 2) {
if ((i + 1) < args.size()) {
if (cs.run(args[i].get_code()).get_bool()) {
cs.run(args[i + 1].get_code(), res);
break;
}
} else {
cs.run(args[i].get_code(), res);
break;
}
}
});
gcs.new_command("case", "ite2V", [](auto &cs, auto args, auto &res) {
2017-02-13 18:10:40 +01:00
cs_int val = args[0].get_int();
2017-01-25 02:09:50 +01:00
for (size_t i = 1; (i + 1) < args.size(); i += 2) {
if (
2021-03-18 20:55:14 +01:00
(args[i].get_type() == cs_value_type::NONE) ||
(args[i].get_int() == val)
) {
cs.run(args[i + 1].get_code(), res);
2016-08-17 18:53:38 +02:00
return;
}
}
});
gcs.new_command("casef", "fte2V", [](auto &cs, auto args, auto &res) {
2017-02-13 18:10:40 +01:00
cs_float val = args[0].get_float();
2017-01-25 02:09:50 +01:00
for (size_t i = 1; (i + 1) < args.size(); i += 2) {
if (
2021-03-18 20:55:14 +01:00
(args[i].get_type() == cs_value_type::NONE) ||
(args[i].get_float() == val)
) {
cs.run(args[i + 1].get_code(), res);
2016-08-17 18:53:38 +02:00
return;
}
}
});
gcs.new_command("cases", "ste2V", [](auto &cs, auto args, auto &res) {
cs_strref val = args[0].get_str();
2017-01-25 02:09:50 +01:00
for (size_t i = 1; (i + 1) < args.size(); i += 2) {
if (
2021-03-18 20:55:14 +01:00
(args[i].get_type() == cs_value_type::NONE) ||
(args[i].get_str() == val)
) {
cs.run(args[i + 1].get_code(), res);
2016-08-17 18:53:38 +02:00
return;
}
}
});
gcs.new_command("pushif", "rte", [](auto &cs, auto args, auto &res) {
cs_stacked_value idv{cs, args[0].get_ident()};
2016-08-31 19:49:24 +02:00
if (!idv.has_alias() || (idv.get_alias()->get_index() < MaxArguments)) {
return;
2016-08-17 18:53:38 +02:00
}
2016-08-31 19:49:24 +02:00
if (args[1].get_bool()) {
idv = args[1];
2016-08-31 19:49:24 +02:00
idv.push();
cs.run(args[2].get_code(), res);
}
});
gcs.new_command("loop", "rie", [](auto &cs, auto args, auto &) {
cs_do_loop(
cs, *args[0].get_ident(), 0, args[1].get_int(), 1, nullptr,
args[2].get_code()
);
});
gcs.new_command("loop+", "riie", [](auto &cs, auto args, auto &) {
cs_do_loop(
cs, *args[0].get_ident(), args[1].get_int(), args[2].get_int(), 1,
nullptr, args[3].get_code()
);
});
gcs.new_command("loop*", "riie", [](auto &cs, auto args, auto &) {
cs_do_loop(
cs, *args[0].get_ident(), 0, args[1].get_int(), args[2].get_int(),
nullptr, args[3].get_code()
);
});
gcs.new_command("loop+*", "riiie", [](auto &cs, auto args, auto &) {
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()
);
});
gcs.new_command("loopwhile", "riee", [](auto &cs, auto args, auto &) {
cs_do_loop(
cs, *args[0].get_ident(), 0, args[1].get_int(), 1,
args[2].get_code(), args[3].get_code()
);
});
gcs.new_command("loopwhile+", "riiee", [](auto &cs, auto args, auto &) {
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()
);
});
gcs.new_command("loopwhile*", "riiee", [](auto &cs, auto args, auto &) {
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()
);
});
gcs.new_command("loopwhile+*", "riiiee", [](auto &cs, auto args, auto &) {
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()
);
});
gcs.new_command("while", "ee", [](auto &cs, auto args, auto &) {
2017-02-13 18:10:40 +01:00
cs_bcode *cond = args[0].get_code(), *body = args[1].get_code();
while (cs.run(cond).get_bool()) {
2016-09-14 23:24:13 +02:00
switch (cs.run_loop(body)) {
2021-03-18 20:55:14 +01:00
case cs_loop_state::BREAK:
2016-09-14 23:24:13 +02:00
goto end;
default: /* continue and normal */
break;
}
}
2016-09-14 23:24:13 +02:00
end:
return;
});
gcs.new_command("loopconcat", "rie", [](auto &cs, auto args, auto &res) {
cs_loop_conc(
cs, res, *args[0].get_ident(), 0, args[1].get_int(), 1,
args[2].get_code(), true
);
});
gcs.new_command("loopconcat+", "riie", [](auto &cs, auto args, auto &res) {
cs_loop_conc(
cs, res, *args[0].get_ident(), args[1].get_int(),
args[2].get_int(), 1, args[3].get_code(), true
);
});
gcs.new_command("loopconcat*", "riie", [](auto &cs, auto args, auto &res) {
cs_loop_conc(
cs, res, *args[0].get_ident(), 0, args[2].get_int(),
args[1].get_int(), args[3].get_code(), true
);
});
gcs.new_command("loopconcat+*", "riiie", [](auto &cs, auto args, auto &res) {
cs_loop_conc(
cs, res, *args[0].get_ident(), args[1].get_int(),
args[3].get_int(), args[2].get_int(), args[4].get_code(), true
);
});
gcs.new_command("loopconcatword", "rie", [](auto &cs, auto args, auto &res) {
cs_loop_conc(
cs, res, *args[0].get_ident(), 0, args[1].get_int(), 1,
args[2].get_code(), false
);
});
gcs.new_command("loopconcatword+", "riie", [](
auto &cs, auto args, auto &res
) {
cs_loop_conc(
cs, res, *args[0].get_ident(), args[1].get_int(),
args[2].get_int(), 1, args[3].get_code(), false
);
});
gcs.new_command("loopconcatword*", "riie", [](
auto &cs, auto args, auto &res
) {
cs_loop_conc(
cs, res, *args[0].get_ident(), 0, args[2].get_int(),
args[1].get_int(), args[3].get_code(), false
);
});
gcs.new_command("loopconcatword+*", "riiie", [](
auto &cs, auto args, auto &res
) {
cs_loop_conc(
cs, res, *args[0].get_ident(), args[1].get_int(), args[3].get_int(),
args[2].get_int(), args[4].get_code(), false
);
});
gcs.new_command("push", "rte", [](auto &cs, auto args, auto &res) {
cs_stacked_value idv{cs, args[0].get_ident()};
2016-08-31 19:49:24 +02:00
if (!idv.has_alias() || (idv.get_alias()->get_index() < MaxArguments)) {
2016-08-17 18:53:38 +02:00
return;
}
idv = args[1];
2016-08-31 19:49:24 +02:00
idv.push();
cs.run(args[2].get_code(), res);
});
gcs.new_command("resetvar", "s", [](auto &cs, auto args, auto &) {
2021-03-17 21:57:47 +01:00
cs.reset_var(args[0].get_str());
});
gcs.new_command("alias", "st", [](auto &cs, auto args, auto &) {
2021-03-17 21:57:47 +01:00
cs.set_alias(args[0].get_str(), args[1]);
});
gcs.new_command("getvarmin", "s", [](auto &cs, auto args, auto &res) {
2021-03-17 21:57:47 +01:00
res.set_int(cs.get_var_min_int(args[0].get_str()).value_or(0));
});
gcs.new_command("getvarmax", "s", [](auto &cs, auto args, auto &res) {
2021-03-17 21:57:47 +01:00
res.set_int(cs.get_var_max_int(args[0].get_str()).value_or(0));
});
gcs.new_command("getfvarmin", "s", [](auto &cs, auto args, auto &res) {
2021-03-17 21:57:47 +01:00
res.set_float(cs.get_var_min_float(args[0].get_str()).value_or(0.0f));
});
gcs.new_command("getfvarmax", "s", [](auto &cs, auto args, auto &res) {
2021-03-17 21:57:47 +01:00
res.set_float(cs.get_var_max_float(args[0].get_str()).value_or(0.0f));
});
gcs.new_command("identexists", "s", [](auto &cs, auto args, auto &res) {
2021-03-17 21:57:47 +01:00
res.set_int(cs.have_ident(args[0].get_str()));
});
gcs.new_command("getalias", "s", [](auto &cs, auto args, auto &res) {
2021-03-17 21:57:47 +01:00
auto s0 = cs.get_alias_val(args[0].get_str());
if (s0) {
res.set_str(*s0);
} else {
res.set_str("");
}
});
}
2017-02-13 18:10:40 +01:00
void cs_init_lib_math(cs_state &cs);
void cs_init_lib_string(cs_state &cs);
void cs_init_lib_list(cs_state &cs);
2015-08-08 02:40:29 +02:00
LIBCUBESCRIPT_EXPORT void cs_state::init_libs(int libs) {
2021-03-18 20:55:14 +01:00
if (libs & CS_LIB_MATH) {
2016-08-18 20:47:29 +02:00
cs_init_lib_math(*this);
2016-08-17 18:53:38 +02:00
}
2021-03-18 20:55:14 +01:00
if (libs & CS_LIB_STRING) {
2016-08-18 20:47:29 +02:00
cs_init_lib_string(*this);
2016-08-17 18:53:38 +02:00
}
2021-03-18 20:55:14 +01:00
if (libs & CS_LIB_LIST) {
2016-08-18 20:47:29 +02:00
cs_init_lib_list(*this);
2016-08-17 18:53:38 +02:00
}
2016-02-28 23:21:28 +01:00
}
2016-02-07 22:22:39 +01:00
} /* namespace cscript */