re-add some support for persistent/overridable flags + fix unknown
parent
f0bb6b1410
commit
6777eb73d5
|
@ -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);
|
||||
|
|
|
@ -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 = *
|
||||
static_cast<alias_impl *>(p_alias)->p_flags &= ~IDENT_FLAG_UNKNOWN;
|
||||
ast.flags &= ~IDENT_FLAG_UNKNOWN;
|
||||
}
|
||||
|
||||
LIBCUBESCRIPT_EXPORT alias_local::~alias_local() {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
97
src/cs_vm.cc
97
src/cs_vm.cc
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue