DMS/DMS/value.cpp

521 lines
13 KiB
C++

#include "value.h"
#include "dms_state.h"
#include "utils.h"
namespace dms {
const std::string datatype[] = { "escape", "nil", "number", "int", "boolean", "env", "string", "custom", "variable", "block" , "error"};
value::value() {
// Nothing to do here!
}
value::value(char const* str, datatypes t) {
type = t;
s = str;
}
value::value(char const* str) {
type = datatypes::string;
s = str;
}
value::value(size_t val) {
type = datatypes::int64;
i = val;
}
value::value(std::string str) {
type = datatypes::string;
s = str;
}
value::value(int64_t n) {
type = datatypes::int64;
i = n;
}
value::value(std::string str,datatypes t) {
type = t;
s = str;
}
value::value(double d) {
type = datatypes::number;
n = d;
}
value::value(int d) {
type = datatypes::int64;
i = d;
}
value::value(bool bo) {
type = datatypes::boolean;
b = bo;
}
value::~value() {
nuke();
}
size_t count = 0;
value::value(datatypes t) : value() {
if (t == datatypes::variable) {
set(utils::concat("$",++count));
}
type = t;
}
value::value(const value& other) {
if (this != &other) {
type = other.type;
switch (other.type) {
case datatypes::block:
s = other.s;
break;
case datatypes::boolean:
b = other.b;
break;
case datatypes::custom:
// Handle this later
break;
case datatypes::env:
// Handle this later
break;
case datatypes::escape:
s = other.s;
break;
case datatypes::nil:
// No need to do anything
break;
case datatypes::number:
n = other.n;
break;
case datatypes::int64:
i = other.i;
break;
case datatypes::string:
s = other.s;
break;
case datatypes::variable:
s = other.s;
break;
case datatypes::error:
s = other.s;
default:
break;
}
}
}
value& value::operator=(value& other) {
if (this != &other) {
nuke(); // Delete it all
type = other.type;
switch (other.type) {
case datatypes::block:
s = other.s;
break;
case datatypes::boolean:
b = other.b;
break;
case datatypes::custom:
// Handle this later
break;
case datatypes::env:
// Handle this later
break;
case datatypes::escape:
s = other.s;
break;
case datatypes::nil:
// No need to do anything
break;
case datatypes::number:
n = other.n;
break;
case datatypes::int64:
i = other.i;
break;
case datatypes::string:
s = other.s;
break;
case datatypes::variable:
s = other.s;
break;
case datatypes::error:
s = other.s;
default:
break;
}
//other.nuke();
}
// by convention, always return *this
return *this;
}
bool value::isNil() const {
return type == datatypes::nil;
}
value& value::operator=(const value& other) {
if (this != &other) {
nuke();
type = other.type;
switch (other.type) {
case datatypes::block:
s = other.s;
break;
case datatypes::boolean:
b = other.b;
break;
case datatypes::custom:
// Handle this later
break;
case datatypes::env:
// Handle this later
break;
case datatypes::escape:
s = other.s;
break;
case datatypes::nil:
// No need to do anything
break;
case datatypes::number:
n = other.n;
break;
case datatypes::int64:
i = other.i;
break;
case datatypes::string:
s = other.s;
break;
case datatypes::variable:
s = other.s;
break;
case datatypes::error:
s = other.s;
default:
break;
}
}
// by convention, always return *this
return *this;
}
bool value::isNum() const
{
return (type == datatypes::number || type == datatypes::int64);
}
bool operator==(const value& lhs, const value& rhs) {
return lhs.getPrintable() == rhs.getPrintable();
}
value operator+(const value& lhs, const value& rhs) {
if (lhs.type == datatypes::nil || rhs.type == datatypes::nil) {
return value("Attempt to concat a nil value!",datatypes::error);
}
else if (lhs.type == datatypes::number && rhs.type == datatypes::number) {
return value(lhs.n + rhs.n);
}
else if (lhs.type == datatypes::int64 && rhs.type == datatypes::number) {
return value(lhs.i + rhs.n);
}
else if (lhs.type == datatypes::int64 && rhs.type == datatypes::int64) {
return value(lhs.i + rhs.i);
}
else if (lhs.type == datatypes::number && rhs.type == datatypes::int64) {
return value(lhs.n + rhs.i);
}
else if (lhs.type == datatypes::boolean && rhs.type == datatypes::boolean) {
return value((bool)(lhs.b + rhs.b));
}
else if ((lhs.type == datatypes::string || rhs.type == datatypes::string)) {
return lhs.getPrintable() + rhs.getPrintable();
}
else {
return value("Invalid use of '+'!", datatypes::error);
}
}
value operator-(const value& lhs, const value& rhs) {
if (lhs.type == datatypes::number && rhs.type == datatypes::number) {
return value(lhs.n - rhs.n);
}
else if (lhs.type == datatypes::int64 && rhs.type == datatypes::number) {
return value(lhs.i - rhs.n);
}
else if (lhs.type == datatypes::int64 && rhs.type == datatypes::int64) {
return value(lhs.i - rhs.i);
}
else if (lhs.type == datatypes::number && rhs.type == datatypes::int64) {
return value(lhs.n - rhs.i);
}
else {
if(lhs.type!=datatypes::number)
return value(utils::concat("Attempted to perform arithmetic on a ", datatype[lhs.type] ," value!"),datatypes::error);
else
return value(utils::concat("Attempted to perform arithmetic on a ", datatype[rhs.type], " value!"), datatypes::error);
}
}
value operator/(const value& lhs, const value& rhs) {
if (lhs.type == datatypes::number && rhs.type == datatypes::number) {
return value(lhs.n / rhs.n);
}
else if (lhs.type == datatypes::int64 && rhs.type == datatypes::number) {
return value(lhs.i / rhs.n);
}
else if (lhs.type == datatypes::int64 && rhs.type == datatypes::int64) {
return value(lhs.i / rhs.i);
}
else if (lhs.type == datatypes::number && rhs.type == datatypes::int64) {
return value(lhs.n / rhs.i);
}
else {
if (lhs.type != datatypes::number)
return value(utils::concat("Attempted to perform arithmetic on a ", datatype[lhs.type], " value!"), datatypes::error);
else
return value(utils::concat("Attempted to perform arithmetic on a ", datatype[rhs.type], " value!"), datatypes::error);
}
}
value operator*(const value& lhs, const value& rhs) {
if (lhs.type == datatypes::number && rhs.type == datatypes::number) {
return value(lhs.n * rhs.n);
}
else if (lhs.type == datatypes::int64 && rhs.type == datatypes::number) {
return value(lhs.i * rhs.n);
}
else if (lhs.type == datatypes::int64 && rhs.type == datatypes::int64) {
return value(lhs.i * rhs.i);
}
else if (lhs.type == datatypes::number && rhs.type == datatypes::int64) {
return value(lhs.n * rhs.i);
}
else if (lhs.type == datatypes::boolean && rhs.type == datatypes::boolean) {
return value((bool)(lhs.b * rhs.b));
}
else {
if (lhs.type != datatypes::number)
return value(utils::concat("Attempted to perform arithmetic on a ", datatype[lhs.type], " value!"), datatypes::error);
else
return value(utils::concat("Attempted to perform arithmetic on a ", datatype[rhs.type], " value!"), datatypes::error);
}
}
bool operator!=(const value& lhs, const value& rhs) {
return !(lhs.getPrintable() == rhs.getPrintable());
}
bool operator>(const value& lhs, const value& rhs) {
if (lhs.type == datatypes::number && rhs.type == datatypes::number) {
return lhs.n > rhs.n;
}
else if (lhs.type == datatypes::int64 && rhs.type == datatypes::number) {
return lhs.i > rhs.n;
}
else if (lhs.type == datatypes::int64 && rhs.type == datatypes::int64) {
return lhs.i > rhs.i;
}
else if (lhs.type == datatypes::number && rhs.type == datatypes::int64) {
return lhs.n > rhs.i;
}
return false;
}
bool operator<(const value& lhs, const value& rhs) {
if (lhs.type == datatypes::number && rhs.type == datatypes::number) {
return lhs.n < rhs.n;
}
else if (lhs.type == datatypes::int64 && rhs.type == datatypes::number) {
return lhs.i < rhs.n;
}
else if (lhs.type == datatypes::int64 && rhs.type == datatypes::int64) {
return lhs.i < rhs.i;
}
else if (lhs.type == datatypes::number && rhs.type == datatypes::int64) {
return lhs.n < rhs.i;
}
return false;
}
bool operator>=(const value& lhs, const value& rhs) {
if (lhs.type == datatypes::number && rhs.type == datatypes::number) {
return lhs.n >= rhs.n;
}
else if (lhs.type == datatypes::int64 && rhs.type == datatypes::number) {
return lhs.i >= rhs.n;
}
else if (lhs.type == datatypes::int64 && rhs.type == datatypes::int64) {
return lhs.i >= rhs.i;
}
else if (lhs.type == datatypes::number && rhs.type == datatypes::int64) {
return lhs.n >= rhs.i;
}
return false;
}
bool operator<=(const value& lhs, const value& rhs) {
if (lhs.type == datatypes::number && rhs.type == datatypes::number) {
return lhs.n <= rhs.n;
}
else if (lhs.type == datatypes::int64 && rhs.type == datatypes::number) {
return lhs.i <= rhs.n;
}
else if (lhs.type == datatypes::int64 && rhs.type == datatypes::int64) {
return lhs.i <= rhs.i;
}
else if (lhs.type == datatypes::number && rhs.type == datatypes::int64) {
return lhs.n <= rhs.i;
}
return false;
}
value value::resolve(dms_state* state) {
if (type == datatypes::variable && (*this)!=(*state->getMem())[getPrintable()]) {
return (*state->getMem())[getPrintable()].resolve(state);
}
return *this;
}
void dms_args::push(value val) {
args.push_back(val);
}
size_t dms_args::size() {
return args.size();
}
std::string value::getPrintable() const {
if (type == string) {
return s;
}
else if (type == number) {
std::string temp = std::to_string(n);
while (temp.find(".") != std::string::npos // !=string::npos is important!!!
&& temp.substr(temp.length() - 1, 1) == "0"
|| temp.substr(temp.length() - 1, 1) == ".")
{
temp.pop_back();
}
return temp;
}
else if (type == int64) {
return std::to_string(i);
}
else if (type == nil) {
return "nil";
}
else if (type == boolean) {
if (b)
return "true";
else
return "false";
}
else if (type == env) {
return "env";
}
else if (type == custom) {
return "custom";
}
else if (type == block) {
return s;
}
else if (type == datatypes::variable) {
return s; // Do the lookup
}
else if (type == datatypes::error) {
return std::string("ERROR: ") + s;
}
else if (type == datatypes::escape) {
return "";
}
return "unknown";
}
std::string value::toString() const {
return getPrintable();
}
// Compile time
void value::nuke() {
delete e;
delete c;
e = nullptr;
c = nullptr;
}
std::ostream& operator << (std::ostream& out, const value& c) {
if (c.type == string) {
out << (char)c.type << c.s << (char)0;
}
else if (c.type == number) {
out << (char)c.type << c.n;
}
else if (c.type == int64) {
out << (char)c.type << c.i;
}
else if (c.type == nil) {
out << (char)c.type << "nil";
}
else if (c.type == boolean) {
if(c.b)
out << (char)c.type << "true";
else
out << (char)c.type << "false";
}
else if (c.type == env) {
out << (char)c.type << "Env: " << c;
}
else if (c.type == custom) {
out << (char)c.type << "Custom Data: " << c;
}
else if (c.type == block) {
out << (char)c.type << c.s;
}
else if (c.type == datatypes::variable) {
out << (char)c.type << c.s; // Do the lookup
}
else if (c.type == datatypes::escape) {
out << (char)0;
}
return out;
};
// Fixed issue with memory not properly being cleaned up
bool value::typeMatch(const value* o) const {
return type == o->type;
}
void value::set(value val) {
type = val.type;
s = val.s;
n = val.n;
i = val.i;
b = val.b;
e = val.e;
c = val.c;
}
void value::set(std::string str) {
nuke();
s = str;
type = string;
}
void value::set(bool bo) {
nuke();
b = bo;
type = boolean;
}
void value::set(double num) {
nuke();
n = num;
type = number;
}
void dms::value::set(dms_list* en) {
nuke();
e = en;
type = env;
}
void dms::value::set(dms_custom* cus) {
nuke();
c = cus;
c->_set(this);
type = custom;
}
void value::set() {
nuke();
type = nil;
}
void dms_list::pushValue(value val) {
ipart.push_back(val);
}
value dms_list::getValue(value ind) {
if (ind.type == number) {
return ipart.at((int)ind.n);
}
else {
return new value();
}
}
std::ostream& operator << (std::ostream& out, const dms_args& c) {
for (size_t i = 0; i < c.args.size(); i++) {
if (i == c.args.size() - 1)
out << c.args[i];
else
out << c.args[i] << ", ";
}
return out;
}
std::string dms_args::toString() {
std::stringstream str;
for (size_t i = 0; i < args.size(); i++) {
str << args[i];
}
return str.str();
}
}