Ink_HashExpression::ProtoSearchRet Ink_HashExpression::searchPrototype(Ink_InterpreteEngine *engine, Ink_Object *obj, const char *id) { if (engine->prototypeHasTraced(obj)) { InkWarn_Circular_Prototype_Reference(engine); return Ink_HashExpression::ProtoSearchRet(NULL, obj); } engine->addPrototypeTrace(obj); Ink_HashTable *hash = obj->getSlotMapping(engine, id); Ink_HashTable *proto; Ink_Object *proto_obj = NULL; Ink_HashExpression::ProtoSearchRet search_res; if (!hash) { /* cannot find slot in object itself */ /* get prototype */ proto = obj->getSlotMapping(engine, "prototype"); /* prototype exists and it's not undefined */ if (proto && proto->getValue()->type != INK_UNDEFINED) { /* search the slot in prototype, and get the result */ hash = (search_res = searchPrototype(engine, proto->getValue(), id)).hash; proto_obj = search_res.base; } } /* return result with base pointed to the prototype(if has) * in which found the slot */ return Ink_HashExpression::ProtoSearchRet(hash, proto_obj ? proto_obj : obj); }
Ink_Object *InkNative_Object_Each(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_Object *base, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p) { Ink_Object **args; Ink_Object *ret_tmp; Ink_HashTable *hash; Ink_Array *ret = NULL; IGC_CollectEngine *gc_engine = engine->getCurrentGC(); if (!checkArgument(engine, argc, argv, 1, INK_FUNCTION)) { return NULL_OBJ; } ret = new Ink_Array(engine); engine->addPardonObject(ret); args = (Ink_Object **)malloc(2 * sizeof(Ink_Object *)); for (hash = base->hash_table; hash; hash = hash->next) { if (!hash->getValue()) continue; gc_engine->checkGC(); args[0] = new Ink_String(engine, string(hash->key)); args[1] = hash->getValue() ? hash->getValue() : UNDEFINED; ret->value.push_back(new Ink_HashTable(ret_tmp = argv[0]->call(engine, context, base, 2, args), ret)); if (engine->getSignal() != INTER_NONE) { switch (engine->getSignal()) { case INTER_RETURN: free(args); engine->removePardonObject(ret); return engine->getInterruptValue(); // signal penetrated case INTER_DROP: case INTER_BREAK: free(args); engine->removePardonObject(ret); return engine->trapSignal(); // trap the signal case INTER_CONTINUE: engine->trapSignal(); // trap the signal, but do not return continue; default: free(args); engine->removePardonObject(ret); return NULL_OBJ; } } } free(args); engine->removePardonObject(ret); return ret; }
Ink_Object *InkNative_Array_Index(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p) { Ink_Object *base = context->searchSlot(engine, "base"); Ink_Array *obj = as<Ink_Array>(base); Ink_Object *ret; Ink_HashTable *hash; Ink_ArrayValue::size_type index; ASSUME_BASE_TYPE(engine, INK_ARRAY); if (!checkArgument(false, argc, argv, 1, INK_NUMERIC)) { InkNote_Method_Fallthrough(engine, "[]", INK_ARRAY, INK_OBJECT); return InkNative_Object_Index(engine, context, argc, argv, this_p); } index = getRealIndex(as<Ink_Numeric>(argv[0])->value, obj->value.size()); if (index < obj->value.size()) { if (!obj->value[index]) obj->value[index] = new Ink_HashTable(UNDEFINED); for (hash = obj->value[index]; hash->bonding; hash = hash->bonding) ; hash->bondee = obj->value[index]; ret = hash->getValue(); ret->address = hash; ret->setSlot("base", base); } else { InkWarn_Index_Exceed(engine); return UNDEFINED; } return ret; }
Ink_Object *InkNative_Object_Each(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p) { Ink_Object *base = context->searchSlot(engine, "base"); Ink_Object **args; Ink_Object *ret_tmp; Ink_HashTable *hash; Ink_ArrayValue ret_val; if (!checkArgument(engine, argc, argv, 1, INK_FUNCTION)) { return NULL_OBJ; } args = (Ink_Object **)malloc(2 * sizeof(Ink_Object *)); for (hash = base->hash_table; hash && hash->getValue(); hash = hash->next) { args[0] = new Ink_String(engine, string(hash->key)); args[1] = hash->getValue() ? hash->getValue() : UNDEFINED; ret_val.push_back(new Ink_HashTable(ret_tmp = argv[0]->call(engine, context, 2, args))); if (engine->getSignal() != INTER_NONE) { switch (engine->getSignal()) { case INTER_RETURN: free(args); cleanArrayHashTable(ret_val); return engine->getInterruptValue(); // signal penetrated case INTER_DROP: case INTER_BREAK: free(args); cleanArrayHashTable(ret_val); return engine->trapSignal(); // trap the signal case INTER_CONTINUE: engine->trapSignal(); // trap the signal, but do not return continue; default: free(args); cleanArrayHashTable(ret_val); return NULL_OBJ; } } } free(args); return new Ink_Array(engine, ret_val); }
Ink_Object *InkNative_Object_Debond(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_Object *base, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p) { Ink_HashTable *tmp; if (base->address && (tmp = base->address->getBondee())) { tmp->setBonding(engine, NULL); return tmp->getValue(); } return NULL_OBJ; }