#include "ccm.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; istack.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_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; idata.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; } } 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; } 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; isize; 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; 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; 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)); }