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; }
void InkMod_Loader(Ink_InterpreteEngine *engine, Ink_ContextChain *context) { Ink_Object *tmp; Ink_TypeTag *type_p = NULL; if (!engine->getEngineComAs<Ink_TypeTag>(ink_native_file_mod_id)) { type_p = (Ink_TypeTag *)malloc(sizeof(Ink_TypeTag) * 2); type_p[0] = (Ink_TypeTag)engine->registerType("io.file.File"); type_p[1] = (Ink_TypeTag)engine->registerType("io.direct.Directory"); engine->addEngineCom(ink_native_file_mod_id, type_p); engine->addDestructor(Ink_EngineDestructor(InkNative_IO_EngineComCleaner, new com_cleaner_arg(ink_native_file_mod_id))); context->getGlobal()->context->setSlot("$io.file.File", tmp = new Ink_FilePointer(engine)); tmp->derivedMethodInit(engine); context->getGlobal()->context->setSlot("$io.direct.Directory", tmp = new Ink_DirectPointer(engine)); tmp->derivedMethodInit(engine); } Ink_Object *io_pkg = addPackage(engine, context, "io", new Ink_FunctionObject(engine, InkMod_IO_Loader)); Ink_Object *io_file_pkg = addPackage(engine, io_pkg, "file", new Ink_FunctionObject(engine, InkMod_File_Loader)); Ink_Object *io_direct_pkg = addPackage(engine, io_pkg, "direct", new Ink_FunctionObject(engine, InkMod_Direct_Loader)); InkMod_IO_bondTo(engine, io_pkg); InkMod_File_bondTo(engine, io_file_pkg); InkMod_Direct_bondTo(engine, io_direct_pkg); }
Ink_Object *InkNative_Actor_Send(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_Object *base, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p) { if (!checkArgument(engine, argc, argv, 1, INK_STRING)) { return NULL_OBJ; } Ink_Object *sender = new Ink_Object(engine); sender->setSlot_c("->", new Ink_FunctionObject(engine, InkNative_Actor_Send_Sub)); sender->setSlot_c("msg", argv[0]); return sender; }
Ink_Object *InkNative_Object_Index(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p) { Ink_Object *base = context->searchSlot(engine, "base"); if (!checkArgument(engine, argc, argv, 1, INK_STRING)) { return NULL_OBJ; } if (!base->getSlotMapping(engine, as<Ink_String>(argv[0])->getValue().c_str())) { string *tmp = new string(as<Ink_String>(argv[0])->getValue()); return getSlotWithProto(engine, context, base, tmp->c_str(), tmp); } return getSlotWithProto(engine, context, base, as<Ink_String>(argv[0])->getValue().c_str()); }
Ink_Object *InkNative_Object_New(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 *new_obj = new Ink_Object(engine); Ink_HashTable *prototype_hash = base->getSlotMapping(engine, "prototype"); if (prototype_hash) { new_obj->setSlot("prototype", prototype_hash->getValue()); } if (base->type == INK_FUNCTION) { return base->call(engine, context, argc, argv, new_obj); } return new_obj; }
Ink_Object *InkNative_Object_SetSetter(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p) { Ink_Object *base = context->searchSlot(engine, "base"); Ink_HashTable *hash; const char *tmp; if (!checkArgument(engine, argc, argv, 1, INK_STRING)) { return NULL_OBJ; } tmp = as<Ink_String>(argv[0])->getValue().c_str(); if (!(hash = base->getSlotMapping(engine, tmp))) { string *tmp_p = new string(tmp); hash = base->setSlot(tmp_p->c_str(), NULL, tmp_p); } hash->setter = argc > 1 ? argv[1] : NULL; return NULL_OBJ; }
Ink_Object *InkMod_IO_Loader(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_Object *base, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p) { if (!checkArgument(engine, argc, 2)) { return NULL_OBJ; } Ink_Object *self = argv[0]; Ink_Object *apply_to = argv[1]; Ink_Object **tmp_argv = (Ink_Object **)malloc(sizeof(Ink_Object *) * 2); Ink_Object *file_pkg = self->getSlot(engine, "file"); Ink_Object *direct_pkg = self->getSlot(engine, "direct"); Ink_Object *file_loader = file_pkg->getSlot(engine, "load"); Ink_Object *direct_loader = direct_pkg->getSlot(engine, "load"); tmp_argv[0] = file_pkg; tmp_argv[1] = apply_to; if (file_loader->type == INK_FUNCTION) { file_loader->call(engine, context, file_pkg, 2, tmp_argv); } else { InkWarn_Package_Broken(engine, "io.file"); return NULL_OBJ; } tmp_argv[0] = direct_pkg; if (direct_loader->type == INK_FUNCTION) { direct_loader->call(engine, context, direct_pkg, 2, tmp_argv); } else { InkWarn_Package_Broken(engine, "io.direct"); return NULL_OBJ; } free(tmp_argv); InkMod_IO_bondTo(engine, apply_to); return NULL_OBJ; }
Ink_Object *Ink_HashTableExpression::eval(Ink_InterpreteEngine *engine, Ink_ContextChain *context_chain, Ink_EvalFlag flags) { const char *file_name_back; Ink_LineNoType line_num_back; SET_LINE_NUM; Ink_Object *ret = new Ink_Object(engine), *key; Ink_HashTableMapping::size_type i; for (i = 0; i < mapping.size(); i++) { /* two possibility: 1. identifier key; 2. expression key with brackets */ if (mapping[i]->name) { ret->setSlot(mapping[i]->name->c_str(), mapping[i]->value->eval(engine, context_chain)); if (INTER_SIGNAL_RECEIVED) { RESTORE_LINE_NUM; return engine->getInterruptValue(); } } else { key = mapping[i]->key->eval(engine, context_chain); if (INTER_SIGNAL_RECEIVED) { RESTORE_LINE_NUM; return engine->getInterruptValue(); } if (key->type != INK_STRING) { InkWarn_Hash_Table_Mapping_Expect_String(engine); return NULL_OBJ; } string *tmp = new string(as<Ink_String>(key)->getValue().c_str()); ret->setSlot(tmp->c_str(), mapping[i]->value->eval(engine, context_chain), true, tmp); if (INTER_SIGNAL_RECEIVED) { RESTORE_LINE_NUM; return engine->getInterruptValue(); } } } RESTORE_LINE_NUM; return ret; }
void InkMod_Bignum_bondType(Ink_InterpreteEngine *engine, Ink_ContextChain *context) { Ink_Object *tmp; com_struct *com = NULL; Ink_Object *obj_proto = engine->getTypePrototype(INK_OBJECT); if (!(com = engine->getEngineComAs<com_struct>(ink_native_bignum_mod_id))) { com = new com_struct(); engine->addEngineCom(ink_native_bignum_mod_id, com); engine->addDestructor(Ink_EngineDestructor(InkMod_Bignum_EngineComCleaner, new com_cleaner_arg(ink_native_bignum_mod_id))); } else if (com->bignum_type != (Ink_TypeTag)-1) /* has registered */ return; com->bignum_type = engine->registerType("bignum"); context->getGlobal()->setSlot_c("$bignum", tmp = new Ink_BigNumeric(engine, "0")); engine->setTypePrototype(com->bignum_type, tmp); tmp->setProto(obj_proto); tmp->derivedMethodInit(engine); return; }
Ink_Object *InkNative_Actor_Send_Sub(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p) { Ink_Object *base = context->searchSlot(engine, "base"); if (!checkArgument(engine, argc, argv, 1, INK_STRING)) { return NULL_OBJ; } Ink_Object *msg = base->getSlot(engine, "msg"); if (msg->type != INK_STRING) { InkWarn_Multink_Message_is_not_a_String(engine); return NULL_OBJ; } Ink_InterpreteEngine *dest = InkActor_getActor(as<Ink_String>(argv[0])->getValue()); if (!dest) { InkWarn_Multink_Actor_Not_Found(engine, as<Ink_String>(argv[0])->getValue().c_str()); return NULL_OBJ; } dest->sendInMessage(engine, as<Ink_String>(msg)->getValue()); return TRUE_OBJ; }
Ink_Object *Ink_CallExpression::eval(Ink_InterpreteEngine *engine, Ink_ContextChain *context_chain, Ink_EvalFlag flags) { const char *file_name_back; Ink_LineNoType line_num_back; SET_LINE_NUM; Ink_ArgumentList::size_type i; Ink_Object **argv = NULL, **argv_back = NULL; Ink_Object *ret_val, *expandee; /* eval callee to get parameter declaration */ Ink_Object *func = callee->eval(engine, context_chain); Ink_FunctionObject *tmp_func = NULL; if (INTER_SIGNAL_RECEIVED) return engine->getInterruptValue(); Ink_ParamList param_list = Ink_ParamList(); Ink_ArgumentList dispose_list, tmp_arg_list, another_tmp_arg_list; /* this part was moved from Ink_FunctionObject::call */ bool is_arg_completed = true, if_delete_argv = false; Ink_ArgcType tmp_argc, j, argi, argc; Ink_Object **tmp_argv; if (func->type == INK_FUNCTION) { param_list = as<Ink_FunctionObject>(func)->param; tmp_func = as<Ink_FunctionObject>(func); } if (is_new) { func = Ink_HashExpression::getSlot(engine, context_chain, func, "new"); } tmp_arg_list = Ink_ArgumentList(); for (Ink_ArgumentList::iterator arg_list_iter = arg_list.begin(); arg_list_iter != arg_list.end(); arg_list_iter++) { if ((*arg_list_iter)->is_expand) { /* if the argument is 'with' argument attachment */ /* eval expandee */ expandee = (*arg_list_iter)->expandee->eval(engine, context_chain); if (INTER_SIGNAL_RECEIVED) { ret_val = engine->getInterruptValue(); goto DISPOSE_LIST; } /* expand argument */ another_tmp_arg_list = expandArgument(engine, expandee); /* insert expanded argument to dispose list and temporary argument list */ dispose_list.insert(dispose_list.end(), another_tmp_arg_list.begin(), another_tmp_arg_list.end()); tmp_arg_list.insert(tmp_arg_list.end(), another_tmp_arg_list.begin(), another_tmp_arg_list.end()); } else { /* normal argument, directly push to argument list */ tmp_arg_list.push_back(*arg_list_iter); } } if (tmp_arg_list.size()) { /* allocate argument list */ argv = (Ink_Object **)malloc(tmp_arg_list.size() * sizeof(Ink_Object *)); argv_back = argv; /* set argument list, according to the parameter declaration */ for (i = 0; i < tmp_arg_list.size(); i++) { if (i < param_list.size() && param_list[i].is_ref) { /* if the paramete is declared as reference, seal the expression to a anonymous function */ if (param_list[i].is_variant) { for (; i < tmp_arg_list.size(); i++) { if (tmp_arg_list[i]->arg->is_unknown) { argv[i] = new Ink_Unknown(engine); } else { Ink_ExpressionList exp_list = Ink_ExpressionList(); exp_list.push_back(tmp_arg_list[i]->arg); argv[i] = new Ink_FunctionObject(engine, Ink_ParamList(), exp_list, context_chain->copyContextChain(), true); } } } else { if (tmp_arg_list[i]->arg->is_unknown) { argv[i] = new Ink_Unknown(engine); } else { Ink_ExpressionList exp_list = Ink_ExpressionList(); exp_list.push_back(tmp_arg_list[i]->arg); argv[i] = new Ink_FunctionObject(engine, Ink_ParamList(), exp_list, context_chain->copyContextChain(), true); } } } else { /* normal argument */ argv[i] = tmp_arg_list[i]->arg->eval(engine, context_chain); if (INTER_SIGNAL_RECEIVED) { ret_val = engine->getInterruptValue(); /* goto dispose and interrupt */ goto DISPOSE_ARGV; } } } } argc = tmp_arg_list.size(); /* if some arguments have been applied already */ if (tmp_func && tmp_func->partial_applied_argv) { tmp_argc = tmp_func->partial_applied_argc; tmp_argv = copyArgv(tmp_func->partial_applied_argc, tmp_func->partial_applied_argv); for (j = 0, argi = 0; j < tmp_argc; j++) { /* find unknown place to put in arguments */ if (isUnknown(tmp_argv[j])) { if (argi < argc /* not excess */ && !isUnknown(argv[argi]) /* not another unknown argument */) tmp_argv[j] = argv[argi]; else is_arg_completed = false; argi++; } } if (!is_arg_completed) { /* still missing arguments -- return another PAF */ if (argi < argc) { Ink_ArgcType remainc = argc - argi; /* remaining arguments */ argc = remainc + tmp_argc; /* link the PA arguments and remaining arguments */ argv = linkArgv(tmp_argc, tmp_argv, remainc, &argv[argi]); free(tmp_argv); tmp_argc = argc; tmp_argv = argv; } ret_val = tmp_func->cloneWithPA(engine, tmp_argc, tmp_argv, true); goto DISPOSE_ARGV; } Ink_ArgcType remainc = argc - argi; /* remaining arguments */ argc = remainc + tmp_argc; /* link the PA arguments and remaining arguments */ argv = linkArgv(tmp_argc, tmp_argv, remainc, &argv[argi]); free(tmp_argv); if_delete_argv = true; } for (argi = 0; tmp_func && argi < argc; argi++) { if (isUnknown(argv[argi])) { /* find unknown argument */ ret_val = tmp_func->cloneWithPA(engine, argc, copyArgv(argc, argv), true); goto DISPOSE_ARGV; } } ret_val = func->call(engine, context_chain, argc, argv); DISPOSE_ARGV: if (if_delete_argv) free(argv); if (argv_back) free(argv_back); DISPOSE_LIST: for (i = 0; i < dispose_list.size(); i++) { delete dispose_list[i]; } RESTORE_LINE_NUM; return ret_val; }
Ink_Object *Ink_HashExpression::getSlot(Ink_InterpreteEngine *engine, Ink_ContextChain *context_chain, Ink_Object *obj, const char *id, Ink_EvalFlag flags, string *id_p) { const char *debug_name_back; Ink_HashTable *hash, *address; Ink_Object *base = obj, *ret, *tmp; Ink_Object **argv; ProtoSearchRet search_res; if (!(hash = obj->getSlotMapping(engine, id)) /* cannot find slot in the origin object */) { if (obj->type == INK_UNDEFINED) { InkWarn_Get_Slot_Of_Undefined(engine, id); } /* search prototype */ engine->initPrototypeSearch(); hash = (search_res = searchPrototype(engine, obj, id)).hash; /* create barrier to prevent changes on prototype */ address = obj->setSlot(id, NULL, id_p); if (hash) { /* if found the slot in prototype */ base = search_res.base; /* set base as the prototype(to make some native method run correctly) */ ret = hash->getValue(); } else { if ((tmp = obj->getSlot(engine, "missing"))->type == INK_FUNCTION) { /* has missing method, call it */ tmp->setSlot("base", obj); argv = (Ink_Object **)malloc(sizeof(Ink_Object *)); argv[0] = new Ink_String(engine, string(id)); ret = tmp->call(engine, context_chain, 1, argv); free(argv); goto END; } else { /* return undefined */ ret = UNDEFINED; } } } else { /* found slot correctly */ ret = hash->getValue(); address = hash; delete id_p; } /* set address for possible assignment */ ret->address = address; /* set base */ debug_name_back = base->getDebugName(); ret->setSlot("base", base); base->setDebugName(debug_name_back); /* call getter if has one */ if (!flags.is_left_value && address->getter) { address->getter->setSlot("base", address->getValue()); ret = address->getter->call(engine, context_chain, 0, NULL); // /* trap all interrupt signal */ // engine->setSignal(INTER_NONE); if (INTER_SIGNAL_RECEIVED) { return engine->getInterruptValue(); } } END: return ret; }
Ink_Object *InkNative_Direct_Each(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p) { Ink_Object *base = context->searchSlot(engine, "base"); string *tmp_path; Ink_Object **args = NULL; Ink_Object *ret_tmp; Ink_ArrayValue ret_val; Ink_ArrayValue::size_type i; Ink_Object *block = NULL; ASSUME_BASE_TYPE(engine, DIRECT_TYPE); if (!(tmp_path = as<Ink_DirectPointer>(base)->path)) { InkWarn_IO_Uninitialized_Direct_Pointer(engine); return NULL_OBJ; } if (argc && argv[0]->type == INK_FUNCTION) block = argv[0]; args = (Ink_Object **)malloc(sizeof(Ink_Object *)); #if defined(INK_PLATFORM_LINUX) DIR *dir_handle = opendir(tmp_path->c_str()); struct dirent *child; if (!dir_handle) { InkWarn_Direct_Not_Exist(engine, tmp_path->c_str()); free(args); return NULL_OBJ; } while ((child = readdir(dir_handle)) != NULL) { #define CLOSE_HANDLER closedir(dir_handle) #define CHILD_NAME (child->d_name) #elif defined(INK_PLATFORM_WIN32) WIN32_FIND_DATA data; HANDLE dir_handle = NULL; dir_handle = FindFirstFile((string(INK_MODULE_DIR) + "/*").c_str(), &data); if (dir_handle == INVALID_HANDLE_VALUE) { do { #define CLOSE_HANDLER FindClose(dir_handle) #define CHILD_NAME (data.cFileName) #endif if (block) { args[0] = new Ink_String(engine, string(CHILD_NAME)); ret_val.push_back(new Ink_HashTable(ret_tmp = block->call(engine, context, 1, args))); if (engine->getSignal() != INTER_NONE) { switch (engine->getSignal()) { case INTER_RETURN: free(args); cleanArrayHashTable(ret_val); CLOSE_HANDLER; return engine->getInterruptValue(); // signal penetrated case INTER_DROP: case INTER_BREAK: free(args); cleanArrayHashTable(ret_val); CLOSE_HANDLER; 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); CLOSE_HANDLER; return NULL_OBJ; } } } else { ret_val.push_back(new Ink_HashTable(new Ink_String(engine, string(CHILD_NAME)))); } #if defined(INK_PLATFORM_LINUX) } closedir(dir_handle); #elif defined(INK_PLATFORM_WIN32) } while (FindNextFile(dir_handle, &data)); } else {
Ink_Object *InkNative_Object_Clone(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p) { Ink_Object *base = context->searchSlot(engine, "base"); return base->clone(engine); }