diff --git a/include/cubescript/cubescript.hh b/include/cubescript/cubescript.hh index ec2b5b4..3ea5eb6 100644 --- a/include/cubescript/cubescript.hh +++ b/include/cubescript/cubescript.hh @@ -507,8 +507,6 @@ protected: command() = default; }; -struct ident_link; - enum { LIB_MATH = 1 << 0, LIB_STRING = 1 << 1, @@ -818,6 +816,31 @@ private: stack_state p_stack; }; +struct LIBCUBESCRIPT_EXPORT alias_stack { + alias_stack(state &cs, ident *a); + ~alias_stack(); + + alias_stack(alias_stack const &) = delete; + alias_stack(alias_stack &&) = delete; + + alias_stack &operator=(alias_stack const &) = delete; + alias_stack &operator=(alias_stack &&v) = delete; + + bool set_alias(ident *id); + alias *get_alias() const noexcept; + bool has_alias() const noexcept; + + bool push(any_value val); + bool pop(); + + explicit operator bool() const noexcept; + +private: + state &p_state; + alias *p_alias; + bool p_pushed; +}; + struct LIBCUBESCRIPT_EXPORT stacked_value: any_value { stacked_value(state &cs, ident *id = nullptr); ~stacked_value(); diff --git a/src/cs_ident.cc b/src/cs_ident.cc index b653f51..628d832 100644 --- a/src/cs_ident.cc +++ b/src/cs_ident.cc @@ -412,4 +412,61 @@ LIBCUBESCRIPT_EXPORT int command::get_num_args() const { return static_cast(this)->p_numargs; } +/* external API for alias stack management */ + +LIBCUBESCRIPT_EXPORT alias_stack::alias_stack(state &cs, ident *a): + p_state{cs}, p_pushed{false} +{ + set_alias(a); +} + +LIBCUBESCRIPT_EXPORT alias_stack::~alias_stack() { + pop(); +} + +LIBCUBESCRIPT_EXPORT bool alias_stack::set_alias(ident *id) { + if (!id || !id->is_alias()) { + return false; + } + p_alias = static_cast(id); + return true; +} + +LIBCUBESCRIPT_EXPORT alias *alias_stack::get_alias() const noexcept { + return p_alias; +} + +LIBCUBESCRIPT_EXPORT bool alias_stack::has_alias() const noexcept { + return !!p_alias; +} + +LIBCUBESCRIPT_EXPORT bool alias_stack::push(any_value val) { + if (!p_alias) { + return false; + } + auto &ts = *p_state.thread_pointer(); + if (!p_pushed) { + static_cast(p_alias)->push_arg( + val, ts.idstack.emplace_back(p_state) + ); + p_pushed = true; + } else { + static_cast(p_alias)->p_val = std::move(val); + } + return true; +} + +LIBCUBESCRIPT_EXPORT bool alias_stack::pop() { + if (!p_pushed || !p_alias) { + return false; + } + static_cast(p_alias)->pop_arg(); + p_pushed = false; + return true; +} + +LIBCUBESCRIPT_EXPORT alias_stack::operator bool() const noexcept { + return has_alias(); +} + } /* namespace cubescript */ diff --git a/src/lib_base.cc b/src/lib_base.cc index b9b0af0..3b5658f 100644 --- a/src/lib_base.cc +++ b/src/lib_base.cc @@ -9,55 +9,57 @@ static inline void do_loop( state &cs, ident &id, integer_type offset, integer_type n, integer_type step, bcode *cond, bcode *body ) { - stacked_value idv{cs, &id}; - if (n <= 0 || !idv.has_alias()) { + if (n <= 0) { return; } - for (integer_type i = 0; i < n; ++i) { - idv.set_int(offset + i * step); - idv.push(); - if (cond && !cs.run(cond).get_bool()) { - break; - } - switch (cs.run_loop(body)) { - case loop_state::BREAK: - goto end; - default: /* continue and normal */ + if (alias_stack st{cs, &id}; st) { + any_value idv{cs}; + for (integer_type i = 0; i < n; ++i) { + idv.set_int(offset + i * step); + st.push(idv); + if (cond && !cs.run(cond).get_bool()) { break; + } + switch (cs.run_loop(body)) { + case loop_state::BREAK: + return; + default: /* continue and normal */ + break; + } } } -end: - return; } static inline void do_loop_conc( state &cs, any_value &res, ident &id, integer_type offset, integer_type n, integer_type step, bcode *body, bool space ) { - stacked_value idv{cs, &id}; - if (n <= 0 || !idv.has_alias()) { + if (n <= 0) { return; } - charbuf s{cs}; - for (integer_type i = 0; i < n; ++i) { - idv.set_int(offset + i * step); - idv.push(); - any_value v{cs}; - switch (cs.run_loop(body, v)) { - case loop_state::BREAK: - goto end; - case loop_state::CONTINUE: - continue; - default: - break; + if (alias_stack st{cs, &id}; st) { + charbuf s{cs}; + any_value idv{cs}; + for (integer_type i = 0; i < n; ++i) { + idv.set_int(offset + i * step); + st.push(idv); + any_value v{cs}; + 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_str()); } - if (space && i) { - s.push_back(' '); - } - s.append(v.get_str()); - } end: - res.set_str(s.str()); + res.set_str(s.str()); + } } void init_lib_base(state &gcs) { @@ -66,8 +68,8 @@ void init_lib_base(state &gcs) { }); gcs.new_command("pcall", "err", [](auto &cs, auto args, auto &ret) { - alias *cret = args[1].get_ident()->get_alias(), - *css = args[2].get_ident()->get_alias(); + alias *cret = args[1].get_ident()->get_alias(); + alias *css = args[2].get_ident()->get_alias(); if (!cret || !css) { ret.set_int(0); return; @@ -156,17 +158,14 @@ void init_lib_base(state &gcs) { }); gcs.new_command("pushif", "rte", [](auto &cs, auto args, auto &res) { - stacked_value idv{cs, args[0].get_ident()}; - if (!idv.has_alias()) { - return; - } - if (idv.get_alias()->get_flags() & IDENT_FLAG_ARG) { - return; - } - if (args[1].get_bool()) { - idv = args[1]; - idv.push(); - cs.run(args[2].get_code(), res); + if (alias_stack st{cs, args[0].get_ident()}; st) { + if (st.get_alias()->get_flags() & IDENT_FLAG_ARG) { + return; + } + if (args[1].get_bool()) { + st.push(args[1]); + cs.run(args[2].get_code(), res); + } } }); @@ -303,16 +302,13 @@ end: }); gcs.new_command("push", "rte", [](auto &cs, auto args, auto &res) { - stacked_value idv{cs, args[0].get_ident()}; - if (!idv.has_alias()) { - return; + if (alias_stack st{cs, args[0].get_ident()}; st) { + if (st.get_alias()->get_flags() & IDENT_FLAG_ARG) { + return; + } + st.push(args[1]); + cs.run(args[2].get_code(), res); } - if (idv.get_alias()->get_flags() & IDENT_FLAG_ARG) { - return; - } - idv = args[1]; - idv.push(); - cs.run(args[2].get_code(), res); }); gcs.new_command("resetvar", "s", [](auto &cs, auto args, auto &) {