ccm/lib/value.c

196 lines
4.4 KiB
C

#include "value.h"
void value_init_num(value_t* self, double num, int line)
{
assert(self);
self->data.num = num;
self->type = TYPE_NUM;
self->line = line;
}
void value_init_new_tuple(value_t* self, vec_t* values, int line)
{
assert(self);
assert(values);
self->data.tuple = values;
self->type = TYPE_TUPLE;
self->line = line;
}
void value_init_boolean(value_t* self, int boolean, int line)
{
assert(self);
self->data.boolean = boolean;
self->type = TYPE_BOOLEAN;
self->line = line;
}
void value_init_str(value_t* self, char const* value, int line)
{
assert(self);
assert(value);
self->data.str = strdup(value);
self->type = TYPE_STR;
self->line = line;
}
value_t* value_new_clone(value_t* self)
{
assert(self);
value_t* value = malloc(sizeof(value_t));
switch (self->type)
{
case TYPE_STR: {
value_init_str(value, self->data.str, self->line);
} break;
case TYPE_NUM: {
value_init_num(value, self->data.num, self->line);
} break;
case TYPE_BOOLEAN: {
value_init_boolean(value, self->data.boolean, self->line);
} break;
case TYPE_TUPLE: {
vec_t* vec = malloc(sizeof(vec_t));
vec_init(vec);
for (size_t i=0; i<self->data.tuple->size; i++)
{
vec_push(
vec,
value_new_clone(self->data.tuple->data[i])
);
}
value_init_new_tuple(value, vec, self->line);
} break;
default: {
free(value);
fprintf(stderr, "cannot clone value of type '%s'\n",
TypeStr[self->type]);
abort();
} break;
}
return value;
}
void value_free(value_t* self)
{
if (self->type == TYPE_TUPLE)
{
vec_free_elements(self->data.tuple, (void*) value_free);
vec_free(self->data.tuple);
free(self->data.tuple);
}
if (self->type == TYPE_STR)
{
free(self->data.str);
}
}
size_t value_str(value_t* self, char* buffer, size_t size)
{
assert(self);
assert(buffer);
size_t sz = 0;
switch (self->type)
{
case TYPE_STR: {
sz += snprintf(buffer + sz, size - sz, "%s",
self->data.str);
} break;
case TYPE_NUM: {
sz += snprintf(buffer + sz, size - sz, "%lf",
self->data.num);
} break;
case TYPE_BOOLEAN: {
sz += snprintf(buffer + sz, size - sz, "%s",
self->data.boolean ? "true" : "false");
} break;
case TYPE_TUPLE: {
sz += snprintf(buffer + sz, size - sz, "(");
for (size_t i=0; i < self->data.tuple->size; i++)
{
if (i > 0)
{
sz += snprintf(buffer + sz, size - sz, ", ");
}
sz += value_str(self->data.tuple->data[i],
buffer + sz,
size - sz);
}
sz += snprintf(buffer + sz, size - sz, ")");
} break;
default: assert(0);
}
return sz;
}
int value_equals(value_t* self, value_t* rhs)
{
assert(self);
assert(rhs);
if (self->type != rhs->type)
{
return 0;
}
switch (self->type)
{
case TYPE_STR: {
return strcmp(self->data.str, rhs->data.str) == 0;
} break;
case TYPE_NUM: {
return self->data.num == rhs->data.num;
} break;
case TYPE_BOOLEAN: {
return self->data.boolean == rhs->data.boolean;
} break;
case TYPE_TUPLE: {
if (self->data.tuple->size != rhs->data.tuple->size)
{
return 0;
}
for (size_t i=0; i<self->data.tuple->size; i++)
{
if (!value_equals(
self->data.tuple->data[i],
rhs->data.tuple->data[i]
))
{
return 0;
}
}
return 1;
} break;
default: {
fprintf(
stderr,
"cannot test equality on value of type '%s'\n",
TypeStr[self->type]);
abort();
} break;
}
}