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};