remove call() methods from state

master
Daniel Kolesa 2021-05-02 22:44:38 +02:00
parent 4dd1518f6c
commit 5b54c74f2a
16 changed files with 289 additions and 280 deletions

View File

@ -31,7 +31,7 @@ private:
base() {} base() {}
virtual ~base() {} virtual ~base() {}
virtual void move_to(base *) = 0; virtual void move_to(base *) = 0;
virtual R operator()(A &&...args) = 0; virtual R operator()(A &&...args) const = 0;
}; };
template<typename F> template<typename F>
@ -42,9 +42,9 @@ private:
::new (p) store{std::move(p_stor)}; ::new (p) store{std::move(p_stor)};
} }
virtual R operator()(A &&...args) { virtual R operator()(A &&...args) const {
return std::invoke(*std::launder( return std::invoke(*std::launder(
reinterpret_cast<F *>(&p_stor) reinterpret_cast<F const *>(&p_stor)
), std::forward<A>(args)...); ), std::forward<A>(args)...);
} }
@ -184,25 +184,25 @@ public:
f.p_func = as_base(&f.p_stor); f.p_func = as_base(&f.p_stor);
} else if (small_storage()) { } else if (small_storage()) {
/* copy allocator address/size */ /* copy allocator address/size */
memcpy(&tmp_stor, &f.p_stor, sizeof(tmp_stor)); std::memcpy(&tmp_stor, &f.p_stor, sizeof(tmp_stor));
p_func->move_to(as_base(&f.p_stor)); p_func->move_to(as_base(&f.p_stor));
p_func->~base(); p_func->~base();
p_func = f.p_func; p_func = f.p_func;
f.p_func = as_base(&f.p_stor); f.p_func = as_base(&f.p_stor);
memcpy(&p_stor, &tmp_stor, sizeof(tmp_stor)); std::memcpy(&p_stor, &tmp_stor, sizeof(tmp_stor));
} else if (f.small_storage()) { } else if (f.small_storage()) {
/* copy allocator address/size */ /* copy allocator address/size */
memcpy(&tmp_stor, &p_stor, sizeof(tmp_stor)); std::memcpy(&tmp_stor, &p_stor, sizeof(tmp_stor));
f.p_func->move_to(as_base(&p_stor)); f.p_func->move_to(as_base(&p_stor));
f.p_func->~base(); f.p_func->~base();
f.p_func = p_func; f.p_func = p_func;
p_func = as_base(&p_stor); p_func = as_base(&p_stor);
memcpy(&f.p_stor, &tmp_stor, sizeof(tmp_stor)); std::memcpy(&f.p_stor, &tmp_stor, sizeof(tmp_stor));
} else { } else {
/* copy allocator address/size */ /* copy allocator address/size */
memcpy(&tmp_stor, &p_stor, sizeof(tmp_stor)); std::memcpy(&tmp_stor, &p_stor, sizeof(tmp_stor));
memcpy(&p_stor, &f.p_stor, sizeof(tmp_stor)); std::memcpy(&p_stor, &f.p_stor, sizeof(tmp_stor));
memcpy(&f.p_stor, &tmp_stor, sizeof(tmp_stor)); std::memcpy(&f.p_stor, &tmp_stor, sizeof(tmp_stor));
std::swap(p_func, f.p_func); std::swap(p_func, f.p_func);
} }
} }
@ -211,7 +211,7 @@ public:
return !!p_func; return !!p_func;
} }
R operator()(A ...args) { R operator()(A ...args) const {
return (*p_func)(std::forward<A>(args)...); return (*p_func)(std::forward<A>(args)...);
} }
}; };

View File

@ -132,10 +132,26 @@ struct LIBCUBESCRIPT_EXPORT ident {
*/ */
bool is_persistent(state &cs) const; bool is_persistent(state &cs) const;
/** @brief Call the ident.
*
* The default implementation just throws a cubescript::error, since it
* is not callable. It can be overridden as needed.
*
* If a command, it will simply be executed with the given arguments,
* ensuring that missing ones are filled in and types are set properly.
* If a builtin variable, the appropriate handler will be called. If
* an alias, the value of it will be compiled and executed. Any other
* ident type will simply do nothing.
*
* @return the return value
*/
virtual any_value call(span_type<any_value> args, state &cs);
protected: protected:
friend struct ident_p; friend struct ident_p;
ident() = default; ident() = default;
virtual ~ident();
struct ident_impl *p_impl{}; struct ident_impl *p_impl{};
}; };
@ -195,6 +211,16 @@ struct LIBCUBESCRIPT_EXPORT global_var: ident {
*/ */
void save(state &cs); void save(state &cs);
/** @brief Call the variable.
*
* While variables are not callable by themselves, this acts like
* if calling the variable in the language. By default, that means
* doing it with zero arguments retrieves its value, while passing
* arguments will set its value. The actual semantics depend on how
* the handler is set up for each variable type.
*/
any_value call(span_type<any_value> args, state &cs);
protected: protected:
global_var() = default; global_var() = default;
}; };
@ -229,6 +255,9 @@ struct LIBCUBESCRIPT_EXPORT integer_var: global_var {
*/ */
void set_raw_value(integer_type val); void set_raw_value(integer_type val);
/** @brief Call override for integer vars. */
any_value call(span_type<any_value> args, state &cs);
protected: protected:
integer_var() = default; integer_var() = default;
}; };
@ -263,6 +292,9 @@ struct LIBCUBESCRIPT_EXPORT float_var: global_var {
*/ */
void set_raw_value(float_type val); void set_raw_value(float_type val);
/** @brief Call override for float vars. */
any_value call(span_type<any_value> args, state &cs);
protected: protected:
float_var() = default; float_var() = default;
}; };
@ -297,6 +329,9 @@ struct LIBCUBESCRIPT_EXPORT string_var: global_var {
*/ */
void set_raw_value(string_ref val); void set_raw_value(string_ref val);
/** @brief Call override for string vars. */
any_value call(span_type<any_value> args, state &cs);
protected: protected:
string_var() = default; string_var() = default;
}; };
@ -324,6 +359,12 @@ struct LIBCUBESCRIPT_EXPORT alias: ident {
/** @brief Set the value of the alias for the given thread. */ /** @brief Set the value of the alias for the given thread. */
void set_value(state &cs, any_value v); void set_value(state &cs, any_value v);
/** @brief Call an alias.
*
* The alias will be called like if it was called in the language.
*/
any_value call(span_type<any_value> args, state &cs);
protected: protected:
alias() = default; alias() = default;
}; };
@ -345,6 +386,12 @@ struct LIBCUBESCRIPT_EXPORT command: ident {
*/ */
int get_num_args() const; int get_num_args() const;
/** @brief Call a command.
*
* The command will be called like if it was called in the language.
*/
any_value call(span_type<any_value> args, state &cs);
protected: protected:
command() = default; command() = default;
}; };

