add better api to deal with alias stack

master
Daniel Kolesa 2021-03-30 03:57:43 +02:00
parent 3dc6ad866f
commit d1243c5cc3
3 changed files with 134 additions and 58 deletions

View File

@ -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();

View File

@ -412,4 +412,61 @@ LIBCUBESCRIPT_EXPORT int command::get_num_args() const {
return static_cast<command_impl const *>(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<alias *>(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<alias_impl *>(p_alias)->push_arg(
val, ts.idstack.emplace_back(p_state)
);
p_pushed = true;
} else {
static_cast<alias_impl *>(p_alias)->p_val = std::move(val);
}
return true;
}
LIBCUBESCRIPT_EXPORT bool alias_stack::pop() {
if (!p_pushed || !p_alias) {
return false;
}
static_cast<alias_impl *>(p_alias)->pop_arg();
p_pushed = false;
return true;
}
LIBCUBESCRIPT_EXPORT alias_stack::operator bool() const noexcept {
return has_alias();
}
} /* namespace cubescript */

View File

@ -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 &) {