moka/lib/value.c

262 lines
5.9 KiB
C

#include "value.h"
#include "node.h"
#include "moka.h"
MK_ENUM_C(TypeKind, TYPE_KIND);
void value_init_int(struct value* self, int value, int line)
{
assert(self);
self->data.integer = value;
self->type = TY_INT;
self->line = line;
}
void value_init_float(struct value* self, float value, int line)
{
assert(self);
self->data.real = value;
self->type = TY_FLOAT;
self->line = line;
}
void value_init_bool(struct value* self, bool value, int line)
{
assert(self);
self->data.boolean = value;
self->type = TY_BOOL;
self->line = line;
}
void value_init_string(struct value* self, char const* value, int line)
{
assert(self);
assert(value);
self->data.str = strdup(value);
self->type = TY_STRING;
self->line = line;
}
void value_init_symbol(struct value* self, char const* value, int line)
{
assert(self);
assert(value);
self->data.sym = strdup(value);
self->type = TY_SYMBOL;
self->line = line;
}
void value_init_ref(struct value* self, size_t value, int line)
{
assert(self);
self->data.ref = value;
self->type = TY_REF;
self->line = line;
}
void value_init_native(struct value* self, struct native* value, int line)
{
assert(self);
assert(value);
self->data.native = value;
self->type = TY_NATIVE;
self->line = line;
}
void value_init_lazy(struct value* self, struct node* value, int line)
{
assert(self);
assert(value);
self->data.lazy = value;
self->type = TY_LAZY;
self->line = line;
}
void value_init_array(struct value* self, struct vec* new_values, int line)
{
assert(self);
assert(new_values);
self->data.array = malloc(sizeof(struct array));
array_init(self->data.array);
for (size_t i=0; i<new_values->size; i++)
{
array_push_value(self->data.array, (MOKA) new_values->data[i]);
}
self->type = TY_ARRAY;
self->line = line;
}
size_t value_str(struct value* self,
char* buffer,
size_t size,
struct moka* moka)
{
assert(self);
assert(buffer);
switch (self->type)
{
case TY_INT: {
return snprintf(buffer, size, "%d", self->data.integer);
} break;
case TY_FLOAT: {
return snprintf(buffer, size, "%f", self->data.real);
} break;
case TY_BOOL: {
return snprintf(buffer, size, "%s",
self->data.boolean ? "true" : "false");
} break;
case TY_STRING: {
return snprintf(buffer, size, "%s", self->data.str);
} break;
case TY_SYMBOL: {
return snprintf(buffer, size, "%s", self->data.sym);
} break;
case TY_REF: {
return snprintf(buffer, size, "<ref:%zu>", self->data.ref);
} break;
case TY_NATIVE: {
return snprintf(buffer, size, "<native: %p>", self->data.native);
} break;
case TY_LAZY: {
return snprintf(buffer, size, "<lazy:%s>",
NodeKindStr[self->data.lazy->kind]
+ strlen("NODE_"));
} break;
case TY_ARRAY: {
size_t sz = 0;
sz += snprintf(buffer + sz, size - sz, "[");
for (size_t i=0; i<self->data.array->values.size; i++)
{
if (i > 0)
{
sz += snprintf(buffer + sz, size - sz, " ");
}
MOKA val = (MOKA) self->data.array->values.data[i];
sz += moka_str(moka, val, buffer + sz, size - sz);
}
sz += snprintf(buffer + sz, size - sz, "]");
return sz;
} break;
default: {
fprintf(stderr, "cannot stringify value <%s>\n",
TypeKindStr[self->type]);
abort();
} break;
}
}
bool value_is_eqv(struct value* self,
struct value* rhs,
struct moka* moka)
{
if (self->type != rhs->type)
{
return false;
}
switch (self->type)
{
case TY_INT: {
return self->data.integer == rhs->data.integer;
} break;
case TY_FLOAT: {
return self->data.real == rhs->data.real;
} break;
case TY_BOOL: {
return self->data.boolean == rhs->data.boolean;
} break;
case TY_STRING: {
return strcmp(self->data.str, rhs->data.str) == 0;
} break;
case TY_SYMBOL: {
return strcmp(self->data.sym, rhs->data.sym) == 0;
} break;
case TY_REF: {
return self->data.ref == rhs->data.ref;
} break;
case TY_ARRAY: {
if (self->data.array->values.size
!= rhs->data.array->values.size)
{
return false;
}
for (size_t i=0; i<self->data.array->values.size; i++)
{
MOKA first = (MOKA) self->data.array->values.data[i];
MOKA second = (MOKA) rhs->data.array->values.data[i];
if (!moka_is_eqv(moka, first, second))
{
return false;
}
}
return true;
} break;
case TY_NATIVE: {
return false;
} break;
case TY_LAZY: {
return true;
} break;
default: {
fprintf(stderr, "cannot test eqv on type <%s>\n",
TypeKindStr[self->type]);
abort();
} break;
}
}
void value_free(struct value* self)
{
assert(self);
if (self->type == TY_STRING)
{
free(self->data.str);
}
if (self->type == TY_SYMBOL)
{
free(self->data.sym);
}
if (self->type == TY_NATIVE)
{
native_free(self->data.native);
free(self->data.native);
}
if (self->type == TY_ARRAY)
{
array_free(self->data.array);
free(self->data.array);
}
}