Commits

Bart van Strien committed 7b8743b

Start implementing objc->lua, lua can now construct classes, and have functions be called (without arguments)

Comments (0)

Files changed (1)

 	return [self initWithReceiver: receiver andMethod: m];
 }
 
-- (id) initWithReceiver: (id) receiver_ andMethod: (Method) method_
+- (id) initWithReceiver: (id) receiver andMethod: (Method) method
 {
 	self->receiver = receiver;
 	self->method = method;
 
 static void wrapInstance(lua_State *L, id instance);
 static void wrapClass(lua_State *L, Class cls);
+static id checkReceiver(lua_State *L, int idx);
+
+static int pushValue(lua_State *L, ObjLuaValue *val, char type)
+{
+	switch(type)
+	{
+	case 'c':
+	case 'C':
+		lua_pushlstring(L, (const char*) &val->uint8, 1);
+		return 1;
+	case 'i':
+	case 's':
+	case 'l':
+		lua_pushnumber(L, val->sint32);
+		return 1;
+	case 'I':
+	case 'S':
+	case 'L':
+		lua_pushnumber(L, val->uint32);
+		return 1;
+	case 'q':
+		lua_pushnumber(L, val->sint64);
+		return 1;
+	case 'Q':
+		lua_pushnumber(L, val->uint64);
+		return 1;
+	case 'f':
+		lua_pushnumber(L, val->singleFloat);
+		return 1;
+	case 'd':
+		lua_pushnumber(L, val->doubleFloat);
+		return 1;
+	case '*':
+		lua_pushstring(L, val->pointer);
+		return 1;
+	case '@':
+		wrapInstance(L, val->pointer);
+		return 1;
+	case '#':
+		wrapClass(L, val->pointer);
+		return 1;
+	case ':':
+	case '[':
+	case '{':
+	case '^':
+	case '?':
+		lua_pushlightuserdata(L, val->pointer);
+		return 1;
+	}
+	return 0;
+}
+
+static void getValue(lua_State *L, int idx, ObjLuaValue *value, char type)
+{
+	switch(type)
+	{
+	case 'c':
+	case 'C':
+		value->uint8 = *luaL_checkstring(L, idx);
+		break;
+	case 'i':
+	case 's':
+	case 'l':
+		value->sint32 = luaL_checkint(L, idx);
+		break;
+	case 'I':
+	case 'S':
+	case 'L':
+		value->uint32 = luaL_checkint(L, idx);
+		break;
+	case 'q':
+		value->sint64 = (int64_t) luaL_checknumber(L, idx);
+		break;
+	case 'Q':
+		value->uint64 = (uint64_t) luaL_checknumber(L, idx);
+		break;
+	case 'f':
+		value->singleFloat = (float) luaL_checknumber(L, idx);
+		break;
+	case 'd':
+		value->doubleFloat = luaL_checknumber(L, idx);
+		break;
+	case 'v':
+		break;
+	case '*':
+		value->pointer = (void*) luaL_checkstring(L, idx);
+		break;
+	case '@':
+	case '#':
+		value->pointer = (void*) checkReceiver(L, idx);
+		break;
+	case ':':
+	case '[':
+	case '{':
+	case '^':
+	case '?':
+		value->pointer = (void*) lua_touserdata(L, idx);
+		break;
+	default:
+		value->pointer = NULL;
+		break;
+	}
+}
 
 static int callForward(lua_State *L)
 {
 
 	ObjLuaValue *values = malloc(wrapper.numArgs * sizeof(ObjLuaValue));
 	for (unsigned int i = 0; i < wrapper.numArgs; ++i)
-		switch([wrapper argType: i])
-		{
-		case 'c':
-		case 'C':
-			values[i].uint8 = *luaL_checkstring(L, i+2);
-			break;
-		case 'i':
-		case 's':
-		case 'l':
-			values[i].sint32 = luaL_checkint(L, i+2);
-			break;
-		case 'I':
-		case 'S':
-		case 'L':
-			values[i].uint32 = luaL_checkint(L, i+2);
-			break;
-		case 'q':
-			values[i].sint64 = (int64_t) luaL_checknumber(L, i+2);
-			break;
-		case 'Q':
-			values[i].uint64 = (uint64_t) luaL_checknumber(L, i+2);
-			break;
-		case 'f':
-			values[i].singleFloat = (float) luaL_checknumber(L, i+2);
-			break;
-		case 'd':
-			values[i].doubleFloat = luaL_checknumber(L, i+2);
-			break;
-		case 'v':
-			break;
-		case '*':
-			values[i].pointer = (void*) luaL_checkstring(L, i+2);
-			break;
-		case '@':
-		case '#':
-			if (!lua_istable(L, i+2))
-				return luaL_typerror(L, i+2, "Objective-C receiver");
-			lua_getfield(L, i+2, "#receiver#");
-			if (!lua_islightuserdata(L, -1))
-				return luaL_typerror(L, i+2, "Objective-C receiver");
-			values[i].pointer = lua_touserdata(L, -1);
-			lua_pop(L, 1);
-			break;
-		case ':':
-		case '[':
-		case '{':
-		case '^':
-		case '?':
-			values[i].pointer = (void*) lua_touserdata(L, i+2);
-			break;
-		default:
-			values[i].pointer = NULL;
-			break;
-		}
+		getValue(L, i+2, &values[i], [wrapper argType: i]);
 
 	ObjLuaValue retVal;
 	[wrapper callWithReceiver: receiver withReturn: &retVal andArgs: values]; 
 	free(values);
 
-	switch([wrapper returnType])
-	{
-	case 'c':
-	case 'C':
-		lua_pushlstring(L, (const char*) &retVal.uint8, 1);
-		return 1;
-	case 'i':
-	case 's':
-	case 'l':
-		lua_pushnumber(L, retVal.sint32);
-		return 1;
-	case 'I':
-	case 'S':
-	case 'L':
-		lua_pushnumber(L, retVal.uint32);
-		return 1;
-	case 'q':
-		lua_pushnumber(L, retVal.sint64);
-		return 1;
-	case 'Q':
-		lua_pushnumber(L, retVal.uint64);
-		return 1;
-	case 'f':
-		lua_pushnumber(L, retVal.singleFloat);
-		return 1;
-	case 'd':
-		lua_pushnumber(L, retVal.doubleFloat);
-		return 1;
-	case '*':
-		lua_pushstring(L, retVal.pointer);
-		return 1;
-	case '@':
-		wrapInstance(L, retVal.pointer);
-		return 1;
-	case '#':
-		wrapClass(L, retVal.pointer);
-		return 1;
-	case ':':
-	case '[':
-	case '{':
-	case '^':
-	case '?':
-		lua_pushlightuserdata(L, retVal.pointer);
-		return 1;
-	}
-
-	return 0;
+	return pushValue(L, &retVal, [wrapper returnType]);
 }
 
 static void pushWrapper(lua_State *L, ObjLuaMethodWrapper *wrapper)
 
 extern void doWrap(lua_State *L, id receiver, Class cls, Class (*getParent)(Class, void**), void *userdata)
 {
+	if (receiver == nil || receiver == Nil) // the same?
+	{
+		lua_pushnil(L);
+		return;
+	}
+
 	unsigned int count;
 	Method *methodList;
 	
 	return 1;
 }
 
+static id checkReceiver(lua_State *L, int idx)
+{
+	if (lua_isnil(L, idx))
+		return nil;
+
+	if (!lua_istable(L, idx))
+		luaL_typerror(L, idx, "Objective-C receiver");
+	lua_getfield(L, idx, "#receiver#");
+	if (!lua_islightuserdata(L, -1))
+		luaL_typerror(L, idx, "Objective-C receiver");
+	id receiver = lua_touserdata(L, -1);
+	lua_pop(L, 1);
+	return receiver;
+}
+
+struct callbackSpace
+{
+	lua_State *L;
+	int idx;
+};
+
+static int createClass(lua_State *L)
+{
+	id parent = checkReceiver(L, 1);
+	const char *name = luaL_checkstring(L, 2);
+
+	Class luaClass = objc_allocateClassPair([parent class], name, sizeof(struct callbackSpace));
+	struct callbackSpace *cb = (struct callbackSpace*) object_getIndexedIvars(luaClass);
+	cb->L = lua_newthread(L);
+	cb->idx = lua_objlen(L, LUA_REGISTRYINDEX)+1;
+	lua_rawseti(L, LUA_REGISTRYINDEX, cb->idx);
+
+	lua_newtable(cb->L);
+
+	lua_pushlightuserdata(L, (void*) luaClass);
+	return 1;
+}
+
+static id 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_getfield(cb->L, -1, sel_getName(selector));
+	lua_rawgeti(cb->L, -1, 1);
+
+	lua_pcall(cb->L, 0, 0, 0);
+	lua_pop(cb->L, 1);
+	return nil;
+}
+
+static int addMethod_(lua_State *L, char isInstanceMethod)
+{
+	if (!lua_isuserdata(L, 1))
+		return luaL_typerror(L, 1, "Objective-C class");
+	if (!lua_isuserdata(L, 2))
+		return luaL_typerror(L, 2, "Objective-C selector");
+	if (!lua_isfunction(L, 3))
+		return luaL_typerror(L, 3, "function");
+
+	Class class = lua_touserdata(L, 1);
+	SEL selector = lua_touserdata(L, 2);
+	const char *signature = luaL_checkstring(L, 4);
+
+	// discard everything past argument 2
+	lua_pop(L, lua_gettop(L) - 4);
+
+	// Register our function
+	struct callbackSpace *cb = (struct callbackSpace*) object_getIndexedIvars(class);
+	lua_newtable(cb->L);
+	lua_xmove(L, cb->L, 2);
+	lua_rawseti(cb->L, -3, 2); // signature in [2]
+	lua_rawseti(cb->L, -2, 1); // function in [1]
+
+	lua_setfield(cb->L, -2, sel_getName(selector));
+
+	if (!isInstanceMethod)
+		class = object_getClass(class);
+	lua_pushboolean(L, class_addMethod(class, selector, (IMP) forwarder, signature));
+	return 1;
+}
+
+static int addMethod(lua_State *L)
+{
+	return addMethod_(L, YES);
+}
+
+static int addClassMethod(lua_State *L)
+{
+	return addMethod_(L, NO);
+}
+
+static int finalizeClass(lua_State *L)
+{
+	if (!lua_isuserdata(L, 1))
+		return luaL_typerror(L, 1, "Objective-C class");
+	Class class = lua_touserdata(L, 1);
+
+	objc_registerClassPair(class);
+	return 0;
+}
+
 extern int luaopen_ObjLua(lua_State *L)
 {
 	lua_newtable(L);
 	lua_pushcfunction(L, selectorGetter);
 	lua_setfield(L, -2, "getSelector");
 
+	lua_pushcfunction(L, createClass);
+	lua_setfield(L, -2, "createClass");
+	lua_pushcfunction(L, addMethod);
+	lua_setfield(L, -2, "addMethod");
+	lua_pushcfunction(L, addClassMethod);
+	lua_setfield(L, -2, "addClassMethod");
+	lua_pushcfunction(L, finalizeClass);
+	lua_setfield(L, -2, "finalizeClass");
+
 	return 1;
 }