#include #include "cs_vm.hh" #include "cs_std.hh" #include namespace cscript { static std::string_view intstr(cs_int v, cs_charbuf &buf) { buf.reserve(32); int n = snprintf(buf.data(), 32, CS_INT_FORMAT, v); if (n > 32) { buf.reserve(n + 1); int nn = snprintf(buf.data(), n + 1, CS_INT_FORMAT, v); if ((nn > n) || (nn <= 0)) { n = -1; } else { n = nn; } } if (n <= 0) { throw cs_internal_error{"format error"}; } return std::string_view{buf.data(), std::size_t(n)}; } static std::string_view floatstr(cs_float v, cs_charbuf &buf) { buf.reserve(32); int n; if (v == std::floor(v)) { n = snprintf(buf.data(), 32, CS_ROUND_FLOAT_FORMAT, v); } else { n = snprintf(buf.data(), 32, CS_FLOAT_FORMAT, v); } if (n > 32) { buf.reserve(n + 1); int nn; if (v == std::floor(v)) { nn = snprintf(buf.data(), n + 1, CS_ROUND_FLOAT_FORMAT, v); } else { nn = snprintf(buf.data(), n + 1, CS_FLOAT_FORMAT, v); } if ((nn > n) || (nn <= 0)) { n = -1; } else { n = nn; } } if (n <= 0) { throw cs_internal_error{"format error"}; } return std::string_view{buf.data(), std::size_t(n)}; } template struct stor_priv_t { cs_shared_state *state; T val; }; template static inline T &csv_get(U &stor) { /* ugly, but internal and unlikely to cause bugs */ return const_cast(reinterpret_cast const &>(stor).val); } template static inline void csv_cleanup(cs_value_type tv, T &stor) { switch (tv) { case cs_value_type::STRING: reinterpret_cast(&stor)->~cs_strref(); break; case cs_value_type::CODE: { bcode_unref(csv_get(stor)); break; } default: break; } } cs_value::cs_value(cs_state &st): cs_value(*st.p_state) {} cs_value::cs_value(cs_shared_state &st): p_stor(), p_type(cs_value_type::NONE) { reinterpret_cast *>(&p_stor)->state = &st; } cs_value::~cs_value() { csv_cleanup(p_type, p_stor); } cs_value::cs_value(cs_value const &v): cs_value(*v.state()) { *this = v; } cs_value::cs_value(cs_value &&v): cs_value(*v.state()) { *this = std::move(v); } cs_value &cs_value::operator=(cs_value const &v) { csv_cleanup(p_type, p_stor); p_type = cs_value_type::NONE; switch (v.get_type()) { case cs_value_type::INT: case cs_value_type::FLOAT: case cs_value_type::IDENT: p_type = v.p_type; p_stor = v.p_stor; break; case cs_value_type::STRING: p_type = cs_value_type::STRING; new (&p_stor) cs_strref{ *reinterpret_cast(&v.p_stor) }; break; case cs_value_type::CODE: set_code(v.get_code()); break; default: break; } return *this; } cs_value &cs_value::operator=(cs_value &&v) { *this = v; v.set_none(); return *this; } cs_value_type cs_value::get_type() const { return p_type; } void cs_value::set_int(cs_int val) { csv_cleanup(p_type, p_stor); p_type = cs_value_type::INT; csv_get(p_stor) = val; } void cs_value::set_float(cs_float val) { csv_cleanup(p_type, p_stor); p_type = cs_value_type::FLOAT; csv_get(p_stor) = val; } void cs_value::set_str(std::string_view val) { csv_cleanup(p_type, p_stor); new (&p_stor) cs_strref{state(), val}; p_type = cs_value_type::STRING; } void cs_value::set_str(cs_strref const &val) { csv_cleanup(p_type, p_stor); new (&p_stor) cs_strref{val}; p_type = cs_value_type::STRING; } void cs_value::set_none() { csv_cleanup(p_type, p_stor); p_type = cs_value_type::NONE; } void cs_value::set_code(cs_bcode *val) { csv_cleanup(p_type, p_stor); p_type = cs_value_type::CODE; bcode_ref(val->get_raw()); csv_get(p_stor) = val; } void cs_value::set_ident(cs_ident *val) { csv_cleanup(p_type, p_stor); p_type = cs_value_type::IDENT; csv_get(p_stor) = val; } void cs_value::force_none() { if (get_type() == cs_value_type::NONE) { return; } set_none(); } cs_float cs_value::force_float() { cs_float rf = 0.0f; switch (get_type()) { case cs_value_type::INT: rf = csv_get(p_stor); break; case cs_value_type::STRING: rf = parse_float( *reinterpret_cast(&p_stor) ); break; case cs_value_type::FLOAT: return csv_get(p_stor); default: break; } set_float(rf); return rf; } cs_int cs_value::force_int() { cs_int ri = 0; switch (get_type()) { case cs_value_type::FLOAT: ri = csv_get(p_stor); break; case cs_value_type::STRING: ri = parse_int( *reinterpret_cast(&p_stor) ); break; case cs_value_type::INT: return csv_get(p_stor); default: break; } set_int(ri); return ri; } std::string_view cs_value::force_str() { cs_charbuf rs{state()}; std::string_view str; switch (get_type()) { case cs_value_type::FLOAT: str = floatstr(csv_get(p_stor), rs); break; case cs_value_type::INT: str = intstr(csv_get(p_stor), rs); break; case cs_value_type::STRING: return *reinterpret_cast(&p_stor); default: str = rs.str(); break; } set_str(str); return std::string_view(*reinterpret_cast(&p_stor)); } cs_int cs_value::get_int() const { switch (get_type()) { case cs_value_type::FLOAT: return cs_int(csv_get(p_stor)); case cs_value_type::INT: return csv_get(p_stor); case cs_value_type::STRING: return parse_int( *reinterpret_cast(&p_stor) ); default: break; } return 0; } cs_float cs_value::get_float() const { switch (get_type()) { case cs_value_type::FLOAT: return csv_get(p_stor); case cs_value_type::INT: return cs_float(csv_get(p_stor)); case cs_value_type::STRING: return parse_float( *reinterpret_cast(&p_stor) ); default: break; } return 0.0f; } cs_bcode *cs_value::get_code() const { if (get_type() != cs_value_type::CODE) { return nullptr; } return csv_get(p_stor); } cs_ident *cs_value::get_ident() const { if (get_type() != cs_value_type::IDENT) { return nullptr; } return csv_get(p_stor); } cs_strref cs_value::get_str() const { switch (get_type()) { case cs_value_type::STRING: return *reinterpret_cast(&p_stor); case cs_value_type::INT: { cs_charbuf rs{state()}; return cs_strref{state(), intstr(csv_get(p_stor), rs)}; } case cs_value_type::FLOAT: { cs_charbuf rs{state()}; return cs_strref{state(), floatstr(csv_get(p_stor), rs)}; } default: break; } return cs_strref{state(), ""}; } void cs_value::get_val(cs_value &r) const { switch (get_type()) { case cs_value_type::STRING: r = *this; break; case cs_value_type::INT: r.set_int(csv_get(p_stor)); break; case cs_value_type::FLOAT: r.set_float(csv_get(p_stor)); break; default: r.set_none(); break; } } LIBCUBESCRIPT_EXPORT bool cs_code_is_empty(cs_bcode *code) { if (!code) { return true; } return (*code->get_raw() & CS_CODE_OP_MASK) == CS_CODE_EXIT; } bool cs_value::code_is_empty() const { if (get_type() != cs_value_type::CODE) { return true; } return cscript::cs_code_is_empty(csv_get(p_stor)); } static inline bool cs_get_bool(std::string_view s) { if (s.empty()) { return false; } std::string_view end = s; cs_int ival = parse_int(end, &end); if (end.empty()) { return !!ival; } end = s; cs_float fval = parse_float(end, &end); if (end.empty()) { return !!fval; } return true; } bool cs_value::get_bool() const { switch (get_type()) { case cs_value_type::FLOAT: return csv_get(p_stor) != 0; case cs_value_type::INT: return csv_get(p_stor) != 0; case cs_value_type::STRING: return cs_get_bool( *reinterpret_cast(&p_stor) ); default: return false; } } /* stacked value for easy stack management */ cs_stacked_value::cs_stacked_value(cs_state &cs, cs_ident *id): cs_value(cs), p_a(nullptr), p_stack{cs}, p_pushed(false) { set_alias(id); } cs_stacked_value::~cs_stacked_value() { pop(); static_cast(this)->~cs_value(); } cs_stacked_value &cs_stacked_value::operator=(cs_value const &v) { *static_cast(this) = v; return *this; } cs_stacked_value &cs_stacked_value::operator=(cs_value &&v) { *static_cast(this) = std::move(v); return *this; } bool cs_stacked_value::set_alias(cs_ident *id) { if (!id || !id->is_alias()) { return false; } p_a = static_cast(id); return true; } cs_alias *cs_stacked_value::get_alias() const { return p_a; } bool cs_stacked_value::has_alias() const { return p_a != nullptr; } bool cs_stacked_value::push() { if (!p_a) { return false; } static_cast(p_a)->push_arg(*this, p_stack); p_pushed = true; return true; } bool cs_stacked_value::pop() { if (!p_pushed || !p_a) { return false; } static_cast(p_a)->pop_arg(); p_pushed = false; return true; } } /* namespace cscript */