From 6777eb73d548c789c47aeb97e58fd6ce223e7300 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Sun, 4 Apr 2021 01:08:30 +0200 Subject: [PATCH] re-add some support for persistent/overridable flags + fix unknown --- include/cubescript/cubescript.hh | 18 ++++++ src/cs_ident.cc | 57 +++++++++++++++++-- src/cs_ident.hh | 15 +++-- src/cs_state.cc | 31 +++++++++- src/cs_thread.cc | 5 ++ src/cs_thread.hh | 3 + src/cs_vm.cc | 97 +++++++++++++++++--------------- 7 files changed, 172 insertions(+), 54 deletions(-) diff --git a/include/cubescript/cubescript.hh b/include/cubescript/cubescript.hh index cd9709e..ceee42b 100644 --- a/include/cubescript/cubescript.hh +++ b/include/cubescript/cubescript.hh @@ -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 get_alias_val(std::string_view name); diff --git a/src/cs_ident.cc b/src/cs_ident.cc index abd45e5..5ae9c66 100644 --- a/src/cs_ident.cc +++ b/src/cs_ident.cc @@ -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(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(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(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(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(p_alias)->p_flags &= ~IDENT_FLAG_UNKNOWN; + ast.flags &= ~IDENT_FLAG_UNKNOWN; } LIBCUBESCRIPT_EXPORT alias_local::~alias_local() { diff --git a/src/cs_ident.hh b/src/cs_ident.hh index 6f95231..ad609a3 100644 --- a/src/cs_ident.hh +++ b/src/cs_ident.hh @@ -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 { diff --git a/src/cs_state.cc b/src/cs_state.cc index 6b50a4c..7be91a3 100644 --- a/src/cs_state.cc +++ b/src/cs_state.cc @@ -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( - *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 */ diff --git a/src/cs_thread.cc b/src/cs_thread.cc index ccc3f48..5ea496c 100644 --- a/src/cs_thread.cc +++ b/src/cs_thread.cc @@ -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(a)->p_initial; + it.first->second.flags = static_cast(a)->p_flags; } return it.first->second; } +alias_stack const &thread_state::get_astack(alias const *a) { + return get_astack(const_cast(a)); +} + } /* namespace cubescript */ diff --git a/src/cs_thread.hh b/src/cs_thread.hh index e4642d9..a7ec600 100644 --- a/src/cs_thread.hh +++ b/src/cs_thread.hh @@ -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 */ diff --git a/src/cs_vm.cc b/src/cs_vm.cc index 0880f0a..4611390 100644 --- a/src/cs_vm.cc +++ b/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(id)->is_arg()) { auto *aimp = static_cast(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(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(id)); + } else { + ast = &ts.get_astack(static_cast(id)); + if (ast->flags & IDENT_FLAG_UNKNOWN) { + throw error{ + *ts.pstate, "unknown alias lookup: %s", id->get_name().data() + }; + } } return static_cast(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(id); - if (a->p_flags & IDENT_FLAG_UNKNOWN) { + ast = &ts.get_astack(static_cast(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(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( - 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( - 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(id) - ).node->val_s.get_val(arg); + ast->node->val_s.get_val(arg); continue; case ID_SVAR: arg.set_str(static_cast(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,