libcubescript/src/cs_val.cc

495 lines
12 KiB
C++
Raw Normal View History

2017-06-20 21:21:39 +02:00
#include <cubescript/cubescript.hh>
2021-03-24 02:21:27 +01:00
#include "cs_gen.hh"
2021-03-23 01:45:35 +01:00
#include "cs_std.hh"
#include "cs_parser.hh"
#include "cs_state.hh"
#include <cmath>
2021-03-23 23:32:25 +01:00
namespace cubescript {
2021-03-23 23:29:32 +01:00
static std::string_view intstr(integer_type v, charbuf &buf) {
buf.reserve(32);
2021-03-23 23:29:32 +01:00
int n = snprintf(buf.data(), 32, INT_FORMAT, v);
if (n > 32) {
buf.reserve(n + 1);
2021-03-23 23:29:32 +01:00
int nn = snprintf(buf.data(), n + 1, INT_FORMAT, v);
if ((nn > n) || (nn <= 0)) {
n = -1;
} else {
n = nn;
}
}
if (n <= 0) {
2021-03-23 23:29:32 +01:00
throw internal_error{"format error"};
}
return std::string_view{buf.data(), std::size_t(n)};
}
2021-03-23 23:29:32 +01:00
static std::string_view floatstr(float_type v, charbuf &buf) {
buf.reserve(32);
int n;
if (v == std::floor(v)) {
2021-03-23 23:29:32 +01:00
n = snprintf(buf.data(), 32, ROUND_FLOAT_FORMAT, v);
} else {
2021-03-23 23:29:32 +01:00
n = snprintf(buf.data(), 32, FLOAT_FORMAT, v);
}
if (n > 32) {
buf.reserve(n + 1);
int nn;
if (v == std::floor(v)) {
2021-03-23 23:29:32 +01:00
nn = snprintf(buf.data(), n + 1, ROUND_FLOAT_FORMAT, v);
} else {
2021-03-23 23:29:32 +01:00
nn = snprintf(buf.data(), n + 1, FLOAT_FORMAT, v);
}
if ((nn > n) || (nn <= 0)) {
n = -1;
} else {
n = nn;
}
}
if (n <= 0) {
2021-03-23 23:29:32 +01:00
throw internal_error{"format error"};
}
return std::string_view{buf.data(), std::size_t(n)};
}
template<typename T>
struct stor_priv_t {
2021-03-23 23:29:32 +01:00
internal_state *state;
T val;
};
2016-09-06 20:06:49 +02:00
template<typename T, typename U>
2021-03-24 02:42:33 +01:00
static inline T &csv_get(U *stor) {
2016-09-06 20:06:49 +02:00
/* ugly, but internal and unlikely to cause bugs */
2021-03-24 02:42:33 +01:00
return const_cast<T &>(std::launder(
reinterpret_cast<stor_priv_t<T> const *>(stor)
)->val);
2016-09-06 20:06:49 +02:00
}
template<typename T>
2021-03-24 02:42:33 +01:00
static inline void csv_cleanup(value_type tv, T *stor) {
switch (tv) {
2021-03-23 23:29:32 +01:00
case value_type::STRING:
2021-03-24 02:42:33 +01:00
std::launder(reinterpret_cast<string_ref *>(stor))->~string_ref();
break;
2021-03-23 23:29:32 +01:00
case value_type::CODE: {
bcode_unref(csv_get<uint32_t *>(stor));
break;
}
default:
break;
}
}
any_value::any_value(state &st): any_value(*st.p_tstate->istate) {}
2021-03-23 23:29:32 +01:00
any_value::any_value(internal_state &st):
p_stor(), p_type(value_type::NONE)
{
2021-03-24 02:42:33 +01:00
std::launder(reinterpret_cast<stor_priv_t<void *> *>(&p_stor))->state = &st;
}
2021-03-23 23:29:32 +01:00
any_value::~any_value() {
2021-03-24 02:42:33 +01:00
csv_cleanup(p_type, &p_stor);
2016-09-06 22:57:10 +02:00
}
2021-03-23 23:29:32 +01:00
any_value::any_value(any_value const &v): any_value(*v.get_state()) {
*this = v;
}
2021-03-23 23:29:32 +01:00
any_value::any_value(any_value &&v): any_value(*v.get_state()) {
*this = std::move(v);
}
2021-03-23 23:29:32 +01:00
any_value &any_value::operator=(any_value const &v) {
2021-03-24 02:42:33 +01:00
csv_cleanup(p_type, &p_stor);
2021-03-23 23:29:32 +01:00
p_type = value_type::NONE;
switch (v.get_type()) {
2021-03-23 23:29:32 +01:00
case value_type::INT:
case value_type::FLOAT:
case value_type::IDENT:
p_type = v.p_type;
2016-09-06 22:57:10 +02:00
p_stor = v.p_stor;
break;
2021-03-23 23:29:32 +01:00
case value_type::STRING:
p_type = value_type::STRING;
new (&p_stor) string_ref{
2021-03-24 02:42:33 +01:00
*std::launder(reinterpret_cast<string_ref const *>(&v.p_stor))
2021-03-17 02:47:34 +01:00
};
break;
2021-03-23 23:29:32 +01:00
case value_type::CODE:
set_code(v.get_code());
break;
default:
break;
}
return *this;
}
2021-03-23 23:29:32 +01:00
any_value &any_value::operator=(any_value &&v) {
*this = v;
v.set_none();
return *this;
}
2021-03-23 23:29:32 +01:00
value_type any_value::get_type() const {
return p_type;
}
2021-03-23 23:29:32 +01:00
void any_value::set_int(integer_type val) {
2021-03-24 02:42:33 +01:00
csv_cleanup(p_type, &p_stor);
2021-03-23 23:29:32 +01:00
p_type = value_type::INT;
2021-03-24 02:42:33 +01:00
csv_get<integer_type>(&p_stor) = val;
}
2021-03-23 23:29:32 +01:00
void any_value::set_float(float_type val) {
2021-03-24 02:42:33 +01:00
csv_cleanup(p_type, &p_stor);
2021-03-23 23:29:32 +01:00
p_type = value_type::FLOAT;
2021-03-24 02:42:33 +01:00
csv_get<float_type>(&p_stor) = val;
}
2021-03-23 23:29:32 +01:00
void any_value::set_str(std::string_view val) {
2021-03-24 02:42:33 +01:00
csv_cleanup(p_type, &p_stor);
2021-03-23 23:29:32 +01:00
new (&p_stor) string_ref{get_state(), val};
p_type = value_type::STRING;
}
2021-03-23 23:29:32 +01:00
void any_value::set_str(string_ref const &val) {
2021-03-24 02:42:33 +01:00
csv_cleanup(p_type, &p_stor);
2021-03-23 23:29:32 +01:00
new (&p_stor) string_ref{val};
p_type = value_type::STRING;
}
2021-03-23 23:29:32 +01:00
void any_value::set_none() {
2021-03-24 02:42:33 +01:00
csv_cleanup(p_type, &p_stor);
2021-03-23 23:29:32 +01:00
p_type = value_type::NONE;
}
2021-03-23 23:29:32 +01:00
void any_value::set_code(bcode *val) {
2021-03-24 02:42:33 +01:00
csv_cleanup(p_type, &p_stor);
2021-03-23 23:29:32 +01:00
p_type = value_type::CODE;
bcode_addref(val->get_raw());
2021-03-24 02:42:33 +01:00
csv_get<bcode *>(&p_stor) = val;
}
2021-03-23 23:29:32 +01:00
void any_value::set_ident(ident *val) {
2021-03-24 02:42:33 +01:00
csv_cleanup(p_type, &p_stor);
2021-03-23 23:29:32 +01:00
p_type = value_type::IDENT;
2021-03-24 02:42:33 +01:00
csv_get<ident *>(&p_stor) = val;
}
2021-03-23 23:29:32 +01:00
void any_value::force_none() {
if (get_type() == value_type::NONE) {
return;
}
2021-03-18 20:55:14 +01:00
set_none();
}
2021-03-23 23:29:32 +01:00
float_type any_value::force_float() {
float_type rf = 0.0f;
switch (get_type()) {
2021-03-23 23:29:32 +01:00
case value_type::INT:
2021-03-24 02:42:33 +01:00
rf = csv_get<integer_type>(&p_stor);
break;
2021-03-23 23:29:32 +01:00
case value_type::STRING:
2021-03-23 01:45:35 +01:00
rf = parse_float(
2021-03-24 02:42:33 +01:00
*std::launder(reinterpret_cast<string_ref const *>(&p_stor))
);
break;
2021-03-23 23:29:32 +01:00
case value_type::FLOAT:
2021-03-24 02:42:33 +01:00
return csv_get<float_type>(&p_stor);
default:
break;
}
set_float(rf);
return rf;
}
2021-03-23 23:29:32 +01:00
integer_type any_value::force_int() {
integer_type ri = 0;
switch (get_type()) {
2021-03-23 23:29:32 +01:00
case value_type::FLOAT:
2021-03-24 02:42:33 +01:00
ri = csv_get<float_type>(&p_stor);
break;
2021-03-23 23:29:32 +01:00
case value_type::STRING:
2021-03-23 01:45:35 +01:00
ri = parse_int(
2021-03-24 02:42:33 +01:00
*std::launder(reinterpret_cast<string_ref const *>(&p_stor))
);
break;
2021-03-23 23:29:32 +01:00
case value_type::INT:
2021-03-24 02:42:33 +01:00
return csv_get<integer_type>(&p_stor);
default:
break;
}
set_int(ri);
return ri;
}
2021-03-23 23:29:32 +01:00
std::string_view any_value::force_str() {
charbuf rs{get_state()};
std::string_view str;
switch (get_type()) {
2021-03-23 23:29:32 +01:00
case value_type::FLOAT:
2021-03-24 02:42:33 +01:00
str = floatstr(csv_get<float_type>(&p_stor), rs);
break;
2021-03-23 23:29:32 +01:00
case value_type::INT:
2021-03-24 02:42:33 +01:00
str = intstr(csv_get<integer_type>(&p_stor), rs);
break;
2021-03-23 23:29:32 +01:00
case value_type::STRING:
2021-03-24 02:42:33 +01:00
return *std::launder(reinterpret_cast<string_ref const *>(&p_stor));
default:
str = rs.str();
break;
}
set_str(str);
2021-03-24 02:42:33 +01:00
return std::string_view(*std::launder(
reinterpret_cast<string_ref const *>(&p_stor)
));
}
bcode *any_value::force_code(state &cs) {
switch (get_type()) {
case value_type::CODE:
return csv_get<bcode *>(&p_stor);
default:
break;
}
codegen_state gs{cs};
gs.code.reserve(64);
gs.gen_main(get_str());
gs.done();
uint32_t *cbuf = bcode_alloc(cs, gs.code.size());
std::memcpy(cbuf, gs.code.data(), gs.code.size() * sizeof(std::uint32_t));
auto *bc = reinterpret_cast<bcode *>(cbuf + 1);
set_code(bc);
return bc;
}
ident *any_value::force_ident(state &cs) {
switch (get_type()) {
case value_type::IDENT:
return csv_get<ident *>(&p_stor);
default:
break;
}
auto *id = cs.new_ident(get_str());
set_ident(id);
return id;
}
2021-03-23 23:29:32 +01:00
integer_type any_value::get_int() const {
switch (get_type()) {
2021-03-23 23:29:32 +01:00
case value_type::FLOAT:
2021-03-24 02:42:33 +01:00
return integer_type(csv_get<float_type>(&p_stor));
2021-03-23 23:29:32 +01:00
case value_type::INT:
2021-03-24 02:42:33 +01:00
return csv_get<integer_type>(&p_stor);
2021-03-23 23:29:32 +01:00
case value_type::STRING:
2021-03-23 01:45:35 +01:00
return parse_int(
2021-03-24 02:42:33 +01:00
*std::launder(reinterpret_cast<string_ref const *>(&p_stor))
);
default:
break;
}
return 0;
}
2021-03-23 23:29:32 +01:00
float_type any_value::get_float() const {
switch (get_type()) {
2021-03-23 23:29:32 +01:00
case value_type::FLOAT:
2021-03-24 02:42:33 +01:00
return csv_get<float_type>(&p_stor);
2021-03-23 23:29:32 +01:00
case value_type::INT:
2021-03-24 02:42:33 +01:00
return float_type(csv_get<integer_type>(&p_stor));
2021-03-23 23:29:32 +01:00
case value_type::STRING:
2021-03-23 01:45:35 +01:00
return parse_float(
2021-03-24 02:42:33 +01:00
*std::launder(reinterpret_cast<string_ref const *>(&p_stor))
);
default:
break;
}
return 0.0f;
}
2021-03-23 23:29:32 +01:00
bcode *any_value::get_code() const {
if (get_type() != value_type::CODE) {
return nullptr;
}
2021-03-24 02:42:33 +01:00
return csv_get<bcode *>(&p_stor);
}
2021-03-23 23:29:32 +01:00
ident *any_value::get_ident() const {
if (get_type() != value_type::IDENT) {
return nullptr;
}
2021-03-24 02:42:33 +01:00
return csv_get<ident *>(&p_stor);
}
2021-03-23 23:29:32 +01:00
string_ref any_value::get_str() const {
switch (get_type()) {
2021-03-23 23:29:32 +01:00
case value_type::STRING:
2021-03-24 02:42:33 +01:00
return *std::launder(reinterpret_cast<string_ref const *>(&p_stor));
2021-03-23 23:29:32 +01:00
case value_type::INT: {
charbuf rs{get_state()};
return string_ref{
2021-03-24 02:42:33 +01:00
get_state(), intstr(csv_get<integer_type>(&p_stor), rs)
2021-03-23 23:29:32 +01:00
};
}
2021-03-23 23:29:32 +01:00
case value_type::FLOAT: {
charbuf rs{get_state()};
return string_ref{
2021-03-24 02:42:33 +01:00
get_state(), floatstr(csv_get<float_type>(&p_stor), rs)
2021-03-23 23:29:32 +01:00
};
}
default:
break;
}
2021-03-23 23:29:32 +01:00
return string_ref{get_state(), ""};
}
2021-03-23 23:29:32 +01:00
void any_value::get_val(any_value &r) const {
switch (get_type()) {
2021-03-23 23:29:32 +01:00
case value_type::STRING:
2021-03-17 02:47:34 +01:00
r = *this;
break;
2021-03-23 23:29:32 +01:00
case value_type::INT:
2021-03-24 02:42:33 +01:00
r.set_int(csv_get<integer_type>(&p_stor));
break;
2021-03-23 23:29:32 +01:00
case value_type::FLOAT:
2021-03-24 02:42:33 +01:00
r.set_float(csv_get<float_type>(&p_stor));
break;
default:
2021-03-18 20:55:14 +01:00
r.set_none();
break;
}
}
2021-03-23 23:29:32 +01:00
LIBCUBESCRIPT_EXPORT bool code_is_empty(bcode *code) {
if (!code) {
return true;
}
2021-03-23 23:29:32 +01:00
return (*code->get_raw() & BC_INST_OP_MASK) == BC_INST_EXIT;
}
2021-03-23 23:29:32 +01:00
bool any_value::code_is_empty() const {
if (get_type() != value_type::CODE) {
return true;
}
2021-03-24 02:42:33 +01:00
return cubescript::code_is_empty(csv_get<bcode *>(&p_stor));
}
2021-03-23 23:29:32 +01:00
bool any_value::get_bool() const {
switch (get_type()) {
2021-03-23 23:29:32 +01:00
case value_type::FLOAT:
2021-03-24 02:42:33 +01:00
return csv_get<float_type>(&p_stor) != 0;
2021-03-23 23:29:32 +01:00
case value_type::INT:
2021-03-24 02:42:33 +01:00
return csv_get<integer_type>(&p_stor) != 0;
2021-03-23 23:29:32 +01:00
case value_type::STRING: {
2021-03-24 02:42:33 +01:00
std::string_view s = *std::launder(
reinterpret_cast<string_ref const *>(&p_stor)
);
2021-03-23 23:29:32 +01:00
if (s.empty()) {
return false;
}
std::string_view end = s;
integer_type ival = parse_int(end, &end);
if (end.empty()) {
return !!ival;
}
end = s;
float_type fval = parse_float(end, &end);
if (end.empty()) {
return !!fval;
}
return true;
}
default:
return false;
}
}
/* stacked value for easy stack management */
2021-03-23 23:29:32 +01:00
stacked_value::stacked_value(state &cs, ident *id):
any_value(cs), p_a(nullptr), p_stack{cs}, p_pushed(false)
{
set_alias(id);
}
2021-03-23 23:29:32 +01:00
stacked_value::~stacked_value() {
pop();
2021-03-23 23:29:32 +01:00
static_cast<any_value *>(this)->~any_value();
}
2021-03-23 23:29:32 +01:00
stacked_value &stacked_value::operator=(any_value const &v) {
*static_cast<any_value *>(this) = v;
return *this;
}
2021-03-23 23:29:32 +01:00
stacked_value &stacked_value::operator=(any_value &&v) {
*static_cast<any_value *>(this) = std::move(v);
return *this;
}
2021-03-23 23:29:32 +01:00
bool stacked_value::set_alias(ident *id) {
if (!id || !id->is_alias()) {
return false;
2016-09-06 20:06:49 +02:00
}
2021-03-23 23:29:32 +01:00
p_a = static_cast<alias *>(id);
return true;
}
2021-03-23 23:29:32 +01:00
alias *stacked_value::get_alias() const {
return p_a;
}
2021-03-23 23:29:32 +01:00
bool stacked_value::has_alias() const {
return p_a != nullptr;
}
2021-03-23 23:29:32 +01:00
bool stacked_value::push() {
if (!p_a) {
return false;
}
2021-03-23 23:29:32 +01:00
static_cast<alias_impl *>(p_a)->push_arg(*this, p_stack);
p_pushed = true;
return true;
}
2021-03-23 23:29:32 +01:00
bool stacked_value::pop() {
if (!p_pushed || !p_a) {
return false;
}
2021-03-23 23:29:32 +01:00
static_cast<alias_impl *>(p_a)->pop_arg();
p_pushed = false;
return true;
2016-09-06 20:06:49 +02:00
}
2021-03-23 02:00:11 +01:00
/* public utilities */
2021-03-23 23:29:32 +01:00
LIBCUBESCRIPT_EXPORT string_ref concat_values(
state &cs, std::span<any_value> vals, std::string_view sep
2021-03-23 02:00:11 +01:00
) {
2021-03-23 23:29:32 +01:00
charbuf buf{cs};
2021-03-23 02:00:11 +01:00
for (std::size_t i = 0; i < vals.size(); ++i) {
switch (vals[i].get_type()) {
2021-03-23 23:29:32 +01:00
case value_type::INT:
case value_type::FLOAT:
case value_type::STRING:
2021-03-23 02:00:11 +01:00
std::ranges::copy(
2021-03-23 23:29:32 +01:00
any_value{vals[i]}.force_str(), std::back_inserter(buf)
2021-03-23 02:00:11 +01:00
);
break;
default:
break;
}
if (i == (vals.size() - 1)) {
break;
}
std::ranges::copy(sep, std::back_inserter(buf));
}
2021-03-23 23:29:32 +01:00
return string_ref{cs, buf.str()};
2021-03-23 02:00:11 +01:00
}
2021-03-23 23:32:25 +01:00
} /* namespace cubescript */