#include "ccm.h" #include "str.h" void ccm_init(ccm_t* self) { assert(self); sym_init(&self->sym); vec_init(&self->values); vec_init(&self->stack); vec_init(&self->globals); err_init(&self->err); self->id_counter = 0; sym_open_scope(&self->sym); } void ccm_entry_free(ccm_entry_t* self) { value_free(self->value); free(self->value); } void ccm_free(ccm_t* self) { assert(self); sym_free(&self->sym); err_free(&self->err); vec_free_elements(&self->values, (void*) ccm_entry_free); vec_free(&self->values); vec_free(&self->stack); vec_free(&self->globals); } 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++) { if (sz >= size) { break; } value_t* val = ccm_to_value(self, (CCM) self->stack.data[i]); sz += value_str(val, buffer + sz, size - sz); sz += snprintf(buffer + sz, size - sz, "\n"); } return sz; } value_t* ccm_find_value(ccm_t* self, size_t addr) { for (size_t i=0; ivalues.size; i++) { if (((ccm_entry_t*) self->values.data[i])->id == (int) addr) { return ((ccm_entry_t*)self->values.data[i])->value; } } assert(0); } size_t ccm_add_value(ccm_t* self, value_t* value) { assert(self); assert(value); ccm_entry_t* entry = malloc(sizeof(ccm_entry_t)); entry->value = value; entry->id = self->id_counter; self->id_counter++; vec_push(&self->values, entry); return self->id_counter - 1; } size_t ccm_store_global(ccm_t* self, CCM value) { assert(self); vec_push(&self->globals, (void*) value); return self->globals.size - 1; } CCM ccm_load_global(ccm_t* self, size_t addr) { assert(self); assert(addr < self->globals.size); return (CCM) self->globals.data[addr]; } 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_ARRAY: { vec_t * vec = malloc(sizeof(vec_t)); vec_init(vec); for (size_t i=0; idata.array->size; i++) { vec_push(vec, value->data.array->data[i] ); } return ccm_to_array( self, vec, 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); value_t* val = ccm_find_value(self, value); if (val->type == TYPE_REF) { CCM addr = (CCM) self->globals.data[val->data.ref]; return ccm_to_value(self, addr); } return val; } int ccm_is_num(ccm_t* self, CCM value) { value_t const* val = ccm_find_value(self, value); return val->type == TYPE_NUM; } double ccm_from_num(ccm_t* self, CCM value) { assert(self); assert(value < self->values.size); value_t* val = ccm_find_value(self, value); if (!ccm_is_num(self, value)) { err_push(&self->err, val->line, "not a num"); return 0.0; } 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); return ccm_add_value(self, val); } int ccm_is_tuple(ccm_t* self, CCM value) { assert(self); value_t* val = ccm_find_value(self, value); assert(val); return val->type == TYPE_TUPLE; } vec_t* ccm_from_tuple(ccm_t* self, CCM value) { assert(self); value_t* val = ccm_find_value(self, 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); return ccm_add_value(self, value); } int ccm_is_boolean(ccm_t* self, CCM value) { assert(self); return ccm_find_value(self, value)->type == TYPE_BOOLEAN; } int ccm_from_boolean(ccm_t* self, CCM value) { assert(self); return ccm_find_value(self, 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); return ccm_add_value(self, boolean); } int ccm_is_str(ccm_t* self, CCM value) { assert(self); return ccm_find_value(self, value)->type == TYPE_STR; } char* ccm_from_str(ccm_t* self, CCM value) { assert(self); return ccm_find_value(self, value)->data.str; } CCM ccm_to_str(ccm_t* self, char const* value, int line) { assert(self); value_t* val = malloc(sizeof(value_t)); value_init_str(val, value, line); return ccm_add_value(self, val); } int ccm_is_array(ccm_t* self, CCM value) { assert(self); value_t const* val = ccm_find_value(self, value); return val->type == TYPE_ARRAY; } vec_t* ccm_from_array(ccm_t* self, CCM value) { assert(self); value_t* val = ccm_find_value(self, value); return val->data.array; } CCM ccm_to_array(ccm_t* self, vec_t* value, int line) { assert(self); value_t* val = malloc(sizeof(value_t)); value_init_new_array(val, value, line); return ccm_add_value(self, val); } int ccm_is_ref(ccm_t* self, CCM value) { assert(self); return ccm_find_value(self, value)->type == TYPE_REF; } size_t ccm_from_ref(ccm_t* self, CCM value) { assert(self); return ccm_find_value(self, value)->data.ref; } CCM ccm_to_ref(ccm_t* self, size_t value, int line) { assert(self); value_t* val = malloc(sizeof(value_t)); value_init_ref(val, value, line); return ccm_add_value(self, val); } 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_set(ccm_t* self, CCM value, int addr) { assert(self); while (addr >= (ssize_t) self->stack.size) { ccm_push(self, 0); } self->stack.data[addr] = (void*) value; } CCM ccm_get(ccm_t* self, int addr) { assert(self); assert(addr < (ssize_t) self->stack.size); assert(addr >= 0); return (CCM) self->stack.data[addr]; } void ccm_in(ccm_t* self) { assert(self); CCM ccm_rhs = ccm_pop(self); CCM ccm_lhs = ccm_pop(self); int line = ccm_find_value(self, ccm_lhs)->line; if (ccm_is_ref(self, ccm_rhs)) { value_t* rhs_val = ccm_to_value(self, ccm_rhs); value_t* val = ccm_to_value(self, ccm_lhs); assert(rhs_val->type == TYPE_ARRAY); vec_t* rhs = rhs_val->data.array; 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)); return; } if (ccm_is_tuple(self, ccm_rhs)) { vec_t* rhs = ccm_from_tuple(self, ccm_rhs); value_t* val = ccm_find_value(self, 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)); return; } err_push(&self->err, line, "cannot test membership"); return; } void ccm_add(ccm_t* self) { assert(self); CCM ccm_rhs = ccm_pop(self); CCM ccm_lhs = ccm_pop(self); int line = ccm_find_value(self, ccm_lhs)->line; if (ccm_is_ref(self, ccm_rhs) && ccm_is_ref(self, ccm_lhs)) { value_t* lhs = ccm_to_value(self, ccm_lhs); value_t* rhs = ccm_to_value(self, ccm_rhs); vec_t* data = malloc(sizeof(vec_t)); vec_init(data); for (size_t i=0; idata.array->size; i++) { vec_push(data, lhs->data.array->data[i]); } for (size_t i=0; idata.array->size; i++) { vec_push(data, rhs->data.array->data[i]); } value_t* res = malloc(sizeof(value_t)); value_init_new_array(res, data, lhs->line); CCM res_id = ccm_store_global( self, ccm_add_value(self, res) ); value_t* ref = malloc(sizeof(value_t)); value_init_ref(ref, res_id, lhs->line); ccm_push(self, ccm_add_value(self, ref)); return; } 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 = ccm_find_value(self, 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 = ccm_find_value(self, 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 = ccm_find_value(self, ccm_lhs)->line; if (ccm_is_ref(self, ccm_rhs) && ccm_is_num(self, ccm_lhs)) { CCM tmp = ccm_lhs; ccm_lhs = ccm_rhs; ccm_rhs = tmp; } if (ccm_is_ref(self, ccm_lhs) && ccm_is_num(self, ccm_rhs)) { int count = ccm_from_num(self, ccm_rhs); value_t* val = ccm_to_value(self, ccm_lhs); vec_t* vec = malloc(sizeof(vec_t)); vec_init(vec); for (int i=0; idata.array->size; j++) { vec_push( vec, val->data.array->data[j] ); } } value_t* result = malloc(sizeof(value_t)); value_init_new_array(result, vec, val->line); int id = ccm_store_global( self, ccm_add_value(self, result) ); CCM res = ccm_to_ref(self, id, val->line); ccm_push(self, res); return; } 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; iline; 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 = ccm_find_value(self, 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 = ccm_find_value(self, 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 = ccm_find_value(self, 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 = ccm_find_value(self, 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 = ccm_find_value(self, 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 = ccm_find_value(self, 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 = ccm_find_value(self, 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); }