From b00a08ea88d1edf2b008fecce77c32a296d1ca6a Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Sat, 3 Apr 2021 03:14:52 +0200 Subject: [PATCH] remove most variable code and leave it to user-defined handlers the user can now define commands '//ivar', '//fvar' and '//svar' which take identity (which is the variable) as the first argument followed by any number of user defined arguments with types (one can use the N argument type to check argument count, and when no value arguments are provided, print the variable); this allows us to implement different styles of variable setting without the interpreter itself knowing about it, as well as ditch all the stuff with overridden vars and hex vars and whatnot since this is all specific to the engine and has no place in here there is still leftover code remaining, which will get cleaned up afterwards... --- include/cubescript/cubescript.hh | 43 ---- src/cs_bcode.hh | 11 - src/cs_gen.cc | 177 ++++++------- src/cs_ident.cc | 16 -- src/cs_state.cc | 415 +++++-------------------------- src/cs_state.hh | 1 - src/cs_std.hh | 4 + src/cs_vm.cc | 140 +++++------ src/cs_vm.hh | 4 +- src/lib_base.cc | 17 -- tools/repl.cc | 103 ++++---- 11 files changed, 271 insertions(+), 660 deletions(-) diff --git a/include/cubescript/cubescript.hh b/include/cubescript/cubescript.hh index d209f5d..d43f368 100644 --- a/include/cubescript/cubescript.hh +++ b/include/cubescript/cubescript.hh @@ -58,7 +58,6 @@ struct global_var; using hook_func = callable; using var_cb_func = callable; -using var_print_func = callable; using command_func = callable< void, state &, std::span, any_value & >; @@ -267,9 +266,6 @@ protected: }; struct LIBCUBESCRIPT_EXPORT integer_var: global_var { - integer_type get_val_min() const; - integer_type get_val_max() const; - integer_type get_value() const; void set_value(integer_type val); @@ -278,9 +274,6 @@ protected: }; struct LIBCUBESCRIPT_EXPORT float_var: global_var { - float_type get_val_min() const; - float_type get_val_max() const; - float_type get_value() const; void set_value(float_type val); @@ -357,14 +350,6 @@ struct LIBCUBESCRIPT_EXPORT state { hook_func const &get_call_hook() const; hook_func &get_call_hook(); - template - var_print_func set_var_printer(F &&f) { - return set_var_printer( - var_print_func{std::forward(f), callable_alloc, this} - ); - } - var_print_func const &get_var_printer() const; - void init_libs(int libs = LIB_ALL); void clear_override(ident &id); @@ -454,33 +439,6 @@ struct LIBCUBESCRIPT_EXPORT state { void set_alias(std::string_view name, any_value v); - void set_var_int( - std::string_view name, integer_type v, - bool dofunc = true, bool doclamp = true - ); - void set_var_float( - std::string_view name, float_type v, - bool dofunc = true, bool doclamp = true - ); - void set_var_str( - std::string_view name, std::string_view v, bool dofunc = true - ); - - void set_var_int_checked(integer_var *iv, integer_type v); - void set_var_int_checked(integer_var *iv, std::span args); - void set_var_float_checked(float_var *fv, float_type v); - void set_var_str_checked(string_var *fv, std::string_view v); - - std::optional get_var_int(std::string_view name); - std::optional get_var_float(std::string_view name); - std::optional get_var_str(std::string_view name); - - std::optional get_var_min_int(std::string_view name); - std::optional get_var_max_int(std::string_view name); - - std::optional get_var_min_float(std::string_view name); - std::optional get_var_max_float(std::string_view name); - std::optional get_alias_val(std::string_view name); void print_var(global_var const &v) const; @@ -495,7 +453,6 @@ struct LIBCUBESCRIPT_EXPORT state { private: hook_func set_call_hook(hook_func func); - var_print_func set_var_printer(var_print_func func); integer_var *new_ivar( std::string_view n, integer_type m, integer_type x, integer_type v, diff --git a/src/cs_bcode.hh b/src/cs_bcode.hh index e540b6f..3ab331b 100644 --- a/src/cs_bcode.hh +++ b/src/cs_bcode.hh @@ -80,8 +80,6 @@ enum { * integral values between -0x800000 and 0x7FFFFF inclusive */ BC_INST_VAL_INT, - /* print builtin variable with index D using user provided call */ - BC_INST_PRINT, /* pop D aliases off the stack, push their values and recurse the VM * pop their values afterwards (i.e. they are local to the execution) */ @@ -144,17 +142,8 @@ enum { BC_INST_CONC_W, /* push the value of svar with index D on the stack according to M */ BC_INST_SVAR, - /* pop a value off the stack and set svar with index D to it */ - BC_INST_SVAR1, /* push the value of ivar with index D on the stack according to M */ BC_INST_IVAR, - /* pop up to 3 values off the stack and set ivar with index D to: - * - * ivar1: top - * ivar2: (top << 8) | ((top - 1) << 16) - * ivar3: top | ((top - 1) << 8) | ((top - 2) << 16) - */ - BC_INST_IVAR1, BC_INST_IVAR2, BC_INST_IVAR3, /* push the value of fvar with index D on the stack according to M */ BC_INST_FVAR, /* pop a value off the stack and set vvar with index D to it */ diff --git a/src/cs_gen.cc b/src/cs_gen.cc index 746a28f..5eee842 100644 --- a/src/cs_gen.cc +++ b/src/cs_gen.cc @@ -800,18 +800,19 @@ static bool compilearg( } static void compile_cmd( - codegen_state &gs, command_impl *id, bool &more, int rettype + codegen_state &gs, command_impl *id, ident *self, bool &more, int rettype, + std::uint32_t limit = 0 ) { - std::uint32_t comtype = BC_INST_COM, numargs = 0, fakeargs = 0; + std::uint32_t comtype = BC_INST_COM, numargs = 0, numcargs = 0, fakeargs = 0; bool rep = false; auto fmt = id->get_args(); for (auto it = fmt.begin(); it != fmt.end(); ++it) { switch (*it) { case 's': /* string */ - if (more) { + if (more && (!limit || (numcargs < limit))) { more = compilearg(gs, VAL_STRING); } - if (!more) { + if (!more || (limit && (numcargs >= limit))) { if (rep) { break; } @@ -831,12 +832,13 @@ static void compile_cmd( } } numargs++; + numcargs++; break; case 'i': /* integer */ - if (more) { + if (more && (!limit || (numcargs < limit))) { more = compilearg(gs, VAL_INT); } - if (!more) { + if (!more || (limit && (numcargs >= limit))) { if (rep) { break; } @@ -844,12 +846,13 @@ static void compile_cmd( fakeargs++; } numargs++; + numcargs++; break; case 'b': /* integer, INT_MIN default */ - if (more) { + if (more && (!limit || (numcargs < limit))) { more = compilearg(gs, VAL_INT); } - if (!more) { + if (!more || (limit && (numcargs >= limit))) { if (rep) { break; } @@ -857,12 +860,13 @@ static void compile_cmd( fakeargs++; } numargs++; + numcargs++; break; case 'f': /* float */ - if (more) { + if (more && (!limit || (numcargs < limit))) { more = compilearg(gs, VAL_FLOAT); } - if (!more) { + if (!more || (limit && (numcargs >= limit))) { if (rep) { break; } @@ -870,12 +874,13 @@ static void compile_cmd( fakeargs++; } numargs++; + numcargs++; break; case 'F': /* float, prev-argument default */ - if (more) { + if (more && (!limit || (numcargs < limit))) { more = compilearg(gs, VAL_FLOAT); } - if (!more) { + if (!more || (limit && (numcargs >= limit))) { if (rep) { break; } @@ -883,12 +888,13 @@ static void compile_cmd( fakeargs++; } numargs++; + numcargs++; break; case 't': /* any arg */ - if (more) { + if (more && (!limit || (numcargs < limit))) { more = compilearg(gs, VAL_ANY); } - if (!more) { + if (!more || (limit && (numcargs >= limit))) { if (rep) { break; } @@ -896,12 +902,13 @@ static void compile_cmd( fakeargs++; } numargs++; + numcargs++; break; case 'E': /* condition */ - if (more) { + if (more && (!limit || (numcargs < limit))) { more = compilearg(gs, VAL_COND); } - if (!more) { + if (!more || (limit && (numcargs >= limit))) { if (rep) { break; } @@ -909,12 +916,13 @@ static void compile_cmd( fakeargs++; } numargs++; + numcargs++; break; case 'e': /* code */ - if (more) { + if (more && (!limit || (numcargs < limit))) { more = compilearg(gs, VAL_CODE); } - if (!more) { + if (!more || (limit && (numcargs >= limit))) { if (rep) { break; } @@ -922,12 +930,13 @@ static void compile_cmd( fakeargs++; } numargs++; + numcargs++; break; case 'r': /* ident */ - if (more) { + if (more && (!limit || (numcargs < limit))) { more = compilearg(gs, VAL_IDENT); } - if (!more) { + if (!more || (limit && (numcargs >= limit))) { if (rep) { break; } @@ -935,9 +944,10 @@ static void compile_cmd( fakeargs++; } numargs++; + numcargs++; break; case '$': /* self */ - gs.gen_ident(id); + gs.gen_ident(self); numargs++; break; case 'N': /* number of arguments */ @@ -946,25 +956,27 @@ static void compile_cmd( break; case 'C': /* concatenated string */ comtype = BC_INST_COM_C; - if (more) { + if (more && (!limit || (numcargs < limit))) { for (;;) { more = compilearg(gs, VAL_ANY); - if (!more) { + if (!more || (limit && (numcargs >= limit))) { break; } numargs++; + numcargs++; } } goto compilecomv; case 'V': /* varargs */ comtype = BC_INST_COM_V; - if (more) { + if (more && (!limit || (numcargs < limit))) { for(;;) { more = compilearg(gs, VAL_ANY); - if (!more) { + if (!more || (limit && (numcargs >= limit))) { break; } numargs++; + numcargs++; } } goto compilecomv; @@ -972,7 +984,7 @@ static void compile_cmd( case '2': case '3': case '4': - if (more) { + if (more && (!limit || (numcargs < limit))) { int numrep = *it - '0' + 1; it -= numrep; rep = true; @@ -1191,33 +1203,39 @@ static void compilestatements(codegen_state &gs, int rettype, int brak) { BC_INST_ALIAS | (id->get_index() << 8) ); goto endstatement; - case ident_type::IVAR: - more = compilearg(gs, VAL_INT); - if (!more) { - gs.gen_int(); + case ident_type::IVAR: { + auto *hid = gs.ts.pstate->get_ident("//ivar"); + if (!hid || !hid->is_command()) { + throw error{gs.ts, "invalid ivar handler"}; } - gs.code.push_back( - BC_INST_IVAR1 | (id->get_index() << 8) + compile_cmd( + gs, static_cast(hid), + id, more, rettype, 1 ); goto endstatement; - case ident_type::FVAR: - more = compilearg(gs, VAL_FLOAT); - if (!more) { - gs.gen_float(); + } + case ident_type::FVAR: { + auto *hid = gs.ts.pstate->get_ident("//fvar"); + if (!hid || !hid->is_command()) { + throw error{gs.ts, "invalid fvar handler"}; } - gs.code.push_back( - BC_INST_FVAR1 | (id->get_index() << 8) + compile_cmd( + gs, static_cast(hid), + id, more, rettype, 1 ); goto endstatement; - case ident_type::SVAR: - more = compilearg(gs, VAL_STRING); - if (!more) { - gs.gen_str(); + } + case ident_type::SVAR: { + auto *hid = gs.ts.pstate->get_ident("//svar"); + if (!hid || !hid->is_command()) { + throw error{gs.ts, "invalid svar handler"}; } - gs.code.push_back( - BC_INST_SVAR1 | (id->get_index() << 8) + compile_cmd( + gs, static_cast(hid), + id, more, rettype, 1 ); goto endstatement; + } default: break; } @@ -1276,7 +1294,7 @@ noid: break; case ID_COMMAND: compile_cmd( - gs, static_cast(id), more, + gs, static_cast(id), id, more, rettype ); break; @@ -1319,54 +1337,39 @@ noid: case ID_OR: compile_and_or(gs, id, more, rettype); break; - case ID_IVAR: - more = compilearg(gs, VAL_INT); /* first arg */ - if (!more) { - gs.code.push_back(BC_INST_PRINT | (id->get_index() << 8)); - break; + case ID_IVAR: { + auto *hid = gs.ts.pstate->get_ident("//ivar"); + if (!hid || !hid->is_command()) { + throw error{gs.ts, "invalid ivar handler"}; } - if (id->get_flags() & IDENT_FLAG_HEX) { - more = compilearg(gs, VAL_INT); /* second arg */ - } else { - more = false; - } - if (!more) { - gs.code.push_back(BC_INST_IVAR1 | (id->get_index() << 8)); - break; - } - more = compilearg(gs, VAL_INT); /* third arg */ - if (!more) { - gs.code.push_back(BC_INST_IVAR2 | (id->get_index() << 8)); - break; - } - gs.code.push_back(BC_INST_IVAR3 | (id->get_index() << 8)); + compile_cmd( + gs, static_cast(hid), + id, more, rettype + ); break; - case ID_FVAR: - more = compilearg(gs, VAL_FLOAT); - if (!more) { - gs.code.push_back(BC_INST_PRINT | (id->get_index() << 8)); - } else { - gs.code.push_back(BC_INST_FVAR1 | (id->get_index() << 8)); + } + case ID_FVAR: { + auto *hid = gs.ts.pstate->get_ident("//fvar"); + if (!hid || !hid->is_command()) { + throw error{gs.ts, "invalid fvar handler"}; } + compile_cmd( + gs, static_cast(hid), + id, more, rettype + ); break; - case ID_SVAR: - more = compilearg(gs, VAL_STRING); - if (!more) { - gs.code.push_back(BC_INST_PRINT | (id->get_index() << 8)); - } else { - std::uint32_t numargs = 0; - do { - ++numargs; - more = compilearg(gs, VAL_ANY); - } while (more); - if (numargs > 1) { - gs.code.push_back( - BC_INST_CONC | BC_RET_STRING | (numargs << 8) - ); - } - gs.code.push_back(BC_INST_SVAR1 | (id->get_index() << 8)); + } + case ID_SVAR: { + auto *hid = gs.ts.pstate->get_ident("//svar"); + if (!hid || !hid->is_command()) { + throw error{gs.ts, "invalid svar handler"}; } + compile_cmd( + gs, static_cast(hid), + id, more, rettype + ); break; + } } } } diff --git a/src/cs_ident.cc b/src/cs_ident.cc index 3eb0508..7c13b8e 100644 --- a/src/cs_ident.cc +++ b/src/cs_ident.cc @@ -305,14 +305,6 @@ LIBCUBESCRIPT_EXPORT string_var const *ident::get_svar() const { return static_cast(this); } -LIBCUBESCRIPT_EXPORT integer_type integer_var::get_val_min() const { - return static_cast(this)->p_minval; -} - -LIBCUBESCRIPT_EXPORT integer_type integer_var::get_val_max() const { - return static_cast(this)->p_maxval; -} - LIBCUBESCRIPT_EXPORT integer_type integer_var::get_value() const { return static_cast(this)->p_storage; } @@ -321,14 +313,6 @@ LIBCUBESCRIPT_EXPORT void integer_var::set_value(integer_type val) { static_cast(this)->p_storage = val; } -LIBCUBESCRIPT_EXPORT float_type float_var::get_val_min() const { - return static_cast(this)->p_minval; -} - -LIBCUBESCRIPT_EXPORT float_type float_var::get_val_max() const { - return static_cast(this)->p_maxval; -} - LIBCUBESCRIPT_EXPORT float_type float_var::get_value() const { return static_cast(this)->p_storage; } diff --git a/src/cs_state.cc b/src/cs_state.cc index 1d3f266..f8aa60f 100644 --- a/src/cs_state.cc +++ b/src/cs_state.cc @@ -14,7 +14,6 @@ internal_state::internal_state(alloc_func af, void *data): allocf{af}, aptr{data}, idents{allocator_type{this}}, identmap{allocator_type{this}}, - varprintf{}, strman{create(this)}, empty{bcode_init_empty(this)} {} @@ -220,24 +219,6 @@ LIBCUBESCRIPT_EXPORT hook_func &state::get_call_hook() { return p_tstate->get_hook(); } -LIBCUBESCRIPT_EXPORT var_print_func state::set_var_printer( - var_print_func func -) { - auto fn = std::move(p_tstate->istate->varprintf); - p_tstate->istate->varprintf = std::move(func); - return fn; -} - -LIBCUBESCRIPT_EXPORT var_print_func const &state::get_var_printer() const { - return p_tstate->istate->varprintf; -} - -LIBCUBESCRIPT_EXPORT void state::print_var(global_var const &v) const { - if (p_tstate->istate->varprintf) { - p_tstate->istate->varprintf(*this, v); - } -} - LIBCUBESCRIPT_EXPORT void *state::alloc(void *ptr, size_t os, size_t ns) { return p_tstate->istate->alloc(ptr, os, ns); } @@ -340,17 +321,6 @@ LIBCUBESCRIPT_EXPORT string_var *state::new_svar( return sv; } -LIBCUBESCRIPT_EXPORT void state::reset_var(std::string_view name) { - ident *id = get_ident(name); - if (!id) { - throw error{*this, "variable %s does not exist", name.data()}; - } - if (id->get_flags() & IDENT_FLAG_READONLY) { - throw error{*this, "variable %s is read only", name.data()}; - } - clear_override(*id); -} - LIBCUBESCRIPT_EXPORT void state::touch_var(std::string_view name) { ident *id = get_ident(name); if (id && id->is_var()) { @@ -375,14 +345,12 @@ LIBCUBESCRIPT_EXPORT void state::set_alias( return; } case ident_type::IVAR: - set_var_int_checked(static_cast(id), v.get_int()); - break; case ident_type::FVAR: - set_var_float_checked(static_cast(id), v.get_float()); - break; - case ident_type::SVAR: - set_var_str_checked(static_cast(id), v.get_str()); + case ident_type::SVAR: { + any_value ret{*this}; + run(id, std::span{&v, 1}, ret); break; + } default: throw error{ *this, "cannot redefine builtin %s with an alias", @@ -454,194 +422,6 @@ LIBCUBESCRIPT_EXPORT command *state::new_command( return cmd; } -LIBCUBESCRIPT_EXPORT void state::clear_override(ident &id) { - if (!(id.get_flags() & IDENT_FLAG_OVERRIDDEN)) { - return; - } - switch (id.get_type()) { - case ident_type::ALIAS: { - auto &ast = p_tstate->get_astack(static_cast(&id)); - ast.node->val_s.set_str(""); - ast.node->code = bcode_ref{}; - break; - } - case ident_type::IVAR: { - ivar_impl &iv = static_cast(id); - iv.set_value(iv.p_overrideval); - iv.changed(*this); - break; - } - case ident_type::FVAR: { - fvar_impl &fv = static_cast(id); - fv.set_value(fv.p_overrideval); - fv.changed(*this); - break; - } - case ident_type::SVAR: { - svar_impl &sv = static_cast(id); - sv.set_value(sv.p_overrideval); - sv.changed(*this); - break; - } - default: - break; - } - id.p_impl->p_flags &= ~IDENT_FLAG_OVERRIDDEN; -} - -LIBCUBESCRIPT_EXPORT void state::clear_overrides() { - for (auto &p: p_tstate->istate->idents) { - clear_override(*(p.second)); - } -} - -template -inline void override_var(state &cs, global_var *v, int &vflags, SF sf) { - if ((cs.identflags & IDENT_FLAG_OVERRIDDEN) || (vflags & IDENT_FLAG_OVERRIDE)) { - if (vflags & IDENT_FLAG_PERSIST) { - throw error{ - cs, "cannot override persistent variable '%s'", - v->get_name().data() - }; - } - if (!(vflags & IDENT_FLAG_OVERRIDDEN)) { - sf(); - vflags |= IDENT_FLAG_OVERRIDDEN; - } - } else { - if (vflags & IDENT_FLAG_OVERRIDDEN) { - vflags &= ~IDENT_FLAG_OVERRIDDEN; - } - } -} - -LIBCUBESCRIPT_EXPORT void state::set_var_int( - std::string_view name, integer_type v, bool dofunc, bool doclamp -) { - ident *id = get_ident(name); - if (!id || id->is_ivar()) { - return; - } - ivar_impl *iv = static_cast(id); - override_var( - *this, iv, iv->p_flags, - [&iv]() { iv->p_overrideval = iv->get_value(); } - ); - if (doclamp) { - iv->set_value(std::clamp(v, iv->get_val_min(), iv->get_val_max())); - } else { - iv->set_value(v); - } - if (dofunc) { - iv->changed(*this); - } -} - -LIBCUBESCRIPT_EXPORT void state::set_var_float( - std::string_view name, float_type v, bool dofunc, bool doclamp -) { - ident *id = get_ident(name); - if (!id || id->is_fvar()) { - return; - } - fvar_impl *fv = static_cast(id); - override_var( - *this, fv, fv->p_flags, - [&fv]() { fv->p_overrideval = fv->get_value(); } - ); - if (doclamp) { - fv->set_value(std::clamp(v, fv->get_val_min(), fv->get_val_max())); - } else { - fv->set_value(v); - } - if (dofunc) { - fv->changed(*this); - } -} - -LIBCUBESCRIPT_EXPORT void state::set_var_str( - std::string_view name, std::string_view v, bool dofunc -) { - ident *id = get_ident(name); - if (!id || id->is_svar()) { - return; - } - svar_impl *sv = static_cast(id); - override_var( - *this, sv, sv->p_flags, - [&sv]() { sv->p_overrideval = sv->get_value(); } - ); - sv->set_value(string_ref{p_tstate->istate, v}); - if (dofunc) { - sv->changed(*this); - } -} - -LIBCUBESCRIPT_EXPORT std::optional -state::get_var_int(std::string_view name) { - ident *id = get_ident(name); - if (!id || id->is_ivar()) { - return std::nullopt; - } - return static_cast(id)->get_value(); -} - -LIBCUBESCRIPT_EXPORT std::optional -state::get_var_float(std::string_view name) { - ident *id = get_ident(name); - if (!id || id->is_fvar()) { - return std::nullopt; - } - return static_cast(id)->get_value(); -} - -LIBCUBESCRIPT_EXPORT std::optional -state::get_var_str(std::string_view name) { - ident *id = get_ident(name); - if (!id || id->is_svar()) { - return std::nullopt; - } - return string_ref{ - p_tstate->istate, static_cast(id)->get_value() - }; -} - -LIBCUBESCRIPT_EXPORT std::optional -state::get_var_min_int(std::string_view name) { - ident *id = get_ident(name); - if (!id || id->is_ivar()) { - return std::nullopt; - } - return static_cast(id)->get_val_min(); -} - -LIBCUBESCRIPT_EXPORT std::optional -state::get_var_max_int(std::string_view name) { - ident *id = get_ident(name); - if (!id || id->is_ivar()) { - return std::nullopt; - } - return static_cast(id)->get_val_max(); -} - -LIBCUBESCRIPT_EXPORT std::optional -state::get_var_min_float(std::string_view name) { - ident *id = get_ident(name); - if (!id || id->is_fvar()) { - return std::nullopt; - } - return static_cast(id)->get_val_min(); -} - -LIBCUBESCRIPT_EXPORT std::optional -state::get_var_max_float(std::string_view name) { - ident *id = get_ident(name); - if (!id || id->is_fvar()) { - return std::nullopt; - } - return static_cast(id)->get_val_max(); -} - LIBCUBESCRIPT_EXPORT std::optional state::get_alias_val(std::string_view name) { alias *a = get_alias(name); @@ -654,114 +434,6 @@ state::get_alias_val(std::string_view name) { return p_tstate->get_astack(a).node->val_s.get_str(); } -integer_type clamp_var(state &cs, integer_var *iv, integer_type v) { - if (v < iv->get_val_min()) { - v = iv->get_val_min(); - } else if (v > iv->get_val_max()) { - v = iv->get_val_max(); - } else { - return v; - } - throw error{ - cs, - (iv->get_flags() & IDENT_FLAG_HEX) - ? ( - (iv->get_val_min() <= 255) - ? "valid range for '%s' is %d..0x%X" - : "valid range for '%s' is 0x%X..0x%X" - ) - : "valid range for '%s' is %d..%d", - iv->get_name().data(), iv->get_val_min(), iv->get_val_max() - }; -} - -LIBCUBESCRIPT_EXPORT void state::set_var_int_checked( - integer_var *iv, integer_type v -) { - if (iv->get_flags() & IDENT_FLAG_READONLY) { - throw error{ - *this, "variable '%s' is read only", iv->get_name().data() - }; - } - ivar_impl *ivp = static_cast(iv); - override_var( - *this, iv, ivp->p_flags, - [&ivp]() { ivp->p_overrideval = ivp->p_storage; } - ); - if ((v < iv->get_val_min()) || (v > iv->get_val_max())) { - v = clamp_var(*this, iv, v); - } - iv->set_value(v); - ivp->changed(*this); -} - -LIBCUBESCRIPT_EXPORT void state::set_var_int_checked( - integer_var *iv, std::span args -) { - integer_type v = args[0].force_int(); - if ((iv->get_flags() & IDENT_FLAG_HEX) && (args.size() > 1)) { - v = (v << 16) | (args[1].force_int() << 8); - if (args.size() > 2) { - v |= args[2].force_int(); - } - } - set_var_int_checked(iv, v); -} - -float_type clamp_fvar(state &cs, float_var *fv, float_type v) { - if (v < fv->get_val_min()) { - v = fv->get_val_min(); - } else if (v > fv->get_val_max()) { - v = fv->get_val_max(); - } else { - return v; - } - any_value vmin{cs}, vmax{cs}; - vmin.set_float(fv->get_val_min()); - vmax.set_float(fv->get_val_max()); - throw error{ - cs, "valid range for '%s' is %s..%s", fv->get_name().data(), - vmin.force_str(), vmax.force_str() - }; -} - -LIBCUBESCRIPT_EXPORT void state::set_var_float_checked( - float_var *fv, float_type v -) { - if (fv->get_flags() & IDENT_FLAG_READONLY) { - throw error{ - *this, "variable '%s' is read only", fv->get_name().data() - }; - } - fvar_impl *fvp = static_cast(fv); - override_var( - *this, fv, fvp->p_flags, - [&fvp]() { fvp->p_overrideval = fvp->p_storage; } - ); - if ((v < fv->get_val_min()) || (v > fv->get_val_max())) { - v = clamp_fvar(*this, fv, v); - } - fv->set_value(v); - fvp->changed(*this); -} - -LIBCUBESCRIPT_EXPORT void state::set_var_str_checked( - string_var *sv, std::string_view v -) { - if (sv->get_flags() & IDENT_FLAG_READONLY) { - throw error{ - *this, "variable '%s' is read only", sv->get_name().data() - }; - } - svar_impl *svp = static_cast(sv); - override_var( - *this, sv, svp->p_flags, - [&svp]() { svp->p_overrideval = svp->p_storage; } - ); - sv->set_value(string_ref{p_tstate->istate, v}); - svp->changed(*this); -} - LIBCUBESCRIPT_EXPORT void state::init_libs(int libs) { if (libs & LIB_MATH) { init_lib_math(*this); @@ -829,41 +501,76 @@ LIBCUBESCRIPT_EXPORT void state::run( targs[osz + i] = args[i]; } exec_command( - *p_tstate, cimpl, &targs[osz], ret, nargs, false + *p_tstate, cimpl, id, &targs[osz], ret, nargs, false ); } else { exec_command( - *p_tstate, cimpl, &args[0], ret, nargs, false + *p_tstate, cimpl, id, &args[0], ret, nargs, false ); } nargs = 0; break; } - case ident_type::IVAR: - if (args.empty()) { - print_var(*static_cast(id)); - } else { - set_var_int_checked(static_cast(id), args); + case ident_type::IVAR: { + auto *hid = get_ident("//ivar"); + if (!hid || !hid->is_command()) { + throw error{*p_tstate, "invalid ivar handler"}; } - break; - case ident_type::FVAR: - if (args.empty()) { - print_var(*static_cast(id)); - } else { - set_var_float_checked( - static_cast(id), args[0].force_float() - ); + auto *cimp = static_cast(hid); + auto &targs = p_tstate->vmstack; + auto osz = targs.size(); + auto anargs = std::size_t(cimp->get_num_args()); + targs.resize( + osz + std::max(args.size(), anargs + 1), any_value{*this} + ); + for (std::size_t i = 0; i < nargs; ++i) { + targs[osz + i + 1] = args[i]; } + exec_command( + *p_tstate, cimp, id, &targs[osz], ret, nargs + 1, false + ); break; - case ident_type::SVAR: - if (args.empty()) { - print_var(*static_cast(id)); - } else { - set_var_str_checked( - static_cast(id), args[0].force_str() - ); + } + case ident_type::FVAR: { + auto *hid = get_ident("//fvar"); + if (!hid || !hid->is_command()) { + throw error{*p_tstate, "invalid fvar handler"}; } + auto *cimp = static_cast(hid); + auto &targs = p_tstate->vmstack; + auto osz = targs.size(); + auto anargs = std::size_t(cimp->get_num_args()); + targs.resize( + osz + std::max(args.size(), anargs + 1), any_value{*this} + ); + for (std::size_t i = 0; i < nargs; ++i) { + targs[osz + i + 1] = args[i]; + } + exec_command( + *p_tstate, cimp, id, &targs[osz], ret, nargs + 1, false + ); break; + } + case ident_type::SVAR: { + auto *hid = get_ident("//svar"); + if (!hid || !hid->is_command()) { + throw error{*p_tstate, "invalid svar handler"}; + } + auto *cimp = static_cast(hid); + auto &targs = p_tstate->vmstack; + auto osz = targs.size(); + auto anargs = std::size_t(cimp->get_num_args()); + targs.resize( + osz + std::max(args.size(), anargs + 1), any_value{*this} + ); + for (std::size_t i = 0; i < nargs; ++i) { + targs[osz + i + 1] = args[i]; + } + exec_command( + *p_tstate, cimp, id, &targs[osz], ret, nargs + 1, false + ); + break; + } case ident_type::ALIAS: { alias *a = static_cast(id); if ( diff --git a/src/cs_state.hh b/src/cs_state.hh index 0a52695..536dfd1 100644 --- a/src/cs_state.hh +++ b/src/cs_state.hh @@ -48,7 +48,6 @@ struct internal_state { > idents; std::vector> identmap; - var_print_func varprintf; string_pool *strman; empty_block *empty; diff --git a/src/cs_std.hh b/src/cs_std.hh index 1bfd124..4c91df8 100644 --- a/src/cs_std.hh +++ b/src/cs_std.hh @@ -37,6 +37,10 @@ struct valbuf { buf.insert(buf.end(), beg, end); } + void insert(std::size_t i, T const &it) { + buf.insert(buf.begin() + i, it); + } + template reference emplace_back(A &&...args) { return buf.emplace_back(std::forward(args)...); diff --git a/src/cs_vm.cc b/src/cs_vm.cc index 1560e92..67b58a5 100644 --- a/src/cs_vm.cc +++ b/src/cs_vm.cc @@ -44,8 +44,8 @@ static inline void force_arg(any_value &v, int type) { } void exec_command( - thread_state &ts, command_impl *id, any_value *args, any_value &res, - std::size_t nargs, bool lookup + thread_state &ts, command_impl *id, ident *self, any_value *args, + any_value &res, std::size_t nargs, bool lookup ) { int i = -1, fakeargs = 0, numargs = int(nargs); bool rep = false; @@ -159,7 +159,7 @@ void exec_command( break; case '$': i += 1; - args[i].set_ident(id); + args[i].set_ident(self); break; case 'N': i += 1; @@ -337,7 +337,7 @@ static inline int get_lookupu_type( /* pad with as many empty values as we need */ args.resize(osz + cimpl->get_num_args(), any_value{*ts.pstate}); arg.set_none(); - exec_command(ts, cimpl, &args[osz], arg, 0, true); + exec_command(ts, cimpl, cimpl, &args[osz], arg, 0, true); force_arg(arg, op & BC_INST_RET_MASK); return -2; /* ignore */ } @@ -530,10 +530,6 @@ std::uint32_t *vm_exec( ); continue; - case BC_INST_PRINT: - cs.print_var(*static_cast(ts.istate->identmap[op >> 8])); - continue; - case BC_INST_LOCAL: { std::size_t numlocals = op >> 8; std::size_t offset = args.size() - numlocals; @@ -981,15 +977,6 @@ std::uint32_t *vm_exec( )->get_value() )); continue; - case BC_INST_SVAR1: { - auto v = std::move(args.back()); - args.pop_back(); - cs.set_var_str_checked( - static_cast(ts.istate->identmap[op >> 8]), - v.get_str() - ); - continue; - } case BC_INST_IVAR | BC_RET_INT: case BC_INST_IVAR | BC_RET_NULL: @@ -1012,34 +999,6 @@ std::uint32_t *vm_exec( )->get_value() )); continue; - case BC_INST_IVAR1: { - auto v = std::move(args.back()); - args.pop_back(); - cs.set_var_int_checked( - static_cast(ts.istate->identmap[op >> 8]), - v.get_int() - ); - continue; - } - case BC_INST_IVAR2: { - auto v1 = std::move(args.back()); args.pop_back(); - auto v2 = std::move(args.back()); args.pop_back(); - cs.set_var_int_checked( - static_cast(ts.istate->identmap[op >> 8]), - (v2.get_int() << 16) | (v1.get_int() << 8) - ); - continue; - } - case BC_INST_IVAR3: { - auto v1 = std::move(args.back()); args.pop_back(); - auto v2 = std::move(args.back()); args.pop_back(); - auto v3 = std::move(args.back()); args.pop_back(); - cs.set_var_int_checked( - static_cast(ts.istate->identmap[op >> 8]), - (v3.get_int() << 16) | (v2.get_int() << 8) | (v1.get_int()) - ); - continue; - } case BC_INST_FVAR | BC_RET_FLOAT: case BC_INST_FVAR | BC_RET_NULL: @@ -1060,15 +1019,6 @@ std::uint32_t *vm_exec( ts.istate->identmap[op >> 8] )->get_value())); continue; - case BC_INST_FVAR1: { - auto &v = args.back(); - cs.set_var_float_checked( - static_cast(ts.istate->identmap[op >> 8]), - v.get_float() - ); - args.pop_back(); - continue; - } case BC_INST_ALIAS: { auto *a = static_cast( @@ -1159,14 +1109,18 @@ noid: continue; } /* fallthrough */ - case ID_COMMAND: + case ID_COMMAND: { + auto *cimp = static_cast(id); + args.resize(offset + std::max( + std::size_t(cimp->get_num_args()), callargs + ), any_value{cs}); exec_command( - ts, static_cast(id), - &args[offset], result, callargs + ts, cimp, cimp, &args[offset], result, callargs ); force_arg(result, op & BC_INST_RET_MASK); args.resize(offset - 1, any_value{cs}); continue; + } case ID_LOCAL: { std::size_t idstsz = ts.idstack.size(); for (size_t j = 0; j < size_t(callargs); ++j) { @@ -1190,42 +1144,60 @@ noid: cleanup(); return code; } - case ID_IVAR: - if (callargs <= 0) { - cs.print_var(*static_cast(id)); - } else { - cs.set_var_int_checked( - static_cast(id), - std::span{&args[offset], std::size_t(callargs)} - ); + case ID_IVAR: { + auto *hid = cs.get_ident("//ivar"); + if (!hid || !hid->is_command()) { + throw error{ts, "invalid ivar handler"}; } - args.resize(offset - 1, any_value{cs}); + auto *cimp = static_cast(hid); + /* the $ argument */ + args.insert(offset, any_value{cs}); + args.resize(offset + std::max( + std::size_t(cimp->get_num_args()), callargs + ), any_value{cs}); + exec_command( + ts, cimp, id, &args[offset], result, callargs + ); force_arg(result, op & BC_INST_RET_MASK); + args.resize(offset - 1, any_value{cs}); continue; - case ID_FVAR: - if (callargs <= 0) { - cs.print_var(*static_cast(id)); - } else { - cs.set_var_float_checked( - static_cast(id), - args[offset].force_float() - ); + } + case ID_FVAR: { + auto *hid = cs.get_ident("//fvar"); + if (!hid || !hid->is_command()) { + throw error{ts, "invalid fvar handler"}; } - args.resize(offset - 1, any_value{cs}); + auto *cimp = static_cast(hid); + /* the $ argument */ + args.insert(offset, any_value{cs}); + args.resize(offset + std::max( + std::size_t(cimp->get_num_args()), callargs + ), any_value{cs}); + exec_command( + ts, cimp, id, &args[offset], result, callargs + ); force_arg(result, op & BC_INST_RET_MASK); + args.resize(offset - 1, any_value{cs}); continue; - case ID_SVAR: - if (callargs <= 0) { - cs.print_var(*static_cast(id)); - } else { - cs.set_var_str_checked( - static_cast(id), - args[offset].force_str() - ); + } + case ID_SVAR: { + auto *hid = cs.get_ident("//svar"); + if (!hid || !hid->is_command()) { + throw error{ts, "invalid svar handler"}; } - args.resize(offset - 1, any_value{cs}); + auto *cimp = static_cast(hid); + /* the $ argument */ + args.insert(offset, any_value{cs}); + args.resize(offset + std::max( + std::size_t(cimp->get_num_args()), callargs + ), any_value{cs}); + exec_command( + ts, cimp, id, &args[offset], result, callargs + ); force_arg(result, op & BC_INST_RET_MASK); + args.resize(offset - 1, any_value{cs}); continue; + } case ID_ALIAS: { alias *a = static_cast(id); if ( diff --git a/src/cs_vm.hh b/src/cs_vm.hh index 8e8f9e1..4a1edfb 100644 --- a/src/cs_vm.hh +++ b/src/cs_vm.hh @@ -95,8 +95,8 @@ static void call_with_args(thread_state &ts, F body) { } void exec_command( - thread_state &ts, command_impl *id, any_value *args, any_value &res, - std::size_t nargs, bool lookup = false + thread_state &ts, command_impl *id, ident *self, any_value *args, + any_value &res, std::size_t nargs, bool lookup = false ); bool exec_alias( diff --git a/src/lib_base.cc b/src/lib_base.cc index b199550..86a7729 100644 --- a/src/lib_base.cc +++ b/src/lib_base.cc @@ -312,27 +312,10 @@ end: } }); - gcs.new_command("resetvar", "s", [](auto &cs, auto args, auto &) { - cs.reset_var(args[0].get_str()); - }); - gcs.new_command("alias", "st", [](auto &cs, auto args, auto &) { cs.set_alias(args[0].get_str(), args[1]); }); - gcs.new_command("getvarmin", "s", [](auto &cs, auto args, auto &res) { - res.set_int(cs.get_var_min_int(args[0].get_str()).value_or(0)); - }); - gcs.new_command("getvarmax", "s", [](auto &cs, auto args, auto &res) { - res.set_int(cs.get_var_max_int(args[0].get_str()).value_or(0)); - }); - gcs.new_command("getfvarmin", "s", [](auto &cs, auto args, auto &res) { - res.set_float(cs.get_var_min_float(args[0].get_str()).value_or(0.0f)); - }); - gcs.new_command("getfvarmax", "s", [](auto &cs, auto args, auto &res) { - res.set_float(cs.get_var_max_float(args[0].get_str()).value_or(0.0f)); - }); - gcs.new_command("identexists", "s", [](auto &cs, auto args, auto &res) { res.set_int(cs.have_ident(args[0].get_str())); }); diff --git a/tools/repl.cc b/tools/repl.cc index 58124d5..47c8704 100644 --- a/tools/repl.cc +++ b/tools/repl.cc @@ -199,50 +199,6 @@ static void do_sigint(int n) { }); } -/* an example of what var printer would look like in real usage */ -static void repl_print_var(cs::state const &, cs::global_var const &var) { - switch (var.get_type()) { - case cs::ident_type::IVAR: { - auto &iv = static_cast(var); - auto val = iv.get_value(); - if (!(iv.get_flags() & cs::IDENT_FLAG_HEX) || (val < 0)) { - std::printf("%s = %d\n", iv.get_name().data(), val); - } else if (iv.get_val_max() == 0xFFFFFF) { - std::printf( - "%s = 0x%.6X (%d, %d, %d)\n", - iv.get_name().data(), - val, (val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF - ); - } else { - std::printf("%s = 0x%X\n", iv.get_name().data(), val); - } - break; - } - case cs::ident_type::FVAR: { - auto &fv = static_cast(var); - auto val = fv.get_value(); - if (std::floor(val) == val) { - std::printf("%s = %.1f", fv.get_name().data(), val); - } else { - std::printf("%s = %.7g", fv.get_name().data(), val); - } - break; - } - case cs::ident_type::SVAR: { - auto &sv = static_cast(var); - auto val = std::string_view{sv.get_value()}; - if (val.find('"') == val.npos) { - std::printf("%s = \"%s\"", sv.get_name().data(), val.data()); - } else { - std::printf("%s = [%s]", sv.get_name().data(), val.data()); - } - break; - } - default: - break; - } -} - static bool do_run_file( cs::state &cs, std::string_view fname, cs::any_value &ret ) { @@ -362,9 +318,66 @@ static void do_tty(cs::state &cs) { int main(int argc, char **argv) { cs::state gcs; - gcs.set_var_printer(repl_print_var); gcs.init_libs(); + gcs.new_command("//ivar", "$iiiN", [](auto &, auto args, auto &) { + auto *iv = args[0].get_ident()->get_ivar(); + auto nargs = args[4].get_int(); + if (nargs <= 1) { + auto val = iv->get_value(); + if ((val >= 0) && (val < 0xFFFFFF)) { + std::printf( + "%s = %d (0x%.6X: %d, %d, %d)\n", + iv->get_name().data(), val, val, + (val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF + ); + } else { + std::printf("%s = %d\n", iv->get_name().data(), val); + } + } else if (nargs == 2) { + iv->set_value(args[1].get_int()); + } else if (nargs == 3) { + iv->set_value( + (args[1].get_int() << 8) | (args[2].get_int() << 16) + ); + } else { + iv->set_value( + args[1].get_int() | (args[2].get_int() << 8) | + (args[3].get_int() << 16) + ); + } + }); + + gcs.new_command("//fvar", "$fN", [](auto &, auto args, auto &) { + auto *fv = args[0].get_ident()->get_fvar(); + auto nargs = args[2].get_int(); + if (nargs <= 1) { + auto val = fv->get_value(); + if (std::floor(val) == val) { + std::printf("%s = %.1f\n", fv->get_name().data(), val); + } else { + std::printf("%s = %.7g\n", fv->get_name().data(), val); + } + } else { + fv->set_value(args[1].get_float()); + } + }); + + gcs.new_command("//svar", "$sN", [](auto &, auto args, auto &) { + auto sv = args[0].get_ident()->get_svar(); + auto nargs = args[2].get_int(); + if (nargs <= 1) { + auto val = std::string_view{sv->get_value()}; + if (val.find('"') == val.npos) { + std::printf("%s = \"%s\"\n", sv->get_name().data(), val.data()); + } else { + std::printf("%s = [%s]\n", sv->get_name().data(), val.data()); + } + } else { + sv->set_value(args[1].get_str()); + } + }); + gcs.new_command("exec", "s", [](auto &css, auto args, auto &) { auto file = args[0].get_str(); cs::any_value val{css};