re-add some support for persistent/overridable flags + fix unknown

master
Daniel Kolesa 2021-04-04 01:08:30 +02:00
parent f0bb6b1410
commit 6777eb73d5
7 changed files with 172 additions and 54 deletions

View File

@ -230,6 +230,9 @@ struct LIBCUBESCRIPT_EXPORT ident {
string_var *get_svar();
string_var const *get_svar() const;
bool is_overridden(state &cs) const;
bool is_persistent(state &cs) const;
protected:
ident() = default;
@ -238,8 +241,17 @@ protected:
struct ident_impl *p_impl{};
};
enum class var_type {
DEFAULT = 0,
PERSISTENT,
OVERRIDABLE
};
struct LIBCUBESCRIPT_EXPORT global_var: ident {
bool is_read_only() const;
bool is_overridable() const;
var_type get_variable_type() const;
protected:
global_var() = default;
@ -375,6 +387,12 @@ struct LIBCUBESCRIPT_EXPORT state {
bool is_in_loop() const;
bool get_override_mode() const;
bool set_override_mode(bool v);
bool get_persist_mode() const;
bool set_persist_mode(bool v);
void set_alias(std::string_view name, any_value v);
std::optional<string_ref> get_alias_val(std::string_view name);

View File

@ -24,15 +24,15 @@ var_impl::var_impl(
{}
ivar_impl::ivar_impl(string_ref name, integer_type v, int fl):
var_impl{ident_type::IVAR, name, fl}, p_storage{v}
var_impl{ident_type::IVAR, name, fl}, p_storage{v}, p_override{v}
{}
fvar_impl::fvar_impl(string_ref name, float_type v, int fl):
var_impl{ident_type::FVAR, name, fl}, p_storage{v}
var_impl{ident_type::FVAR, name, fl}, p_storage{v}, p_override{v}
{}
svar_impl::svar_impl(string_ref name, string_ref v, int fl):
var_impl{ident_type::SVAR, name, fl}, p_storage{v}
var_impl{ident_type::SVAR, name, fl}, p_storage{v}, p_override{v}
{}
alias_impl::alias_impl(
@ -120,9 +120,10 @@ void alias_stack::set_arg(alias *a, thread_state &ts, any_value &v) {
node->val_s = std::move(v);
}
void alias_stack::set_alias(alias *, thread_state &, any_value &v) {
void alias_stack::set_alias(alias *, thread_state &ts, any_value &v) {
node->val_s = std::move(v);
node->code = bcode_ref{};
flags = ts.ident_flags;
}
/* public interface */
@ -266,10 +267,56 @@ LIBCUBESCRIPT_EXPORT string_var const *ident::get_svar() const {
return static_cast<string_var const *>(this);
}
LIBCUBESCRIPT_EXPORT bool ident::is_overridden(state &cs) const {
switch (get_type()) {
case ident_type::IVAR:
case ident_type::FVAR:
case ident_type::SVAR:
return (p_impl->p_flags & IDENT_FLAG_OVERRIDDEN);
case ident_type::ALIAS:
return (cs.thread_pointer()->get_astack(
static_cast<alias const *>(this)
).flags & IDENT_FLAG_OVERRIDDEN);
default:
break;
}
return false;
}
LIBCUBESCRIPT_EXPORT bool ident::is_persistent(state &cs) const {
switch (get_type()) {
case ident_type::IVAR:
case ident_type::FVAR:
case ident_type::SVAR:
return (p_impl->p_flags & IDENT_FLAG_PERSIST);
case ident_type::ALIAS:
return (cs.thread_pointer()->get_astack(
static_cast<alias const *>(this)
).flags & IDENT_FLAG_PERSIST);
default:
break;
}
return false;
}
LIBCUBESCRIPT_EXPORT bool global_var::is_read_only() const {
return (p_impl->p_flags & IDENT_FLAG_READONLY);
}
LIBCUBESCRIPT_EXPORT bool global_var::is_overridable() const {
return (p_impl->p_flags & IDENT_FLAG_OVERRIDE);
}
LIBCUBESCRIPT_EXPORT var_type global_var::get_variable_type() const {
if (p_impl->p_flags & IDENT_FLAG_OVERRIDE) {
return var_type::OVERRIDABLE;
} else if (p_impl->p_flags & IDENT_FLAG_PERSIST) {
return var_type::PERSISTENT;
} else {
return var_type::DEFAULT;
}
}
LIBCUBESCRIPT_EXPORT integer_type integer_var::get_value() const {
return static_cast<ivar_impl const *>(this)->p_storage;
}
@ -318,7 +365,7 @@ LIBCUBESCRIPT_EXPORT alias_local::alias_local(state &cs, ident *a) {
auto &ast = ts.get_astack(p_alias);
ast.push(ts.idstack.emplace_back(cs));
p_sp = &ast;
static_cast<alias_impl *>(p_alias)->p_flags &= ~IDENT_FLAG_UNKNOWN;
ast.flags &= ~IDENT_FLAG_UNKNOWN;
}
LIBCUBESCRIPT_EXPORT alias_local::~alias_local() {

View File

@ -17,9 +17,12 @@ enum {
};
enum {
IDENT_FLAG_UNKNOWN = 1 << 0,
IDENT_FLAG_ARG = 1 << 1,
IDENT_FLAG_READONLY = 1 << 2
IDENT_FLAG_UNKNOWN = 1 << 0,
IDENT_FLAG_ARG = 1 << 1,
IDENT_FLAG_READONLY = 1 << 2,
IDENT_FLAG_OVERRIDE = 1 << 3,
IDENT_FLAG_OVERRIDDEN = 1 << 4,
IDENT_FLAG_PERSIST = 1 << 5
};
struct ident_stack {
@ -30,7 +33,8 @@ struct ident_stack {
};
struct alias_stack {
ident_stack *node;
ident_stack *node = nullptr;
int flags = 0;
void push(ident_stack &st);
void pop();
@ -77,18 +81,21 @@ struct ivar_impl: var_impl, integer_var {
ivar_impl(string_ref n, integer_type v, int flags);
integer_type p_storage;
integer_type p_override;
};
struct fvar_impl: var_impl, float_var {
fvar_impl(string_ref n, float_type v, int flags);
float_type p_storage;
float_type p_override;
};
struct svar_impl: var_impl, string_var {
svar_impl(string_ref n, string_ref v, int flags);
string_ref p_storage;
string_ref p_override;
};
struct alias_impl: ident_impl, alias {

View File

@ -354,7 +354,8 @@ LIBCUBESCRIPT_EXPORT void state::set_alias(
throw error{*this, "cannot alias invalid name '%s'", name.data()};
} else {
auto *a = p_tstate->istate->create<alias_impl>(
*this, string_ref{p_tstate->istate, name}, std::move(v), 0
*this, string_ref{p_tstate->istate, name}, std::move(v),
p_tstate->ident_flags
);
p_tstate->istate->add_ident(a, a);
}
@ -635,4 +636,32 @@ LIBCUBESCRIPT_EXPORT bool state::is_in_loop() const {
return !!p_tstate->loop_level;
}
LIBCUBESCRIPT_EXPORT bool state::get_override_mode() const {
return (p_tstate->ident_flags & IDENT_FLAG_OVERRIDDEN);
}
LIBCUBESCRIPT_EXPORT bool state::set_override_mode(bool v) {
bool was = get_override_mode();
if (v) {
p_tstate->ident_flags |= IDENT_FLAG_OVERRIDDEN;
} else {
p_tstate->ident_flags &= ~IDENT_FLAG_OVERRIDDEN;
}
return was;
}
LIBCUBESCRIPT_EXPORT bool state::get_persist_mode() const {
return (p_tstate->ident_flags & IDENT_FLAG_PERSIST);
}
LIBCUBESCRIPT_EXPORT bool state::set_persist_mode(bool v) {
bool was = get_persist_mode();
if (v) {
p_tstate->ident_flags |= IDENT_FLAG_PERSIST;
} else {
p_tstate->ident_flags &= ~IDENT_FLAG_PERSIST;
}
return was;
}
} /* namespace cubescript */

View File

@ -21,8 +21,13 @@ alias_stack &thread_state::get_astack(alias *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;
}
return it.first->second;
}
alias_stack const &thread_state::get_astack(alias const *a) {
return get_astack(const_cast<alias *>(a));
}
} /* namespace cubescript */

View File

@ -37,6 +37,8 @@ struct thread_state {
hook_func call_hook{};
/* loop nesting level */
int loop_level = 0;
/* thread ident flags */
int ident_flags = 0;
/* whether we own the internal state (i.e. not a side thread */
bool owner = false;
@ -48,6 +50,7 @@ struct thread_state {
hook_func const &get_hook() const { return call_hook; }
alias_stack &get_astack(alias *a);
alias_stack const &get_astack(alias const *a);
};
} /* namespace cubescript */

View File

@ -12,8 +12,9 @@ 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);
ts.get_astack(aimp).push(st);
aimp->p_flags &= ~IDENT_FLAG_UNKNOWN;
auto ast = ts.get_astack(aimp);
ast.push(st);
ast.flags &= ~IDENT_FLAG_UNKNOWN;
}
}
@ -205,8 +206,14 @@ bool exec_alias(
std::size_t offset, std::size_t skip, std::uint32_t op, bool ncheck
) {
auto &aast = ts.get_astack(a);
if (ncheck && aast.node->val_s.get_type() == value_type::NONE) {
return false;
if (ncheck) {
if (aast.node->val_s.get_type() == value_type::NONE) {
return false;
}
} else if (aast.flags & IDENT_FLAG_UNKNOWN) {
throw error {
*ts.pstate, "unknown command: %s", a->get_name().data()
};
}
/* excess arguments get ignored (make error maybe?) */
callargs = std::min(callargs, MAX_ARGUMENTS);
@ -225,6 +232,8 @@ bool exec_alias(
uargs[i] = true;
}
auto oldargs = anargs->get_value();
auto oldflags = ts.ident_flags;
ts.ident_flags = aast.flags;
anargs->set_value(integer_type(callargs));
ident_link aliaslink = {a, ts.callstack, uargs};
ts.callstack = &aliaslink;
@ -240,6 +249,7 @@ bool exec_alias(
bcode_ref coderef = aast.node->code;
auto cleanup = [&]() {
ts.callstack = aliaslink.next;
ts.ident_flags = oldflags;
auto amask = aliaslink.usedargs;
for (std::size_t i = 0; i < callargs; i++) {
ts.get_astack(
@ -283,7 +293,9 @@ run_depth_guard::run_depth_guard(thread_state &ts) {
run_depth_guard::~run_depth_guard() { --rundepth; }
static inline alias *get_lookup_id(thread_state &ts, std::uint32_t op) {
static inline alias *get_lookup_id(
thread_state &ts, std::uint32_t op, alias_stack *&ast
) {
ident *id = ts.istate->identmap[op >> 8];
auto *a = static_cast<alias_impl *>(id);
@ -291,16 +303,21 @@ static inline alias *get_lookup_id(thread_state &ts, std::uint32_t op) {
if (!ident_is_used_arg(id, ts)) {
return nullptr;
}
} else if (a->p_flags & IDENT_FLAG_UNKNOWN) {
throw error{
*ts.pstate, "unknown alias lookup: %s", id->get_name().data()
};
ast = &ts.get_astack(static_cast<alias *>(id));
} else {
ast = &ts.get_astack(static_cast<alias *>(id));
if (ast->flags & IDENT_FLAG_UNKNOWN) {
throw error{
*ts.pstate, "unknown alias lookup: %s", id->get_name().data()
};
}
}
return static_cast<alias *>(id);
}
static inline int get_lookupu_type(
thread_state &ts, any_value &arg, ident *&id, std::uint32_t op
thread_state &ts, any_value &arg, ident *&id, std::uint32_t op,
alias_stack *&ast
) {
if (arg.get_type() != value_type::STRING) {
return -2; /* default case */
@ -310,7 +327,8 @@ static inline int get_lookupu_type(
switch(id->get_type()) {
case ident_type::ALIAS: {
auto *a = static_cast<alias_impl *>(id);
if (a->p_flags & IDENT_FLAG_UNKNOWN) {
ast = &ts.get_astack(static_cast<alias *>(id));
if (ast->flags & IDENT_FLAG_UNKNOWN) {
break;
}
if (a->is_arg() && !ident_is_used_arg(id, ts)) {
@ -770,12 +788,11 @@ std::uint32_t *vm_exec(
case BC_INST_LOOKUP_U | BC_RET_STRING: {
ident *id = nullptr;
alias_stack *ast;
any_value &arg = args.back();
switch (get_lookupu_type(ts, arg, id, op)) {
switch (get_lookupu_type(ts, arg, id, op, ast)) {
case ID_ALIAS:
arg = ts.get_astack(
static_cast<alias *>(id)
).node->val_s;
arg = ast->node->val_s;
arg.force_str();
continue;
case ID_SVAR:
@ -798,12 +815,13 @@ std::uint32_t *vm_exec(
}
case BC_INST_LOOKUP | BC_RET_STRING: {
alias *a = get_lookup_id(ts, op);
alias_stack *ast;
alias *a = get_lookup_id(ts, op, ast);
if (!a) {
args.emplace_back(cs).set_str("");
} else {
auto &v = args.emplace_back(cs);
v = ts.get_astack(a).node->val_s;
v = ast->node->val_s;
v.force_str();
}
continue;
@ -811,12 +829,11 @@ std::uint32_t *vm_exec(
case BC_INST_LOOKUP_U | BC_RET_INT: {
ident *id = nullptr;
alias_stack *ast;
any_value &arg = args.back();
switch (get_lookupu_type(ts, arg, id, op)) {
switch (get_lookupu_type(ts, arg, id, op, ast)) {
case ID_ALIAS:
arg.set_int(ts.get_astack(static_cast<alias *>(
id
)).node->val_s.get_int());
arg.set_int(ast->node->val_s.get_int());
continue;
case ID_SVAR:
arg.set_int(parse_int(
@ -839,24 +856,22 @@ std::uint32_t *vm_exec(
}
}
case BC_INST_LOOKUP | BC_RET_INT: {
alias *a = get_lookup_id(ts, op);
alias_stack *ast;
alias *a = get_lookup_id(ts, op, ast);
if (!a) {
args.emplace_back(cs).set_int(0);
} else {
args.emplace_back(cs).set_int(
ts.get_astack(a).node->val_s.get_int()
);
args.emplace_back(cs).set_int(ast->node->val_s.get_int());
}
continue;
}
case BC_INST_LOOKUP_U | BC_RET_FLOAT: {
ident *id = nullptr;
alias_stack *ast;
any_value &arg = args.back();
switch (get_lookupu_type(ts, arg, id, op)) {
switch (get_lookupu_type(ts, arg, id, op, ast)) {
case ID_ALIAS:
arg.set_float(ts.get_astack(static_cast<alias *>(
id
)).node->val_s.get_float());
arg.set_float(ast->node->val_s.get_float());
continue;
case ID_SVAR:
arg.set_float(parse_float(
@ -881,24 +896,24 @@ std::uint32_t *vm_exec(
}
}
case BC_INST_LOOKUP | BC_RET_FLOAT: {
alias *a = get_lookup_id(ts, op);
alias_stack *ast;
alias *a = get_lookup_id(ts, op, ast);
if (!a) {
args.emplace_back(cs).set_float(float_type(0));
} else {
args.emplace_back(cs).set_float(
ts.get_astack(a).node->val_s.get_float()
ast->node->val_s.get_float()
);
}
continue;
}
case BC_INST_LOOKUP_U | BC_RET_NULL: {
ident *id = nullptr;
alias_stack *ast;
any_value &arg = args.back();
switch (get_lookupu_type(ts, arg, id, op)) {
switch (get_lookupu_type(ts, arg, id, op, ast)) {
case ID_ALIAS:
ts.get_astack(
static_cast<alias *>(id)
).node->val_s.get_val(arg);
ast->node->val_s.get_val(arg);
continue;
case ID_SVAR:
arg.set_str(static_cast<string_var *>(id)->get_value());
@ -919,13 +934,12 @@ std::uint32_t *vm_exec(
}
}
case BC_INST_LOOKUP | BC_RET_NULL: {
alias *a = get_lookup_id(ts, op);
alias_stack *ast;
alias *a = get_lookup_id(ts, op, ast);
if (!a) {
args.emplace_back(cs).set_none();
} else {
ts.get_astack(a).node->val_s.get_val(
args.emplace_back(cs)
);
ast->node->val_s.get_val(args.emplace_back(cs));
}
continue;
}
@ -1049,11 +1063,6 @@ std::uint32_t *vm_exec(
force_arg(result, op & BC_INST_RET_MASK);
continue;
}
} else if (imp->p_flags & IDENT_FLAG_UNKNOWN) {
force_arg(result, op & BC_INST_RET_MASK);
throw error{
cs, "unknown command: %s", id->get_name().data()
};
}
exec_alias(
ts, imp, &args[0], result, callargs,