280 lines
6.5 KiB
C
280 lines
6.5 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);
|
|
self->data.str = strdup(value);
|
|
self->type = TYPE_STR;
|
|
self->line = line;
|
|
}
|
|
|
|
void value_init_new_array(value_t* self, vec_t* value, int line)
|
|
{
|
|
assert(self);
|
|
assert(value);
|
|
|
|
self->data.array = value;
|
|
self->type = TYPE_ARRAY;
|
|
self->line = line;
|
|
}
|
|
|
|
void value_init_ref(value_t* self, size_t value, int line)
|
|
{
|
|
assert(self);
|
|
|
|
self->data.ref = value;
|
|
self->type = TYPE_REF;
|
|
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_REF: {
|
|
value_init_ref(value, self->data.ref, self->line);
|
|
} break;
|
|
case TYPE_ARRAY: {
|
|
vec_t* array = malloc(sizeof(vec_t));
|
|
vec_init(array);
|
|
for (size_t i=0; i<self->data.array->size; i++)
|
|
{
|
|
vec_push(array,
|
|
self->data.array->data[i]
|
|
);
|
|
}
|
|
value_init_new_array(value, array, self->line);
|
|
} break;
|
|
|
|
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_ARRAY)
|
|
{
|
|
vec_free(self->data.array);
|
|
free(self->data.array);
|
|
}
|
|
|
|
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 && self->data.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_ARRAY: {
|
|
sz += snprintf(buffer + sz, size - sz, "[");
|
|
|
|
for (size_t i=0; i<self->data.array->size; i++)
|
|
{
|
|
if (i > 0)
|
|
{
|
|
sz += snprintf(buffer + sz, size - sz, ", ");
|
|
}
|
|
|
|
sz += value_str(
|
|
self->data.array->data[i],
|
|
buffer + sz,
|
|
size - sz
|
|
);
|
|
}
|
|
|
|
sz += snprintf(buffer + sz, size - sz, "]");
|
|
} break;
|
|
case TYPE_REF: {
|
|
sz += snprintf(buffer + sz, size - sz, "<ref:%zu>",
|
|
self->data.ref);
|
|
} break;
|
|
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_ARRAY: {
|
|
if (self->data.array->size != rhs->data.array->size) {
|
|
return 0;
|
|
}
|
|
|
|
for (size_t i=0; i<self->data.array->size; i++)
|
|
{
|
|
value_t* a = self->data.array->data[i];
|
|
value_t* b = rhs->data.array->data[i];
|
|
|
|
if (!value_equals(a, b))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
} break;
|
|
|
|
case TYPE_REF: {
|
|
return self->data.ref == rhs->data.ref;
|
|
} break;
|
|
|
|
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;
|
|
}
|
|
}
|