candle 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +20 -0
- data/README.md +4 -0
- data/VERSION +1 -0
- data/bin/candle +21 -0
- data/lib/candle.rb +68 -0
- data/lib/candle/command.rb +27 -0
- data/lib/candle/generators/actions.rb +183 -0
- data/lib/candle/generators/blank.rb +127 -0
- data/lib/candle/generators/cli.rb +55 -0
- data/lib/candle/generators/help.rb +47 -0
- data/lib/candle/generators/jam.rb +80 -0
- data/lib/candle/generators/lua/scripts/AppDelegate.lua +36 -0
- data/lib/candle/generators/lua/scripts/tests/init.lua +6 -0
- data/lib/candle/generators/lua/scripts/tests/someTest.lua +12 -0
- data/lib/candle/generators/lua/wax/ProtocolLoader.h +12 -0
- data/lib/candle/generators/lua/wax/bin/hammer +157 -0
- data/lib/candle/generators/lua/wax/bin/update-xibs +131 -0
- data/lib/candle/generators/lua/wax/bin/waxsim +0 -0
- data/lib/candle/generators/lua/wax/lib/build-scripts/compile-stdlib.sh +14 -0
- data/lib/candle/generators/lua/wax/lib/build-scripts/copy-scripts.sh +58 -0
- data/lib/candle/generators/lua/wax/lib/build-scripts/luac.lua +80 -0
- data/lib/candle/generators/lua/wax/lib/extensions/CGAffine/wax_CGTransform.h +12 -0
- data/lib/candle/generators/lua/wax/lib/extensions/CGAffine/wax_CGTransform.m +85 -0
- data/lib/candle/generators/lua/wax/lib/extensions/CGContext/wax_CGContext.h +12 -0
- data/lib/candle/generators/lua/wax/lib/extensions/CGContext/wax_CGContext.m +251 -0
- data/lib/candle/generators/lua/wax/lib/extensions/HTTP/wax_http.h +14 -0
- data/lib/candle/generators/lua/wax/lib/extensions/HTTP/wax_http.m +240 -0
- data/lib/candle/generators/lua/wax/lib/extensions/HTTP/wax_http_connection.h +54 -0
- data/lib/candle/generators/lua/wax/lib/extensions/HTTP/wax_http_connection.m +304 -0
- data/lib/candle/generators/lua/wax/lib/extensions/filesystem/wax_filesystem.h +9 -0
- data/lib/candle/generators/lua/wax/lib/extensions/filesystem/wax_filesystem.m +273 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/Rakefile +10 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/wax_json.c +304 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/wax_json.h +11 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl-1.0.9.tar.gz +0 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/api/yajl_common.h +85 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/api/yajl_gen.h +159 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/api/yajl_parse.h +193 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/yajl.c +159 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/yajl_alloc.c +65 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/yajl_alloc.h +50 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/yajl_buf.c +119 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/yajl_buf.h +73 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/yajl_bytestack.h +85 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/yajl_common.h +85 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/yajl_encode.c +188 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/yajl_encode.h +50 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/yajl_gen.c +322 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/yajl_gen.h +159 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/yajl_lex.c +737 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/yajl_lex.h +133 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/yajl_parse.h +193 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/yajl_parser.c +448 -0
- data/lib/candle/generators/lua/wax/lib/extensions/json/yajl/yajl_parser.h +82 -0
- data/lib/candle/generators/lua/wax/lib/lua/lapi.c +1087 -0
- data/lib/candle/generators/lua/wax/lib/lua/lapi.h +16 -0
- data/lib/candle/generators/lua/wax/lib/lua/lauxlib.c +652 -0
- data/lib/candle/generators/lua/wax/lib/lua/lauxlib.h +174 -0
- data/lib/candle/generators/lua/wax/lib/lua/lbaselib.c +653 -0
- data/lib/candle/generators/lua/wax/lib/lua/lcode.c +839 -0
- data/lib/candle/generators/lua/wax/lib/lua/lcode.h +76 -0
- data/lib/candle/generators/lua/wax/lib/lua/ldblib.c +397 -0
- data/lib/candle/generators/lua/wax/lib/lua/ldebug.c +638 -0
- data/lib/candle/generators/lua/wax/lib/lua/ldebug.h +33 -0
- data/lib/candle/generators/lua/wax/lib/lua/ldo.c +518 -0
- data/lib/candle/generators/lua/wax/lib/lua/ldo.h +57 -0
- data/lib/candle/generators/lua/wax/lib/lua/ldump.c +164 -0
- data/lib/candle/generators/lua/wax/lib/lua/lfunc.c +174 -0
- data/lib/candle/generators/lua/wax/lib/lua/lfunc.h +34 -0
- data/lib/candle/generators/lua/wax/lib/lua/lgc.c +711 -0
- data/lib/candle/generators/lua/wax/lib/lua/lgc.h +110 -0
- data/lib/candle/generators/lua/wax/lib/lua/linit.c +38 -0
- data/lib/candle/generators/lua/wax/lib/lua/liolib.c +553 -0
- data/lib/candle/generators/lua/wax/lib/lua/llex.c +461 -0
- data/lib/candle/generators/lua/wax/lib/lua/llex.h +81 -0
- data/lib/candle/generators/lua/wax/lib/lua/llimits.h +128 -0
- data/lib/candle/generators/lua/wax/lib/lua/lmathlib.c +263 -0
- data/lib/candle/generators/lua/wax/lib/lua/lmem.c +86 -0
- data/lib/candle/generators/lua/wax/lib/lua/lmem.h +49 -0
- data/lib/candle/generators/lua/wax/lib/lua/loadlib.c +666 -0
- data/lib/candle/generators/lua/wax/lib/lua/lobject.c +214 -0
- data/lib/candle/generators/lua/wax/lib/lua/lobject.h +381 -0
- data/lib/candle/generators/lua/wax/lib/lua/lopcodes.c +102 -0
- data/lib/candle/generators/lua/wax/lib/lua/lopcodes.h +268 -0
- data/lib/candle/generators/lua/wax/lib/lua/loslib.c +243 -0
- data/lib/candle/generators/lua/wax/lib/lua/lparser.c +1339 -0
- data/lib/candle/generators/lua/wax/lib/lua/lparser.h +82 -0
- data/lib/candle/generators/lua/wax/lib/lua/lstate.c +214 -0
- data/lib/candle/generators/lua/wax/lib/lua/lstate.h +169 -0
- data/lib/candle/generators/lua/wax/lib/lua/lstring.c +111 -0
- data/lib/candle/generators/lua/wax/lib/lua/lstring.h +31 -0
- data/lib/candle/generators/lua/wax/lib/lua/lstrlib.c +869 -0
- data/lib/candle/generators/lua/wax/lib/lua/ltable.c +588 -0
- data/lib/candle/generators/lua/wax/lib/lua/ltable.h +40 -0
- data/lib/candle/generators/lua/wax/lib/lua/ltablib.c +287 -0
- data/lib/candle/generators/lua/wax/lib/lua/ltm.c +75 -0
- data/lib/candle/generators/lua/wax/lib/lua/ltm.h +54 -0
- data/lib/candle/generators/lua/wax/lib/lua/lua.h +388 -0
- data/lib/candle/generators/lua/wax/lib/lua/luaconf.h +753 -0
- data/lib/candle/generators/lua/wax/lib/lua/lualib.h +53 -0
- data/lib/candle/generators/lua/wax/lib/lua/lundump.c +227 -0
- data/lib/candle/generators/lua/wax/lib/lua/lundump.h +36 -0
- data/lib/candle/generators/lua/wax/lib/lua/lvm.c +763 -0
- data/lib/candle/generators/lua/wax/lib/lua/lvm.h +36 -0
- data/lib/candle/generators/lua/wax/lib/lua/lzio.c +82 -0
- data/lib/candle/generators/lua/wax/lib/lua/lzio.h +67 -0
- data/lib/candle/generators/lua/wax/lib/lua/print.c +227 -0
- data/lib/candle/generators/lua/wax/lib/project.rake +159 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/enums.lua +396 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/ext/http.lua +43 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/ext/init.lua +4 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/ext/number.lua +21 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/ext/string.lua +97 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/ext/table.lua +165 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/helpers/WaxServer.lua +49 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/helpers/autoload.lua +10 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/helpers/base64.lua +64 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/helpers/bit.lua +274 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/helpers/cache.lua +73 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/helpers/callback.lua +22 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/helpers/frame.lua +76 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/helpers/init.lua +78 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/helpers/pickView.lua +54 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/helpers/time.lua +102 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/init.lua +18 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/luaspec/init.lua +2 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/luaspec/luamock.lua +84 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/luaspec/luaspec.lua +377 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/repl.lua +9 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/structs.lua +11 -0
- data/lib/candle/generators/lua/wax/lib/stdlib/waxClass.lua +42 -0
- data/lib/candle/generators/lua/wax/lib/wax.h +16 -0
- data/lib/candle/generators/lua/wax/lib/wax.m +260 -0
- data/lib/candle/generators/lua/wax/lib/wax_class.h +18 -0
- data/lib/candle/generators/lua/wax/lib/wax_class.m +190 -0
- data/lib/candle/generators/lua/wax/lib/wax_gc.h +20 -0
- data/lib/candle/generators/lua/wax/lib/wax_gc.m +56 -0
- data/lib/candle/generators/lua/wax/lib/wax_helpers.h +102 -0
- data/lib/candle/generators/lua/wax/lib/wax_helpers.m +870 -0
- data/lib/candle/generators/lua/wax/lib/wax_instance.h +34 -0
- data/lib/candle/generators/lua/wax/lib/wax_instance.m +810 -0
- data/lib/candle/generators/lua/wax/lib/wax_server.h +47 -0
- data/lib/candle/generators/lua/wax/lib/wax_server.m +252 -0
- data/lib/candle/generators/lua/wax/lib/wax_stdlib.h +3 -0
- data/lib/candle/generators/lua/wax/lib/wax_struct.h +26 -0
- data/lib/candle/generators/lua/wax/lib/wax_struct.m +335 -0
- data/lib/candle/generators/templates/blank/WaxApplication.xcodeproj/project.pbxproj +836 -0
- data/lib/candle/generators/templates/blank/WaxApplication.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- data/lib/candle/generators/templates/blank/WaxApplication.xcodeproj/project.xcworkspace/xcuserdata/eiffel.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- data/lib/candle/generators/templates/blank/WaxApplication.xcodeproj/xcuserdata/eiffel.xcuserdatad/xcschemes/WaxApplication.xcscheme +86 -0
- data/lib/candle/generators/templates/blank/WaxApplication.xcodeproj/xcuserdata/eiffel.xcuserdatad/xcschemes/xcschememanagement.plist +22 -0
- data/lib/candle/generators/templates/blank/WaxApplication/Default-568h@2x.png +0 -0
- data/lib/candle/generators/templates/blank/WaxApplication/Default.png +0 -0
- data/lib/candle/generators/templates/blank/WaxApplication/Default@2x.png +0 -0
- data/lib/candle/generators/templates/blank/WaxApplication/ProtocolLoader.h +12 -0
- data/lib/candle/generators/templates/blank/WaxApplication/WaxApplication-Info.plist.tt +38 -0
- data/lib/candle/generators/templates/blank/WaxApplication/WaxApplication-Prefix.pch.tt +14 -0
- data/lib/candle/generators/templates/blank/WaxApplication/en.lproj/InfoPlist.strings +2 -0
- data/lib/candle/generators/templates/blank/WaxApplication/main.m.tt +20 -0
- data/lib/candle/tasks.rb +22 -0
- data/lib/candle/utility.rb +30 -0
- data/lib/candle/version.rb +9 -0
- data/lib/candle/view.rb +48 -0
- metadata +582 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
/*
|
2
|
+
* wax_instance.h
|
3
|
+
* Lua
|
4
|
+
*
|
5
|
+
* Created by ProbablyInteractive on 5/18/09.
|
6
|
+
* Copyright 2009 Probably Interactive. All rights reserved.
|
7
|
+
*
|
8
|
+
*/
|
9
|
+
|
10
|
+
#import <Foundation/Foundation.h>
|
11
|
+
#import <objc/runtime.h>
|
12
|
+
#import <objc/message.h>
|
13
|
+
|
14
|
+
#import "lua.h"
|
15
|
+
|
16
|
+
#define WAX_INSTANCE_METATABLE_NAME "wax.instance"
|
17
|
+
|
18
|
+
typedef struct _wax_instance_userdata {
|
19
|
+
id instance;
|
20
|
+
BOOL isClass;
|
21
|
+
Class isSuper; // isSuper not only stores whether the class is a super, but it also contains the value of the next superClass.
|
22
|
+
BOOL actAsSuper; // It only acts like a super once, when it is called for the first time.
|
23
|
+
} wax_instance_userdata;
|
24
|
+
|
25
|
+
int luaopen_wax_instance(lua_State *L);
|
26
|
+
|
27
|
+
wax_instance_userdata *wax_instance_create(lua_State *L, id instance, BOOL isClass);
|
28
|
+
wax_instance_userdata *wax_instance_createSuper(lua_State *L, wax_instance_userdata *instanceUserdata);
|
29
|
+
void wax_instance_pushUserdataTable(lua_State *L);
|
30
|
+
void wax_instance_pushStrongUserdataTable(lua_State *L);
|
31
|
+
|
32
|
+
BOOL wax_instance_pushFunction(lua_State *L, id self, SEL selector);
|
33
|
+
void wax_instance_pushUserdata(lua_State *L, id object);
|
34
|
+
BOOL wax_instance_isWaxClass(id instance);
|
@@ -0,0 +1,810 @@
|
|
1
|
+
/*
|
2
|
+
* wax_instance.c
|
3
|
+
* Lua
|
4
|
+
*
|
5
|
+
* Created by ProbablyInteractive on 5/18/09.
|
6
|
+
* Copyright 2009 Probably Interactive. All rights reserved.
|
7
|
+
*
|
8
|
+
*/
|
9
|
+
|
10
|
+
#import "wax_instance.h"
|
11
|
+
#import "wax_class.h"
|
12
|
+
#import "wax.h"
|
13
|
+
#import "wax_helpers.h"
|
14
|
+
|
15
|
+
#import "lauxlib.h"
|
16
|
+
#import "lobject.h"
|
17
|
+
|
18
|
+
static int __index(lua_State *L);
|
19
|
+
static int __newindex(lua_State *L);
|
20
|
+
static int __gc(lua_State *L);
|
21
|
+
static int __tostring(lua_State *L);
|
22
|
+
static int __eq(lua_State *L);
|
23
|
+
|
24
|
+
static int methods(lua_State *L);
|
25
|
+
|
26
|
+
static int methodClosure(lua_State *L);
|
27
|
+
static int superMethodClosure(lua_State *L);
|
28
|
+
static int customInitMethodClosure(lua_State *L);
|
29
|
+
|
30
|
+
static BOOL overrideMethod(lua_State *L, wax_instance_userdata *instanceUserdata);
|
31
|
+
static int pcallUserdata(lua_State *L, id self, SEL selector, va_list args);
|
32
|
+
|
33
|
+
static const struct luaL_Reg metaFunctions[] = {
|
34
|
+
{"__index", __index},
|
35
|
+
{"__newindex", __newindex},
|
36
|
+
{"__gc", __gc},
|
37
|
+
{"__tostring", __tostring},
|
38
|
+
{"__eq", __eq},
|
39
|
+
{NULL, NULL}
|
40
|
+
};
|
41
|
+
|
42
|
+
static const struct luaL_Reg functions[] = {
|
43
|
+
{"methods", methods},
|
44
|
+
{NULL, NULL}
|
45
|
+
};
|
46
|
+
|
47
|
+
int luaopen_wax_instance(lua_State *L) {
|
48
|
+
BEGIN_STACK_MODIFY(L);
|
49
|
+
|
50
|
+
luaL_newmetatable(L, WAX_INSTANCE_METATABLE_NAME);
|
51
|
+
luaL_register(L, NULL, metaFunctions);
|
52
|
+
luaL_register(L, WAX_INSTANCE_METATABLE_NAME, functions);
|
53
|
+
|
54
|
+
END_STACK_MODIFY(L, 0)
|
55
|
+
|
56
|
+
return 1;
|
57
|
+
}
|
58
|
+
|
59
|
+
#pragma mark Instance Utils
|
60
|
+
#pragma mark -------------------
|
61
|
+
|
62
|
+
// Creates userdata object for obj-c instance/class and pushes it onto the stack
|
63
|
+
wax_instance_userdata *wax_instance_create(lua_State *L, id instance, BOOL isClass) {
|
64
|
+
BEGIN_STACK_MODIFY(L)
|
65
|
+
|
66
|
+
// Does user data already exist?
|
67
|
+
wax_instance_pushUserdata(L, instance);
|
68
|
+
|
69
|
+
if (lua_isnil(L, -1)) {
|
70
|
+
//wax_log(LOG_GC, @"Creating %@ for %@(%p)", isClass ? @"class" : @"instance", [instance class], instance);
|
71
|
+
lua_pop(L, 1); // pop nil stack
|
72
|
+
}
|
73
|
+
else {
|
74
|
+
//wax_log(LOG_GC, @"Found existing userdata %@ for %@(%p)", isClass ? @"class" : @"instance", [instance class], instance);
|
75
|
+
return lua_touserdata(L, -1);
|
76
|
+
}
|
77
|
+
|
78
|
+
size_t nbytes = sizeof(wax_instance_userdata);
|
79
|
+
wax_instance_userdata *instanceUserdata = (wax_instance_userdata *)lua_newuserdata(L, nbytes);
|
80
|
+
instanceUserdata->instance = instance;
|
81
|
+
instanceUserdata->isClass = isClass;
|
82
|
+
instanceUserdata->isSuper = nil;
|
83
|
+
instanceUserdata->actAsSuper = NO;
|
84
|
+
|
85
|
+
if (!isClass) {
|
86
|
+
//wax_log(LOG_GC, @"Retaining %@ for %@(%p -> %p)", isClass ? @"class" : @"instance", [instance class], instance, instanceUserdata);
|
87
|
+
[instanceUserdata->instance retain];
|
88
|
+
}
|
89
|
+
|
90
|
+
// set the metatable
|
91
|
+
luaL_getmetatable(L, WAX_INSTANCE_METATABLE_NAME);
|
92
|
+
lua_setmetatable(L, -2);
|
93
|
+
|
94
|
+
// give it a nice clean environment
|
95
|
+
lua_newtable(L);
|
96
|
+
lua_setfenv(L, -2);
|
97
|
+
|
98
|
+
wax_instance_pushUserdataTable(L);
|
99
|
+
|
100
|
+
// register the userdata table in the metatable (so we can access it from obj-c)
|
101
|
+
//wax_log(LOG_GC, @"Storing reference of %@ to userdata table %@(%p -> %p)", isClass ? @"class" : @"instance", [instance class], instance, instanceUserdata);
|
102
|
+
lua_pushlightuserdata(L, instanceUserdata->instance);
|
103
|
+
lua_pushvalue(L, -3); // Push userdata
|
104
|
+
lua_rawset(L, -3);
|
105
|
+
|
106
|
+
lua_pop(L, 1); // Pop off userdata table
|
107
|
+
|
108
|
+
|
109
|
+
wax_instance_pushStrongUserdataTable(L);
|
110
|
+
lua_pushlightuserdata(L, instanceUserdata->instance);
|
111
|
+
lua_pushvalue(L, -3); // Push userdata
|
112
|
+
lua_rawset(L, -3);
|
113
|
+
|
114
|
+
//wax_log(LOG_GC, @"Storing reference to strong userdata table %@(%p -> %p)", [instance class], instance, instanceUserdata);
|
115
|
+
|
116
|
+
lua_pop(L, 1); // Pop off strong userdata table
|
117
|
+
|
118
|
+
END_STACK_MODIFY(L, 1)
|
119
|
+
|
120
|
+
return instanceUserdata;
|
121
|
+
}
|
122
|
+
|
123
|
+
// Creates pseudo-super userdata object for obj-c instance and pushes it onto the stack
|
124
|
+
wax_instance_userdata *wax_instance_createSuper(lua_State *L, wax_instance_userdata *instanceUserdata) {
|
125
|
+
BEGIN_STACK_MODIFY(L)
|
126
|
+
|
127
|
+
size_t nbytes = sizeof(wax_instance_userdata);
|
128
|
+
wax_instance_userdata *superInstanceUserdata = (wax_instance_userdata *)lua_newuserdata(L, nbytes);
|
129
|
+
superInstanceUserdata->instance = instanceUserdata->instance;
|
130
|
+
superInstanceUserdata->isClass = instanceUserdata->isClass;
|
131
|
+
superInstanceUserdata->actAsSuper = YES;
|
132
|
+
|
133
|
+
// isSuper not only stores whether the class is a super, but it also contains the value of the next superClass
|
134
|
+
if (instanceUserdata->isSuper) {
|
135
|
+
superInstanceUserdata->isSuper = [instanceUserdata->isSuper superclass];
|
136
|
+
}
|
137
|
+
else {
|
138
|
+
superInstanceUserdata->isSuper = [instanceUserdata->instance superclass];
|
139
|
+
}
|
140
|
+
|
141
|
+
|
142
|
+
// set the metatable
|
143
|
+
luaL_getmetatable(L, WAX_INSTANCE_METATABLE_NAME);
|
144
|
+
lua_setmetatable(L, -2);
|
145
|
+
|
146
|
+
wax_instance_pushUserdata(L, instanceUserdata->instance);
|
147
|
+
if (lua_isnil(L, -1)) { // instance has no lua object, push empty env table (This shouldn't happen, tempted to remove it)
|
148
|
+
lua_pop(L, 1); // Remove nil and superclass userdata
|
149
|
+
lua_newtable(L);
|
150
|
+
}
|
151
|
+
else {
|
152
|
+
lua_getfenv(L, -1);
|
153
|
+
lua_remove(L, -2); // Remove nil and superclass userdata
|
154
|
+
}
|
155
|
+
|
156
|
+
// Give it the instance's metatable
|
157
|
+
lua_setfenv(L, -2);
|
158
|
+
|
159
|
+
END_STACK_MODIFY(L, 1)
|
160
|
+
|
161
|
+
return superInstanceUserdata;
|
162
|
+
}
|
163
|
+
|
164
|
+
// The userdata table holds weak references too all the instance userdata
|
165
|
+
// created. This is used to manage all instances of Objective-C objects created
|
166
|
+
// via Lua so we can release/gc them when both Lua and Objective-C are finished with
|
167
|
+
// them.
|
168
|
+
void wax_instance_pushUserdataTable(lua_State *L) {
|
169
|
+
BEGIN_STACK_MODIFY(L)
|
170
|
+
static const char* userdataTableName = "__wax_userdata";
|
171
|
+
luaL_getmetatable(L, WAX_INSTANCE_METATABLE_NAME);
|
172
|
+
lua_getfield(L, -1, userdataTableName);
|
173
|
+
|
174
|
+
if (lua_isnil(L, -1)) { // Create new userdata table, add it to metatable
|
175
|
+
lua_pop(L, 1); // Remove nil
|
176
|
+
|
177
|
+
lua_pushstring(L, userdataTableName); // Table name
|
178
|
+
lua_newtable(L);
|
179
|
+
lua_rawset(L, -3); // Add userdataTableName table to WAX_INSTANCE_METATABLE_NAME
|
180
|
+
lua_getfield(L, -1, userdataTableName);
|
181
|
+
|
182
|
+
lua_pushvalue(L, -1);
|
183
|
+
lua_setmetatable(L, -2); // userdataTable is it's own metatable
|
184
|
+
|
185
|
+
lua_pushstring(L, "v");
|
186
|
+
lua_setfield(L, -2, "__mode"); // Make weak table
|
187
|
+
}
|
188
|
+
|
189
|
+
END_STACK_MODIFY(L, 1)
|
190
|
+
}
|
191
|
+
|
192
|
+
// Holds strong references to userdata created by wax... if the retain count dips below
|
193
|
+
// 2, then we can remove it because we know obj-c doesn't care about it anymore
|
194
|
+
void wax_instance_pushStrongUserdataTable(lua_State *L) {
|
195
|
+
BEGIN_STACK_MODIFY(L)
|
196
|
+
static const char* userdataTableName = "__wax_strong_userdata";
|
197
|
+
luaL_getmetatable(L, WAX_INSTANCE_METATABLE_NAME);
|
198
|
+
lua_getfield(L, -1, userdataTableName);
|
199
|
+
|
200
|
+
if (lua_isnil(L, -1)) { // Create new userdata table, add it to metatable
|
201
|
+
lua_pop(L, 1); // Remove nil
|
202
|
+
|
203
|
+
lua_pushstring(L, userdataTableName); // Table name
|
204
|
+
lua_newtable(L);
|
205
|
+
lua_rawset(L, -3); // Add userdataTableName table to WAX_INSTANCE_METATABLE_NAME
|
206
|
+
lua_getfield(L, -1, userdataTableName);
|
207
|
+
}
|
208
|
+
|
209
|
+
END_STACK_MODIFY(L, 1)
|
210
|
+
}
|
211
|
+
|
212
|
+
|
213
|
+
// First look in the object's userdata for the function, then look in the object's class's userdata
|
214
|
+
BOOL wax_instance_pushFunction(lua_State *L, id self, SEL selector) {
|
215
|
+
BEGIN_STACK_MODIFY(L)
|
216
|
+
|
217
|
+
wax_instance_pushUserdata(L, self);
|
218
|
+
if (lua_isnil(L, -1)) {
|
219
|
+
END_STACK_MODIFY(L, 0)
|
220
|
+
return NO; // userdata doesn't exist
|
221
|
+
}
|
222
|
+
|
223
|
+
lua_getfenv(L, -1);
|
224
|
+
wax_pushMethodNameFromSelector(L, selector);
|
225
|
+
lua_rawget(L, -2);
|
226
|
+
|
227
|
+
BOOL result = YES;
|
228
|
+
|
229
|
+
if (!lua_isfunction(L, -1)) { // function not found in userdata
|
230
|
+
lua_pop(L, 3); // Remove userdata, env and non-function
|
231
|
+
if ([self class] == self) { // This is a class, not an instance
|
232
|
+
result = wax_instance_pushFunction(L, [self superclass], selector); // Check to see if the super classes know about this function
|
233
|
+
}
|
234
|
+
else {
|
235
|
+
result = wax_instance_pushFunction(L, [self class], selector);
|
236
|
+
}
|
237
|
+
}
|
238
|
+
|
239
|
+
END_STACK_MODIFY(L, 1)
|
240
|
+
|
241
|
+
return result;
|
242
|
+
}
|
243
|
+
|
244
|
+
// Retrieves associated userdata for an object from the wax instance userdata table
|
245
|
+
void wax_instance_pushUserdata(lua_State *L, id object) {
|
246
|
+
BEGIN_STACK_MODIFY(L);
|
247
|
+
|
248
|
+
wax_instance_pushUserdataTable(L);
|
249
|
+
lua_pushlightuserdata(L, object);
|
250
|
+
lua_rawget(L, -2);
|
251
|
+
lua_remove(L, -2); // remove userdataTable
|
252
|
+
|
253
|
+
|
254
|
+
END_STACK_MODIFY(L, 1)
|
255
|
+
}
|
256
|
+
|
257
|
+
BOOL wax_instance_isWaxClass(id instance) {
|
258
|
+
// If this is a wax class, or an instance of a wax class, it has the userdata ivar set
|
259
|
+
return class_getInstanceVariable([instance class], WAX_CLASS_INSTANCE_USERDATA_IVAR_NAME) != nil;
|
260
|
+
}
|
261
|
+
|
262
|
+
|
263
|
+
#pragma mark Override Metatable Functions
|
264
|
+
#pragma mark ---------------------------------
|
265
|
+
|
266
|
+
static int __index(lua_State *L) {
|
267
|
+
wax_instance_userdata *instanceUserdata = (wax_instance_userdata *)luaL_checkudata(L, 1, WAX_INSTANCE_METATABLE_NAME);
|
268
|
+
|
269
|
+
if (lua_isstring(L, 2) && strcmp("super", lua_tostring(L, 2)) == 0) { // call to super!
|
270
|
+
wax_instance_createSuper(L, instanceUserdata);
|
271
|
+
return 1;
|
272
|
+
}
|
273
|
+
|
274
|
+
// Check instance userdata, unless we are acting like a super
|
275
|
+
if (!instanceUserdata->actAsSuper) {
|
276
|
+
lua_getfenv(L, -2);
|
277
|
+
lua_pushvalue(L, -2);
|
278
|
+
lua_rawget(L, 3);
|
279
|
+
}
|
280
|
+
else {
|
281
|
+
lua_pushnil(L);
|
282
|
+
}
|
283
|
+
|
284
|
+
// Check instance's class userdata, or if it is a super, check the super's class data
|
285
|
+
Class classToCheck = instanceUserdata->actAsSuper ? instanceUserdata->isSuper : [instanceUserdata->instance class];
|
286
|
+
while (lua_isnil(L, -1) && wax_instance_isWaxClass(classToCheck)) {
|
287
|
+
// Keep checking superclasses if they are waxclasses, we want to treat those like they are lua
|
288
|
+
lua_pop(L, 1);
|
289
|
+
wax_instance_pushUserdata(L, classToCheck);
|
290
|
+
|
291
|
+
// If there is no userdata for this instance's class, then leave the nil on the stack and don't anything else
|
292
|
+
if (!lua_isnil(L, -1)) {
|
293
|
+
lua_getfenv(L, -1);
|
294
|
+
lua_pushvalue(L, 2);
|
295
|
+
lua_rawget(L, -2);
|
296
|
+
lua_remove(L, -2); // Get rid of the userdata env
|
297
|
+
lua_remove(L, -2); // Get rid of the userdata
|
298
|
+
}
|
299
|
+
|
300
|
+
classToCheck = class_getSuperclass(classToCheck);
|
301
|
+
}
|
302
|
+
|
303
|
+
if (lua_isnil(L, -1)) { // If we are calling a super class, or if we couldn't find the index in the userdata environment table, assume it is defined in obj-c classes
|
304
|
+
SEL foundSelectors[2] = {nil, nil};
|
305
|
+
BOOL foundSelector = wax_selectorForInstance(instanceUserdata, foundSelectors, lua_tostring(L, 2), NO);
|
306
|
+
|
307
|
+
if (foundSelector) { // If the class has a method with this name, push as a closure
|
308
|
+
lua_pushstring(L, sel_getName(foundSelectors[0]));
|
309
|
+
foundSelectors[1] ? lua_pushstring(L, sel_getName(foundSelectors[1])) : lua_pushnil(L);
|
310
|
+
lua_pushcclosure(L, instanceUserdata->actAsSuper ? superMethodClosure : methodClosure, 2);
|
311
|
+
}
|
312
|
+
}
|
313
|
+
else if (!instanceUserdata->isSuper && instanceUserdata->isClass && wax_isInitMethod(lua_tostring(L, 2))) { // Is this an init method create in lua?
|
314
|
+
lua_pushcclosure(L, customInitMethodClosure, 1);
|
315
|
+
}
|
316
|
+
|
317
|
+
// Always reset this, an object only acts like a super ONE TIME!
|
318
|
+
instanceUserdata->actAsSuper = NO;
|
319
|
+
|
320
|
+
return 1;
|
321
|
+
}
|
322
|
+
|
323
|
+
static int __newindex(lua_State *L) {
|
324
|
+
wax_instance_userdata *instanceUserdata = (wax_instance_userdata *)luaL_checkudata(L, 1, WAX_INSTANCE_METATABLE_NAME);
|
325
|
+
|
326
|
+
// If this already exists in a protocol, or superclass make sure it will call the lua functions
|
327
|
+
if (instanceUserdata->isClass && lua_type(L, 3) == LUA_TFUNCTION) {
|
328
|
+
overrideMethod(L, instanceUserdata);
|
329
|
+
}
|
330
|
+
|
331
|
+
// Add value to the userdata's environment table
|
332
|
+
lua_getfenv(L, 1);
|
333
|
+
lua_insert(L, 2);
|
334
|
+
lua_rawset(L, 2);
|
335
|
+
|
336
|
+
return 0;
|
337
|
+
}
|
338
|
+
|
339
|
+
static int __gc(lua_State *L) {
|
340
|
+
wax_instance_userdata *instanceUserdata = (wax_instance_userdata *)luaL_checkudata(L, 1, WAX_INSTANCE_METATABLE_NAME);
|
341
|
+
|
342
|
+
//wax_log(LOG_GC, @"Releasing %@ %@(%p)", instanceUserdata->isClass ? @"Class" : @"Instance", [instanceUserdata->instance class], instanceUserdata->instance);
|
343
|
+
|
344
|
+
if (!instanceUserdata->isClass && !instanceUserdata->isSuper) {
|
345
|
+
// This seems like a stupid hack. But...
|
346
|
+
// If we want to call methods on an object durring gc, we have to readd
|
347
|
+
// the instance/userdata to the userdata table. Why? Because it is
|
348
|
+
// removed from the weak table before GC is called.
|
349
|
+
wax_instance_pushUserdataTable(L);
|
350
|
+
lua_pushlightuserdata(L, instanceUserdata->instance);
|
351
|
+
lua_pushvalue(L, -3);
|
352
|
+
lua_rawset(L, -3);
|
353
|
+
|
354
|
+
[instanceUserdata->instance release];
|
355
|
+
|
356
|
+
lua_pushlightuserdata(L, instanceUserdata->instance);
|
357
|
+
lua_pushnil(L);
|
358
|
+
lua_rawset(L, -3);
|
359
|
+
lua_pop(L, 1);
|
360
|
+
}
|
361
|
+
|
362
|
+
return 0;
|
363
|
+
}
|
364
|
+
|
365
|
+
static int __tostring(lua_State *L) {
|
366
|
+
wax_instance_userdata *instanceUserdata = (wax_instance_userdata *)luaL_checkudata(L, 1, WAX_INSTANCE_METATABLE_NAME);
|
367
|
+
lua_pushstring(L, [[NSString stringWithFormat:@"(%p => %p) %@", instanceUserdata, instanceUserdata->instance, instanceUserdata->instance] UTF8String]);
|
368
|
+
|
369
|
+
return 1;
|
370
|
+
}
|
371
|
+
|
372
|
+
static int __eq(lua_State *L) {
|
373
|
+
wax_instance_userdata *o1 = (wax_instance_userdata *)luaL_checkudata(L, 1, WAX_INSTANCE_METATABLE_NAME);
|
374
|
+
wax_instance_userdata *o2 = (wax_instance_userdata *)luaL_checkudata(L, 2, WAX_INSTANCE_METATABLE_NAME);
|
375
|
+
|
376
|
+
lua_pushboolean(L, [o1->instance isEqual:o2->instance]);
|
377
|
+
return 1;
|
378
|
+
}
|
379
|
+
|
380
|
+
#pragma mark Userdata Functions
|
381
|
+
#pragma mark -----------------------
|
382
|
+
|
383
|
+
static int methods(lua_State *L) {
|
384
|
+
wax_instance_userdata *instanceUserdata = (wax_instance_userdata *)luaL_checkudata(L, 1, WAX_INSTANCE_METATABLE_NAME);
|
385
|
+
|
386
|
+
uint count;
|
387
|
+
Method *methods = class_copyMethodList([instanceUserdata->instance class], &count);
|
388
|
+
|
389
|
+
lua_newtable(L);
|
390
|
+
|
391
|
+
for (int i = 0; i < count; i++) {
|
392
|
+
Method method = methods[i];
|
393
|
+
lua_pushstring(L, sel_getName(method_getName(method)));
|
394
|
+
lua_rawseti(L, -2, i + 1);
|
395
|
+
}
|
396
|
+
|
397
|
+
return 1;
|
398
|
+
}
|
399
|
+
|
400
|
+
#pragma mark Function Closures
|
401
|
+
#pragma mark ----------------------
|
402
|
+
|
403
|
+
static int methodClosure(lua_State *L) {
|
404
|
+
if (![[NSThread currentThread] isEqual:[NSThread mainThread]]) NSLog(@"METHODCLOSURE: OH NO SEPERATE THREAD");
|
405
|
+
|
406
|
+
wax_instance_userdata *instanceUserdata = (wax_instance_userdata *)luaL_checkudata(L, 1, WAX_INSTANCE_METATABLE_NAME);
|
407
|
+
const char *selectorName = luaL_checkstring(L, lua_upvalueindex(1));
|
408
|
+
|
409
|
+
// If the only arg is 'self' and there is a selector with no args. USE IT!
|
410
|
+
if (lua_gettop(L) == 1 && lua_isstring(L, lua_upvalueindex(2))) {
|
411
|
+
selectorName = luaL_checkstring(L, lua_upvalueindex(2));
|
412
|
+
}
|
413
|
+
|
414
|
+
SEL selector = sel_getUid(selectorName);
|
415
|
+
id instance = instanceUserdata->instance;
|
416
|
+
BOOL autoAlloc = NO;
|
417
|
+
|
418
|
+
// If init is called on a class, auto-allocate it.
|
419
|
+
if (instanceUserdata->isClass && wax_isInitMethod(selectorName)) {
|
420
|
+
autoAlloc = YES;
|
421
|
+
instance = [instance alloc];
|
422
|
+
}
|
423
|
+
|
424
|
+
NSMethodSignature *signature = [instance methodSignatureForSelector:selector];
|
425
|
+
if (!signature) {
|
426
|
+
const char *className = [NSStringFromClass([instance class]) UTF8String];
|
427
|
+
luaL_error(L, "'%s' has no method selector '%s'", className, selectorName);
|
428
|
+
}
|
429
|
+
|
430
|
+
NSInvocation *invocation = nil;
|
431
|
+
invocation = [NSInvocation invocationWithMethodSignature:signature];
|
432
|
+
|
433
|
+
[invocation setTarget:instance];
|
434
|
+
[invocation setSelector:selector];
|
435
|
+
|
436
|
+
int objcArgumentCount = [signature numberOfArguments] - 2; // skip the hidden self and _cmd argument
|
437
|
+
int luaArgumentCount = lua_gettop(L) - 1;
|
438
|
+
|
439
|
+
|
440
|
+
if (objcArgumentCount > luaArgumentCount && !wax_instance_isWaxClass(instance)) {
|
441
|
+
luaL_error(L, "Not Enough arguments given! Method named '%s' requires %d argument(s), you gave %d. (Make sure you used ':' to call the method)", selectorName, objcArgumentCount + 1, lua_gettop(L));
|
442
|
+
}
|
443
|
+
|
444
|
+
void **arguements = calloc(sizeof(void*), objcArgumentCount);
|
445
|
+
for (int i = 0; i < objcArgumentCount; i++) {
|
446
|
+
arguements[i] = wax_copyToObjc(L, [signature getArgumentTypeAtIndex:i + 2], i + 2, nil);
|
447
|
+
[invocation setArgument:arguements[i] atIndex:i + 2];
|
448
|
+
}
|
449
|
+
|
450
|
+
@try {
|
451
|
+
[invocation invoke];
|
452
|
+
}
|
453
|
+
@catch (NSException *exception) {
|
454
|
+
luaL_error(L, "Error invoking method '%s' on '%s' because %s", selector, class_getName([instance class]), [[exception description] UTF8String]);
|
455
|
+
}
|
456
|
+
|
457
|
+
for (int i = 0; i < objcArgumentCount; i++) {
|
458
|
+
free(arguements[i]);
|
459
|
+
}
|
460
|
+
free(arguements);
|
461
|
+
|
462
|
+
int methodReturnLength = [signature methodReturnLength];
|
463
|
+
if (methodReturnLength > 0) {
|
464
|
+
void *buffer = calloc(1, methodReturnLength);
|
465
|
+
[invocation getReturnValue:buffer];
|
466
|
+
|
467
|
+
wax_fromObjc(L, [signature methodReturnType], buffer);
|
468
|
+
|
469
|
+
if (autoAlloc) {
|
470
|
+
if (lua_isnil(L, -1)) {
|
471
|
+
// The init method returned nil... means initialization failed!
|
472
|
+
// Remove it from the userdataTable (We don't ever want to clean up after this... it should have cleaned up after itself)
|
473
|
+
wax_instance_pushUserdataTable(L);
|
474
|
+
lua_pushlightuserdata(L, instance);
|
475
|
+
lua_pushnil(L);
|
476
|
+
lua_rawset(L, -3);
|
477
|
+
lua_pop(L, 1); // Pop the userdataTable
|
478
|
+
|
479
|
+
lua_pushnil(L);
|
480
|
+
[instance release];
|
481
|
+
}
|
482
|
+
else {
|
483
|
+
wax_instance_userdata *returnedInstanceUserdata = (wax_instance_userdata *)lua_topointer(L, -1);
|
484
|
+
if (returnedInstanceUserdata) { // Could return nil
|
485
|
+
[returnedInstanceUserdata->instance release]; // Wax automatically retains a copy of the object, so the alloc needs to be released
|
486
|
+
}
|
487
|
+
}
|
488
|
+
}
|
489
|
+
|
490
|
+
free(buffer);
|
491
|
+
}
|
492
|
+
|
493
|
+
return 1;
|
494
|
+
}
|
495
|
+
|
496
|
+
static int superMethodClosure(lua_State *L) {
|
497
|
+
wax_instance_userdata *instanceUserdata = (wax_instance_userdata *)luaL_checkudata(L, 1, WAX_INSTANCE_METATABLE_NAME);
|
498
|
+
const char *selectorName = luaL_checkstring(L, lua_upvalueindex(1));
|
499
|
+
|
500
|
+
// If the only arg is 'self' and there is a selector with no args. USE IT!
|
501
|
+
if (lua_gettop(L) == 1 && lua_isstring(L, lua_upvalueindex(2))) {
|
502
|
+
selectorName = luaL_checkstring(L, lua_upvalueindex(2));
|
503
|
+
}
|
504
|
+
|
505
|
+
SEL selector = sel_getUid(selectorName);
|
506
|
+
|
507
|
+
// Super Swizzle
|
508
|
+
Method selfMethod = class_getInstanceMethod([instanceUserdata->instance class], selector);
|
509
|
+
Method superMethod = class_getInstanceMethod(instanceUserdata->isSuper, selector);
|
510
|
+
|
511
|
+
if (superMethod && selfMethod != superMethod) { // Super's got what you're looking for
|
512
|
+
IMP selfMethodImp = method_getImplementation(selfMethod);
|
513
|
+
IMP superMethodImp = method_getImplementation(superMethod);
|
514
|
+
method_setImplementation(selfMethod, superMethodImp);
|
515
|
+
|
516
|
+
methodClosure(L);
|
517
|
+
|
518
|
+
method_setImplementation(selfMethod, selfMethodImp); // Swap back to self's original method
|
519
|
+
}
|
520
|
+
else {
|
521
|
+
methodClosure(L);
|
522
|
+
}
|
523
|
+
|
524
|
+
return 1;
|
525
|
+
}
|
526
|
+
|
527
|
+
static int customInitMethodClosure(lua_State *L) {
|
528
|
+
wax_instance_userdata *classInstanceUserdata = (wax_instance_userdata *)luaL_checkudata(L, 1, WAX_INSTANCE_METATABLE_NAME);
|
529
|
+
wax_instance_userdata *instanceUserdata = nil;
|
530
|
+
|
531
|
+
id instance = nil;
|
532
|
+
BOOL shouldRelease = NO;
|
533
|
+
if (classInstanceUserdata->isClass) {
|
534
|
+
shouldRelease = YES;
|
535
|
+
instance = [classInstanceUserdata->instance alloc];
|
536
|
+
instanceUserdata = wax_instance_create(L, instance, NO);
|
537
|
+
lua_replace(L, 1); // replace the old userdata with the new one!
|
538
|
+
}
|
539
|
+
else {
|
540
|
+
luaL_error(L, "I WAS TOLD THIS WAS A CUSTOM INIT METHOD. BUT YOU LIED TO ME");
|
541
|
+
return -1;
|
542
|
+
}
|
543
|
+
|
544
|
+
lua_pushvalue(L, lua_upvalueindex(1)); // Grab the function!
|
545
|
+
lua_insert(L, 1); // push it up top
|
546
|
+
|
547
|
+
if (wax_pcall(L, lua_gettop(L) - 1, 1)) {
|
548
|
+
const char* errorString = lua_tostring(L, -1);
|
549
|
+
luaL_error(L, "Custom init method on '%s' failed.\n%s", class_getName([instanceUserdata->instance class]), errorString);
|
550
|
+
}
|
551
|
+
|
552
|
+
if (shouldRelease) {
|
553
|
+
[instance release];
|
554
|
+
}
|
555
|
+
|
556
|
+
if (lua_isnil(L, -1)) { // The init method returned nil... return the instanceUserdata instead
|
557
|
+
luaL_error(L, "Init method must return the self");
|
558
|
+
}
|
559
|
+
|
560
|
+
return 1;
|
561
|
+
}
|
562
|
+
|
563
|
+
#pragma mark Override Methods
|
564
|
+
#pragma mark ---------------------
|
565
|
+
|
566
|
+
static int pcallUserdata(lua_State *L, id self, SEL selector, va_list args) {
|
567
|
+
BEGIN_STACK_MODIFY(L)
|
568
|
+
|
569
|
+
if (![[NSThread currentThread] isEqual:[NSThread mainThread]]) NSLog(@"PCALLUSERDATA: OH NO SEPERATE THREAD");
|
570
|
+
|
571
|
+
// A WaxClass could have been created via objective-c (like via NSKeyUnarchiver)
|
572
|
+
// In this case, no lua object was ever associated with it, so we've got to
|
573
|
+
// create one.
|
574
|
+
if (wax_instance_isWaxClass(self)) {
|
575
|
+
BOOL isClass = self == [self class];
|
576
|
+
wax_instance_create(L, self, isClass); // If it already exists, then it will just return without doing anything
|
577
|
+
lua_pop(L, 1); // Pops userdata off
|
578
|
+
}
|
579
|
+
|
580
|
+
// Find the function... could be in the object or in the class
|
581
|
+
if (!wax_instance_pushFunction(L, self, selector)) {
|
582
|
+
lua_pushfstring(L, "Could not find function named \"%s\" associated with object %s(%p).(It may have been released by the GC)", selector, class_getName([self class]), self);
|
583
|
+
goto error; // function not found in userdata...
|
584
|
+
}
|
585
|
+
|
586
|
+
// Push userdata as the first argument
|
587
|
+
wax_fromInstance(L, self);
|
588
|
+
if (lua_isnil(L, -1)) {
|
589
|
+
lua_pushfstring(L, "Could not convert '%s' into lua", class_getName([self class]));
|
590
|
+
goto error;
|
591
|
+
}
|
592
|
+
|
593
|
+
NSMethodSignature *signature = [self methodSignatureForSelector:selector];
|
594
|
+
int nargs = [signature numberOfArguments] - 1; // Don't send in the _cmd argument, only self
|
595
|
+
int nresults = [signature methodReturnLength] ? 1 : 0;
|
596
|
+
|
597
|
+
for (int i = 2; i < [signature numberOfArguments]; i++) { // start at 2 because to skip the automatic self and _cmd arugments
|
598
|
+
const char *type = [signature getArgumentTypeAtIndex:i];
|
599
|
+
int size = wax_fromObjc(L, type, args);
|
600
|
+
args += size; // HACK! Since va_arg requires static type, I manually increment the args
|
601
|
+
}
|
602
|
+
|
603
|
+
if (wax_pcall(L, nargs, nresults)) { // Userdata will allways be the first object sent to the function
|
604
|
+
goto error;
|
605
|
+
}
|
606
|
+
|
607
|
+
END_STACK_MODIFY(L, nresults)
|
608
|
+
return nresults;
|
609
|
+
|
610
|
+
error:
|
611
|
+
END_STACK_MODIFY(L, 1)
|
612
|
+
return -1;
|
613
|
+
}
|
614
|
+
|
615
|
+
#define WAX_METHOD_NAME(_type_) wax_##_type_##_call
|
616
|
+
|
617
|
+
#define WAX_METHOD(_type_) \
|
618
|
+
static _type_ WAX_METHOD_NAME(_type_)(id self, SEL _cmd, ...) { \
|
619
|
+
va_list args; \
|
620
|
+
va_start(args, _cmd); \
|
621
|
+
va_list args_copy; \
|
622
|
+
va_copy(args_copy, args); \
|
623
|
+
/* Grab the static L... this is a hack */ \
|
624
|
+
lua_State *L = wax_currentLuaState(); \
|
625
|
+
BEGIN_STACK_MODIFY(L); \
|
626
|
+
int result = pcallUserdata(L, self, _cmd, args_copy); \
|
627
|
+
va_end(args_copy); \
|
628
|
+
va_end(args); \
|
629
|
+
if (result == -1) { \
|
630
|
+
luaL_error(L, "Error calling '%s' on '%s'\n%s", _cmd, [[self description] UTF8String], lua_tostring(L, -1)); \
|
631
|
+
} \
|
632
|
+
else if (result == 0) { \
|
633
|
+
_type_ returnValue; \
|
634
|
+
bzero(&returnValue, sizeof(_type_)); \
|
635
|
+
END_STACK_MODIFY(L, 0) \
|
636
|
+
return returnValue; \
|
637
|
+
} \
|
638
|
+
\
|
639
|
+
NSMethodSignature *signature = [self methodSignatureForSelector:_cmd]; \
|
640
|
+
_type_ *pReturnValue = (_type_ *)wax_copyToObjc(L, [signature methodReturnType], -1, nil); \
|
641
|
+
_type_ returnValue = *pReturnValue; \
|
642
|
+
free(pReturnValue); \
|
643
|
+
END_STACK_MODIFY(L, 0) \
|
644
|
+
return returnValue; \
|
645
|
+
}
|
646
|
+
|
647
|
+
typedef struct _buffer_16 {char b[16];} buffer_16;
|
648
|
+
|
649
|
+
WAX_METHOD(buffer_16)
|
650
|
+
WAX_METHOD(id)
|
651
|
+
WAX_METHOD(int)
|
652
|
+
WAX_METHOD(long)
|
653
|
+
WAX_METHOD(float)
|
654
|
+
WAX_METHOD(BOOL)
|
655
|
+
|
656
|
+
// Only allow classes to do this
|
657
|
+
static BOOL overrideMethod(lua_State *L, wax_instance_userdata *instanceUserdata) {
|
658
|
+
BEGIN_STACK_MODIFY(L);
|
659
|
+
BOOL success = NO;
|
660
|
+
const char *methodName = lua_tostring(L, 2);
|
661
|
+
|
662
|
+
SEL foundSelectors[2] = {nil, nil};
|
663
|
+
wax_selectorForInstance(instanceUserdata, foundSelectors, methodName, YES);
|
664
|
+
SEL selector = foundSelectors[0];
|
665
|
+
if (foundSelectors[1]) {
|
666
|
+
//NSLog(@"Found two selectors that match %s. Defaulting to %s over %s", methodName, foundSelectors[0], foundSelectors[1]);
|
667
|
+
}
|
668
|
+
|
669
|
+
Class klass = [instanceUserdata->instance class];
|
670
|
+
|
671
|
+
char *typeDescription = nil;
|
672
|
+
char *returnType = nil;
|
673
|
+
|
674
|
+
Method method = class_getInstanceMethod(klass, selector);
|
675
|
+
|
676
|
+
if (method) { // Is method defined in the superclass?
|
677
|
+
typeDescription = (char *)method_getTypeEncoding(method);
|
678
|
+
returnType = method_copyReturnType(method);
|
679
|
+
}
|
680
|
+
else { // Is this method implementing a protocol?
|
681
|
+
Class currentClass = klass;
|
682
|
+
|
683
|
+
while (!returnType && [currentClass superclass] != [currentClass class]) { // Walk up the object heirarchy
|
684
|
+
uint count;
|
685
|
+
Protocol **protocols = class_copyProtocolList(currentClass, &count);
|
686
|
+
|
687
|
+
SEL possibleSelectors[2];
|
688
|
+
wax_selectorsForName(methodName, possibleSelectors);
|
689
|
+
|
690
|
+
for (int i = 0; !returnType && i < count; i++) {
|
691
|
+
Protocol *protocol = protocols[i];
|
692
|
+
struct objc_method_description m_description;
|
693
|
+
|
694
|
+
for (int j = 0; !returnType && j < 2; j++) {
|
695
|
+
selector = possibleSelectors[j];
|
696
|
+
if (!selector) continue; // There may be only one acceptable selector sent back
|
697
|
+
|
698
|
+
m_description = protocol_getMethodDescription(protocol, selector, YES, YES);
|
699
|
+
if (!m_description.name) m_description = protocol_getMethodDescription(protocol, selector, NO, YES); // Check if it is not a "required" method
|
700
|
+
|
701
|
+
if (m_description.name) {
|
702
|
+
typeDescription = m_description.types;
|
703
|
+
returnType = method_copyReturnType((Method)&m_description);
|
704
|
+
}
|
705
|
+
}
|
706
|
+
}
|
707
|
+
|
708
|
+
free(protocols);
|
709
|
+
|
710
|
+
currentClass = [currentClass superclass];
|
711
|
+
}
|
712
|
+
}
|
713
|
+
|
714
|
+
if (returnType) { // Matching method found! Create an Obj-C method on the
|
715
|
+
if (!instanceUserdata->isClass) {
|
716
|
+
luaL_error(L, "Trying to override method '%s' on an instance. You can only override classes", methodName);
|
717
|
+
}
|
718
|
+
|
719
|
+
const char *simplifiedReturnType = wax_removeProtocolEncodings(returnType);
|
720
|
+
IMP imp;
|
721
|
+
switch (simplifiedReturnType[0]) {
|
722
|
+
case WAX_TYPE_VOID:
|
723
|
+
case WAX_TYPE_ID:
|
724
|
+
imp = (IMP)WAX_METHOD_NAME(id);
|
725
|
+
break;
|
726
|
+
|
727
|
+
case WAX_TYPE_CHAR:
|
728
|
+
case WAX_TYPE_INT:
|
729
|
+
case WAX_TYPE_SHORT:
|
730
|
+
case WAX_TYPE_UNSIGNED_CHAR:
|
731
|
+
case WAX_TYPE_UNSIGNED_INT:
|
732
|
+
case WAX_TYPE_UNSIGNED_SHORT:
|
733
|
+
imp = (IMP)WAX_METHOD_NAME(int);
|
734
|
+
break;
|
735
|
+
|
736
|
+
case WAX_TYPE_LONG:
|
737
|
+
case WAX_TYPE_LONG_LONG:
|
738
|
+
case WAX_TYPE_UNSIGNED_LONG:
|
739
|
+
case WAX_TYPE_UNSIGNED_LONG_LONG:
|
740
|
+
imp = (IMP)WAX_METHOD_NAME(long);
|
741
|
+
break;
|
742
|
+
|
743
|
+
case WAX_TYPE_FLOAT:
|
744
|
+
imp = (IMP)WAX_METHOD_NAME(float);
|
745
|
+
break;
|
746
|
+
|
747
|
+
case WAX_TYPE_C99_BOOL:
|
748
|
+
imp = (IMP)WAX_METHOD_NAME(BOOL);
|
749
|
+
break;
|
750
|
+
|
751
|
+
case WAX_TYPE_STRUCT: {
|
752
|
+
int size = wax_sizeOfTypeDescription(simplifiedReturnType);
|
753
|
+
switch (size) {
|
754
|
+
case 16:
|
755
|
+
imp = (IMP)WAX_METHOD_NAME(buffer_16);
|
756
|
+
break;
|
757
|
+
default:
|
758
|
+
luaL_error(L, "Trying to override a method that has a struct return type of size '%d'. There is no implementation for this size yet.", size);
|
759
|
+
return NO;
|
760
|
+
break;
|
761
|
+
}
|
762
|
+
break;
|
763
|
+
}
|
764
|
+
|
765
|
+
default:
|
766
|
+
luaL_error(L, "Can't override method with return type %s", simplifiedReturnType);
|
767
|
+
return NO;
|
768
|
+
break;
|
769
|
+
}
|
770
|
+
|
771
|
+
id metaclass = objc_getMetaClass(object_getClassName(klass));
|
772
|
+
success = class_addMethod(klass, selector, imp, typeDescription) && class_addMethod(metaclass, selector, imp, typeDescription);
|
773
|
+
|
774
|
+
if (returnType) free(returnType);
|
775
|
+
}
|
776
|
+
else {
|
777
|
+
SEL possibleSelectors[2];
|
778
|
+
wax_selectorsForName(methodName, possibleSelectors);
|
779
|
+
|
780
|
+
success = YES;
|
781
|
+
for (int i = 0; i < 2; i++) {
|
782
|
+
selector = possibleSelectors[i];
|
783
|
+
if (!selector) continue; // There may be only one acceptable selector sent back
|
784
|
+
|
785
|
+
int argCount = 0;
|
786
|
+
char *match = (char *)sel_getName(selector);
|
787
|
+
while ((match = strchr(match, ':'))) {
|
788
|
+
match += 1; // Skip past the matched char
|
789
|
+
argCount++;
|
790
|
+
}
|
791
|
+
|
792
|
+
size_t typeDescriptionSize = 3 + argCount;
|
793
|
+
typeDescription = calloc(typeDescriptionSize + 1, sizeof(char));
|
794
|
+
memset(typeDescription, '@', typeDescriptionSize);
|
795
|
+
typeDescription[2] = ':'; // Never forget _cmd!
|
796
|
+
|
797
|
+
IMP imp = (IMP)WAX_METHOD_NAME(id);
|
798
|
+
id metaclass = objc_getMetaClass(object_getClassName(klass));
|
799
|
+
|
800
|
+
success = success &&
|
801
|
+
class_addMethod(klass, possibleSelectors[i], imp, typeDescription) &&
|
802
|
+
class_addMethod(metaclass, possibleSelectors[i], imp, typeDescription);
|
803
|
+
|
804
|
+
free(typeDescription);
|
805
|
+
}
|
806
|
+
}
|
807
|
+
|
808
|
+
END_STACK_MODIFY(L, 1)
|
809
|
+
return success;
|
810
|
+
}
|