View File

@ -71,16 +71,6 @@ using command_func = internal::callable<
void, state &, span_type<any_value>, any_value & void, state &, span_type<any_value>, any_value &
>; >;
/** @brief The loop state
*
* This is returned by state::call_loop().
*/
enum class loop_state {
NORMAL = 0, /**< @brief The iteration ended normally. */
BREAK, /**< @brief The iteration was broken out of. */
CONTINUE /**< @brief The iteration ended early. */
};
/** @brief The Cubescript thread /** @brief The Cubescript thread
* *
* Represents a Cubescript thread, either the main thread or a side thread * Represents a Cubescript thread, either the main thread or a side thread
@ -377,59 +367,17 @@ struct LIBCUBESCRIPT_EXPORT state {
/** @brief Get a span of all idents */ /** @brief Get a span of all idents */
span_type<ident const *> get_idents() const; span_type<ident const *> get_idents() const;
/** @brief Execute the given bytecode reference /** @brief Compile a string.
* *
* @return the return value * This compiles the given string, optionally using `source` as a filename
* for debug information (useful when implementing file I/O functions).
*
* @return a bytecode reference
* @throw cubescript::error on compilation failure
*/ */
any_value call(bcode_ref const &code); bcode_ref compile(
std::string_view v, std::string_view source = std::string_view{}
/** @brief Execute the given string as code );
*
* @return the return value
*/
any_value call(std::string_view code);
/** @brief Execute the given string as code
*
* This variant takes a file name to be included in debug information.
* While the library provides no way to deal with file I/O, this is a
* support function to make implementing these better.
*
* @param source a source file name
*
* @return the return value
*/
any_value call(std::string_view code, std::string_view source);
/** @brief Execute the given ident
*
* If a command, it will simply be executed with the given arguments,
* ensuring that missing ones are filled in and types are set properly.
* If a builtin variable, the appropriate handler will be called. If
* an alias, the value of it will be compiled and executed. Any other
* ident type will simply do nothing.
*
* @return the return value
*/
any_value call(ident &id, span_type<any_value> args);
/** @brief Execute a loop body
*
* This exists to implement custom loop commands. A loop command will
* consist of your desired loop and will take a body as an argument
* (with bytecode type); this body will be run using this API. The
* return value can be used to check if the loop was broken out of
* or continued, and take steps accordingly.
*
* Some loops may evaluate to values, while others may not.
*/
loop_state call_loop(bcode_ref const &code, any_value &ret);
/** @brief Execute a loop body
*
* This version ignores the return value of the body.
*/
loop_state call_loop(bcode_ref const &code);
/** @brief Get if the thread is in override mode /** @brief Get if the thread is in override mode
* *

View File

@ -20,6 +20,17 @@
namespace cubescript { namespace cubescript {
struct ident; struct ident;
struct any_value;
/** @brief The loop state
*
* This is returned by state::call_loop().
*/
enum class loop_state {
NORMAL = 0, /**< @brief The iteration ended normally. */
BREAK, /**< @brief The iteration was broken out of. */
CONTINUE /**< @brief The iteration ended early. */
};
/** @brief Bytecode reference. /** @brief Bytecode reference.
* *
@ -100,6 +111,30 @@ struct LIBCUBESCRIPT_EXPORT bcode_ref {
*/ */
explicit operator bool() const; explicit operator bool() const;
/** @brief Execute the bytecode
*
* @return the return value
*/
any_value call(state &cs) const;
/** @brief Execute the bytecode as a loop body
*
* This exists to implement custom loop commands. A loop command will
* consist of your desired loop and will take a body as an argument
* (with bytecode type); this body will be run using this API. The
* return value can be used to check if the loop was broken out of
* or continued, and take steps accordingly.
*
* Some loops may evaluate to values, while others may not.
*/
loop_state call_loop(state &cs, any_value &ret) const;
/** @brief Execute the byctecode as a loop body
*
* This version ignores the return value of the body.
*/
loop_state call_loop(state &cs) const;
private: private:
friend struct bcode_p; friend struct bcode_p;
@ -447,11 +482,13 @@ struct LIBCUBESCRIPT_EXPORT any_value {
* *
* If the contained value is already bytecode, nothing happens. Otherwise * If the contained value is already bytecode, nothing happens. Otherwise
* the value is converted to a string (like get_string()) and this string * the value is converted to a string (like get_string()) and this string
* is compiled as bytecode. * is compiled as bytecode (as if using state::compile())
* *
* @return A bytecode reference. * @return A bytecode reference.
*/ */
bcode_ref force_code(state &cs); bcode_ref force_code(
state &cs, std::string_view source = std::string_view{}
);
/** @brief Force the type to value_type::IDENT. /** @brief Force the type to value_type::IDENT.
* *

View File

@ -1,5 +1,6 @@
#include "cs_bcode.hh" #include "cs_bcode.hh"
#include "cs_state.hh" #include "cs_state.hh"
#include "cs_vm.hh"
namespace cubescript { namespace cubescript {
@ -45,6 +46,37 @@ LIBCUBESCRIPT_EXPORT bcode_ref::operator bool() const {
return p_code != nullptr; return p_code != nullptr;
} }
LIBCUBESCRIPT_EXPORT any_value bcode_ref::call(state &cs) const {
any_value ret{};
vm_exec(state_p{cs}.ts(), p_code->get_raw(), ret);
return ret;
}
LIBCUBESCRIPT_EXPORT loop_state bcode_ref::call_loop(
state &cs, any_value &ret
) const {
auto &ts = state_p{cs}.ts();
++ts.loop_level;
try {
ret = call(cs);
} catch (break_exception) {
--ts.loop_level;
return loop_state::BREAK;
} catch (continue_exception) {
--ts.loop_level;
return loop_state::CONTINUE;
} catch (...) {
--ts.loop_level;
throw;
}
return loop_state::NORMAL;
}
LIBCUBESCRIPT_EXPORT loop_state bcode_ref::call_loop(state &cs) const {
any_value ret{};
return call_loop(cs, ret);
}
/* private funcs */ /* private funcs */
struct bcode_hdr { struct bcode_hdr {

View File

@ -2,6 +2,7 @@
#include "cs_bcode.hh" #include "cs_bcode.hh"
#include "cs_thread.hh" #include "cs_thread.hh"
#include "cs_vm.hh"
namespace cubescript { namespace cubescript {
@ -106,7 +107,7 @@ void svar_impl::save_val() {
void command_impl::call( void command_impl::call(
thread_state &ts, span_type<any_value> args, any_value &ret thread_state &ts, span_type<any_value> args, any_value &ret
) { ) const {
auto idstsz = ts.idstack.size(); auto idstsz = ts.idstack.size();
try { try {
p_cb_cftv(*ts.pstate, args, ret); p_cb_cftv(*ts.pstate, args, ret);
@ -117,7 +118,7 @@ void command_impl::call(
ts.idstack.resize(idstsz); ts.idstack.resize(idstsz);
} }
bool ident_is_used_arg(ident *id, thread_state &ts) { bool ident_is_used_arg(ident const *id, thread_state &ts) {
if (!ts.callstack) { if (!ts.callstack) {
return true; return true;
} }
@ -155,6 +156,8 @@ void alias_stack::set_alias(alias *a, thread_state &ts, any_value &v) {
/* public interface */ /* public interface */
LIBCUBESCRIPT_EXPORT ident::~ident() {}
LIBCUBESCRIPT_EXPORT ident_type ident::get_type() const { LIBCUBESCRIPT_EXPORT ident_type ident::get_type() const {
if (p_impl->p_type > ID_ALIAS) { if (p_impl->p_type > ID_ALIAS) {
return ident_type::SPECIAL; return ident_type::SPECIAL;
@ -246,6 +249,10 @@ LIBCUBESCRIPT_EXPORT bool ident::is_persistent(state &cs) const {
return false; return false;
} }
LIBCUBESCRIPT_EXPORT any_value ident::call(span_type<any_value>, state &cs) {
throw error{cs, "this ident type is not callable"};
}
LIBCUBESCRIPT_EXPORT bool global_var::is_read_only() const { LIBCUBESCRIPT_EXPORT bool global_var::is_read_only() const {
return (p_impl->p_flags & IDENT_FLAG_READONLY); return (p_impl->p_flags & IDENT_FLAG_READONLY);
} }
@ -282,6 +289,12 @@ LIBCUBESCRIPT_EXPORT void global_var::save(state &cs) {
} }
} }
LIBCUBESCRIPT_EXPORT any_value global_var::call(
span_type<any_value> args, state &cs
) {
return ident::call(args, cs);
}
LIBCUBESCRIPT_EXPORT integer_type integer_var::get_value() const { LIBCUBESCRIPT_EXPORT integer_type integer_var::get_value() const {
return static_cast<ivar_impl const *>(this)->p_storage; return static_cast<ivar_impl const *>(this)->p_storage;
} }
@ -308,6 +321,32 @@ LIBCUBESCRIPT_EXPORT void integer_var::set_raw_value(integer_type val) {
static_cast<ivar_impl *>(this)->p_storage = val; static_cast<ivar_impl *>(this)->p_storage = val;
} }
inline any_value call_var(
ident &id, command *hid, span_type<any_value> &args, state &cs
) {
any_value ret{};
auto &ts = state_p{cs}.ts();
auto *cimp = static_cast<command_impl *>(hid);
auto &targs = ts.vmstack;
auto osz = targs.size();
auto anargs = std::size_t(cimp->get_num_args());
auto nargs = args.size();
targs.resize(
osz + std::max(args.size(), anargs + 1)
);
for (std::size_t i = 0; i < nargs; ++i) {
targs[osz + i + 1] = args[i];
}
exec_command(ts, cimp, &id, &targs[osz], ret, nargs + 1, false);
return ret;
}
LIBCUBESCRIPT_EXPORT any_value integer_var::call(
span_type<any_value> args, state &cs
) {
return call_var(*this, state_p{cs}.ts().istate->cmd_ivar, args, cs);
}
LIBCUBESCRIPT_EXPORT float_type float_var::get_value() const { LIBCUBESCRIPT_EXPORT float_type float_var::get_value() const {
return static_cast<fvar_impl const *>(this)->p_storage; return static_cast<fvar_impl const *>(this)->p_storage;
} }
@ -334,6 +373,12 @@ LIBCUBESCRIPT_EXPORT void float_var::set_raw_value(float_type val) {
static_cast<fvar_impl *>(this)->p_storage = val; static_cast<fvar_impl *>(this)->p_storage = val;
} }
LIBCUBESCRIPT_EXPORT any_value float_var::call(
span_type<any_value> args, state &cs
) {
return call_var(*this, state_p{cs}.ts().istate->cmd_fvar, args, cs);
}
LIBCUBESCRIPT_EXPORT string_ref string_var::get_value() const { LIBCUBESCRIPT_EXPORT string_ref string_var::get_value() const {
return static_cast<svar_impl const *>(this)->p_storage; return static_cast<svar_impl const *>(this)->p_storage;
} }
@ -360,6 +405,12 @@ LIBCUBESCRIPT_EXPORT void string_var::set_raw_value(string_ref val) {
static_cast<svar_impl *>(this)->p_storage = val; static_cast<svar_impl *>(this)->p_storage = val;
} }
LIBCUBESCRIPT_EXPORT any_value string_var::call(
span_type<any_value> args, state &cs
) {
return call_var(*this, state_p{cs}.ts().istate->cmd_svar, args, cs);
}
LIBCUBESCRIPT_EXPORT any_value alias::get_value(state &cs) const { LIBCUBESCRIPT_EXPORT any_value alias::get_value(state &cs) const {
return state_p{cs}.ts().get_astack(this).node->val_s; return state_p{cs}.ts().get_astack(this).node->val_s;
} }
@ -377,6 +428,19 @@ LIBCUBESCRIPT_EXPORT bool alias::is_arg() const {
return (static_cast<alias_impl const *>(this)->p_flags & IDENT_FLAG_ARG); return (static_cast<alias_impl const *>(this)->p_flags & IDENT_FLAG_ARG);
} }
LIBCUBESCRIPT_EXPORT any_value alias::call(
span_type<any_value> args, state &cs
) {
any_value ret{};
auto &ts = state_p{cs}.ts();
if (is_arg() && !ident_is_used_arg(this, ts)) {
return ret;
}
auto nargs = args.size();
exec_alias(ts, this, &args[0], ret, nargs, nargs, 0, 0, BC_RET_NULL, true);
return ret;
}
LIBCUBESCRIPT_EXPORT std::string_view command::get_args() const { LIBCUBESCRIPT_EXPORT std::string_view command::get_args() const {
return static_cast<command_impl const *>(this)->p_cargs; return static_cast<command_impl const *>(this)->p_cargs;
} }
@ -385,6 +449,31 @@ LIBCUBESCRIPT_EXPORT int command::get_num_args() const {
return static_cast<command_impl const *>(this)->p_numargs; return static_cast<command_impl const *>(this)->p_numargs;
} }
LIBCUBESCRIPT_EXPORT any_value command::call(
span_type<any_value> args, state &cs
) {
any_value ret{};
auto &cimpl = static_cast<command_impl &>(*this);
if (!cimpl.p_cb_cftv) {
return ret;
}
auto nargs = args.size();
auto &ts = state_p{cs}.ts();
if (nargs < std::size_t(cimpl.get_num_args())) {
stack_guard s{ts}; /* restore after call */
auto &targs = ts.vmstack;
auto osz = targs.size();
targs.resize(osz + cimpl.get_num_args());
for (std::size_t i = 0; i < nargs; ++i) {
targs[osz + i] = args[i];
}
exec_command(ts, &cimpl, this, &targs[osz], ret, nargs, false);
} else {
exec_command(ts, &cimpl, this, &args[0], ret, nargs, false);
}
return ret;
}
/* external API for alias stack management */ /* external API for alias stack management */
LIBCUBESCRIPT_EXPORT alias_local::alias_local(state &cs, ident &a) { LIBCUBESCRIPT_EXPORT alias_local::alias_local(state &cs, ident &a) {

View File

@ -44,7 +44,7 @@ struct alias_stack {
}; };
struct ident_link { struct ident_link {
ident *id; ident const *id;
ident_link *next; ident_link *next;
std::bitset<MAX_ARGUMENTS> usedargs; std::bitset<MAX_ARGUMENTS> usedargs;
}; };
@ -126,14 +126,16 @@ struct command_impl: ident_impl, command {
string_ref name, string_ref args, int numargs, command_func func string_ref name, string_ref args, int numargs, command_func func
); );
void call(thread_state &ts, span_type<any_value> args, any_value &ret); void call(
thread_state &ts, span_type<any_value> args, any_value &ret
) const;
string_ref p_cargs; string_ref p_cargs;
command_func p_cb_cftv; command_func p_cb_cftv;
int p_numargs; int p_numargs;
}; };
bool ident_is_used_arg(ident *id, thread_state &ts); bool ident_is_used_arg(ident const *id, thread_state &ts);
struct ident_p { struct ident_p {
ident_p(ident &id): ip{&id} {} ident_p(ident &id): ip{&id} {}

View File

@ -173,19 +173,19 @@ state::state(alloc_func func, void *data) {
/* builtins */ /* builtins */
p = &new_command("do", "b", [](auto &cs, auto args, auto &res) { p = &new_command("do", "b", [](auto &cs, auto args, auto &res) {
res = cs.call(args[0].get_code()); res = args[0].get_code().call(cs);
}); });
static_cast<command_impl *>(p)->p_type = ID_DO; static_cast<command_impl *>(p)->p_type = ID_DO;
p = &new_command("doargs", "b", [](auto &cs, auto args, auto &res) { p = &new_command("doargs", "b", [](auto &cs, auto args, auto &res) {
call_with_args(*cs.p_tstate, [&cs, &res, &args]() { call_with_args(*cs.p_tstate, [&cs, &res, &args]() {
res = cs.call(args[0].get_code()); res = args[0].get_code().call(cs);
}); });
}); });
static_cast<command_impl *>(p)->p_type = ID_DOARGS; static_cast<command_impl *>(p)->p_type = ID_DOARGS;
p = &new_command("if", "abb", [](auto &cs, auto args, auto &res) { p = &new_command("if", "abb", [](auto &cs, auto args, auto &res) {
res = cs.call((args[0].get_bool() ? args[1] : args[2]).get_code()); res = (args[0].get_bool() ? args[1] : args[2]).get_code().call(cs);
}); });
static_cast<command_impl *>(p)->p_type = ID_IF; static_cast<command_impl *>(p)->p_type = ID_IF;
@ -206,7 +206,7 @@ state::state(alloc_func func, void *data) {
for (size_t i = 0; i < args.size(); ++i) { for (size_t i = 0; i < args.size(); ++i) {
auto code = args[i].get_code(); auto code = args[i].get_code();
if (code) { if (code) {
res = cs.call(code); res = code.call(cs);
} else { } else {
res = std::move(args[i]); res = std::move(args[i]);
} }
@ -225,7 +225,7 @@ state::state(alloc_func func, void *data) {
for (size_t i = 0; i < args.size(); ++i) { for (size_t i = 0; i < args.size(); ++i) {
auto code = args[i].get_code(); auto code = args[i].get_code();
if (code) { if (code) {
res = cs.call(code); res = code.call(cs);
} else { } else {
res = std::move(args[i]); res = std::move(args[i]);
} }
@ -485,7 +485,7 @@ LIBCUBESCRIPT_EXPORT void state::assign_value(
case ident_type::IVAR: case ident_type::IVAR:
case ident_type::FVAR: case ident_type::FVAR:
case ident_type::SVAR: case ident_type::SVAR:
call(id->get(), span_type<any_value>{&v, 1}); id->get().call(span_type<any_value>{&v, 1}, *this);
break; break;
default: default:
throw error{ throw error{
@ -693,154 +693,12 @@ do_add:
return *cmd; return *cmd;
} }
LIBCUBESCRIPT_EXPORT any_value state::call(bcode_ref const &code) { LIBCUBESCRIPT_EXPORT bcode_ref state::compile(
any_value ret{}; std::string_view v, std::string_view source
vm_exec(*p_tstate, bcode_p{code}.get()->get_raw(), ret);
return ret;
}
static any_value do_call(
thread_state &ts, std::string_view file, std::string_view code
) { ) {
any_value ret{}; gen_state gs{*p_tstate};
gen_state gs{ts}; gs.gen_main(v, source);
gs.gen_main(code, file); return gs.steal_ref();
auto cref = gs.steal_ref();
vm_exec(ts, bcode_p{cref}.get()->get_raw(), ret);
return ret;
}
LIBCUBESCRIPT_EXPORT any_value state::call(std::string_view code) {
return do_call(*p_tstate, std::string_view{}, code);
}
LIBCUBESCRIPT_EXPORT any_value state::call(
std::string_view code, std::string_view source
) {
return do_call(*p_tstate, source, code);
}
LIBCUBESCRIPT_EXPORT any_value state::call(
ident &id, span_type<any_value> args
) {
any_value ret{};
std::size_t nargs = args.size();
call_depth_guard level{*p_tstate}; /* incr and decr on scope exit */
switch (id.get_type()) {
default:
if (!ident_is_callable(&id)) {
break;
}
/* fallthrough */
case ident_type::COMMAND: {
auto &cimpl = static_cast<command_impl &>(id);
if (nargs < std::size_t(cimpl.get_num_args())) {
stack_guard s{*p_tstate}; /* restore after call */
auto &targs = p_tstate->vmstack;
auto osz = targs.size();
targs.resize(osz + cimpl.get_num_args());
for (std::size_t i = 0; i < nargs; ++i) {
targs[osz + i] = args[i];
}
exec_command(
*p_tstate, &cimpl, &id, &targs[osz], ret, nargs, false
);
} else {
exec_command(
*p_tstate, &cimpl, &id, &args[0], ret, nargs, false
);
}
nargs = 0;
break;
}
case ident_type::IVAR: {
auto *hid = p_tstate->istate->cmd_ivar;
auto *cimp = static_cast<command_impl *>(hid);
auto &targs = p_tstate->vmstack;
auto osz = targs.size();
auto anargs = std::size_t(cimp->get_num_args());
targs.resize(
osz + std::max(args.size(), anargs + 1)
);
for (std::size_t i = 0; i < nargs; ++i) {
targs[osz + i + 1] = args[i];
}
exec_command(
*p_tstate, cimp, &id, &targs[osz], ret, nargs + 1, false
);
break;
}
case ident_type::FVAR: {
auto *hid = p_tstate->istate->cmd_fvar;
auto *cimp = static_cast<command_impl *>(hid);
auto &targs = p_tstate->vmstack;
auto osz = targs.size();
auto anargs = std::size_t(cimp->get_num_args());
targs.resize(
osz + std::max(args.size(), anargs + 1)
);
for (std::size_t i = 0; i < nargs; ++i) {
targs[osz + i + 1] = args[i];
}
exec_command(
*p_tstate, cimp, &id, &targs[osz], ret, nargs + 1, false
);
break;
}
case ident_type::SVAR: {
auto *hid = p_tstate->istate->cmd_svar;
auto *cimp = static_cast<command_impl *>(hid);
auto &targs = p_tstate->vmstack;
auto osz = targs.size();
auto anargs = std::size_t(cimp->get_num_args());
targs.resize(
osz + std::max(args.size(), anargs + 1)
);
for (std::size_t i = 0; i < nargs; ++i) {
targs[osz + i + 1] = args[i];
}
exec_command(
*p_tstate, cimp, &id, &targs[osz], ret, nargs + 1, false
);
break;
}
case ident_type::ALIAS: {
alias &a = static_cast<alias &>(id);
if (a.is_arg() && !ident_is_used_arg(&a, *p_tstate)) {
break;
}
exec_alias(
*p_tstate, &a, &args[0], ret, nargs, nargs, 0, 0,
BC_RET_NULL, true
);
break;
}
}
return ret;
}
LIBCUBESCRIPT_EXPORT loop_state state::call_loop(
bcode_ref const &code, any_value &ret
) {
++p_tstate->loop_level;
try {
ret = call(code);
} catch (break_exception) {
--p_tstate->loop_level;
return loop_state::BREAK;
} catch (continue_exception) {
--p_tstate->loop_level;
return loop_state::CONTINUE;
} catch (...) {
--p_tstate->loop_level;
throw;
}
return loop_state::NORMAL;
}
LIBCUBESCRIPT_EXPORT loop_state state::call_loop(bcode_ref const &code) {
any_value ret{};
return call_loop(code, ret);
} }
LIBCUBESCRIPT_EXPORT bool state::get_override_mode() const { LIBCUBESCRIPT_EXPORT bool state::get_override_mode() const {

View File

@ -15,17 +15,16 @@ hook_func thread_state::set_hook(hook_func f) {
return hk; return hk;
} }
alias_stack &thread_state::get_astack(alias *a) { alias_stack &thread_state::get_astack(alias const *a) {
auto it = astacks.try_emplace(a->get_index()); auto it = astacks.try_emplace(a->get_index());
if (it.second) { if (it.second) {
it.first->second.node = &static_cast<alias_impl *>(a)->p_initial; auto *imp = const_cast<alias_impl *>(
it.first->second.flags = static_cast<alias_impl *>(a)->p_flags; static_cast<alias_impl const *>(a)
);
it.first->second.node = &imp->p_initial;
it.first->second.flags = imp->p_flags;
} }
return it.first->second; return it.first->second;
} }
alias_stack const &thread_state::get_astack(alias const *a) {
return get_astack(const_cast<alias *>(a));
}
} /* namespace cubescript */ } /* namespace cubescript */

View File

@ -52,8 +52,7 @@ struct thread_state {
hook_func &get_hook() { return call_hook; } hook_func &get_hook() { return call_hook; }
hook_func const &get_hook() const { return call_hook; } hook_func const &get_hook() const { return call_hook; }
alias_stack &get_astack(alias *a); alias_stack &get_astack(alias const *a);
alias_stack const &get_astack(alias const *a);
}; };
} /* namespace cubescript */ } /* namespace cubescript */

View File

@ -246,7 +246,7 @@ std::string_view any_value::force_string(state &cs) {
return str_managed_view(csv_get<char const *>(&p_stor)); return str_managed_view(csv_get<char const *>(&p_stor));
} }
bcode_ref any_value::force_code(state &cs) { bcode_ref any_value::force_code(state &cs, std::string_view source) {
switch (get_type()) { switch (get_type()) {
case value_type::CODE: case value_type::CODE:
return bcode_p::make_ref(csv_get<bcode *>(&p_stor)); return bcode_p::make_ref(csv_get<bcode *>(&p_stor));
@ -254,7 +254,7 @@ bcode_ref any_value::force_code(state &cs) {
break; break;
} }
gen_state gs{state_p{cs}.ts()}; gen_state gs{state_p{cs}.ts()};
gs.gen_main(get_string(cs)); gs.gen_main(get_string(cs), source);
auto bc = gs.steal_ref(); auto bc = gs.steal_ref();
set_code(bc); set_code(bc);
return bc; return bc;

View File

@ -114,9 +114,7 @@ void exec_command(
break; break;
case '.': case '.':
i = std::max(i + 1, numargs); i = std::max(i + 1, numargs);
static_cast<command_impl *>(id)->call( id->call(ts, span_type<any_value>{args, std::size_t(i)}, res);
ts, span_type<any_value>{args, std::size_t(i)}, res
);
return; return;
case '1': case '1':
case '2': case '2':
@ -130,9 +128,7 @@ void exec_command(
} }
} }
++i; ++i;
static_cast<command_impl *>(id)->call( id->call(ts, span_type<any_value>{args, std::size_t(i)}, res);
ts, span_type<any_value>{args, std::size_t(i)}, res
);
res.force_plain(); res.force_plain();
} }
@ -458,7 +454,7 @@ std::uint32_t *vm_exec(
call_with_args(ts, [&]() { call_with_args(ts, [&]() {
auto v = std::move(args.back()); auto v = std::move(args.back());
args.pop_back(); args.pop_back();
result = cs.call(v.get_code()); result = v.get_code().call(cs);
force_arg(cs, result, op & BC_INST_RET_MASK); force_arg(cs, result, op & BC_INST_RET_MASK);
}); });
continue; continue;
@ -469,7 +465,7 @@ std::uint32_t *vm_exec(
case BC_INST_DO | BC_RET_FLOAT: { case BC_INST_DO | BC_RET_FLOAT: {
auto v = std::move(args.back()); auto v = std::move(args.back());
args.pop_back(); args.pop_back();
result = cs.call(v.get_code()); result = v.get_code().call(cs);
force_arg(cs, result, op & BC_INST_RET_MASK); force_arg(cs, result, op & BC_INST_RET_MASK);
continue; continue;
} }
@ -500,7 +496,7 @@ std::uint32_t *vm_exec(
auto v = std::move(args.back()); auto v = std::move(args.back());
args.pop_back(); args.pop_back();
if (v.get_type() == value_type::CODE) { if (v.get_type() == value_type::CODE) {
result = cs.call(v.get_code()); result = v.get_code().call(cs);
} else { } else {
result = std::move(v); result = std::move(v);
} }
@ -514,7 +510,7 @@ std::uint32_t *vm_exec(
auto v = std::move(args.back()); auto v = std::move(args.back());
args.pop_back(); args.pop_back();
if (v.get_type() == value_type::CODE) { if (v.get_type() == value_type::CODE) {
result = cs.call(v.get_code()); result = v.get_code().call(cs);
} else { } else {
result = std::move(v); result = std::move(v);
} }

View File

@ -20,10 +20,10 @@ static inline void do_loop(
for (integer_type i = 0; i < n; ++i) { for (integer_type i = 0; i < n; ++i) {
idv.set_integer(offset + i * step); idv.set_integer(offset + i * step);
st.set(idv); st.set(idv);
if (cond && !cs.call(cond).get_bool()) { if (cond && !cond.call(cs).get_bool()) {
break; break;
} }
switch (cs.call_loop(body)) { switch (body.call_loop(cs)) {
case loop_state::BREAK: case loop_state::BREAK:
return; return;
default: /* continue and normal */ default: /* continue and normal */
@ -46,7 +46,7 @@ static inline void do_loop_conc(
idv.set_integer(offset + i * step); idv.set_integer(offset + i * step);
st.set(idv); st.set(idv);
any_value v{}; any_value v{};
switch (cs.call_loop(body, v)) { switch (body.call_loop(cs, v)) {
case loop_state::BREAK: case loop_state::BREAK:
goto end; goto end;
case loop_state::CONTINUE: case loop_state::CONTINUE:
@ -80,7 +80,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
any_value result{}, tback{}; any_value result{}, tback{};
bool rc = true; bool rc = true;
try { try {
result = cs.call(args[0].get_code()); result = args[0].get_code().call(cs);
} catch (error const &e) { } catch (error const &e) {
result.set_string(e.what(), cs); result.set_string(e.what(), cs);
if (e.get_stack().get()) { if (e.get_stack().get()) {
@ -109,12 +109,12 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
new_cmd_quiet(gcs, "cond", "bb2...", [](auto &cs, auto args, auto &res) { new_cmd_quiet(gcs, "cond", "bb2...", [](auto &cs, auto args, auto &res) {
for (size_t i = 0; i < args.size(); i += 2) { for (size_t i = 0; i < args.size(); i += 2) {
if ((i + 1) < args.size()) { if ((i + 1) < args.size()) {
if (cs.call(args[i].get_code()).get_bool()) { if (args[i].get_code().call(cs).get_bool()) {
res = cs.call(args[i + 1].get_code()); res = args[i + 1].get_code().call(cs);
break; break;
} }
} else { } else {
res = cs.call(args[i].get_code()); res = args[i].get_code().call(cs);
break; break;
} }
} }
@ -127,7 +127,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
(args[i].get_type() == value_type::NONE) || (args[i].get_type() == value_type::NONE) ||
(args[i].get_integer() == val) (args[i].get_integer() == val)
) { ) {
res = cs.call(args[i + 1].get_code()); res = args[i + 1].get_code().call(cs);
return; return;
} }
} }
@ -140,7 +140,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
(args[i].get_type() == value_type::NONE) || (args[i].get_type() == value_type::NONE) ||
(args[i].get_float() == val) (args[i].get_float() == val)
) { ) {
res = cs.call(args[i + 1].get_code()); res = args[i + 1].get_code().call(cs);
return; return;
} }
} }
@ -153,7 +153,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
(args[i].get_type() == value_type::NONE) || (args[i].get_type() == value_type::NONE) ||
(args[i].get_string(cs) == val) (args[i].get_string(cs) == val)
) { ) {
res = cs.call(args[i + 1].get_code()); res = args[i + 1].get_code().call(cs);
return; return;
} }
} }
@ -166,7 +166,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
} }
if (args[1].get_bool()) { if (args[1].get_bool()) {
st.set(args[1]); st.set(args[1]);
res = cs.call(args[2].get_code()); res = args[2].get_code().call(cs);
} }
}); });
@ -233,8 +233,8 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
new_cmd_quiet(gcs, "while", "bb", [](auto &cs, auto args, auto &) { new_cmd_quiet(gcs, "while", "bb", [](auto &cs, auto args, auto &) {
auto cond = args[0].get_code(); auto cond = args[0].get_code();
auto body = args[1].get_code(); auto body = args[1].get_code();
while (cs.call(cond).get_bool()) { while (cond.call(cs).get_bool()) {
switch (cs.call_loop(body)) { switch (body.call_loop(cs)) {
case loop_state::BREAK: case loop_state::BREAK:
goto end; goto end;
default: /* continue and normal */ default: /* continue and normal */
@ -325,7 +325,7 @@ end:
throw error{cs, "cannot push an argument"}; throw error{cs, "cannot push an argument"};
} }
st.set(args[1]); st.set(args[1]);
res = cs.call(args[2].get_code()); res = args[2].get_code().call(cs);
}); });
new_cmd_quiet(gcs, "resetvar", "s", [](auto &cs, auto args, auto &) { new_cmd_quiet(gcs, "resetvar", "s", [](auto &cs, auto args, auto &) {

View File

@ -87,7 +87,7 @@ static void loop_list_conc(
r.push_back(' '); r.push_back(' ');
} }
any_value v{}; any_value v{};
switch (cs.call_loop(body, v)) { switch (body.call_loop(cs, v)) {
case loop_state::BREAK: case loop_state::BREAK:
goto end; goto end;
case loop_state::CONTINUE: case loop_state::CONTINUE:
@ -213,7 +213,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
++n; ++n;
idv.set_string(p.get_raw_item(), cs); idv.set_string(p.get_raw_item(), cs);
st.set(std::move(idv)); st.set(std::move(idv));
if (cs.call(body).get_bool()) { if (body.call(cs).get_bool()) {
res.set_integer(integer_type(n)); res.set_integer(integer_type(n));
return; return;
} }
@ -230,7 +230,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
++n; ++n;
idv.set_string(p.get_raw_item(), cs); idv.set_string(p.get_raw_item(), cs);
st.set(std::move(idv)); st.set(std::move(idv));
if (cs.call(body).get_bool()) { if (body.call(cs).get_bool()) {
if (p.parse()) { if (p.parse()) {
res.set_string(p.get_item()); res.set_string(p.get_item());
} }
@ -294,7 +294,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
for (list_parser p{cs, args[1].get_string(cs)}; p.parse(); ++n) { for (list_parser p{cs, args[1].get_string(cs)}; p.parse(); ++n) {
idv.set_string(p.get_item()); idv.set_string(p.get_item());
st.set(std::move(idv)); st.set(std::move(idv));
switch (cs.call_loop(body)) { switch (body.call_loop(cs)) {
case loop_state::BREAK: case loop_state::BREAK:
return; return;
default: /* continue and normal */ default: /* continue and normal */
@ -318,7 +318,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
idv.set_string("", cs); idv.set_string("", cs);
} }
st2.set(std::move(idv)); st2.set(std::move(idv));
switch (cs.call_loop(body)) { switch (body.call_loop(cs)) {
case loop_state::BREAK: case loop_state::BREAK:
return; return;
default: /* continue and normal */ default: /* continue and normal */
@ -349,7 +349,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
idv.set_string("", cs); idv.set_string("", cs);
} }
st3.set(std::move(idv)); st3.set(std::move(idv));
switch (cs.call_loop(body)) { switch (body.call_loop(cs)) {
case loop_state::BREAK: case loop_state::BREAK:
return; return;
default: /* continue and normal */ default: /* continue and normal */
@ -387,7 +387,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
for (list_parser p{cs, args[1].get_string(cs)}; p.parse(); ++n) { for (list_parser p{cs, args[1].get_string(cs)}; p.parse(); ++n) {
idv.set_string(p.get_raw_item(), cs); idv.set_string(p.get_raw_item(), cs);
st.set(std::move(idv)); st.set(std::move(idv));
if (cs.call(body).get_bool()) { if (body.call(cs).get_bool()) {
if (r.size()) { if (r.size()) {
r.push_back(' '); r.push_back(' ');
} }
@ -405,7 +405,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
for (list_parser p{cs, args[1].get_string(cs)}; p.parse(); ++n) { for (list_parser p{cs, args[1].get_string(cs)}; p.parse(); ++n) {
idv.set_string(p.get_raw_item(), cs); idv.set_string(p.get_raw_item(), cs);
st.set(std::move(idv)); st.set(std::move(idv));
if (cs.call(body).get_bool()) { if (body.call(cs).get_bool()) {
r++; r++;
} }
} }
@ -525,7 +525,7 @@ struct ListSortFun {
xst.set(std::move(v)); xst.set(std::move(v));
v.set_string(yval.str, cs); v.set_string(yval.str, cs);
yst.set(std::move(v)); yst.set(std::move(v));
return cs.call(*body).get_bool(); return body->call(cs).get_bool();
} }
}; };

View File

@ -38,7 +38,7 @@ static bool do_exec_file(cs::state &cs, char const *fname) {
buf[len] = '\0'; buf[len] = '\0';
cs.call(std::string_view{buf.get(), std::size_t(len)}, fname); cs.compile(std::string_view{buf.get(), std::size_t(len)}, fname).call(cs);
return true; return true;
} }
@ -62,7 +62,7 @@ int main(int argc, char **argv) {
gcs.new_command("assert", "ss#", [](auto &s, auto args, auto &ret) { gcs.new_command("assert", "ss#", [](auto &s, auto args, auto &ret) {
auto val = args[0]; auto val = args[0];
val.force_code(s); val.force_code(s);
if (!s.call(val.get_code()).get_bool()) { if (!val.get_code().call(s).get_bool()) {
if (args[2].get_integer() > 1) { if (args[2].get_integer() > 1) {
throw cs::error{ throw cs::error{
s, "assertion failed: [%s] (%s)", s, "assertion failed: [%s] (%s)",

View File

@ -214,7 +214,9 @@ static bool do_exec_file(
buf[len] = '\0'; buf[len] = '\0';
ret = cs.call(std::string_view{buf.get(), std::size_t(len)}, fname); ret = cs.compile(
std::string_view{buf.get(), std::size_t(len)}, fname
).call(cs);
return true; return true;
} }
@ -228,7 +230,7 @@ static bool do_call(cs::state &cs, std::string_view line, bool file = false) {
std::fprintf(stderr, "cannot read file: %s\n", line.data()); std::fprintf(stderr, "cannot read file: %s\n", line.data());
} }
} else { } else {
ret = cs.call(line); ret = cs.compile(line).call(cs);
} }
} catch (cs::error const &e) { } catch (cs::error const &e) {
signal(SIGINT, SIG_DFL); signal(SIGINT, SIG_DFL);