Expression *TypeCompiler::visit(CallExpression *call) { MethodBase *methodBase = call->methodBase; call->function->visitExpression(this); // check whether we're calling a methodbase if (methodBase) { lmAssert(methodBase->isMethod(), "Non-method called"); MethodInfo *method = (MethodInfo *)methodBase; generateCall(&call->function->e, call->arguments, method); call->e = call->function->e; } else { lmAssert(call->function->type, "Untyped call"); // if we're calling a delegate we need to load up the call method if (call->function->type->isDelegate()) { MethodInfo *method = (MethodInfo *)call->function->type->findMember("call"); lmAssert(method, "delegate with no call method"); ExpDesc right; BC::initExpDesc(&right, VKNUM, 0); right.u.nval = method->getOrdinal(); BC::expToNextReg(cs->fs, &call->function->e); BC::expToNextReg(cs->fs, &right); BC::expToVal(cs->fs, &right); BC::indexed(cs->fs, &call->function->e, &right); generateCall(&call->function->e, call->arguments, NULL); call->e = call->function->e; } else { // we're directly calling a local, instance (bound), or static method of type Function generateCall(&call->function->e, call->arguments, NULL); call->e = call->function->e; } } return call; }
PropertyInfo *PropertyInfoReader::deserializePropertyInfo(Type *declaringType, json_t *json) { PropertyInfo *pi = new PropertyInfo(); MemberInfoReader::deserialize(pi, json); // handle attr json_t *marray = json_object_get(json, "propertyattributes"); for (size_t i = 0; i < json_array_size(marray); i++) { utString modifier = json_string_value(json_array_get(marray, i)); if (modifier == "static") { pi->attr.isStatic = true; } else if (modifier == "public") { pi->attr.isPublic = true; } else if (modifier == "private") { pi->attr.isPrivate = true; } else if (modifier == "protected") { pi->attr.isProtected = true; } else if (modifier == "native") { pi->attr.isNative = true; } } utString stype = json_string_value(json_object_get(json, "type")); if (stype.size() > 0) { // a shortcut? pi->type = declaringType->getModule()->getAssembly()->getLuaState()->getType( stype.c_str()); assert(pi->type); } json_t *getter = json_object_get(json, "getter"); json_t *setter = json_object_get(json, "setter"); if (getter) { MethodBase *m = NULL; m = MethodReader::deserializeMethodInfo(declaringType, getter); assert(m->isMethod()); pi->getter = (MethodInfo *)m; m->setPropertyInfo(pi); } if (setter) { MethodBase *m = NULL; m = MethodReader::deserializeMethodInfo(declaringType, setter); assert(m->isMethod()); pi->setter = (MethodInfo *)m; m->setPropertyInfo(pi); } json_t *ttypes = json_object_get(json, "templatetypes"); if (ttypes && json_is_object(ttypes)) { TemplateInfo *info = MemberInfoReader::readTemplateTypeInfo(ttypes); assert(info); info->resolveTypes(Assembly::getAssembly(declaringType)->getLuaState()); pi->setTemplateInfo(info); } return pi; }
/* * Static methods use the lsr_method closure which is generated at class initialization time * Instance methods are bound to a generated lsr_method closure the first time the method is referenced (at runtime) * lsr_method is a thin wrapper which handles catching native calls for profiling, default arguments, etc */ int lsr_method(lua_State *L) { int nargs = lua_gettop(L); MethodBase *method = (MethodBase *)lua_topointer(L, lua_upvalueindex(1)); bool staticCall = method->isStatic(); if (staticCall) { lua_pushvalue(L, lua_upvalueindex(2)); lua_insert(L, 1); // method } else { lua_pushvalue(L, lua_upvalueindex(2)); lua_insert(L, 1); // this (can be a loomscript table or luabridge userdata lua_pushvalue(L, lua_upvalueindex(3)); lua_insert(L, 1); // method } int dargs = nargs; int fidx = method->getFirstDefaultParm(); int varArgIdx = method->getVarArgIndex(); int varArgVectorIdx = lua_gettop(L); // don't consider the varargs in when // checking whether we need to insert default arguments if ((fidx != -1) && (varArgIdx != -1)) { dargs--; } if (dargs < method->getNumParameters()) { // TODO: Report line numbers LOOM-603 // if we have var args and not enough parameters, VM will insert null for ...args value // otherwise, we have a compiler error if (varArgIdx < 0) { lmAssert(fidx >= 0, "Method '%s::%s' called with too few arguments.", method->getDeclaringType()->getFullName().c_str(), method->getStringSignature().c_str()); } bool inserted = false; for (int i = dargs; i < method->getNumParameters(); i++) { if (i == varArgIdx) { break; } lua_pushvalue(L, lua_upvalueindex(i - fidx + (staticCall ? 3 : 4))); inserted = true; nargs++; } // if we inserted *and* have var args, we // need to shift the var args to the end if (inserted && (varArgIdx != -1)) { lua_pushvalue(L, varArgVectorIdx); lua_remove(L, varArgVectorIdx); } } LSLuaState *ls = LSLuaState::getLuaState(L); // error handling lua_getglobal(L, "__ls_traceback"); lua_insert(L, 1); if (lua_pcall(L, nargs + (staticCall ? 0 : 1), LUA_MULTRET, 1)) { ls->triggerRuntimeError("Error calling %s:%s", method->getDeclaringType()->getFullName().c_str(), method->getName()); } // get rid of the traceback lua_remove(L, 1); int nreturn = lua_gettop(L); if (nreturn == 1) { if (method->isNative() && method->isMethod() && lua_isuserdata(L, -1)) { lualoom_pushnative_userdata(L, ((MethodInfo *)method)->getReturnType(), -1); } } return nreturn; }