1. Bart van Strien
  2. llvmloader

Commits

Bart van Strien  committed 35628ee

Fix defining objc classes from lua

  • Participants
  • Parent commits 7b8743b
  • Branches default

Comments (0)

Files changed (1)

File ObjLua.m

View file
 	lua_rawseti(L, LUA_REGISTRYINDEX, cb->idx);
 
 	lua_newtable(cb->L);
+	lua_setglobal(cb->L, "__objlua__");
 
 	lua_pushlightuserdata(L, (void*) luaClass);
 	return 1;
 }
 
-static id forwarder(id receiver, SEL selector, ...)
+static ObjLuaValue forwarder(id receiver, SEL selector, ...)
 {
 	Class luaClass = object_getClass(receiver);
 	if (class_isMetaClass(luaClass))
 		luaClass = receiver;
 
 	struct callbackSpace *cb = (struct callbackSpace*) object_getIndexedIvars(luaClass);
+	lua_getglobal(cb->L, "__objlua__");
 	lua_getfield(cb->L, -1, sel_getName(selector));
-	lua_rawgeti(cb->L, -1, 1);
+	lua_rawgeti(cb->L, -1, 2);
+	lua_rawgeti(cb->L, -2, 1);
 
-	lua_pcall(cb->L, 0, 0, 0);
-	lua_pop(cb->L, 1);
-	return nil;
+	va_list vargs;
+	va_start(vargs, selector);
+
+	const char *signature = lua_tostring(cb->L, -2);
+	unsigned int nargs = strlen(signature)-3;
+	ObjLuaValue *values = malloc(nargs*sizeof(ObjLuaValue));
+	char type;
+	for (unsigned int i = 0; i < nargs && (type = signature[i+3]); ++i)
+		switch(type)
+		{
+		case 'c':
+		case 'C':
+			values[i].uint8 = va_arg(vargs, uint8_t);
+			break;
+		case 'i':
+		case 's':
+		case 'l': // whether it's signed or not, this is all about bits
+		case 'I':
+		case 'S':
+		case 'L':
+			values[i].uint32 = va_arg(vargs, uint32_t);
+			break;
+		case 'q':
+		case 'Q':
+			values[i].uint64 = va_arg(vargs, uint64_t);
+			break;
+		case 'f':
+			values[i].singleFloat = va_arg(vargs, float);
+			break;
+		case 'd':
+			values[i].doubleFloat = va_arg(vargs, double);
+			break;
+		case 'v':
+			break;
+		case '*':
+		case '@':
+		case '#':
+		case ':':
+		case '[':
+		case '{':
+		case '^':
+		case '?':
+			values[i].pointer = va_arg(vargs, void*);
+			break;
+		default:
+			values[i].pointer = NULL;
+			break;
+		}
+
+	ObjLuaValue selfReference = (ObjLuaValue) (void*) receiver;
+	pushValue(cb->L, &selfReference, '@');
+	for (unsigned int i = 0; i < nargs && (type = signature[i+3]); ++i)
+		pushValue(cb->L, &values[i], type);
+
+	va_end(vargs);
+
+	ObjLuaValue retVal = (ObjLuaValue) NULL;
+	int numRetVals = 1;
+	if (signature[0] == 'v')
+		numRetVals = 0;
+
+	lua_pcall(cb->L, nargs+1, numRetVals, 0);
+	if (numRetVals)
+		getValue(cb->L, -1, &retVal, signature[0]);
+
+	lua_pop(cb->L, 3);
+
+	free(values);
+	return retVal;
 }
 
 static int addMethod_(lua_State *L, char isInstanceMethod)
 
 	Class class = lua_touserdata(L, 1);
 	SEL selector = lua_touserdata(L, 2);
-	const char *signature = luaL_checkstring(L, 4);
+	const char *returnType = luaL_optstring(L, 4, "v");
+	const char *argTypes = luaL_optstring(L, 5, "");
+
+	unsigned int sigLength = 3+strlen(argTypes);
+	char *signature = malloc(sigLength+1);
+	signature[0] = returnType[0];
+	signature[1] = '@';
+	signature[2] = ':';
+	memcpy(&signature[3], argTypes, sigLength-3);
+	signature[sigLength] = 0;
 
 	// discard everything past argument 2
-	lua_pop(L, lua_gettop(L) - 4);
+	lua_pop(L, lua_gettop(L) - 3);
 
 	// Register our function
 	struct callbackSpace *cb = (struct callbackSpace*) object_getIndexedIvars(class);
+	lua_getglobal(cb->L, "__objlua__");
 	lua_newtable(cb->L);
-	lua_xmove(L, cb->L, 2);
+	lua_xmove(L, cb->L, 1);
+	lua_pushstring(cb->L, signature);
 	lua_rawseti(cb->L, -3, 2); // signature in [2]
 	lua_rawseti(cb->L, -2, 1); // function in [1]
 
 	if (!isInstanceMethod)
 		class = object_getClass(class);
 	lua_pushboolean(L, class_addMethod(class, selector, (IMP) forwarder, signature));
+
+	free(signature);
 	return 1;
 }