#include #include "cs_vm.hh" #include "cs_util.hh" namespace cscript { template static inline T &csv_get(U &stor) { /* ugly, but internal and unlikely to cause bugs */ return const_cast(reinterpret_cast(stor)); } template static inline void csv_cleanup(cs_value_type tv, T &stor) { switch (tv) { case cs_value_type::String: delete[] csv_get(stor); break; case cs_value_type::Code: { uint32_t *bcode = csv_get(stor); if (bcode[-1] == CsCodeStart) { delete[] &bcode[-1]; } break; } default: break; } } cs_value::cs_value(): p_stor(), p_len(0), p_type(cs_value_type::Null) {} cs_value::~cs_value() { csv_cleanup(p_type, p_stor); } cs_value::cs_value(cs_value const &v): cs_value() { *this = v; } cs_value::cs_value(cs_value &&v): cs_value() { *this = std::move(v); } cs_value &cs_value::operator=(cs_value const &v) { csv_cleanup(p_type, p_stor); p_type = cs_value_type::Null; switch (v.get_type()) { case cs_value_type::Int: case cs_value_type::Float: case cs_value_type::Ident: p_len = v.p_len; p_type = v.p_type; p_stor = v.p_stor; break; case cs_value_type::String: case cs_value_type::Cstring: case cs_value_type::Macro: set_str(cs_string{csv_get(v.p_stor), v.p_len}); break; case cs_value_type::Code: set_code(cs_copy_code(v.get_code())); break; default: break; } return *this; } cs_value &cs_value::operator=(cs_value &&v) { csv_cleanup(p_type, p_stor); p_stor = v.p_stor; p_type = v.p_type; p_len = v.p_len; v.p_type = cs_value_type::Null; 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(cs_string val) { csv_cleanup(p_type, p_stor); p_type = cs_value_type::String; p_len = val.size(); char *buf = new char[p_len + 1]; memcpy(buf, val.data(), p_len + 1); csv_get(p_stor) = buf; } void cs_value::set_null() { csv_cleanup(p_type, p_stor); p_type = cs_value_type::Null; } void cs_value::set_code(cs_bcode *val) { csv_cleanup(p_type, p_stor); p_type = cs_value_type::Code; csv_get(p_stor) = val; } void cs_value::set_cstr(ostd::string_range val) { csv_cleanup(p_type, p_stor); p_type = cs_value_type::Cstring; p_len = val.size(); csv_get(p_stor) = val.data(); } 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::set_macro(ostd::string_range val) { csv_cleanup(p_type, p_stor); p_type = cs_value_type::Macro; p_len = val.size(); csv_get(p_stor) = val.data(); } void cs_value::force_null() { if (get_type() == cs_value_type::Null) { return; } set_null(); } 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: case cs_value_type::Macro: case cs_value_type::Cstring: rf = cs_parse_float(ostd::string_range( csv_get(p_stor), csv_get(p_stor) + p_len )); 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: case cs_value_type::Macro: case cs_value_type::Cstring: ri = cs_parse_int(ostd::string_range( csv_get(p_stor), csv_get(p_stor) + p_len )); break; case cs_value_type::Int: return csv_get(p_stor); default: break; } set_int(ri); return ri; } ostd::string_range cs_value::force_str() { cs_string rs; switch (get_type()) { case cs_value_type::Float: rs = floatstr(csv_get(p_stor)); break; case cs_value_type::Int: rs = intstr(csv_get(p_stor)); break; case cs_value_type::Macro: case cs_value_type::Cstring: rs = ostd::string_range( csv_get(p_stor), csv_get(p_stor) + p_len ); break; case cs_value_type::String: return ostd::string_range( csv_get(p_stor), csv_get(p_stor) + p_len ); default: break; } set_str(std::move(rs)); return ostd::string_range( csv_get(p_stor), csv_get(p_stor) + p_len ); } 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: case cs_value_type::Macro: case cs_value_type::Cstring: return cs_parse_int(ostd::string_range( csv_get(p_stor), csv_get(p_stor) + p_len )); 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: case cs_value_type::Macro: case cs_value_type::Cstring: return cs_parse_float(ostd::string_range( csv_get(p_stor), csv_get(p_stor) + p_len )); 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_string cs_value::get_str() const { switch (get_type()) { case cs_value_type::String: case cs_value_type::Macro: case cs_value_type::Cstring: return cs_string{csv_get(p_stor), p_len}; case cs_value_type::Int: return intstr(csv_get(p_stor)); case cs_value_type::Float: return floatstr(csv_get(p_stor)); default: break; } return cs_string(""); } ostd::string_range cs_value::get_strr() const { switch (get_type()) { case cs_value_type::String: case cs_value_type::Macro: case cs_value_type::Cstring: return ostd::string_range( csv_get(p_stor), csv_get(p_stor)+ p_len ); default: break; } return ostd::string_range(); } void cs_value::get_val(cs_value &r) const { switch (get_type()) { case cs_value_type::String: case cs_value_type::Macro: case cs_value_type::Cstring: r.set_str( cs_string{csv_get(p_stor), p_len} ); 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_null(); break; } } OSTD_EXPORT bool cs_code_is_empty(cs_bcode *code) { if (!code) { return true; } return ( *reinterpret_cast(code) & CsCodeOpMask ) == CsCodeExit; } 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(ostd::string_range s) { if (s.empty()) { return false; } ostd::string_range end = s; cs_int ival = cs_parse_int(end, &end); if (end.empty()) { return !!ival; } end = s; cs_float fval = cs_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: case cs_value_type::Macro: case cs_value_type::Cstring: return cs_get_bool(ostd::string_range( csv_get(p_stor), csv_get(p_stor) + p_len )); default: return false; } } /* stacked value for easy stack management */ cs_stacked_value::cs_stacked_value(cs_ident *id): cs_value(), p_a(nullptr), p_stack(), 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; } cs_alias_internal::push_arg(p_a, *this, p_stack); p_pushed = true; return true; } bool cs_stacked_value::pop() { if (!p_pushed || !p_a) { return false; } cs_alias_internal::pop_arg(p_a); p_pushed = false; return true; } } /* namespace cscript */