alias_local and get_ident() memory safety (always return refs)
This commit is contained in:
parent
960f463259
commit
f4b8d077bb
|
@ -68,6 +68,12 @@ struct LIBCUBESCRIPT_EXPORT ident {
|
|||
*/
|
||||
int get_index() const;
|
||||
|
||||
/** @brief Check if the idents are the same. */
|
||||
bool operator==(ident &other) const;
|
||||
|
||||
/** @brief Check if the idents are not the same. */
|
||||
bool operator!=(ident &other) const;
|
||||
|
||||
/** @brief Check if the ident is a cubescript::alias.
|
||||
*
|
||||
* Effectively like `get_type() == ident_type::ALIAS`.
|
||||
|
|
|
@ -36,20 +36,18 @@ namespace cubescript {
|
|||
* Therefore, what you can do is something like this:
|
||||
*
|
||||
* ```
|
||||
* if (alias_local s{my_thread, &my_thread.new_ident("test")}; s) {
|
||||
* {
|
||||
* alias_local s{my_thread, "test"};
|
||||
* // branch taken when the alias was successfully pushed
|
||||
* // setting the alias will only be visible within this scope
|
||||
* s.set(some_value); // a convenient setter
|
||||
* my_thread.run(...);
|
||||
* } else {
|
||||
* // you can handle an error here
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The `else` branch can happen one case; either the given ident is `nullptr`
|
||||
* (which will never happen here) or it's not a cubescript::alias (which can
|
||||
* happen if an ident of such name already exists and is not an alias). If
|
||||
* it fails, obviously no push/pop happens.
|
||||
* If the provided input is not an alias, a cubescript::error will be thrown.
|
||||
* Often you don't have to catch it (since this is primarily intended for use
|
||||
* within commands, the error will propagate outside your command).
|
||||
*
|
||||
* Since the goal is to interact tightly with RAII and ensure consistency at
|
||||
* all times, it is not possible to copy or move this object. That means you
|
||||
|
@ -58,7 +56,20 @@ namespace cubescript {
|
|||
*/
|
||||
struct LIBCUBESCRIPT_EXPORT alias_local {
|
||||
/** @brief Construct the local handler */
|
||||
alias_local(state &cs, ident *a);
|
||||
alias_local(state &cs, ident &a);
|
||||
|
||||
/** @brief Construct the local handler
|
||||
*
|
||||
* The ident will be retrieved using state::new_ident().
|
||||
*/
|
||||
alias_local(state &cs, std::string_view name);
|
||||
|
||||
/** @brief Construct the local handler
|
||||
*
|
||||
* The ident will be retrieved from the value. If the contained value
|
||||
* is not an ident, it will be treated as a name.
|
||||
*/
|
||||
alias_local(state &cs, any_value const &val);
|
||||
|
||||
/** @brief Destroy the local handler */
|
||||
~alias_local();
|
||||
|
@ -93,9 +104,6 @@ struct LIBCUBESCRIPT_EXPORT alias_local {
|
|||
*/
|
||||
bool set(any_value val);
|
||||
|
||||
/** @brief Get if there is an alias associated with this handler */
|
||||
explicit operator bool() const noexcept;
|
||||
|
||||
private:
|
||||
alias *p_alias;
|
||||
void *p_sp;
|
||||
|
|
|
@ -220,6 +220,13 @@ struct LIBCUBESCRIPT_EXPORT string_ref {
|
|||
*/
|
||||
bool operator==(string_ref const &s) const;
|
||||
|
||||
/** @brief Check if the string does not equal another.
|
||||
*
|
||||
* This is effectively a `data() != s.data()` address comparison, and
|
||||
* therefore always has constant time complexity.
|
||||
*/
|
||||
bool operator!=(string_ref const &s) const;
|
||||
|
||||
private:
|
||||
string_ref(char const *p);
|
||||
|
||||
|
@ -374,9 +381,9 @@ struct LIBCUBESCRIPT_EXPORT any_value {
|
|||
|
||||
/** @brief Get the value as an ident.
|
||||
*
|
||||
* If the contained value is not an ident, `nullptr` is returned.
|
||||
* If the contained value is not an ident, a dummy is returned.
|
||||
*/
|
||||
ident *get_ident() const;
|
||||
ident &get_ident(state &cs) const;
|
||||
|
||||
/** @brief Get the value as representable inside the language.
|
||||
*
|
||||
|
|
|
@ -170,6 +170,14 @@ LIBCUBESCRIPT_EXPORT int ident::get_index() const {
|
|||
return p_impl->p_index;
|
||||
}
|
||||
|
||||
LIBCUBESCRIPT_EXPORT bool ident::operator==(ident &other) const {
|
||||
return this == &other;
|
||||
}
|
||||
|
||||
LIBCUBESCRIPT_EXPORT bool ident::operator!=(ident &other) const {
|
||||
return this != &other;
|
||||
}
|
||||
|
||||
LIBCUBESCRIPT_EXPORT bool ident::is_alias() const {
|
||||
return get_type() == ident_type::ALIAS;
|
||||
}
|
||||
|
@ -463,19 +471,28 @@ LIBCUBESCRIPT_EXPORT int command::get_num_args() const {
|
|||
|
||||
/* external API for alias stack management */
|
||||
|
||||
LIBCUBESCRIPT_EXPORT alias_local::alias_local(state &cs, ident *a) {
|
||||
if (!a || !a->is_alias()) {
|
||||
p_alias = nullptr;
|
||||
return;
|
||||
LIBCUBESCRIPT_EXPORT alias_local::alias_local(state &cs, ident &a) {
|
||||
if (!a.is_alias()) {
|
||||
throw error{cs, "ident '%s' is not an alias", a.get_name().data()};
|
||||
}
|
||||
auto &ts = state_p{cs}.ts();
|
||||
p_alias = static_cast<alias *>(a);
|
||||
p_alias = static_cast<alias *>(&a);
|
||||
auto &ast = ts.get_astack(p_alias);
|
||||
ast.push(ts.idstack.emplace_back());
|
||||
p_sp = *
|
||||
ast.flags &= ~IDENT_FLAG_UNKNOWN;
|
||||
}
|
||||
|
||||
LIBCUBESCRIPT_EXPORT alias_local::alias_local(state &cs, std::string_view name):
|
||||
alias_local{cs, cs.new_ident(name)}
|
||||
{}
|
||||
|
||||
LIBCUBESCRIPT_EXPORT alias_local::alias_local(state &cs, any_value const &v):
|
||||
alias_local{cs, (
|
||||
v.get_type() == value_type::IDENT
|
||||
) ? v.get_ident(cs) : cs.new_ident(v.get_string(cs))}
|
||||
{}
|
||||
|
||||
LIBCUBESCRIPT_EXPORT alias_local::~alias_local() {
|
||||
if (p_alias) {
|
||||
static_cast<alias_stack *>(p_sp)->pop();
|
||||
|
@ -490,8 +507,4 @@ LIBCUBESCRIPT_EXPORT bool alias_local::set(any_value val) {
|
|||
return true;
|
||||
}
|
||||
|
||||
LIBCUBESCRIPT_EXPORT alias_local::operator bool() const noexcept {
|
||||
return !!p_alias;
|
||||
}
|
||||
|
||||
} /* namespace cubescript */
|
||||
|
|
|
@ -124,7 +124,7 @@ state::state(alloc_func func, void *data) {
|
|||
statep->cmd_ivar = &new_command("//ivar_builtin", "$iN", [](
|
||||
auto &cs, auto args, auto &
|
||||
) {
|
||||
auto *iv = args[0].get_ident()->get_ivar();
|
||||
auto *iv = args[0].get_ident(cs).get_ivar();
|
||||
if (args[2].get_integer() <= 1) {
|
||||
std::printf("%s = ", iv->get_name().data());
|
||||
std::printf(INTEGER_FORMAT, iv->get_value());
|
||||
|
@ -137,7 +137,7 @@ state::state(alloc_func func, void *data) {
|
|||
statep->cmd_fvar = &new_command("//fvar_builtin", "$fN", [](
|
||||
auto &cs, auto args, auto &
|
||||
) {
|
||||
auto *fv = args[0].get_ident()->get_fvar();
|
||||
auto *fv = args[0].get_ident(cs).get_fvar();
|
||||
if (args[2].get_integer() <= 1) {
|
||||
auto val = fv->get_value();
|
||||
std::printf("%s = ", fv->get_name().data());
|
||||
|
@ -155,7 +155,7 @@ state::state(alloc_func func, void *data) {
|
|||
statep->cmd_svar = &new_command("//svar_builtin", "$sN", [](
|
||||
auto &cs, auto args, auto &
|
||||
) {
|
||||
auto *sv = args[0].get_ident()->get_svar();
|
||||
auto *sv = args[0].get_ident(cs).get_svar();
|
||||
if (args[2].get_integer() <= 1) {
|
||||
auto val = sv->get_value();
|
||||
if (val.view().find('"') == std::string_view::npos) {
|
||||
|
|
|
@ -158,4 +158,8 @@ LIBCUBESCRIPT_EXPORT bool string_ref::operator==(string_ref const &s) const {
|
|||
return p_str == s.p_str;
|
||||
}
|
||||
|
||||
LIBCUBESCRIPT_EXPORT bool string_ref::operator!=(string_ref const &s) const {
|
||||
return p_str != s.p_str;
|
||||
}
|
||||
|
||||
} /* namespace cubescript */
|
||||
|
|
|
@ -311,11 +311,11 @@ bcode_ref any_value::get_code() const {
|
|||
return bcode_p::make_ref(csv_get<bcode *>(&p_stor));
|
||||
}
|
||||
|
||||
ident *any_value::get_ident() const {
|
||||
ident &any_value::get_ident(state &cs) const {
|
||||
if (get_type() != value_type::IDENT) {
|
||||
return nullptr;
|
||||
return *state_p{cs}.ts().istate->id_dummy;
|
||||
}
|
||||
return csv_get<ident *>(&p_stor);
|
||||
return *csv_get<ident *>(&p_stor);
|
||||
}
|
||||
|
||||
string_ref any_value::get_string(state &cs) const {
|
||||
|
|
20
src/cs_vm.cc
20
src/cs_vm.cc
|
@ -9,18 +9,18 @@
|
|||
|
||||
namespace cubescript {
|
||||
|
||||
static inline void push_alias(thread_state &ts, ident *id, ident_stack &st) {
|
||||
if (id->is_alias() && !static_cast<alias *>(id)->is_arg()) {
|
||||
auto *aimp = static_cast<alias_impl *>(id);
|
||||
static inline void push_alias(thread_state &ts, ident &id, ident_stack &st) {
|
||||
if (id.is_alias() && !static_cast<alias &>(id).is_arg()) {
|
||||
auto *aimp = static_cast<alias_impl *>(&id);
|
||||
auto ast = ts.get_astack(aimp);
|
||||
ast.push(st);
|
||||
ast.flags &= ~IDENT_FLAG_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void pop_alias(thread_state &ts, ident *id) {
|
||||
if (id->is_alias() && !static_cast<alias *>(id)->is_arg()) {
|
||||
ts.get_astack(static_cast<alias *>(id)).pop();
|
||||
static inline void pop_alias(thread_state &ts, ident &id) {
|
||||
if (id.is_alias() && !static_cast<alias &>(id).is_arg()) {
|
||||
ts.get_astack(static_cast<alias *>(&id)).pop();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -548,13 +548,13 @@ std::uint32_t *vm_exec(
|
|||
std::size_t idstsz = ts.idstack.size();
|
||||
for (std::size_t i = 0; i < numlocals; ++i) {
|
||||
push_alias(
|
||||
ts, args[offset + i].get_ident(),
|
||||
ts, args[offset + i].get_ident(cs),
|
||||
ts.idstack.emplace_back()
|
||||
);
|
||||
}
|
||||
auto cleanup = [&]() {
|
||||
for (std::size_t i = offset; i < args.size(); ++i) {
|
||||
pop_alias(ts, args[i].get_ident());
|
||||
pop_alias(ts, args[i].get_ident(cs));
|
||||
}
|
||||
ts.idstack.resize(idstsz);
|
||||
};
|
||||
|
@ -1111,13 +1111,13 @@ noid:
|
|||
std::size_t idstsz = ts.idstack.size();
|
||||
for (size_t j = 0; j < size_t(callargs); ++j) {
|
||||
push_alias(
|
||||
ts, &args[offset + j].force_ident(cs),
|
||||
ts, args[offset + j].force_ident(cs),
|
||||
ts.idstack.emplace_back()
|
||||
);
|
||||
}
|
||||
auto cleanup = [&]() {
|
||||
for (size_t j = 0; j < size_t(callargs); ++j) {
|
||||
pop_alias(ts, args[offset + j].get_ident());
|
||||
pop_alias(ts, args[offset + j].get_ident(cs));
|
||||
}
|
||||
ts.idstack.resize(idstsz);
|
||||
};
|
||||
|
|
130
src/lib_base.cc
130
src/lib_base.cc
|
@ -15,20 +15,19 @@ static inline void do_loop(
|
|||
if (n <= 0) {
|
||||
return;
|
||||
}
|
||||
if (alias_local st{cs, &id}; st) {
|
||||
any_value idv{};
|
||||
for (integer_type i = 0; i < n; ++i) {
|
||||
idv.set_integer(offset + i * step);
|
||||
st.set(idv);
|
||||
if (cond && !cs.run(cond).get_bool()) {
|
||||
alias_local st{cs, id};
|
||||
any_value idv{};
|
||||
for (integer_type i = 0; i < n; ++i) {
|
||||
idv.set_integer(offset + i * step);
|
||||
st.set(idv);
|
||||
if (cond && !cs.run(cond).get_bool()) {
|
||||
break;
|
||||
}
|
||||
switch (cs.run_loop(body)) {
|
||||
case loop_state::BREAK:
|
||||
return;
|
||||
default: /* continue and normal */
|
||||
break;
|
||||
}
|
||||
switch (cs.run_loop(body)) {
|
||||
case loop_state::BREAK:
|
||||
return;
|
||||
default: /* continue and normal */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,29 +39,28 @@ static inline void do_loop_conc(
|
|||
if (n <= 0) {
|
||||
return;
|
||||
}
|
||||
if (alias_local st{cs, &id}; st) {
|
||||
charbuf s{cs};
|
||||
any_value idv{};
|
||||
for (integer_type i = 0; i < n; ++i) {
|
||||
idv.set_integer(offset + i * step);
|
||||
st.set(idv);
|
||||
any_value v{};
|
||||
switch (cs.run_loop(body, v)) {
|
||||
case loop_state::BREAK:
|
||||
goto end;
|
||||
case loop_state::CONTINUE:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (space && i) {
|
||||
s.push_back(' ');
|
||||
}
|
||||
s.append(v.get_string(cs));
|
||||
alias_local st{cs, id};
|
||||
charbuf s{cs};
|
||||
any_value idv{};
|
||||
for (integer_type i = 0; i < n; ++i) {
|
||||
idv.set_integer(offset + i * step);
|
||||
st.set(idv);
|
||||
any_value v{};
|
||||
switch (cs.run_loop(body, v)) {
|
||||
case loop_state::BREAK:
|
||||
goto end;
|
||||
case loop_state::CONTINUE:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
end:
|
||||
res.set_string(s.str(), cs);
|
||||
if (space && i) {
|
||||
s.push_back(' ');
|
||||
}
|
||||
s.append(v.get_string(cs));
|
||||
}
|
||||
end:
|
||||
res.set_string(s.str(), cs);
|
||||
}
|
||||
|
||||
LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
|
||||
|
@ -71,8 +69,8 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
|
|||
});
|
||||
|
||||
new_cmd_quiet(gcs, "pcall", "err", [](auto &cs, auto args, auto &ret) {
|
||||
alias *cret = args[1].get_ident()->get_alias();
|
||||
alias *css = args[2].get_ident()->get_alias();
|
||||
alias *cret = args[1].get_ident(cs).get_alias();
|
||||
alias *css = args[2].get_ident(cs).get_alias();
|
||||
if (!cret || !css) {
|
||||
ret.set_integer(0);
|
||||
return;
|
||||
|
@ -158,41 +156,40 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
|
|||
});
|
||||
|
||||
new_cmd_quiet(gcs, "pushif", "rte", [](auto &cs, auto args, auto &res) {
|
||||
if (alias_local st{cs, args[0].get_ident()}; st) {
|
||||
if (st.get_alias()->is_arg()) {
|
||||
return;
|
||||
}
|
||||
if (args[1].get_bool()) {
|
||||
st.set(args[1]);
|
||||
res = cs.run(args[2].get_code());
|
||||
}
|
||||
alias_local st{cs, args[0]};
|
||||
if (st.get_alias()->is_arg()) {
|
||||
throw error{cs, "cannot push an argument"};
|
||||
}
|
||||
if (args[1].get_bool()) {
|
||||
st.set(args[1]);
|
||||
res = cs.run(args[2].get_code());
|
||||
}
|
||||
});
|
||||
|
||||
new_cmd_quiet(gcs, "loop", "rie", [](auto &cs, auto args, auto &) {
|
||||
do_loop(
|
||||
cs, *args[0].get_ident(), 0, args[1].get_integer(), 1, bcode_ref{},
|
||||
args[2].get_code()
|
||||
cs, args[0].get_ident(cs), 0, args[1].get_integer(), 1,
|
||||
bcode_ref{}, args[2].get_code()
|
||||
);
|
||||
});
|
||||
|
||||
new_cmd_quiet(gcs, "loop+", "riie", [](auto &cs, auto args, auto &) {
|
||||
do_loop(
|
||||
cs, *args[0].get_ident(), args[1].get_integer(),
|
||||
cs, args[0].get_ident(cs), args[1].get_integer(),
|
||||
args[2].get_integer(), 1, bcode_ref{}, args[3].get_code()
|
||||
);
|
||||
});
|
||||
|
||||
new_cmd_quiet(gcs, "loop*", "riie", [](auto &cs, auto args, auto &) {
|
||||
do_loop(
|
||||
cs, *args[0].get_ident(), 0, args[1].get_integer(),
|
||||
cs, args[0].get_ident(cs), 0, args[1].get_integer(),
|
||||
args[2].get_integer(), bcode_ref{}, args[3].get_code()
|
||||
);
|
||||
});
|
||||
|
||||
new_cmd_quiet(gcs, "loop+*", "riiie", [](auto &cs, auto args, auto &) {
|
||||
do_loop(
|
||||
cs, *args[0].get_ident(), args[1].get_integer(),
|
||||
cs, args[0].get_ident(cs), args[1].get_integer(),
|
||||
args[3].get_integer(), args[2].get_integer(),
|
||||
bcode_ref{}, args[4].get_code()
|
||||
);
|
||||
|
@ -200,21 +197,21 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
|
|||
|
||||
new_cmd_quiet(gcs, "loopwhile", "riee", [](auto &cs, auto args, auto &) {
|
||||
do_loop(
|
||||
cs, *args[0].get_ident(), 0, args[1].get_integer(), 1,
|
||||
cs, args[0].get_ident(cs), 0, args[1].get_integer(), 1,
|
||||
args[2].get_code(), args[3].get_code()
|
||||
);
|
||||
});
|
||||
|
||||
new_cmd_quiet(gcs, "loopwhile+", "riiee", [](auto &cs, auto args, auto &) {
|
||||
do_loop(
|
||||
cs, *args[0].get_ident(), args[1].get_integer(),
|
||||
cs, args[0].get_ident(cs), args[1].get_integer(),
|
||||
args[2].get_integer(), 1, args[3].get_code(), args[4].get_code()
|
||||
);
|
||||
});
|
||||
|
||||
new_cmd_quiet(gcs, "loopwhile*", "riiee", [](auto &cs, auto args, auto &) {
|
||||
do_loop(
|
||||
cs, *args[0].get_ident(), 0, args[2].get_integer(),
|
||||
cs, args[0].get_ident(cs), 0, args[2].get_integer(),
|
||||
args[1].get_integer(), args[3].get_code(), args[4].get_code()
|
||||
);
|
||||
});
|
||||
|
@ -223,7 +220,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
|
|||
auto &cs, auto args, auto &
|
||||
) {
|
||||
do_loop(
|
||||
cs, *args[0].get_ident(), args[1].get_integer(),
|
||||
cs, args[0].get_ident(cs), args[1].get_integer(),
|
||||
args[3].get_integer(), args[2].get_integer(), args[4].get_code(),
|
||||
args[5].get_code()
|
||||
);
|
||||
|
@ -248,7 +245,7 @@ end:
|
|||
auto &cs, auto args, auto &res
|
||||
) {
|
||||
do_loop_conc(
|
||||
cs, res, *args[0].get_ident(), 0, args[1].get_integer(), 1,
|
||||
cs, res, args[0].get_ident(cs), 0, args[1].get_integer(), 1,
|
||||
args[2].get_code(), true
|
||||
);
|
||||
});
|
||||
|
@ -257,7 +254,7 @@ end:
|
|||
auto &cs, auto args, auto &res
|
||||
) {
|
||||
do_loop_conc(
|
||||
cs, res, *args[0].get_ident(), args[1].get_integer(),
|
||||
cs, res, args[0].get_ident(cs), args[1].get_integer(),
|
||||
args[2].get_integer(), 1, args[3].get_code(), true
|
||||
);
|
||||
});
|
||||
|
@ -266,7 +263,7 @@ end:
|
|||
auto &cs, auto args, auto &res
|
||||
) {
|
||||
do_loop_conc(
|
||||
cs, res, *args[0].get_ident(), 0, args[2].get_integer(),
|
||||
cs, res, args[0].get_ident(cs), 0, args[2].get_integer(),
|
||||
args[1].get_integer(), args[3].get_code(), true
|
||||
);
|
||||
});
|
||||
|
@ -275,7 +272,7 @@ end:
|
|||
auto &cs, auto args, auto &res
|
||||
) {
|
||||
do_loop_conc(
|
||||
cs, res, *args[0].get_ident(), args[1].get_integer(),
|
||||
cs, res, args[0].get_ident(cs), args[1].get_integer(),
|
||||
args[3].get_integer(), args[2].get_integer(),
|
||||
args[4].get_code(), true
|
||||
);
|
||||
|
@ -285,7 +282,7 @@ end:
|
|||
auto &cs, auto args, auto &res
|
||||
) {
|
||||
do_loop_conc(
|
||||
cs, res, *args[0].get_ident(), 0, args[1].get_integer(), 1,
|
||||
cs, res, args[0].get_ident(cs), 0, args[1].get_integer(), 1,
|
||||
args[2].get_code(), false
|
||||
);
|
||||
});
|
||||
|
@ -294,7 +291,7 @@ end:
|
|||
auto &cs, auto args, auto &res
|
||||
) {
|
||||
do_loop_conc(
|
||||
cs, res, *args[0].get_ident(), args[1].get_integer(),
|
||||
cs, res, args[0].get_ident(cs), args[1].get_integer(),
|
||||
args[2].get_integer(), 1, args[3].get_code(), false
|
||||
);
|
||||
});
|
||||
|
@ -303,7 +300,7 @@ end:
|
|||
auto &cs, auto args, auto &res
|
||||
) {
|
||||
do_loop_conc(
|
||||
cs, res, *args[0].get_ident(), 0, args[2].get_integer(),
|
||||
cs, res, args[0].get_ident(cs), 0, args[2].get_integer(),
|
||||
args[1].get_integer(), args[3].get_code(), false
|
||||
);
|
||||
});
|
||||
|
@ -312,20 +309,19 @@ end:
|
|||
auto &cs, auto args, auto &res
|
||||
) {
|
||||
do_loop_conc(
|
||||
cs, res, *args[0].get_ident(), args[1].get_integer(),
|
||||
cs, res, args[0].get_ident(cs), args[1].get_integer(),
|
||||
args[3].get_integer(), args[2].get_integer(),
|
||||
args[4].get_code(), false
|
||||
);
|
||||
});
|
||||
|
||||
new_cmd_quiet(gcs, "push", "rte", [](auto &cs, auto args, auto &res) {
|
||||
if (alias_local st{cs, args[0].get_ident()}; st) {
|
||||
if (st.get_alias()->is_arg()) {
|
||||
return;
|
||||
}
|
||||
st.set(args[1]);
|
||||
res = cs.run(args[2].get_code());
|
||||
alias_local st{cs, args[0]};
|
||||
if (st.get_alias()->is_arg()) {
|
||||
throw error{cs, "cannot push an argument"};
|
||||
}
|
||||
st.set(args[1]);
|
||||
res = cs.run(args[2].get_code());
|
||||
});
|
||||
|
||||
new_cmd_quiet(gcs, "resetvar", "s", [](auto &cs, auto args, auto &) {
|
||||
|
|
205
src/lib_list.cc
205
src/lib_list.cc
|
@ -73,33 +73,32 @@ static inline void list_assoc(
|
|||
}
|
||||
|
||||
static void loop_list_conc(
|
||||
state &cs, any_value &res, ident *id, std::string_view list,
|
||||
state &cs, any_value &res, ident &id, std::string_view list,
|
||||
bcode_ref &&body, bool space
|
||||
) {
|
||||
if (alias_local st{cs, id}; st) {
|
||||
any_value idv{};
|
||||
charbuf r{cs};
|
||||
int n = 0;
|
||||
for (list_parser p{cs, list}; p.parse(); ++n) {
|
||||
idv.set_string(p.get_item());
|
||||
st.set(std::move(idv));
|
||||
if (n && space) {
|
||||
r.push_back(' ');
|
||||
}
|
||||
any_value v{};
|
||||
switch (cs.run_loop(body, v)) {
|
||||
case loop_state::BREAK:
|
||||
goto end;
|
||||
case loop_state::CONTINUE:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
r.append(v.get_string(cs));
|
||||
alias_local st{cs, id};
|
||||
any_value idv{};
|
||||
charbuf r{cs};
|
||||
int n = 0;
|
||||
for (list_parser p{cs, list}; p.parse(); ++n) {
|
||||
idv.set_string(p.get_item());
|
||||
st.set(std::move(idv));
|
||||
if (n && space) {
|
||||
r.push_back(' ');
|
||||
}
|
||||
end:
|
||||
res.set_string(r.str(), cs);
|
||||
any_value v{};
|
||||
switch (cs.run_loop(body, v)) {
|
||||
case loop_state::BREAK:
|
||||
goto end;
|
||||
case loop_state::CONTINUE:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
r.append(v.get_string(cs));
|
||||
}
|
||||
end:
|
||||
res.set_string(r.str(), cs);
|
||||
}
|
||||
|
||||
int list_includes(
|
||||
|
@ -206,41 +205,39 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
|
|||
});
|
||||
|
||||
new_cmd_quiet(gcs, "listfind", "rse", [](auto &cs, auto args, auto &res) {
|
||||
if (alias_local st{cs, args[0].get_ident()}; st) {
|
||||
any_value idv{};
|
||||
auto body = args[2].get_code();
|
||||
int n = -1;
|
||||
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.run(body).get_bool()) {
|
||||
res.set_integer(integer_type(n));
|
||||
return;
|
||||
}
|
||||
alias_local st{cs, args[0]};
|
||||
any_value idv{};
|
||||
auto body = args[2].get_code();
|
||||
int n = -1;
|
||||
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.run(body).get_bool()) {
|
||||
res.set_integer(integer_type(n));
|
||||
return;
|
||||
}
|
||||
}
|
||||
res.set_integer(-1);
|
||||
});
|
||||
|
||||
new_cmd_quiet(gcs, "listassoc", "rse", [](auto &cs, auto args, auto &res) {
|
||||
if (alias_local st{cs, args[0].get_ident()}; st) {
|
||||
any_value idv{};
|
||||
auto body = args[2].get_code();
|
||||
int n = -1;
|
||||
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.run(body).get_bool()) {
|
||||
if (p.parse()) {
|
||||
res.set_string(p.get_item());
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!p.parse()) {
|
||||
break;
|
||||
alias_local st{cs, args[0]};
|
||||
any_value idv{};
|
||||
auto body = args[2].get_code();
|
||||
int n = -1;
|
||||
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.run(body).get_bool()) {
|
||||
if (p.parse()) {
|
||||
res.set_string(p.get_item());
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!p.parse()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -290,29 +287,25 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
|
|||
});
|
||||
|
||||
new_cmd_quiet(gcs, "looplist", "rse", [](auto &cs, auto args, auto &) {
|
||||
if (alias_local st{cs, args[0].get_ident()}; st) {
|
||||
any_value idv{};
|
||||
auto body = args[2].get_code();
|
||||
int n = 0;
|
||||
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.run_loop(body)) {
|
||||
case loop_state::BREAK:
|
||||
return;
|
||||
default: /* continue and normal */
|
||||
break;
|
||||
}
|
||||
alias_local st{cs, args[0]};
|
||||
any_value idv{};
|
||||
auto body = args[2].get_code();
|
||||
int n = 0;
|
||||
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.run_loop(body)) {
|
||||
case loop_state::BREAK:
|
||||
return;
|
||||
default: /* continue and normal */
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
new_cmd_quiet(gcs, "looplist2", "rrse", [](auto &cs, auto args, auto &) {
|
||||
alias_local st1{cs, args[0].get_ident()};
|
||||
alias_local st2{cs, args[1].get_ident()};
|
||||
if (!st1 || !st2) {
|
||||
return;
|
||||
}
|
||||
alias_local st1{cs, args[0]};
|
||||
alias_local st2{cs, args[1]};
|
||||
any_value idv{};
|
||||
auto body = args[3].get_code();
|
||||
int n = 0;
|
||||
|
@ -335,12 +328,9 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
|
|||
});
|
||||
|
||||
new_cmd_quiet(gcs, "looplist3", "rrrse", [](auto &cs, auto args, auto &) {
|
||||
alias_local st1{cs, args[0].get_ident()};
|
||||
alias_local st2{cs, args[1].get_ident()};
|
||||
alias_local st3{cs, args[2].get_ident()};
|
||||
if (!st1 || !st2 || !st3) {
|
||||
return;
|
||||
}
|
||||
alias_local st1{cs, args[0]};
|
||||
alias_local st2{cs, args[1]};
|
||||
alias_local st3{cs, args[2]};
|
||||
any_value idv{};
|
||||
auto body = args[4].get_code();
|
||||
int n = 0;
|
||||
|
@ -372,7 +362,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
|
|||
auto &cs, auto args, auto &res
|
||||
) {
|
||||
loop_list_conc(
|
||||
cs, res, args[0].get_ident(), args[1].get_string(cs),
|
||||
cs, res, args[0].get_ident(cs), args[1].get_string(cs),
|
||||
args[2].get_code(), true
|
||||
);
|
||||
});
|
||||
|
@ -381,7 +371,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
|
|||
auto &cs, auto args, auto &res
|
||||
) {
|
||||
loop_list_conc(
|
||||
cs, res, args[0].get_ident(), args[1].get_string(cs),
|
||||
cs, res, args[0].get_ident(cs), args[1].get_string(cs),
|
||||
args[2].get_code(), false
|
||||
);
|
||||
});
|
||||
|
@ -389,39 +379,37 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
|
|||
new_cmd_quiet(gcs, "listfilter", "rse", [](
|
||||
auto &cs, auto args, auto &res
|
||||
) {
|
||||
if (alias_local st{cs, args[0].get_ident()}; st) {
|
||||
any_value idv{};
|
||||
auto body = args[2].get_code();
|
||||
charbuf r{cs};
|
||||
int n = 0;
|
||||
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.run(body).get_bool()) {
|
||||
if (r.size()) {
|
||||
r.push_back(' ');
|
||||
}
|
||||
r.append(p.get_quoted_item());
|
||||
alias_local st{cs, args[0]};
|
||||
any_value idv{};
|
||||
auto body = args[2].get_code();
|
||||
charbuf r{cs};
|
||||
int n = 0;
|
||||
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.run(body).get_bool()) {
|
||||
if (r.size()) {
|
||||
r.push_back(' ');
|
||||
}
|
||||
r.append(p.get_quoted_item());
|
||||
}
|
||||
res.set_string(r.str(), cs);
|
||||
}
|
||||
res.set_string(r.str(), cs);
|
||||
});
|
||||
|
||||
new_cmd_quiet(gcs, "listcount", "rse", [](auto &cs, auto args, auto &res) {
|
||||
if (alias_local st{cs, args[0].get_ident()}; st) {
|
||||
any_value idv{};
|
||||
auto body = args[2].get_code();
|
||||
int n = 0, r = 0;
|
||||
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.run(body).get_bool()) {
|
||||
r++;
|
||||
}
|
||||
alias_local st{cs, args[0]};
|
||||
any_value idv{};
|
||||
auto body = args[2].get_code();
|
||||
int n = 0, r = 0;
|
||||
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.run(body).get_bool()) {
|
||||
r++;
|
||||
}
|
||||
res.set_integer(r);
|
||||
}
|
||||
res.set_integer(r);
|
||||
});
|
||||
|
||||
new_cmd_quiet(gcs, "prettylist", "ss", [](auto &cs, auto args, auto &res) {
|
||||
|
@ -543,16 +531,13 @@ struct ListSortFun {
|
|||
|
||||
static void list_sort(
|
||||
state &cs, any_value &res, std::string_view list,
|
||||
ident *x, ident *y, bcode_ref &&body, bcode_ref &&unique
|
||||
ident &x, ident &y, bcode_ref &&body, bcode_ref &&unique
|
||||
) {
|
||||
if (x == y) {
|
||||
return;
|
||||
}
|
||||
|
||||
alias_local xst{cs, x}, yst{cs, y};
|
||||
if (!xst || !yst) {
|
||||
return;
|
||||
}
|
||||
|
||||
valbuf<ListSortItem> items{state_p{cs}.ts().istate};
|
||||
size_t total = 0;
|
||||
|
@ -627,16 +612,16 @@ static void init_lib_list_sort(state &gcs) {
|
|||
auto &cs, auto args, auto &res
|
||||
) {
|
||||
list_sort(
|
||||
cs, res, args[0].get_string(cs), args[1].get_ident(),
|
||||
args[2].get_ident(), args[3].get_code(), args[4].get_code()
|
||||
cs, res, args[0].get_string(cs), args[1].get_ident(cs),
|
||||
args[2].get_ident(cs), args[3].get_code(), args[4].get_code()
|
||||
);
|
||||
});
|
||||
new_cmd_quiet(gcs, "uniquelist", "srre", [](
|
||||
auto &cs, auto args, auto &res
|
||||
) {
|
||||
list_sort(
|
||||
cs, res, args[0].get_string(cs), args[1].get_ident(),
|
||||
args[2].get_ident(), bcode_ref{}, args[3].get_code()
|
||||
cs, res, args[0].get_string(cs), args[1].get_ident(cs),
|
||||
args[2].get_ident(cs), bcode_ref{}, args[3].get_code()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -325,7 +325,7 @@ int main(int argc, char **argv) {
|
|||
* to be set, but you may also not be using standard i/o and so on
|
||||
*/
|
||||
gcs.new_command("//ivar", "$iiiN", [](auto &css, auto args, auto &) {
|
||||
auto *iv = args[0].get_ident()->get_ivar();
|
||||
auto *iv = args[0].get_ident(css).get_ivar();
|
||||
auto nargs = args[4].get_integer();
|
||||
if (nargs <= 1) {
|
||||
auto val = iv->get_value();
|
||||
|
@ -355,9 +355,10 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
});
|
||||
|
||||
gcs.new_command("//var_changed", "$", [](auto &, auto args, auto &) {
|
||||
gcs.new_command("//var_changed", "$", [](auto &css, auto args, auto &) {
|
||||
std::printf(
|
||||
"changed var trigger: %s\n", args[0].get_ident()->get_name().data()
|
||||
"changed var trigger: %s\n",
|
||||
args[0].get_ident(css).get_name().data()
|
||||
);
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue