HklrObject* hklr_search(HklString* key) { assert(key != NULL); HklScope* scope = ((HklScope*) HKLR.scopes->tail->data); HklPair* pair = NULL; // check your scope first pair = hkl_hash_search(scope->locals, key); if (pair) return pair->value; // now try upvals pair = hkl_hash_search(scope->upvals, key); if (pair) return pair->value; // Now try scopes above HklListNode* node = HKLR.scopes->tail; node = node->last; while(node != NULL) { scope = ((HklScope*) node->data); // check locals first then upvals pair = hkl_hash_search(scope->locals, key); if (!pair) pair = hkl_hash_search(scope->upvals, key); // if you find the object // make it an upval to my scope if (pair) { hklr_upval_insert(key, pair->value); return pair->value; } node = node->last; } // Finally try global scope pair = hkl_hash_search(HKLR.globals, key); if (pair) { hklr_upval_insert(key, pair->value); return pair->value; } // Didn't find it, make a nil object HklrObject* object = hklr_object_new(HKL_TYPE_NIL, HKL_FLAG_NONE); hklr_local_insert(key, object); return object; }
void hklr_init() { // The first and last gc_root are dummy objects HKLR.gc_roots = hklr_object_new(HKL_TYPE_INT, HKL_FLAG_NONE, NULL); HKLR.gc_tail = hklr_object_new(HKL_TYPE_INT, HKL_FLAG_NONE, NULL); // Dont count them in the object count HKLR.gc_created-=2; HKLR.gc_roots->next = HKLR.gc_tail; HKLR.gc_tail->prev = HKLR.gc_roots; HKLR.gc_to_free = hkl_list_new(); HKLR.gc_runs = 0; HKLR.gc_freed = 0; HKLR.gc_rootsize = 0; HKLR.globals = hkl_hash_new(); HKLR.scopes = hkl_list_new(); HKLR.scope_level = 0; hklr_scope_push(); }
static bool hklr_hash_add_list(void* pair, void* hash_index) { HklrObject* object = hklr_object_new(HKL_TYPE_NIL, HKL_FLAG_NONE); // If the user didnt give a value // Give them an integer corresponding to the index in the hash if (((HklPair*) pair)->value == NULL) { ((HklPair*) pair)->value = hklr_expression_new(HKL_EXPR_STRING, hkl_string_new_from_string(((HklPair*) pair)->key)); } hklr_object_assign(object, (HklrExpression*) ((HklPair*) pair)->value); hkl_hash_insert(((struct hash_index*) hash_index)->hash, ((HklPair*) pair)->key, object); return false; }
static bool make_locals(void* string, void* carrier) { HklrObject* object = hklr_object_new(HKL_TYPE_NIL, HKL_FLAG_NONE); //hklr_local_insert((HklString*) string, object); hkl_hash_insert(((struct scope_carier*) carrier)->locals, (HklString*) string, object); // If you have too few args then the rest are nil if (((struct scope_carier*) carrier)->arg == NULL) return true; // Some fancy pointer arithematic // This iterates the argument expression HklrExpression* assign = ((struct scope_carier*) carrier)->arg->data; ((struct scope_carier*) carrier)->arg = ((struct scope_carier*) carrier)->arg->next; hklr_object_assign(object, assign); return false; }
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; }
void hklr_statement_exec(HklrStatement* stmt) { assert(stmt != NULL); switch (stmt->type) { case HKL_STMT_PUTS: hklr_statement_puts(stmt->arg[0].expression); break; case HKL_STMT_HKLR: // Print runtime information fprintf(stdout, "Ops: %zu\n", HKLR.ops); fprintf(stdout, "Objects Created: %zu\n", HKLR.gc_created); fprintf(stdout, "Objects Freed: %zu\n", HKLR.gc_freed); fprintf(stdout, "Object Cycles: %zu\n", HKLR.gc_rootsize); fprintf(stdout, "GC Runs: %zu\n", HKLR.gc_runs); fprintf(stdout, "Scope Level: %zu\n", HKLR.scope_level); fprintf(stdout, "Globals: %zu\n", HKLR.globals->length); fprintf(stdout, "Locals: %zu\n", ((HklScope*) HKLR.scopes->tail->data)->locals->length); fprintf(stdout, "Upvals: %zu\n", ((HklScope*) HKLR.scopes->tail->data)->upvals->length); fflush(stdout); break; case HKL_STMT_INIT: { // This is very much a hack and needs to be made ALOT better // this doesn't actually play nice with flags, but will // do for now to create globals and locals if (stmt->arg[0].flags & HKL_FLAG_GLOBAL) hklr_global_insert(stmt->arg[1].string, hklr_object_new(HKL_TYPE_NIL, stmt->arg[0].flags)); else hklr_local_insert(stmt->arg[1].string, hklr_object_new(HKL_TYPE_NIL, stmt->arg[0].flags)); HklrExpression* temp = hklr_expression_new(HKL_EXPR_ID, stmt->arg[1].string); hklr_statement_assign(temp, stmt->arg[2].expression); hklr_expression_free(temp); } break; case HKL_STMT_ASSIGN: hklr_statement_assign(stmt->arg[0].expression, stmt->arg[1].expression); break; // HKL_STMT_ASSIGN case HKL_STMT_IF: hklr_statement_if(stmt->arg[0].expression, stmt->arg[1].list); break; case HKL_STMT_WHILE: hklr_statement_while(stmt->arg[0].expression, stmt->arg[1].list); break; default: break; } // Increment numbers of completed operations HKLR.ops++; }