HklValue* hklr_object_dereference(HklrObject* object) { assert(object != NULL); switch (object->type) { case HKL_TYPE_NIL: return hkl_value_new(HKL_TYPE_NIL); break; case HKL_TYPE_INT: return hkl_value_new(HKL_TYPE_INT, object->as.integer); break; case HKL_TYPE_REAL: return hkl_value_new(HKL_TYPE_REAL, object->as.real); break; case HKL_TYPE_STRING: return hkl_value_new(HKL_TYPE_STRING, hkl_string_new_from_string(object->as.string)); break; default: assert(false); return NULL; break; } }
HklValue* hklr_op_typeof(HklValue* value) { bool temporary = true; // Dereference if (value->type == HKL_TYPE_REF) { HklValue* temp = value; value = hklr_object_dereference(value->as.object); // Don't free the deque or hash since it can't be a temporary if (value->type == HKL_TYPE_ARRAY || value->type == HKL_TYPE_HASH || value->type == HKL_TYPE_FUNCTION) { temporary = false; // simply spoof the value temp->type = HKL_TYPE_NIL; } hkl_value_free(temp); } HklType type = value->type; // Spoof the value if it not temporary if (temporary == false) value->type = HKL_TYPE_NIL; hkl_value_free(value); value = hkl_value_new(HKL_TYPE_TYPE, type); value->type = HKL_TYPE_TYPE; return value; }
HklValue* hklr_op_bitwise_and(HklValue* left_value, HklValue* right_value) { HklValue* result = NULL; bool left_updated = false, right_updated = false; // Dereference left and right sides if (left_value->type == HKL_TYPE_REF) { left_updated = true; left_value = hklr_object_dereference(left_value->as.object); } if (right_value->type == HKL_TYPE_REF) { right_updated = true; right_value = hklr_object_dereference(right_value->as.object); } switch (left_value->type) { case HKL_TYPE_INT: switch(right_value->type) { case HKL_TYPE_INT: result = hkl_value_new(HKL_TYPE_INT, left_value->as.integer & right_value->as.integer); break; case HKL_TYPE_REAL: case HKL_TYPE_STRING: default: assert(false); break; } break; // HKL_TYPE_INT default: assert(false); break; } if (left_updated) { hkl_value_free(left_value); } if (right_updated) { hkl_value_free(right_value); } return result; }
HklValue* hklr_expression_eval(HklrExpression* expr) { assert(expr != NULL); switch (expr->type) { case HKL_EXPR_NIL: return hkl_value_new(HKL_TYPE_NIL); break; case HKL_EXPR_MAYBE: return hkl_value_new(HKL_TYPE_INT, rand() % 2 == 1); break; case HKL_EXPR_INT: return hkl_value_new(HKL_TYPE_INT, expr->arg[0].integer); break; case HKL_EXPR_TYPE: return hkl_value_new(HKL_TYPE_TYPE, expr->arg[0].type); break; case HKL_EXPR_REAL: return hkl_value_new(HKL_TYPE_REAL, expr->arg[0].real); break; case HKL_EXPR_STRING: { HklString* string = hkl_string_new_from_string(expr->arg[0].string); assert(string != NULL); return hkl_value_new(HKL_TYPE_STRING, string); } break; case HKL_EXPR_VAR: { HklrObject* object = hklr_search(expr->arg[0].string); // apply more list items to the object to fetch deeper ones HklList* list = expr->arg[1].list; if (list->size && object->type != HKL_TYPE_REF) assert(false); HklListNode* node = list->head; while (node && object->type == HKL_TYPE_REF) { HklVariable* var = node->data; if (object->type == HKL_TYPE_REF && object->as.object->type == HKL_TYPE_FUNCTION) { HKLR.reg_return = NULL; // Try a function call HklrFunction* function = object->as.object->as.function; assert(var->type == HKL_VAR_CALL); HklList* args = var->as.list; struct scope_carier carrier; carrier.locals = hkl_hash_new(); carrier.upvals = hkl_hash_new(); carrier.arg = args->head; // Create the closure variables hkl_tree_traverse(function->closure_list, make_closures, &carrier); // Make the args in the function signature local variables hkl_list_traverse(function->args_list, make_locals, &carrier); hklr_scope_push_full(true, carrier.locals, carrier.upvals); // execute the statements within hkl_list_traverse(function->stmt_list, hklr_statement_exec_list, NULL); // the post_object is the function return value if (HKLR.reg_return == NULL) HKLR.reg_return = hkl_value_new(HKL_TYPE_NIL); // if the return value is an object be sure to increase the ref count // Though, this count needs to be decced afterwards if (HKLR.reg_return->type == HKL_TYPE_REF) hklr_gc_inc(HKLR.reg_return->as.object); hklr_scope_pop(); return HKLR.reg_return; } else if (object->type == HKL_TYPE_REF && object->as.object->type == HKL_TYPE_HASH) { HklPair* pair = hkl_hash_search(object->as.object->as.hash, var->as.string); // This key doesnt exist just create it if (pair == NULL) { HklrObject* post_object = hklr_object_new(HKL_TYPE_NIL, HKL_FLAG_NONE); hkl_hash_insert(object->as.object->as.hash, var->as.string, post_object); return hkl_value_new(HKL_TYPE_REF, post_object); } if (node->next == NULL) return hkl_value_new(HKL_TYPE_REF, pair->value); object = pair->value; } node = node->next; } return hkl_value_new(HKL_TYPE_REF, object); } break; case HKL_EXPR_GETS: { HklString* string = hkl_string_new_from_stream(stdin); assert(string != NULL); return hkl_value_new(HKL_TYPE_STRING, string); } break; case HKL_EXPR_ARRAY: { // allocate space ahead of time HklDeque* deque = hkl_deque_new();//_sized(list->size); hkl_list_traverse(expr->arg[0].list, hklr_array_add_list, deque); return hkl_value_new(HKL_TYPE_ARRAY, deque); } break; case HKL_EXPR_HASH: { HklHash* hash = hkl_hash_new(); struct hash_index hash_index; hash_index.index = 0; hash_index.hash = hash; hkl_list_traverse(expr->arg[0].list, hklr_hash_add_list, &hash_index); return hkl_value_new(HKL_TYPE_HASH, hash); } break; case HKL_EXPR_FUNCTION: { return hkl_value_new(HKL_TYPE_FUNCTION, hklr_function_new(expr->arg[0].list, expr->arg[1].tree, expr->arg[2].list)); } break; case HKL_EXPR_UNARY: { HklValue* value = hklr_expression_eval(expr->arg[1].expression); assert(value != NULL); switch (expr->arg[0].op) { case HKL_OP_UNARY_MINUS: switch (value->type) { case HKL_TYPE_INT: value->as.integer = -value->as.integer; return value; break; case HKL_TYPE_REAL: value->as.real = -value->as.real; return value; break; default: assert(false); break; } break; // HKL_OP_UNARY_MINUS case HKL_OP_SIZE: return hklr_op_size(value); break; // HKL_OP_SIZE case HKL_OP_TYPEOF: return hklr_op_typeof(value); break; // HKL_OP_TYPE case HKL_OP_BITWISE_NOT: switch (value->type) { case HKL_TYPE_INT: value->as.integer = ~value->as.integer; return value; break; default: assert(false); break; } default: assert(false); break; } } break; // HKL_EXPR_UNARY case HKL_EXPR_BINARY: { HklValue *left_value = hklr_expression_eval(expr->arg[0].expression); HklValue *right_value = hklr_expression_eval(expr->arg[2].expression); HklValue *result = NULL; assert(left_value != NULL); assert(right_value != NULL); switch (expr->arg[1].op) { case HKL_OP_PLUS: result = hklr_op_plus(left_value, right_value); break; case HKL_OP_MINUS: result = hklr_op_minus(left_value, right_value); break; case HKL_OP_LESS: result = hklr_op_less(left_value, right_value); break; case HKL_OP_LESS_EQUAL: result = hklr_op_less_equal(left_value, right_value); break; case HKL_OP_GREATER: result = hklr_op_greater(left_value, right_value); break; case HKL_OP_GREATER_EQUAL: result = hklr_op_greater_equal(left_value, right_value); break; case HKL_OP_ASTERISK: result = hklr_op_multiply(left_value, right_value); break; case HKL_OP_DIVIDE: result = hklr_op_divide(left_value, right_value); break; case HKL_OP_MOD: result = hklr_op_mod(left_value, right_value); break; case HKL_OP_EQUAL: result = hklr_op_equal(left_value, right_value); break; case HKL_OP_COALESCE: result = hklr_op_coalesce(left_value, right_value); if (result == left_value) { result = hkl_value_new(left_value->type); result->as = left_value->as; left_value->type = HKL_TYPE_NIL; } else if (result == right_value) { result = hkl_value_new(right_value->type); result->as = right_value->as; right_value->type = HKL_TYPE_NIL; } break; case HKL_OP_BITWISE_AND: result = hklr_op_bitwise_and(left_value, right_value); break; case HKL_OP_BITWISE_OR: result = hklr_op_bitwise_or(left_value, right_value); break; case HKL_OP_BITWISE_XOR: result = hklr_op_bitwise_xor(left_value, right_value); break; case HKL_OP_AS: { assert(right_value->type == HKL_TYPE_TYPE); switch (right_value->as.type) { case HKL_TYPE_INT: result = hklr_as_integer(left_value); break; case HKL_TYPE_REAL: result = hklr_as_real(left_value); break; case HKL_TYPE_STRING: result = hklr_as_string(left_value); break; default: assert(false); break; } } break; default: assert(false); break; } hkl_value_free(left_value); hkl_value_free(right_value); return result; } break; // HKL_EXPR_BINARY default: assert(false); break; } assert(false); return NULL; }
HklValue* hklr_op_multiply(HklValue* left_value, HklValue* right_value) { HklValue* result = NULL; bool left_updated = false, right_updated = false; // Dereference left and right sides if (left_value->type == HKL_TYPE_REF) { left_updated = true; left_value = hklr_object_dereference(left_value->as.object); } if (right_value->type == HKL_TYPE_REF) { right_updated = true; right_value = hklr_object_dereference(right_value->as.object); } switch (left_value->type) { case HKL_TYPE_INT: switch(right_value->type) { case HKL_TYPE_INT: result = hkl_value_new(HKL_TYPE_INT, left_value->as.integer * right_value->as.integer); break; case HKL_TYPE_REAL: result = hkl_value_new(HKL_TYPE_REAL, left_value->as.integer * right_value->as.real); break; case HKL_TYPE_STRING: result = hkl_value_new(HKL_TYPE_STRING, hkl_string_new()); int i; for (i=0; i < (int)left_value->as.integer; i ++) { hkl_string_cat(result->as.string, right_value->as.string); } break; default: assert(false); break; } break; // HKL_TYPE_INT case HKL_TYPE_REAL: switch(right_value->type) { case HKL_TYPE_INT: result = hkl_value_new(HKL_TYPE_REAL, left_value->as.real * right_value->as.integer); break; case HKL_TYPE_REAL: result = hkl_value_new(HKL_TYPE_REAL, left_value->as.real * right_value->as.real); break; default: assert(false); break; } break; // HKL_TYPE_REAL case HKL_TYPE_STRING: switch(right_value->type) { case HKL_TYPE_INT: { result = hkl_value_new(HKL_TYPE_STRING, hkl_string_new()); int i; for (i=0; i < (int)right_value->as.integer; i ++) { hkl_string_cat(result->as.string, left_value->as.string); } } break; default: assert(false); break; } break; // HKL_TYPE_STRING default: assert(false); break; } if (left_updated) { hkl_value_free(left_value); } if (right_updated) { hkl_value_free(right_value); } return result; }
HklValue* hklr_op_size(HklValue* value) { bool temporary = true; // Dereference if (value->type == HKL_TYPE_REF) { HklValue* temp = value; value = hklr_object_dereference(value->as.object); // Don't free the deque or hash since it can't be a temporary if (value->type == HKL_TYPE_ARRAY || value->type == HKL_TYPE_HASH || value->type == HKL_TYPE_FUNCTION) { temporary = false; // simply spoof the value temp->type = HKL_TYPE_NIL; } hkl_value_free(temp); } switch (value->type) { case HKL_TYPE_STRING: { HklString* string = value->as.string; value->type = HKL_TYPE_INT; value->as.integer = string->length; hkl_string_free(string); } break; case HKL_TYPE_ARRAY: { HklDeque* deque = value->as.deque; value->type = HKL_TYPE_INT; value->as.integer = deque->size; if (temporary) { // Free the deque hkl_value_free(hkl_value_new(HKL_TYPE_ARRAY, deque)); } } break; case HKL_TYPE_HASH: { HklHash* hash = value->as.hash; value->type = HKL_TYPE_INT; value->as.integer = hash->length; if (temporary) { // Free the hash hkl_value_free(hkl_value_new(HKL_TYPE_HASH, hash)); } } break; case HKL_TYPE_FUNCTION: { HklrFunction* function = value->as.function; value->type = HKL_TYPE_INT; value->as.integer = function->stmt_list->size; if (temporary) { // Free the function hklr_function_free(function); } } break; default: assert(false); break; } return value; }