From f4b8d077bb894f4fb06ed6e764a127c0521eaa3b Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Sat, 24 Apr 2021 23:33:19 +0200 Subject: [PATCH] alias_local and get_ident() memory safety (always return refs) --- include/cubescript/cubescript/ident.hh | 6 + include/cubescript/cubescript/util.hh | 30 ++-- include/cubescript/cubescript/value.hh | 11 +- src/cs_ident.cc | 31 ++-- src/cs_state.cc | 6 +- src/cs_strman.cc | 4 + src/cs_val.cc | 6 +- src/cs_vm.cc | 20 +-- src/lib_base.cc | 130 ++++++++-------- src/lib_list.cc | 205 ++++++++++++------------- tools/repl.cc | 7 +- 11 files changed, 238 insertions(+), 218 deletions(-) diff --git a/include/cubescript/cubescript/ident.hh b/include/cubescript/cubescript/ident.hh index 1c31fa5..c30d458 100644 --- a/include/cubescript/cubescript/ident.hh +++ b/include/cubescript/cubescript/ident.hh @@ -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`. diff --git a/include/cubescript/cubescript/util.hh b/include/cubescript/cubescript/util.hh index 9327d5e..ec2c042 100644 --- a/include/cubescript/cubescript/util.hh +++ b/include/cubescript/cubescript/util.hh @@ -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; diff --git a/include/cubescript/cubescript/value.hh b/include/cubescript/cubescript/value.hh index 216fd36..f393278 100644 --- a/include/cubescript/cubescript/value.hh +++ b/include/cubescript/cubescript/value.hh @@ -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. * diff --git a/src/cs_ident.cc b/src/cs_ident.cc index ffd5e45..bb9493b 100644 --- a/src/cs_ident.cc +++ b/src/cs_ident.cc @@ -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(a); + p_alias = static_cast(&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(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 */ diff --git a/src/cs_state.cc b/src/cs_state.cc index 01cf8ef..4c66b39 100644 --- a/src/cs_state.cc +++ b/src/cs_state.cc @@ -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) { diff --git a/src/cs_strman.cc b/src/cs_strman.cc index c573b2f..7273c22 100644 --- a/src/cs_strman.cc +++ b/src/cs_strman.cc @@ -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 */ diff --git a/src/cs_val.cc b/src/cs_val.cc index 447e5f0..7433cce 100644 --- a/src/cs_val.cc +++ b/src/cs_val.cc @@ -311,11 +311,11 @@ bcode_ref any_value::get_code() const { return bcode_p::make_ref(csv_get(&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(&p_stor); + return *csv_get(&p_stor); } string_ref any_value::get_string(state &cs) const { diff --git a/src/cs_vm.cc b/src/cs_vm.cc index b2a9574..9eb68d5 100644 --- a/src/cs_vm.cc +++ b/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(id)->is_arg()) { - auto *aimp = static_cast(id); +static inline void push_alias(thread_state &ts, ident &id, ident_stack &st) { + if (id.is_alias() && !static_cast(id).is_arg()) { + auto *aimp = static_cast(&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(id)->is_arg()) { - ts.get_astack(static_cast(id)).pop(); +static inline void pop_alias(thread_state &ts, ident &id) { + if (id.is_alias() && !static_cast(id).is_arg()) { + ts.get_astack(static_cast(&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); }; diff --git a/src/lib_base.cc b/src/lib_base.cc index ba5b084..9668b6e 100644 --- a/src/lib_base.cc +++ b/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 &) { diff --git a/src/lib_list.cc b/src/lib_list.cc index 7448531..398870c 100644 --- a/src/lib_list.cc +++ b/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 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() ); }); } diff --git a/tools/repl.cc b/tools/repl.cc index a3e2962..ce6473e 100644 --- a/tools/repl.cc +++ b/tools/repl.cc @@ -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() ); });