remove call() methods from state
parent
4dd1518f6c
commit
5b54c74f2a
|
@ -31,7 +31,7 @@ private:
|
|||
base() {}
|
||||
virtual ~base() {}
|
||||
virtual void move_to(base *) = 0;
|
||||
virtual R operator()(A &&...args) = 0;
|
||||
virtual R operator()(A &&...args) const = 0;
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
|
@ -42,9 +42,9 @@ private:
|
|||
::new (p) store{std::move(p_stor)};
|
||||
}
|
||||
|
||||
virtual R operator()(A &&...args) {
|
||||
virtual R operator()(A &&...args) const {
|
||||
return std::invoke(*std::launder(
|
||||
reinterpret_cast<F *>(&p_stor)
|
||||
reinterpret_cast<F const *>(&p_stor)
|
||||
), std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
|
@ -184,25 +184,25 @@ public:
|
|||
f.p_func = as_base(&f.p_stor);
|
||||
} else if (small_storage()) {
|
||||
/* 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->~base();
|
||||
p_func = f.p_func;
|
||||
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()) {
|
||||
/* 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->~base();
|
||||
f.p_func = p_func;
|
||||
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 {
|
||||
/* copy allocator address/size */
|
||||
memcpy(&tmp_stor, &p_stor, sizeof(tmp_stor));
|
||||
memcpy(&p_stor, &f.p_stor, sizeof(tmp_stor));
|
||||
memcpy(&f.p_stor, &tmp_stor, sizeof(tmp_stor));
|
||||
std::memcpy(&tmp_stor, &p_stor, sizeof(tmp_stor));
|
||||
std::memcpy(&p_stor, &f.p_stor, sizeof(tmp_stor));
|
||||
std::memcpy(&f.p_stor, &tmp_stor, sizeof(tmp_stor));
|
||||
std::swap(p_func, f.p_func);
|
||||
}
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ public:
|
|||
return !!p_func;
|
||||
}
|
||||
|
||||
R operator()(A ...args) {
|
||||
R operator()(A ...args) const {
|
||||
return (*p_func)(std::forward<A>(args)...);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -132,10 +132,26 @@ struct LIBCUBESCRIPT_EXPORT ident {
|
|||
*/
|
||||
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:
|
||||
friend struct ident_p;
|
||||
|
||||
ident() = default;
|
||||
virtual ~ident();
|
||||
|
||||
struct ident_impl *p_impl{};
|
||||
};
|
||||
|
@ -195,6 +211,16 @@ struct LIBCUBESCRIPT_EXPORT global_var: ident {
|
|||
*/
|
||||
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:
|
||||
global_var() = default;
|
||||
};
|
||||
|
@ -229,6 +255,9 @@ struct LIBCUBESCRIPT_EXPORT integer_var: global_var {
|
|||
*/
|
||||
void set_raw_value(integer_type val);
|
||||
|
||||
/** @brief Call override for integer vars. */
|
||||
any_value call(span_type<any_value> args, state &cs);
|
||||
|
||||
protected:
|
||||
integer_var() = default;
|
||||
};
|
||||
|
@ -263,6 +292,9 @@ struct LIBCUBESCRIPT_EXPORT float_var: global_var {
|
|||
*/
|
||||
void set_raw_value(float_type val);
|
||||
|
||||
/** @brief Call override for float vars. */
|
||||
any_value call(span_type<any_value> args, state &cs);
|
||||
|
||||
protected:
|
||||
float_var() = default;
|
||||
};
|
||||
|
@ -297,6 +329,9 @@ struct LIBCUBESCRIPT_EXPORT string_var: global_var {
|
|||
*/
|
||||
void set_raw_value(string_ref val);
|
||||
|
||||
/** @brief Call override for string vars. */
|
||||
any_value call(span_type<any_value> args, state &cs);
|
||||
|
||||
protected:
|
||||
string_var() = default;
|
||||
};
|
||||
|
@ -324,6 +359,12 @@ struct LIBCUBESCRIPT_EXPORT alias: ident {
|
|||
/** @brief Set the value of the alias for the given thread. */
|
||||
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:
|
||||
alias() = default;
|
||||
};
|
||||
|
@ -345,6 +386,12 @@ struct LIBCUBESCRIPT_EXPORT command: ident {
|
|||
*/
|
||||
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:
|
||||
command() = default;
|
||||
};
|
||||
|
|
|
@ -71,16 +71,6 @@ using command_func = internal::callable<
|
|||
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
|
||||
*
|
||||
* 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 */
|
||||
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);
|
||||
|
||||
/** @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);
|
||||
bcode_ref compile(
|
||||
std::string_view v, std::string_view source = std::string_view{}
|
||||
);
|
||||
|
||||
/** @brief Get if the thread is in override mode
|
||||
*
|
||||
|
|
|
@ -20,6 +20,17 @@
|
|||
namespace cubescript {
|
||||
|
||||
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.
|
||||
*
|
||||
|
@ -100,6 +111,30 @@ struct LIBCUBESCRIPT_EXPORT bcode_ref {
|
|||
*/
|
||||
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:
|
||||
friend struct bcode_p;
|
||||
|
||||
|
@ -447,11 +482,13 @@ struct LIBCUBESCRIPT_EXPORT any_value {
|
|||
*
|
||||
* If the contained value is already bytecode, nothing happens. Otherwise
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "cs_bcode.hh"
|
||||
#include "cs_state.hh"
|
||||
#include "cs_vm.hh"
|
||||
|
||||
namespace cubescript {
|
||||
|
||||
|
@ -45,6 +46,37 @@ LIBCUBESCRIPT_EXPORT bcode_ref::operator bool() const {
|
|||
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 */
|
||||
|
||||
struct bcode_hdr {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "cs_bcode.hh"
|
||||
#include "cs_thread.hh"
|
||||
#include "cs_vm.hh"
|
||||
|
||||
namespace cubescript {
|
||||
|
||||
|
@ -106,7 +107,7 @@ void svar_impl::save_val() {
|
|||
|
||||
void command_impl::call(
|
||||
thread_state &ts, span_type<any_value> args, any_value &ret
|
||||
) {
|
||||
) const {
|
||||
auto idstsz = ts.idstack.size();
|
||||
try {
|
||||
p_cb_cftv(*ts.pstate, args, ret);
|
||||
|
@ -117,7 +118,7 @@ void command_impl::call(
|
|||
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) {
|
||||
return true;
|
||||
}
|
||||
|
@ -155,6 +156,8 @@ void alias_stack::set_alias(alias *a, thread_state &ts, any_value &v) {
|
|||
|
||||
/* public interface */
|
||||
|
||||
LIBCUBESCRIPT_EXPORT ident::~ident() {}
|
||||
|
||||
LIBCUBESCRIPT_EXPORT ident_type ident::get_type() const {
|
||||
if (p_impl->p_type > ID_ALIAS) {
|
||||
return ident_type::SPECIAL;
|
||||
|
@ -246,6 +249,10 @@ LIBCUBESCRIPT_EXPORT bool ident::is_persistent(state &cs) const {
|
|||
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 {
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
LIBCUBESCRIPT_EXPORT alias_local::alias_local(state &cs, ident &a) {
|
||||
|
|
|
@ -44,7 +44,7 @@ struct alias_stack {
|
|||
};
|
||||
|
||||
struct ident_link {
|
||||
ident *id;
|
||||
ident const *id;
|
||||
ident_link *next;
|
||||
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
|
||||
);
|
||||
|
||||
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;
|
||||
command_func p_cb_cftv;
|
||||
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 {
|
||||
ident_p(ident &id): ip{&id} {}
|
||||
|
|
164
src/cs_state.cc
164
src/cs_state.cc
|
@ -173,19 +173,19 @@ state::state(alloc_func func, void *data) {
|
|||
/* builtins */
|
||||
|
||||
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;
|
||||
|
||||
p = &new_command("doargs", "b", [](auto &cs, auto args, auto &res) {
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -206,7 +206,7 @@ state::state(alloc_func func, void *data) {
|
|||
for (size_t i = 0; i < args.size(); ++i) {
|
||||
auto code = args[i].get_code();
|
||||
if (code) {
|
||||
res = cs.call(code);
|
||||
res = code.call(cs);
|
||||
} else {
|
||||
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) {
|
||||
auto code = args[i].get_code();
|
||||
if (code) {
|
||||
res = cs.call(code);
|
||||
res = code.call(cs);
|
||||
} else {
|
||||
res = std::move(args[i]);
|
||||
}
|
||||
|
@ -485,7 +485,7 @@ LIBCUBESCRIPT_EXPORT void state::assign_value(
|
|||
case ident_type::IVAR:
|
||||
case ident_type::FVAR:
|
||||
case ident_type::SVAR:
|
||||
call(id->get(), span_type<any_value>{&v, 1});
|
||||
id->get().call(span_type<any_value>{&v, 1}, *this);
|
||||
break;
|
||||
default:
|
||||
throw error{
|
||||
|
@ -693,154 +693,12 @@ do_add:
|
|||
return *cmd;
|
||||
}
|
||||
|
||||
LIBCUBESCRIPT_EXPORT any_value state::call(bcode_ref const &code) {
|
||||
any_value ret{};
|
||||
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
|
||||
LIBCUBESCRIPT_EXPORT bcode_ref state::compile(
|
||||
std::string_view v, std::string_view source
|
||||
) {
|
||||
any_value ret{};
|
||||
gen_state gs{ts};
|
||||
gs.gen_main(code, file);
|
||||
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);
|
||||
gen_state gs{*p_tstate};
|
||||
gs.gen_main(v, source);
|
||||
return gs.steal_ref();
|
||||
}
|
||||
|
||||
LIBCUBESCRIPT_EXPORT bool state::get_override_mode() const {
|
||||
|
|
|
@ -15,17 +15,16 @@ hook_func thread_state::set_hook(hook_func f) {
|
|||
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());
|
||||
if (it.second) {
|
||||
it.first->second.node = &static_cast<alias_impl *>(a)->p_initial;
|
||||
it.first->second.flags = static_cast<alias_impl *>(a)->p_flags;
|
||||
auto *imp = const_cast<alias_impl *>(
|
||||
static_cast<alias_impl const *>(a)
|
||||
);
|
||||
it.first->second.node = &imp->p_initial;
|
||||
it.first->second.flags = imp->p_flags;
|
||||
}
|
||||
return it.first->second;
|
||||
}
|
||||
|
||||
alias_stack const &thread_state::get_astack(alias const *a) {
|
||||
return get_astack(const_cast<alias *>(a));
|
||||
}
|
||||
|
||||
} /* namespace cubescript */
|
||||
|
|
|
@ -52,8 +52,7 @@ struct thread_state {
|
|||
hook_func &get_hook() { return call_hook; }
|
||||
hook_func const &get_hook() const { return call_hook; }
|
||||
|
||||
alias_stack &get_astack(alias *a);
|
||||
alias_stack const &get_astack(alias const *a);
|
||||
alias_stack &get_astack(alias const *a);
|
||||
};
|
||||
|
||||
} /* namespace cubescript */
|
||||
|
|
|
@ -246,7 +246,7 @@ std::string_view any_value::force_string(state &cs) {
|
|||
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()) {
|
||||
case value_type::CODE:
|
||||
return bcode_p::make_ref(csv_get<bcode *>(&p_stor));
|
||||
|
@ -254,7 +254,7 @@ bcode_ref any_value::force_code(state &cs) {
|
|||
break;
|
||||
}
|
||||
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();
|
||||
set_code(bc);
|
||||
return bc;
|
||||
|
|
16
src/cs_vm.cc
16
src/cs_vm.cc
|
@ -114,9 +114,7 @@ void exec_command(
|
|||
break;
|
||||
case '.':
|
||||
i = std::max(i + 1, numargs);
|
||||
static_cast<command_impl *>(id)->call(
|
||||
ts, span_type<any_value>{args, std::size_t(i)}, res
|
||||
);
|
||||
id->call(ts, span_type<any_value>{args, std::size_t(i)}, res);
|
||||
return;
|
||||
case '1':
|
||||
case '2':
|
||||
|
@ -130,9 +128,7 @@ void exec_command(
|
|||
}
|
||||
}
|
||||
++i;
|
||||
static_cast<command_impl *>(id)->call(
|
||||
ts, span_type<any_value>{args, std::size_t(i)}, res
|
||||
);
|
||||
id->call(ts, span_type<any_value>{args, std::size_t(i)}, res);
|
||||
res.force_plain();
|
||||
}
|
||||
|
||||
|
@ -458,7 +454,7 @@ std::uint32_t *vm_exec(
|
|||
call_with_args(ts, [&]() {
|
||||
auto v = std::move(args.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);
|
||||
});
|
||||
continue;
|
||||
|
@ -469,7 +465,7 @@ std::uint32_t *vm_exec(
|
|||
case BC_INST_DO | BC_RET_FLOAT: {
|
||||
auto v = std::move(args.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);
|
||||
continue;
|
||||
}
|
||||
|
@ -500,7 +496,7 @@ std::uint32_t *vm_exec(
|
|||
auto v = std::move(args.back());
|
||||
args.pop_back();
|
||||
if (v.get_type() == value_type::CODE) {
|
||||
result = cs.call(v.get_code());
|
||||
result = v.get_code().call(cs);
|
||||
} else {
|
||||
result = std::move(v);
|
||||
}
|
||||
|
@ -514,7 +510,7 @@ std::uint32_t *vm_exec(
|
|||
auto v = std::move(args.back());
|
||||
args.pop_back();
|
||||
if (v.get_type() == value_type::CODE) {
|
||||
result = cs.call(v.get_code());
|
||||
result = v.get_code().call(cs);
|
||||
} else {
|
||||
result = std::move(v);
|
||||
}
|
||||
|
|
|
@ -20,10 +20,10 @@ static inline void do_loop(
|
|||
for (integer_type i = 0; i < n; ++i) {
|
||||
idv.set_integer(offset + i * step);
|
||||
st.set(idv);
|
||||
if (cond && !cs.call(cond).get_bool()) {
|
||||
if (cond && !cond.call(cs).get_bool()) {
|
||||
break;
|
||||
}
|
||||
switch (cs.call_loop(body)) {
|
||||
switch (body.call_loop(cs)) {
|
||||
case loop_state::BREAK:
|
||||
return;
|
||||
default: /* continue and normal */
|
||||
|
@ -46,7 +46,7 @@ static inline void do_loop_conc(
|
|||
idv.set_integer(offset + i * step);
|
||||
st.set(idv);
|
||||
any_value v{};
|
||||
switch (cs.call_loop(body, v)) {
|
||||
switch (body.call_loop(cs, v)) {
|
||||
case loop_state::BREAK:
|
||||
goto end;
|
||||
case loop_state::CONTINUE:
|
||||
|
@ -80,7 +80,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
|
|||
any_value result{}, tback{};
|
||||
bool rc = true;
|
||||
try {
|
||||
result = cs.call(args[0].get_code());
|
||||
result = args[0].get_code().call(cs);
|
||||
} catch (error const &e) {
|
||||
result.set_string(e.what(), cs);
|
||||
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) {
|
||||
for (size_t i = 0; i < args.size(); i += 2) {
|
||||
if ((i + 1) < args.size()) {
|
||||
if (cs.call(args[i].get_code()).get_bool()) {
|
||||
res = cs.call(args[i + 1].get_code());
|
||||
if (args[i].get_code().call(cs).get_bool()) {
|
||||
res = args[i + 1].get_code().call(cs);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
res = cs.call(args[i].get_code());
|
||||
res = args[i].get_code().call(cs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
|
|||
(args[i].get_type() == value_type::NONE) ||
|
||||
(args[i].get_integer() == val)
|
||||
) {
|
||||
res = cs.call(args[i + 1].get_code());
|
||||
res = args[i + 1].get_code().call(cs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
|
|||
(args[i].get_type() == value_type::NONE) ||
|
||||
(args[i].get_float() == val)
|
||||
) {
|
||||
res = cs.call(args[i + 1].get_code());
|
||||
res = args[i + 1].get_code().call(cs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
|
|||
(args[i].get_type() == value_type::NONE) ||
|
||||
(args[i].get_string(cs) == val)
|
||||
) {
|
||||
res = cs.call(args[i + 1].get_code());
|
||||
res = args[i + 1].get_code().call(cs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
|
|||
}
|
||||
if (args[1].get_bool()) {
|
||||
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 &) {
|
||||
auto cond = args[0].get_code();
|
||||
auto body = args[1].get_code();
|
||||
while (cs.call(cond).get_bool()) {
|
||||
switch (cs.call_loop(body)) {
|
||||
while (cond.call(cs).get_bool()) {
|
||||
switch (body.call_loop(cs)) {
|
||||
case loop_state::BREAK:
|
||||
goto end;
|
||||
default: /* continue and normal */
|
||||
|
@ -325,7 +325,7 @@ end:
|
|||
throw error{cs, "cannot push an argument"};
|
||||
}
|
||||
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 &) {
|
||||
|
|
|
@ -87,7 +87,7 @@ static void loop_list_conc(
|
|||
r.push_back(' ');
|
||||
}
|
||||
any_value v{};
|
||||
switch (cs.call_loop(body, v)) {
|
||||
switch (body.call_loop(cs, v)) {
|
||||
case loop_state::BREAK:
|
||||
goto end;
|
||||
case loop_state::CONTINUE:
|
||||
|
@ -213,7 +213,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
|
|||
++n;
|
||||
idv.set_string(p.get_raw_item(), cs);
|
||||
st.set(std::move(idv));
|
||||
if (cs.call(body).get_bool()) {
|
||||
if (body.call(cs).get_bool()) {
|
||||
res.set_integer(integer_type(n));
|
||||
return;
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
|
|||
++n;
|
||||
idv.set_string(p.get_raw_item(), cs);
|
||||
st.set(std::move(idv));
|
||||
if (cs.call(body).get_bool()) {
|
||||
if (body.call(cs).get_bool()) {
|
||||
if (p.parse()) {
|
||||
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) {
|
||||
idv.set_string(p.get_item());
|
||||
st.set(std::move(idv));
|
||||
switch (cs.call_loop(body)) {
|
||||
switch (body.call_loop(cs)) {
|
||||
case loop_state::BREAK:
|
||||
return;
|
||||
default: /* continue and normal */
|
||||
|
@ -318,7 +318,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
|
|||
idv.set_string("", cs);
|
||||
}
|
||||
st2.set(std::move(idv));
|
||||
switch (cs.call_loop(body)) {
|
||||
switch (body.call_loop(cs)) {
|
||||
case loop_state::BREAK:
|
||||
return;
|
||||
default: /* continue and normal */
|
||||
|
@ -349,7 +349,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
|
|||
idv.set_string("", cs);
|
||||
}
|
||||
st3.set(std::move(idv));
|
||||
switch (cs.call_loop(body)) {
|
||||
switch (body.call_loop(cs)) {
|
||||
case loop_state::BREAK:
|
||||
return;
|
||||
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) {
|
||||
idv.set_string(p.get_raw_item(), cs);
|
||||
st.set(std::move(idv));
|
||||
if (cs.call(body).get_bool()) {
|
||||
if (body.call(cs).get_bool()) {
|
||||
if (r.size()) {
|
||||
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) {
|
||||
idv.set_string(p.get_raw_item(), cs);
|
||||
st.set(std::move(idv));
|
||||
if (cs.call(body).get_bool()) {
|
||||
if (body.call(cs).get_bool()) {
|
||||
r++;
|
||||
}
|
||||
}
|
||||
|
@ -525,7 +525,7 @@ struct ListSortFun {
|
|||
xst.set(std::move(v));
|
||||
v.set_string(yval.str, cs);
|
||||
yst.set(std::move(v));
|
||||
return cs.call(*body).get_bool();
|
||||
return body->call(cs).get_bool();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ static bool do_exec_file(cs::state &cs, char const *fname) {
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ int main(int argc, char **argv) {
|
|||
gcs.new_command("assert", "ss#", [](auto &s, auto args, auto &ret) {
|
||||
auto val = args[0];
|
||||
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) {
|
||||
throw cs::error{
|
||||
s, "assertion failed: [%s] (%s)",
|
||||
|
|
|
@ -214,7 +214,9 @@ static bool do_exec_file(
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
} else {
|
||||
ret = cs.call(line);
|
||||
ret = cs.compile(line).call(cs);
|
||||
}
|
||||
} catch (cs::error const &e) {
|
||||
signal(SIGINT, SIG_DFL);
|
||||
|
|
Loading…
Reference in New Issue