#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; 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_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; 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; } } 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; 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; 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; ivalues.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); }