ccm/lib/ccm.c

458 lines
10 KiB
C

#include "ccm.h"
#include "str.h"
void ccm_init(ccm_t* self)
{
assert(self);
vec_init(&self->values);
vec_init(&self->stack);
err_init(&self->err);
}
void ccm_free(ccm_t* self)
{
assert(self);
err_free(&self->err);
vec_free_elements(&self->values, (void*) value_free);
vec_free(&self->values);
vec_free(&self->stack);
}
size_t ccm_str(ccm_t* self, char* buffer, size_t size)
{
assert(self);
assert(buffer);
size_t sz = 0;
for (size_t i=0; i<self->stack.size; i++)
{
value_t* val = self->values.data[(CCM) self->stack.data[i]];
sz += value_str(val, buffer + sz, size - sz);
sz += snprintf(buffer + sz, size - sz, "\n");
}
return sz;
}
CCM ccm_from_value(ccm_t* self, value_t* value)
{
assert(self);
assert(value);
switch (value->type)
{
case TYPE_NUM: {
return ccm_to_num(self, value->data.num, value->line);
} break;
case TYPE_STR: {
return ccm_to_str(self, value->data.str, value->line);
} break;
case TYPE_BOOLEAN: {
return ccm_to_boolean(
self,
value->data.boolean,
value->line
);
} break;
case TYPE_TUPLE: {
vec_t * vec = malloc(sizeof(vec_t));
vec_init(vec);
for (size_t i=0; i<value->data.tuple->size; i++)
{
vec_push(vec, value_new_clone(
value->data.tuple->data[i]
));
}
return ccm_to_tuple(
self,
vec,
value->line
);
} break;
default: {
fprintf(stderr,
"cannot convert value of type <%s> to CCM\n",
TypeStr[value->type]);
abort();
} break;
}
}
value_t* ccm_to_value(ccm_t* self, CCM value)
{
assert(self);
assert(value < self->values.size);
return (value_t*) self->values.data[value];
}
int ccm_is_num(ccm_t* self, CCM value)
{
value_t const* val = self->values.data[value];
return val->type == TYPE_NUM;
}
double ccm_from_num(ccm_t* self, CCM value)
{
assert(self);
assert(value < self->values.size);
if (!ccm_is_num(self, value))
{
err_push(&self->err,
((value_t*) self->values.data[value])->line,
"not a num");
return 0.0;
}
value_t* val = self->values.data[value];
return val->data.num;
}
CCM ccm_to_num(ccm_t* self, double value, int line)
{
assert(self);
value_t* val = malloc(sizeof(value_t));
value_init_num(val, value, line);
vec_push(&self->values, val);
return self->values.size - 1;
}
int ccm_is_tuple(ccm_t* self, CCM value)
{
assert(self);
value_t* val = self->values.data[value];
assert(val);
return val->type == TYPE_TUPLE;
}
vec_t* ccm_from_tuple(ccm_t* self, CCM value)
{
assert(self);
value_t* val = self->values.data[value];
if (!ccm_is_tuple(self, value))
{
err_push(&self->err, val->line, "not a tuple");
return NULL;
}
return val->data.tuple;
}
CCM ccm_to_tuple(ccm_t* self, vec_t* values, int line)
{
assert(self);
assert(values);
value_t* value = malloc(sizeof(value_t));
value_init_new_tuple(value, values, line);
vec_push(&self->values, value);
return self->values.size - 1;
}
int ccm_is_boolean(ccm_t* self, CCM value)
{
assert(self);
return ((value_t*) self->values.data[value])->type
== TYPE_BOOLEAN;
}
int ccm_from_boolean(ccm_t* self, CCM value)
{
assert(self);
return ((value_t*) self->values.data[value])->data.boolean;
}
CCM ccm_to_boolean(ccm_t* self, int value, int line)
{
value_t* boolean = malloc(sizeof(value_t));
value_init_boolean(boolean, value, line);
vec_push(&self->values, boolean);
return self->values.size - 1;
}
int ccm_is_str(ccm_t* self, CCM value)
{
assert(self);
return ((value_t*) self->values.data[value])->type == TYPE_STR;
}
char* ccm_from_str(ccm_t* self, CCM value)
{
assert(self);
return ((value_t*) self->values.data[value])->data.str;
}
CCM ccm_to_str(ccm_t* self, char* value, int line)
{
assert(self);
assert(value);
value_t* val = malloc(sizeof(value_t));
value_init_str(val, value, line);
vec_push(&self->values, val);
return self->values.size - 1;
}
void ccm_push(ccm_t* self, CCM value)
{
assert(self);
vec_push(&self->stack, (void*) value);
}
CCM ccm_pop(ccm_t* self)
{
assert(self);
void* val = vec_pop(&self->stack);
return (CCM) val;
}
CCM ccm_top(ccm_t* self, int depth)
{
assert(self);
assert((size_t) depth < self->stack.size);
return (CCM) self->stack.data[self->stack.size - 1 - depth];
}
void ccm_in(ccm_t* self)
{
assert(self);
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
if (!ccm_is_tuple(self, ccm_rhs))
{
err_push(&self->err, line, "cannot test membership");
return;
}
vec_t* rhs = ccm_from_tuple(self, ccm_rhs);
value_t* val = ((value_t*)self->values.data[ccm_lhs]);
for (size_t i=0; i<rhs->size; i++)
{
if (value_equals(val, rhs->data[i]))
{
ccm_push(self, ccm_to_boolean(self, 1, line));
return;
}
}
ccm_push(self, ccm_to_boolean(self, 0, line));
}
void ccm_add(ccm_t* self)
{
assert(self);
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
if (ccm_is_str(self, ccm_rhs)
&& ccm_is_str(self, ccm_lhs))
{
char const* lhs = ccm_from_str(self, ccm_lhs);
char const* rhs = ccm_from_str(self, ccm_rhs);
str_t s;
str_init(&s);
str_push_cstr(&s, lhs);
str_push_cstr(&s, rhs);
ccm_push(self, ccm_to_str(self, s.value, line));
str_free(&s);
return;
}
double rhs = ccm_from_num(self, ccm_rhs);
double lhs = ccm_from_num(self, ccm_lhs);
ccm_push(self, ccm_to_num(self, lhs + rhs, line));
}
void ccm_sub(ccm_t* self)
{
assert(self);
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
double rhs = ccm_from_num(self, ccm_rhs);
double lhs = ccm_from_num(self, ccm_lhs);
ccm_push(self, ccm_to_num(self, lhs - rhs, line));
}
void ccm_usub(ccm_t* self)
{
assert(self);
CCM ccm_lhs = ccm_pop(self);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
double lhs = ccm_from_num(self, ccm_lhs);
ccm_push(self, ccm_to_num(self, -lhs, line));
}
void ccm_mul(ccm_t* self)
{
assert(self);
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
if (ccm_is_str(self, ccm_rhs)
&& ccm_is_num(self, ccm_lhs))
{
CCM tmp = ccm_lhs;
ccm_lhs = ccm_rhs;
ccm_rhs = tmp;
}
if (ccm_is_str(self, ccm_lhs)
&& ccm_is_num(self, ccm_rhs))
{
int count = ccm_from_num(self, ccm_rhs);
char const* val = ccm_from_str(self, ccm_lhs);
str_t s;
str_init(&s);
for (int i=0; i<count; i++)
{
str_push_cstr(&s, val);
}
ccm_push(self, ccm_to_str(self, s.value, line));
str_free(&s);
return;
}
double rhs = ccm_from_num(self, ccm_rhs);
double lhs = ccm_from_num(self, ccm_lhs);
ccm_push(self, ccm_to_num(self, lhs * rhs, line));
}
void ccm_div(ccm_t* self)
{
assert(self);
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
double rhs = ccm_from_num(self, ccm_rhs);
double lhs = ccm_from_num(self, ccm_lhs);
ccm_push(self, ccm_to_num(self, lhs / rhs, line));
}
void ccm_mod(ccm_t* self)
{
assert(self);
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
double rhs = ccm_from_num(self, ccm_rhs);
double lhs = ccm_from_num(self, ccm_lhs);
ccm_push(self, ccm_to_num(self, fmod(lhs, rhs), line));
}
void ccm_pow(ccm_t* self)
{
assert(self);
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
double rhs = ccm_from_num(self, ccm_rhs);
double lhs = ccm_from_num(self, ccm_lhs);
ccm_push(self, ccm_to_num(self, powf(lhs, rhs), line));
}
void ccm_not(ccm_t* self)
{
assert(self);
CCM ccm_lhs = ccm_pop(self);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
int lhs = ccm_from_boolean(self, ccm_lhs);
ccm_push(self, ccm_to_boolean(self, !lhs, line));
}
void ccm_eq(ccm_t* self)
{
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
value_t* lhs = ccm_to_value(self, ccm_lhs);
value_t* rhs = ccm_to_value(self, ccm_rhs);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
int eq = value_equals(lhs, rhs);
ccm_push(self, ccm_to_boolean(self, eq, line));
}
void ccm_ne(ccm_t* self)
{
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
value_t* lhs = ccm_to_value(self, ccm_lhs);
value_t* rhs = ccm_to_value(self, ccm_rhs);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
int eq = value_equals(lhs, rhs);
ccm_push(self, ccm_to_boolean(self, !eq, line));
}
void ccm_lt(ccm_t* self)
{
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
double lhs = ccm_from_num(self, ccm_lhs);
double rhs = ccm_from_num(self, ccm_rhs);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
ccm_push(self, ccm_to_boolean(self, lhs < rhs, line));
}
void ccm_le(ccm_t* self)
{
ccm_gt(self);
ccm_not(self);
}
void ccm_gt(ccm_t* self)
{
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
double lhs = ccm_from_num(self, ccm_lhs);
double rhs = ccm_from_num(self, ccm_rhs);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
ccm_push(self, ccm_to_boolean(self, lhs > rhs, line));
}
void ccm_ge(ccm_t* self)
{
ccm_lt(self);
ccm_not(self);
}