candle 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}
|