Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Tree: 7711c800ef
Fetching contributors…

Cannot retrieve contributors at this time

190 lines (145 sloc) 6.136 kB
//
// wax_class.m
// Lua
//
// Created by ProbablyInteractive on 5/20/09.
// Copyright 2009 Probably Interactive. All rights reserved.
//
#import "wax_class.h"
#import "wax.h"
#import "wax_instance.h"
#import "wax_helpers.h"
#import "lua.h"
#import "lauxlib.h"
static int __index(lua_State *L);
static int __call(lua_State *L);
static int addProtocols(lua_State *L);
static int name(lua_State *L);
static id alloc(id self, SEL _cmd);
static id allocWithZone(id self, SEL _cmd, NSZone *);
static id valueForUndefinedKey(id self, SEL cmd, NSString *key);
static void setValueForUndefinedKey(id self, SEL cmd, id value, NSString *key);
static const struct luaL_Reg MetaMethods[] = {
{"__index", __index},
{"__call", __call},
{NULL, NULL}
};
static const struct luaL_Reg Methods[] = {
{"addProtocols", addProtocols},
{"name", name},
{NULL, NULL}
};
int luaopen_wax_class(lua_State *L) {
BEGIN_STACK_MODIFY(L);
luaL_newmetatable(L, WAX_CLASS_METATABLE_NAME);
luaL_register(L, NULL, MetaMethods);
luaL_register(L, WAX_CLASS_METATABLE_NAME, Methods);
// Set the metatable for the module
luaL_getmetatable(L, WAX_CLASS_METATABLE_NAME);
lua_setmetatable(L, -2);
END_STACK_MODIFY(L, 0)
return 1;
}
// Finds an ObjC class
static int __index(lua_State *L) {
const char *className = luaL_checkstring(L, 2);
Class klass = objc_getClass(className);
if (klass) {
wax_instance_create(L, klass, YES);
}
else {
lua_pushnil(L);
}
return 1;
}
// Creates a new ObjC class
static int __call(lua_State *L) {
const char *className = luaL_checkstring(L, 2);
Class klass = objc_getClass(className);
if (!klass) {
Class superClass;
if (lua_isuserdata(L, 3)) {
wax_instance_userdata *instanceUserdata = (wax_instance_userdata *)luaL_checkudata(L, 3, WAX_INSTANCE_METATABLE_NAME);
superClass = instanceUserdata->instance;
}
else if (lua_isnoneornil(L, 3)) {
superClass = [NSObject class];
}
else {
const char *superClassName = luaL_checkstring(L, 3);
superClass = objc_getClass(superClassName);
}
if (!superClass) {
luaL_error(L, "Failed to create '%s'. Unknown superclass \"%s\" received.", className, luaL_checkstring(L, 3));
}
klass = objc_allocateClassPair(superClass, className, 0);
NSUInteger size;
NSUInteger alignment;
NSGetSizeAndAlignment("*", &size, &alignment);
class_addIvar(klass, WAX_CLASS_INSTANCE_USERDATA_IVAR_NAME, size, alignment, "*"); // Holds a reference to the lua userdata
objc_registerClassPair(klass);
// Make Key-Value complient
class_addMethod(klass, @selector(setValue:forUndefinedKey:), (IMP)setValueForUndefinedKey, "v@:@@");
class_addMethod(klass, @selector(valueForUndefinedKey:), (IMP)valueForUndefinedKey, "@@:@");
id metaclass = object_getClass(klass);
// So objects created in ObjC will get an associated lua object
// Store the original allocWithZone implementation in case something secret goes on in there.
// Calls to `alloc` always are end up calling `allocWithZone:` so we don't bother handling alloc here.
Method m = class_getInstanceMethod(metaclass, @selector(allocWithZone:));
// If we the method has already been swizzled (by the class's super, then
// just leave it up to the super!
if (method_getImplementation(m) != (IMP)allocWithZone) {
class_addMethod(metaclass, @selector(wax_originalAllocWithZone:), method_getImplementation(m), method_getTypeEncoding(m));
class_addMethod(metaclass, @selector(allocWithZone:), (IMP)allocWithZone, "@@:^{_NSZone=}");
}
}
wax_instance_create(L, klass, YES);
return 1;
}
static int addProtocols(lua_State *L) {
wax_instance_userdata *instanceUserdata = (wax_instance_userdata *)luaL_checkudata(L, 1, WAX_INSTANCE_METATABLE_NAME);
if (!instanceUserdata->isClass) {
luaL_error(L, "ERROR: Can only set a protocol on a class (You are trying to set one on an instance)");
return 0;
}
for (int i = 2; i <= lua_gettop(L); i++) {
const char *protocolName = luaL_checkstring(L, i);
Protocol *protocol = objc_getProtocol(protocolName);
if (!protocol) luaL_error(L, "Could not find protocol named '%s'\nHint: Sometimes the runtime cannot automatically find a protocol. Try adding it (via xCode) to the file ProtocolLoader.h", protocolName);
class_addProtocol(instanceUserdata->instance, protocol);
}
return 0;
}
static int name(lua_State *L) {
wax_instance_userdata *instanceUserdata = (wax_instance_userdata *)luaL_checkudata(L, 1, WAX_INSTANCE_METATABLE_NAME);
lua_pushstring(L, [NSStringFromClass([instanceUserdata->instance class]) UTF8String]);
return 1;
}
static id allocWithZone(id self, SEL _cmd, NSZone *zone) {
lua_State *L = wax_currentLuaState();
BEGIN_STACK_MODIFY(L);
id instance = [self wax_originalAllocWithZone:zone];
object_setInstanceVariable(instance, WAX_CLASS_INSTANCE_USERDATA_IVAR_NAME, @"YEAP");
END_STACK_MODIFY(L, 0);
return instance;
}
static void setValueForUndefinedKey(id self, SEL cmd, id value, NSString *key) {
lua_State *L = wax_currentLuaState();
BEGIN_STACK_MODIFY(L);
wax_instance_pushUserdata(L, self);
wax_fromObjc(L, "@", &value);
lua_setfield(L, -2, [key UTF8String]);
END_STACK_MODIFY(L, 0);
}
static id valueForUndefinedKey(id self, SEL cmd, NSString *key) {
lua_State *L = wax_currentLuaState();
id result = nil;
BEGIN_STACK_MODIFY(L);
wax_instance_pushUserdata(L, self);
lua_getfield(L, -1, [key UTF8String]);
id *keyValue = wax_copyToObjc(L, "@", -1, nil);
result = *keyValue;
free(keyValue);
END_STACK_MODIFY(L, 0);
return result;
}
Jump to Line
Something went wrong with that request. Please try again.